Spring MVC详解(上)

一、Spring MVC初步认识

1.1介绍

Spring MVC是Spring Framework提供的Web组件,全称是Spring Web MVC,是目前主流的实现MVC设计模式的框架,提供前端路由映射、视图解析等功能

Java Web开发者必须要掌握的技术框架

1.2MVC是什么

MVC是一种软件架构思想,把软件按照模型,视图,控制器来划分

View:视图层,指工程中的html,jsp等页面,作用是和用户进行交互,展示数据
Controler:控制层,指工程中的Servlet,作用是接收请求和响应浏览器
Model:模型层,指工程中的JavaBean,用来处理数据
JavaBean分成两类:

  • 一类称为实体类Bean:专门用来存储业务数据,比如Student,User
  • 一类称为业务处理Bean:指Servlet或Dao对象,专门用来处理业务逻辑和数据访问

流程:

  1. 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收
  2. Controller调用相应的Model层处理请求,处理完毕后结果返回到Controller
  3. Controller再根据请求处理的结果找到对应的View视图,渲染数据后最终响应给浏览器

在这里插入图片描述

Spring MVC对这套MVC流程进行封装,帮助开发者屏蔽底层细节,并且开放出相关接口供开发者调用,让MVC开发更简单方便
在这里插入图片描述

1.3 核心组件

  • DispatcherServlet:前置控制器,负责调度其他组件的执行,可以降低不同组件之间的耦合性,是整个Spring MVC的核心模块
  • Handler:处理器,完成具体的业务逻辑,相当于Servlet
  • HandlerMapping:DispatcherServlet是通过 HandlerMapping把请求映射到不同的Handler
  • HandlerInterceptor:处理器拦截器,是一个接口,如果我们需要进行一些拦截处理,可以通过实现该接口完成
  • HandlerExecutionChain:处理器执行链,包括两部分内容:Handler和HandlerInterceptor(系统会有一个默认的HandlerInterceptor,如果有额外拦截处理,可以添加拦截器进行设置)
  • HandlerAdapter:处理器适配器,Handler执行业务方法之前,需要进行一系列的操作包括表单的数据验证、数据类型转换、把表单数据封装到POJO等,这些一系列的操作都是由
  • HandlerAdapter完成,DispatcherServlet通过HandlerAdapter执行不同的Handler
  • ModelAndView:封装了模型数据和视图信息,作为Handler的处理结果,返回给DispatcherServlet
  • ViewResolver:视图解析器,DispatcherServlet通过它把逻辑视图解析为物理视图,最终把渲染的结果响应给客户端

1.4 工作流程

  1. 客户端请求被DispatcherServlet接收
  2. 根据HandlerMapping映射到Handler
  3. 生成Handler和HandlerInterceptor
  4. Handler和HandlerInterceptor以HandlerExecutionChain的形式一并返回给DispatcherServlet
    DispatcherServlet通过HandlerAdapter调用Handler的方法完成业务逻辑处理
  5. 返回一个ModelAndView对象给DispatcherServlet
  6. DispatcherServlet把获取的ModelAndView对象传给ViewResolver视图解析器,把逻辑视图解析成物理视图
  7. ViewResolver返回一个View进行视图渲染(把模型填充到视图中)
  8. DispatcherServlet把渲染后的视图响应给客户端

在这里插入图片描述

二、Spring MVC环境搭建

2.1创建maven工程,修改pom.xml加入Spring MVC的依赖

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>SpringMVC</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><name>SpringMVC Maven Webapp</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.19</version></dependency></dependencies></project>

2.2在web.xml中配置Spring MVC的DispatcherServlet

  1. 首先在项目中创建java和resources的目录
    在这里插入图片描述
  2. 在resources目录中添加springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
  1. 然后在web.xml 配置Spring MVC的DispatcherServlet
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Application</display-name><!-- 配置核心控制器 --><servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- springmvc配置文件加载路径1)默认情况下,读取WEB-INF下面的文件2)可以改为加载类路径下(resources目录),加上classpath:--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><!--DispatcherServlet对象创建时间问题1)默认情况下,第一次访问该Servlet的创建对象,意味着在这个时间才去加载springMVC.xml2)可以改变为在项目启动时候就创建该Servlet,提高用户访问体验。<load-on-startup>1</load-on-startup>数值越大,对象创建优先级越低! (数值越低,越先创建)--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><!--/ 匹配所有的请求;(不包括.jsp)--><!--/* 匹配所有的请求;(包括.jsp)--><!--*.do拦截以do结尾的请求--><url-pattern>/</url-pattern></servlet-mapping></web-app>

拦截请求其实就是说,只要是符合这个URL的请求都会进入到Spring MVC中去看看有没有对应的Handler./不会拦截.jsp的路径,但是会拦截.html等静态资源

  • DispatcherServlet是Spring MVC提供的核心控制器,这个一个Servlet程序,该Servlet程序会接收所有请求
  • 核心控制器会读取一个springmvc.xml配置,加载Spring MVC的核心配置
  • 配置/代表拦截所有请求
  • 代表在项目启动时实例化DispathcerServlet,如果没有配置,则在第一次访问Servlet时进行实例化
  1. springmvc.xml进行配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置自动扫包 --><context:component-scan base-package="com.zyh.controller"></context:component-scan><!-- 视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--给逻辑视图加上前缀和后缀 --><!--前缀--><property name="prefix" value="/"></property><!--后缀--><property name="suffix" value=".jsp"></property></bean></beans>
  1. 创建Controller控制器Handler,在里面编写接收参数,调用业务方法,返回视图页面等逻辑
@Controller
public class HelloHandler {/*** 当客户端访问index请求时* 直接自动关联到这个方法* 执行这个方法后,会返回结果* @return*/@RequestMapping("/index")public String index(){System.out.println("接收到了请求");//返回逻辑视图 逻辑视图相当于视图的别名 通过这个找到物理视图,也就是真正的视图//这里返回的只是页面的名称,不是完整的页面访问路径return "index";}
}

@Controller注解是为了让Spring IOC容器初始化时自动扫描到该Controller类;@RequestMapping是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/;方法返回的结果是视图的名称index,该名称不是完整页面路径,最终会经过视图解析器解析为完整页面路径并跳转。

  1. 配置Tomcat
    在这里插入图片描述
    在这里插入图片描述
  2. 测试
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

三、@RequestMapping注解

Spring MVC通过@RequestMapping注解把URL请求和业务方法进行映射,在控制器的类定义处以及方法定义处都可以添加@RequestMapping,在类定义处添加相当于多了一层访问路径
在这里插入图片描述
@RequestMapping常用参数:

  • value:指定URL请求的实际地址,是@RequestMapping的默认值
  • method:指定请求的method类型,包括GET、POST、PUT、DELETE等
  • params:指定request请求中必须包含的参数值,如果不包含的话,就无法调用该方法
   @RequestMapping(value = "/index",method = RequestMethod.POST,params="id")public String index(){System.out.println("接收到了请求");//返回逻辑视图 逻辑视图相当于视图的别名 通过这个找到物理视图,也就是真正的视图//注意:这里返回的只是页面名称,不是完整的页面访问路径return "index";}

四、参数绑定

在这里插入图片描述

4.1 URL风格参数绑定

params是对URL请求参数进行限制,不满足条件的URL无法访问该方法,需要在业务方法中获取URL的参数值。

  1. 在业务方法定义时声明参数列表
  2. 给参数列表添加@RequestParam注解进行绑定
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    Spring MVC可以自动完成数据类型转换,该工作是由HandlerAdapter来完成的

4.2 RESTful风格的URL参数获取

  • 传统的URL:localhost:8080/hello/index?id=1&name=tom
  • RESTful URL:localhost:8080/hello/index/1/tom
 @RequestMapping("/restful/{id}/{name}")public String restful(@PathVariable("id") Integer num, @PathVariable("name") String name){System.out.println(num+"-"+name);return "index";}

在这里插入图片描述

4.3映射Cookie

  @RequestMapping("/cookie")public String getCookie(@CookieValue("JSESSIONID") String sessionId){System.out.println(sessionId);return "index";}

在这里插入图片描述

4.4使用POJO绑定参数

Spring MVC会根据请求参数名和POJO属性名进行匹配,自动为该对象填充属性值,并且支持属性级联
首先创建实体类
在这里插入图片描述
为了方便测试,写一个addUser.jsp页面

<html>
<head><title>Title</title>
</head>
<body>
<form action="/hello/add" method="post"><table><tr><td>编号:</td><td><input type="text" name="id"></td></tr><tr><td>姓名:</td><td><input type="text" name="name"></td></tr><tr><td><input type="submit" value="提交"></td></tr></table></form></body>
</html>

然后在Handler中,编写相关方法
在这里插入图片描述
启动Tomcat服务器
在这里插入图片描述
结果发现出现乱码问题
在这里插入图片描述
为了解决这个问题,我们只需要在web.xml配置文件中配置过滤器就可以了

  <filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

在这里插入图片描述

4.5JSP页面的转发和重定向

Spring MVC默认是通过转发的形式响应JSP,可以手动进行修改

    @RequestMapping("/restful/{id}/{name}")public String restful(@PathVariable("id") Integer num, @PathVariable("name") String name){System.out.println(num+"-"+name);return "index";}

重定向:

    @RequestMapping("/restful/{id}/{name}")public String restful(@PathVariable("id") Integer num, @PathVariable("name") String name){System.out.println(num+"-"+name);return "redirect:/index.jsp";}

在这里插入图片描述
在这里插入图片描述
设置重定向的时候不能写逻辑视图,必须写明资源的物理路径,比如"rediect:/index.jsp"

转发:

    @RequestMapping("/restful/{id}/{name}")public String restful(@PathVariable("id") Integer num, @PathVariable("name") String name){System.out.println(num+"-"+name);return "forward:/index.jsp";}

五、数据绑定

  • 数据绑定:在后台业务方法中,直接获取前端HTTP请求中的参数
  • HTTP请求传输的参数都是String类型的,Handler业务方法中的参数是开发者指定的参数类型,比如int,Object,所以需要进行数据类型的转换
  • Spring MVC的HandlerAdapter组件会在执行Handler业务方法之前,完成参数的绑定,开发者直接使用即可
    在这里插入图片描述

5.1基本数据类型

@RequestMapping("/baseType")
@ResponseBody
public String baseType(int id){return "id:"+id;
}

客户端HTTP请求中必须包含id参数,否则抛出500异常,因为id不能为null
在这里插入图片描述
同时id的值必须为数值,而且必须为整数,否则抛出400异常
在这里插入图片描述

5.2包装类

 @RequestMapping("/packageType")@ResponseBodypublic String packageType(Integer id){return "id:"+id;}

如果HTPP请求中没有包含id参数,不会报错,id的值就是null,会直接返回id:null给客户端,但是如果id=a,或者id=1.2,同样会抛出404异常,因为数据类型无法转换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • value=“id”:把HTTP请求中名字为id的参数和Handler业务方法中的形参进行映射
  • required:true表示id参数必须填,false表示非必填
  • defaultValue=“0”:表示当HTTP请求中没有id参数的时候,形参的默认值是0

5.3数组类型

@RequestMapping("/arrayType")
@ResponseBody
public String arrayType(String[] names){StringBuffer buffer = new StringBuffer();for (String str:names){buffer.append(str).append(" ");}return "names:"+buffer.toString();
}

在这里插入图片描述

5.4POJO(java对象)

public class User {private Integer id;private String name;private Address address;@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", address=" + address +'}';}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
public class Address {private Integer code;private String value;public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}@Overridepublic String toString() {return "Address{" +"code=" + code +", value='" + value + '\'' +'}';}
}
<html>
<head><title>Title</title>
</head>
<body>
<form action="/hello/add" method="post"><table><tr><td>编号:</td><td><input type="text" name="id"></td></tr><tr><td>姓名:</td><td><input type="text" name="name"></td></tr><tr><td>地址编号:</td><td><input type="text" name="address.code"></td></tr><tr><td>地址信息:</td><td><input type="text" name="address.value"></td></tr><tr><td><input type="submit" value="提交"></td></tr></table></form></body>
</html>

在这里插入图片描述
我们可以在springmvc.xml中添加一个消息转换器把中文乱码解决掉
前后端转换的数据称为消息
解决响应时乱码问题,springmvc.xml中配置转换器即可
在这里插入图片描述
在这里插入图片描述

5.5 List

Spring MVC不支持List类型的直接转换,需要包装成Object

public class UserList {private List<User> userList;public List<User> getUserList() {return userList;}public void setUserList(List<User> userList) {this.userList = userList;}
}

注意:User类一定要有无参构造,否则抛出异常

@RequestMapping("/listType")
@ResponseBody
public String listType(UserList userList){StringBuffer buffer = new StringBuffer();for (User user:userList.getUserList()){buffer.append(user);}return "用户:"+buffer.toString();
}

5.6 JSON

  • JSON数据必须用JSON.stringfy()方法转换成字符串
  • contentType:"application/json;charset=UTF-8"不能省略
  • @RequestBody注解
    读取HTTP请求参数,通过SpringMVC提供的HttpMessageConverter接口把读取的参数转换为JSON、XML格式的数据,绑定到业务方法的形参
    需要使用组件结合@RequestBody注解把JSON转为JavaBean,这里使用FastJson,其优势是如果属性为空,就不会将其转为JSON
    把业务方法返回的对象,通过HttpMessageConverter接口转为指定格式的数据,JSON、XML等,响应给客户端

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/28707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue项目中实现骨架占位效果-demo

创建组件 Skeleton.vue <template><div class"skeleton"><div class"skeleton-item" v-for"n in count" :key"n"></div></div> </template><script> export default {props: {count: {ty…

Ruby语言建立Web服务器

这次选择的Web服务器是Nginx&#xff0c;Nginx非常适合处理静态资源&#xff0c;如图片、CSS和JS文件,通过减轻应用服务器的负担&#xff0c;Nginx使得Ruby on Rails应用能够更高效地运行. 安装启动Nginx服务器 sudo apt install nginx nginx -v 启动Nginx服务器&#xff1a;…

(3)图像识别yolov5—训练自定义模型

目录 1. 准备数据集 (1) 收集图像: (2) LabelImg标注图像: 2. 模型训练 3. 评估模型 4. 使用模型进行推理 5. 完整文件下载 YOLOv5 是一个用于目标检测的深度学习模型,它非常流行且易于使用。如果你想使用 YOLOv5 训练自定义的模型,以下是一个基本的步骤指南…

16.重启docker服务,容器全部退出的解决办法

重启docker服务&#xff0c;容器全部退出的解决办法 方法一&#xff1a;docker run --restartalways 表示局部的&#xff0c;也就是针对指定容器进行开启自启动容器 方法二&#xff1a;“live-restore”: true 表示全局的&#xff0c;一般不建议使用 docker server配置文件…

【漏洞复现】畅捷通T+ keyEdit SQL注入漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

Java 集合框架:LinkedList 的介绍、使用、原理与源码解析

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 014 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

AI大模型在运动项目的深度融合和在穿戴设备的实践及未来运动健康技术发展

文章目录 1. 技术架构2. 模型选择2.1 LSTM&#xff08;长短期记忆网络&#xff09;2.2 CNN&#xff08;卷积神经网络&#xff09;2.3 Transformer 3. 数据处理数据预处理 4. 实时性要求4.1 边缘计算4.2 模型优化 5. 数据隐私与安全6. 深入分析AI大模型在穿戴设备的应用和未来发…

计算机专业的未来展望

身份角度一&#xff1a;一名曾经的计算机专业学生  作为一名曾经的计算机专业学生&#xff0c;我认为计算机相关专业仍然是一个值得考虑的选择。随着科技的飞速发展&#xff0c;计算机行业的需求只会越来越高&#xff0c;因此&#xff0c;无论是在就业前景还是个人发展方面&a…

CD4069做陶瓷和晶体振荡器的试验初步

在面包板上面&#xff0c;供电5v。尝试用4069做晶体振荡器 465K&#xff0c;1M陶瓷&#xff0c;不起振 4M陶瓷&#xff0c;不起振&#xff0c;在1脚加上68pf电容后起振&#xff0c;但幅度没有后面写的10M陶瓷和17.6的晶振的幅度大 10M陶瓷&#xff0c;起振ok 16M陶瓷&#…

【面试干货】String、StringBuilder、StringBuffer 的区别

【面试干货】String、StringBuilder、StringBuffer 的区别 1、String2、StringBuffer3、StringBuilder4、性能对比5、使用建议 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java中&#xff0c;String、StringBuilder和StringBuffer是用…

Linux经典常见常用命令50条

文章目录 基础命令1. ls2. cd3. pwd4. cp5. mv6. rm7. echo8. cat9. head10. tail 系统信息与管理命令11. ps12. top13. htop14. kill15. df16. du17. uname18. hostname19. uptime20. who21. man 文件权限与所有权命令22. chmod23. chown 网络管理命令24. ping25. ifconfig26.…

MySQL面试重点-1

1. 数据库基础知识&#xff1a; DDL、DML、DQL、DCL的概念与区别&#xff1f; DDL&#xff08;数据定义语言&#xff09;&#xff1a;创建&#xff08;CREATE&#xff09;数据库中的各种对象&#xff1a;表、视图、索引等DML&#xff08;数据操纵语言&#xff09;&#xff1a…

Vue53-Todo-list案例

一、需求&#xff1a; 二、组件的划分&#xff1a;按照功能划分 组件起名&#xff0c;不要和html内置元素重名&#xff01; Vue鼓励组件名用多个单词。 三、组件化编码流程 3-1、实现静态组件 将各个组件的基本框架写好&#xff0c;并在App.vue文件中进行引入和注册。 将已有…

[Day 8] 區塊鏈與人工智能的聯動應用:理論、技術與實踐

智能合約與去中心化應用 智能合約&#xff08;Smart Contracts&#xff09;是一種基於區塊鏈技術的程式碼&#xff0c;旨在自動執行、驗證或執行合約的內容或執行條款。透過智能合約&#xff0c;合約中的各方可以在無需第三方信任的情況下進行交易&#xff0c;實現自動化、透明…

AI数据分析:集中度分析和离散度分析

在deepseek中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个Python脚本编写的任务&#xff0c;具体步骤如下&#xff1a; 读取Excel表格&#xff1a;"F:\AI自媒体内容\AI行业数据分析\toolify月榜\toolify2023年-2024年月排行榜汇总数据.xlsx&qu…

UniVue第一个版本发布说明

今天终于发布第一个版本了&#xff0c;爆肝了这么多天&#xff0c;对之前的代码优化重构&#xff0c;今天终于做完了&#xff0c;第一个版本的核心基础功能已经全部完成&#xff01; github仓库 稳定版本仓库&#xff1a;https://github.com/Avalon712/UniVue 开发版本仓库&…

196. 删除重复的电子邮箱

196. 删除重复的电子邮箱 题目链接&#xff1a;196. 删除重复的电子邮箱 代码如下&#xff1a; # Write your MySQL query statement below delete from Person as p where p.id not in(select e.id from (select min(id) as idfrom Person group by email ) as e )

(二十一)Java 之多态

目录 一. 前言 二. 多态 2.1. 实例入手 2.2. 虚方法 三. 多态的实现方式 四. 课后习题 一. 前言 多态是同一个行为具有多个不同表现形式或形态的能力。 多态性是对象多种表现形式的体现。 比如我们说“宠物”这个对象&#xff0c;它就有很多不同的表达或实现&#xff0c;…

web前端五行属性:深入探索与实战解析

web前端五行属性&#xff1a;深入探索与实战解析 在Web前端开发中&#xff0c;五行属性这一概念或许听起来有些陌生。然而&#xff0c;如果我们将其与前端开发的核心理念相结合&#xff0c;就能发现其中蕴含的深刻内涵。本文将从四个方面、五个方面、六个方面和七个方面&#…

QT图片转PNG项目实战(含源码)

一、需求说明 最近在换工作,都需要将所有的图片,例如身份证、毕业证等信息都需要合并到一个pdf中。找了软件发现几乎都需要收费,干脆就自己写一个好了。 功能说明如下: 支持鼠标拖动加载图片,可以从桌面将图片类型的文件拖到软件中,一次最多添加150张。支持点击菜单中的…