目录
SpringMVC
为什么出现了SpringMVC?
因为servlet处理请求和数据的时候,存在的问题是一个servlet只能处理一个请求 针对web层进行了优化,采用了MVC设计模式,将其设计为controller、view和Model’
什么是SpringMVC?
SpringMVC是一种基于Java实现MVC模型的轻量级Web框架
优点是使用简单、开发便捷(相比于Servlet) 灵活性强
简单使用
1 依赖引入
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> //解决冲突的问题 <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
2 建立基本目录
目录如下
3 新建SpringMVC配置类
package com.learn.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.learn.controller") public class SpringMVCConfig { }
4 新建web.xml配置类(用于替换web.xml)
package com.learn.config; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer; public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { //加载springmvc配置类 protected WebApplicationContext createServletApplicationContext() { //初始化WebApplicationContext对象 AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); //加载指定配置类 ctx.register(SpringMVCConfig.class); return ctx; } //设置由springmvc控制器处理的请求映射路径 protected String[] getServletMappings() { return new String[]{"/"}; } //加载spring配置类 protected WebApplicationContext createRootApplicationContext() { return null; } }
5 新建控制器
package com.learn.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController { //浏览器请求的路径 @RequestMapping("/save") //标识发送的数据为JSON格式 @ResponseBody public String save(){ System.out.println("user save ..."); return "{'info':'springmvc'}"; } }
6 最终目录
7 配置web服务器
添加webapp框架
配置工件
配置服务器
8 启动调试
相关知识点
SpringMVC是基于Spring的,在pom.xml只导入了spring-webmvc jar包的原因是它会自动依赖 spring相关坐标 AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器 的抽象类 AbstractDispatcherServletInitializer提供了三个接口方法供用户实现 createServletApplicationContext方法,创建Servlet容器时,加载SpringMVC对应 的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用 范围为ServletContext范围,即整个web容器范围 getServletMappings方法,设定SpringMVC对应的请求映射路径,即SpringMVC拦截哪些 请求 createRootApplicationContext方法,如果创建Servlet容器时需要加载非SpringMVC 对应的bean,使用当前方法进行,使用方式和createServletApplicationContext相同。 createServletApplicationContext用来加载SpringMVC环境 createRootApplicationContext用来加载Spring环境
@RequestMapping
SpringMVC控制器类或方法定义上方
设置当前控制器方法请求访问路径
@ResponseBody
SpringMVC控制器类或方法定义上方
设置当前控制器方法响应内容为当前返回值,无需解析
SpringMVC工作流程
1. 发送请求http://localhost/save 2. web容器发现该请求满足SpringMVC拦截规则,将请求交给SpringMVC处理 3. 解析请求路径/save 4. 由/save匹配执行对应的方法save() 上面的第五步已经将请求路径和方法建立了对应关系,通过/save就能找到对应的save方法 5. 执行save() 6. 检测到有@ResponseBody直接将save()方法的返回值作为响应体返回给请求方
设置bean加载控制
1 修改Spring配置类,设定扫描范围为精准范围。
2 修改Spring配置类,设定扫描范围为com.itheima,排除掉controller包中的bean
@Configuration @ComponentScan(value="com.itheima", excludeFilters=@ComponentScan.Filter( type = FilterType.ANNOTATION, classes = Controller.class ) ) public class SpringConfig { }
excludeFilters属性:设置扫描加载bean时,排除的过滤规则 type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除 ANNOTATION:按照注解排除 ASSIGNABLE_TYPE:按照指定的类型过滤 ASPECTJ:按照Aspectj表达式排除,基本上不会用 REGEX:按照正则表达式排除 CUSTOM:按照自定义规则排除 大家只需要知道第一种ANNOTATION即可 classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
在服务器启动时加载SpringConfig
1 更改ServletContainersInitConfig 配置类
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } protected String[] getServletMappings() { return new String[]{"/"}; } protected WebApplicationContext createRootApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringConfig.class); return ctx; } } 1
2 ServletContainersInitConfig 的内容替换成如下
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } }
后台接受五种类型参数传递
普通参数
public String commonParam(@RequestParam("name") String name, int age) { System.out.println("普通参数传递 name ==> "+name); System.out.println("普通参数传递 age ==> "+age); return "{'module':"+name+"}"; }
POJO类型参数
//POJO类型的参数,直接使用实体类接受,但是注意,实体类中的字段必须和参数名相同 public String commonParam(User user) { System.out.println("普通参数传递 name ==> "+user.getName()); System.out.println("普通参数传递 age ==> "+user.getAge()); return "{'module':"+user.getName()+"}"; }
嵌套POJO类型参数
实体
public class Ts { User user; Address address; }
//POJO类型的嵌套参数,直接使用实体类接受,但是注意,实体类中的字段必须和参数名相同 public String commonParam(Ts ts) { System.out.println("普通参数传递 name ==> "+ts.getUser().getName()); System.out.println("普通参数传递 age ==> "+ts.getUser().getAge()); return "{'module':"+ts.getUser().getName()+"}"; }
请求写法
数组类型参数
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中 public void commonParam(String[] array) { System.out.println(Arrays.toString(array)); }
请求参数的名,必须要和后台的数组名相同
集合类型参数
public String listParam(@RequestParam List<String> likes){ System.out.println("集合参数传递 likes ==> "+ likes); return "{'module':'list param'}"; }
请求参数的名,必须要和后台的集合名相同
JSON传输参数
SpringMVC接收JSON数据的实现步骤为:
(1)导入jackson包
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>
(2)使用PostMan发送JSON数据
(3)开启SpringMVC注解驱动,在配置类上添加@EnableWebMvc注解
@EnableWebMvc @RequestMapping("/listPojoParamForJson") @ResponseBody public String listPojoParamForJson(@RequestBody List<User> list){ System.out.println("list pojo(json)参数传递 list ==> "+list); return "{'module':'list pojo for json param'}"; }
(4)Controller方法的参数前添加@RequestBody注解
@RequestParam与@RequestBody的区别:
@RequestParam用于接收url地址传参,表单传参【application/x-www-formurlencoded】 @RequestBody用于接收json数据【application/json】 @RequestMapping("/listPojoParamForJson") @ResponseBody public String listPojoParamForJson(@RequestBody List list){ System.out.println("list pojo(json)参数传递 list ==> "+list); return "{'module':'list pojo for json param'}"; } 应用 后期开发中,发送json格式数据为主,@RequestBody应用较广 如果发送非json格式数据,选用@RequestParam接收请求参数
时间类型参数
如果格式不一致,需要我们使用@DateTimeFormat来进行格式化
@RequestMapping("/dataParam") @ResponseBody public String dataParam(Date date, @DateTimeFormat(pattern="yyyy-MM-dd") Date date1, @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2) System.out.println("参数传递 date ==> "+date); System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1); System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2); return "{'module':'data param'}"; }
响应
controller在接受请求后可以转发给service,从而获得一些响应内容,我们需要把他们返回给前台
@EnableWebMvc @Controller public class UserController { @RequestMapping("/toJsonList") @ResponseBody public List<User> toJsonList(){ System.out.println("返回json集合数据"); User user1 = new User(); user1.setName("传智播客"); user1.setAge(15); User user2 = new User(); user2.setName("黑马程序员"); user2.setAge(12); List<User> userList = new ArrayList<User>(); userList.add(user1); userList.add(user2); return userList; } }
返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖 @ResponseBody注解和@EnableWebMvc注解
返回jsp页面
@Controller public class UserController { @RequestMapping("/toJumpPage") //注意 //1.此处不能添加@ResponseBody,如果加了该注入,会直接将page.jsp当字符串返回前端 //2.方法需要返回String public String toJumpPage(){ System.out.println("跳转页面"); return "page.jsp"; } }
返回纯文本
@Controller public class UserController { @RequestMapping("/toText") //注意此处该注解就不能省略,如果省略了,会把response text当前页面名称去查找,如果没有 回报404错误 @ResponseBody public String toText(){ System.out.println("返回纯文本数据"); return "response text"; } }
REST风格
描述
rest:表现形式状态转换,它是一种软件架构风格
当我们想表示一个网络资源的时候,可以使用两种方式:
传统风格资源描述形式
http://localhost/user/getById?id=1 查询id为1的用户信息
http://localhost/user/saveUser 保存用户信息
REST风格描述形式
http://localhost/user/1
http://localhost/user
传统方式一般是一个请求url对应一种操作,这样做不仅麻烦,也不安全,因为会程序的人读取了你的
请求url地址,就大概知道该url实现的是一个什么样的操作。
查看REST风格的描述,你会发现请求地址变的简单了,并且光看请求URL并不是很能猜出来该URL的
具体功能
所以REST的优点有:
隐藏资源的访问行为,无法通过地址得知对资源是何种操作
书写简化根据REST风格对资源进行访问称为RESTful
RESTful入门
新建以下目录
其中配置文件可看(就在文章的下面)--》IDEA SpringMVC配置详情《---
实体类
public class Book {private String name; private double price;} public class User { private String name; private int age; }
控制器
@RestController @RequestMapping("/books") public class BookController { @Autowired private BookService bookService; @PostMapping public Result save(@RequestBody Book book) { boolean b = bookService.save(book); return new Result(b?Code.SAVE_OK:Code.SAVE_ERR); } @PutMapping public Result update(@RequestBody Book book) { boolean b = bookService.update(book); return new Result(b?Code.UPDATE_OK:Code.UPDATE_ERR); } }
统一异常处理
新建Code类用于记录状态码
package com.learn.entity; public class Code { public static final Integer SAVE_OK = 20011; public static final Integer DELETE_OK = 20021; public static final Integer UPDATE_OK = 20031; public static final Integer GET_OK = 20041; public static final Integer SAVE_ERR = 20010; public static final Integer DELETE_ERR = 20020; public static final Integer UPDATE_ERR = 20030; public static final Integer GET_ERR = 20040; //异常处理状态码 public static final Integer SYSTEM_ERR = 50001; public static final Integer SYSTEM_TIMEOUT_ERR = 50002; public static final Integer SYSTEM_UNKNOW_ERR = 59999; public static final Integer BUSINESS_ERR = 60002; }
新建异常处理类
package com.learn.exception; //让自定义异常类继承RuntimeException的好处是,后期在抛出这两个异常的时候,就不用在 //try...catch...或throws了 //自定义异常类中添加code属性的原因是为了更好的区分异常是来自哪个业务的 public class BusinessException extends RuntimeException{ private Integer code; public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public BusinessException(Integer code, String message) { super(message); this.code = code; } public BusinessException(Integer code, String message, Throwable cause) { // 这里的super直接传到了Throwable类的身上 super(message, cause); this.code = code; } }
package com.learn.exception; public class SystemException extends RuntimeException{ private Integer code; public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public SystemException(Integer code, String message) { super(message); this.code = code; } public SystemException(Integer code, String message, Throwable cause) { super(message, cause); this.code = code; } }
新建异常处理器
package com.learn.exception; import com.learn.entity.Code; import com.learn.entity.Result; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice public class ProjectExceptionAdvice { //@ExceptionHandler用于设置当前处理器类对应的异常类型 @ExceptionHandler(SystemException.class) public Result doSystemException(SystemException ex){ //记录日志 //发送消息给运维 //发送邮件给开发人员,ex对象发送给开发人员 return new Result(null,ex.getCode(),ex.getMessage()); } @ExceptionHandler(BusinessException.class) public Result doBusinessException(BusinessException ex){ return new Result(null,ex.getCode(),ex.getMessage()); } //除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常 @ExceptionHandler(Exception.class) public Result doOtherException(Exception ex){ //记录日志 //发送消息给运维 //发送邮件给开发人员,ex对象发送给开发人员 return new Result(null,Code.SYSTEM_UNKNOW_ERR,"系统繁忙,请稍后再试!"); } }
模拟异常
@DeleteMapping("/{id}") public Result delete(@PathVariable Integer id) { if(id==1) { //抛出异常后下面的delete程序就不会再执行了 throw new BusinessException(Code.BUSINESS_ERR,"有人想干掉管理员!",new Throwable()); } boolean b = bookService.delete(id); return new Result(b?Code.DELETE_OK:Code.DELETE_ERR); }
结果
拦截器
(1)浏览器发送一个请求会先到Tomcat的web服务器
(2)Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源
(3)如果是静态资源,会直接到Tomcat的项目部署目录下去直接访问
(4)如果是动态资源,就需要交给项目的后台代码进行处理
(5)在找到具体的方法之前,我们可以去配置过滤器(可以配置多个),按照顺序进行执行
(6)然后进入到到中央处理器(SpringMVC中的内容),SpringMVC会根据配置的规则进行拦截
(7)如果满足规则,则进行处理,找到其对应的controller类中的方法进行执行,完成后返回结果
(8)如果不满足规则,则不进行处理
(9)这个时候,如果我们需要在每个Controller方法执行的前后添加业务,具体该如何来实现?
这个就是拦截器要做的事。
拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法
的执行
作用:
在指定的方法调用前后执行预先设定的代码
阻止原始方法的执行
总结:拦截器就是用来做增强使用
新建拦截器ProjectInterceptor
package com.learn.interceptor; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class ProjectInterceptor implements HandlerInterceptor { @Override //原始方法调用前执行的内容 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle..."); //获取请求头 String header = request.getHeader("Content-Type"); System.out.println("请求头为:"+header); HandlerMethod method=(HandlerMethod)handler; System.out.println("执行的方法是:"+method.getMethod().getName()); //如果返回为fasle则此拦截器中的方法将不再执行 return true; } @Override //原始方法调用后执行的内容 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle..."); HandlerMethod method=(HandlerMethod)handler; System.out.println("执行的方法是:"+method.getMethod().getName()); } @Override //原始方法调用完成后执行的内容 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion..."); HandlerMethod method=(HandlerMethod)handler; System.out.println("执行的方法是:"+method.getMethod().getName()); } }
在springmvc中配置拦截器
<!-- 拦截器配置--> <!-- 配置拦截器 --> <mvc:interceptors> <!-- 配置一个全局拦截器,拦截所有请求 --> <bean class="com.learn.interceptor.ProjectInterceptor" /> <mvc:interceptor> <!-- 配置拦截器作用的路径 --> <mvc:mapping path="/**" /> <!-- 配置不需要拦截作用的路径 --> <mvc:exclude-mapping path="/a" /> <!-- 定义<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 --> <bean class="com.learn.interceptor.ProjectInterceptor" /> </mvc:interceptor> <mvc:interceptor> <!-- 配置拦截器作用的路径 --> <mvc:mapping path="/gotoTest" /> <!-- 定义在<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 --> <bean class="com.learn.interceptor.ProjectInterceptor" /> </mvc:interceptor> </mvc:interceptors>
文件上传
part方式
新建文件上传控制器
package com.learn.controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.Part; import java.util.Collection; @RestController @CrossOrigin(origins = "*", maxAge = 3600) public class FileUpdateController { // part方式单文件上传 @GetMapping("/updateImg") private String imgUpdate(HttpServletRequest request) { try { Part image = request.getPart("image"); String realPath = request.getServletContext().getRealPath("/WEB-INF/img"); image.write(realPath + image.getSubmittedFileName()); return "success"; } catch (Exception e) { System.out.println("图片上传失败"); return "fail"; } } // part方式多文件上传 @GetMapping("/updateImgs") private String imgsUpdate(HttpServletRequest request) { try { Collection<Part> requestParts = request.getParts(); //获取上传路径(web目录中的) String realPath = request.getServletContext().getRealPath("/WEB-INF/img"); requestParts.forEach(part -> { try { part.write(realPath + part.getSubmittedFileName()); } catch (Exception e) { System.out.println(part.getSubmittedFileName() + "上传出错!"); } }); return "success"; } catch (Exception e) { System.out.println("图片上传失败"); return "fail"; } } }
web.xml配置
<servlet> <!-- 配置文件上传--> <multipart-config> <!-- 单位为字节--> <!-- 单个文件大小--> <max-file-size>5242880</max-file-size> <!-- 一次请求所有文件大小--> <max-request-size>52428800</max-request-size> </multipart-config> </servlet>
Multipart方式
以下的代码可能会上传失败
依赖引入
<!-- springmvc文件上传--> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency>
springmvc.xml
<!-- 配置视图解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
编写控制器
package com.learn.controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; @RestController @CrossOrigin(origins = "*", maxAge = 3600) public class FileUpdate2Controller { @GetMapping("/fileUpdate") protected String fileUpdate(HttpServletRequest request, MultipartFile multipartFile) { try { String realPath = request.getServletContext().getRealPath("/WEB-INF/img/"); String filename = multipartFile.getOriginalFilename(); multipartFile.transferTo(new File(realPath,filename)); return "success"; } catch (Exception e) { System.out.println(e.getMessage()); return "fail"; } } }
IDEA SpringMVC配置详情
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>SSM2</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <!--spring相关的依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.10.RELEASE</version> </dependency> <!-- aspectjweaver--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> <scope>runtime</scope> </dependency> <!--Mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.2</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <!--单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--json--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency> <!-- springmvc文件上传--> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build> </project>
web.xml文件
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--需要给ContextLoaderListener指定Spring配置文件--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:Application.xml</param-value> </context-param> <!-- tomcat整合SpringMVC--> <!--SpringMVC容器,核心:DispatcherServlet--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:SpringMVC.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <!-- 配置文件上传--> <multipart-config> <!-- 单位为字节--> <!-- 单个文件大小--> <max-file-size>5242880</max-file-size> <!-- 一次请求所有文件大小--> <max-request-size>52428800</max-request-size> </multipart-config> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--Filter处理乱码--> <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> <init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <!-- Todo 注意这里如果过滤器不生效,请去掉*号--> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
Application.xml
Spring配置文件
<?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" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="com.learn"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <context:property-placeholder location="classpath:db.properties"></context:property-placeholder> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driveClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.learn.dao"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.learn.controller"/> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**" /> <bean class="com.learn.interceptor.ProjectInterceptor" /> </mvc:interceptor> </mvc:interceptors> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=utf-8</value> <value>application/json;charset=UTF-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="5242880" /> <property name="maxInMemorySize" value="4096" /> <property name="defaultEncoding" value="UTF-8"></property> </bean> <mvc:default-servlet-handler/> <mvc:cors> <mvc:mapping path="/**" /> </mvc:cors> </beans>
路径一览
纯注解方式
(返回给前台的中文可能会出现乱码)
依赖引入
<?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>SSM2</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <!--spring相关的依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.10.RELEASE</version> </dependency> <!-- aspectjweaver--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> <scope>runtime</scope> </dependency> <!--Mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.2</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <!--单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--json--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency> <!-- springmvc文件上传--> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build> </project>
ServletContainersInitConfig
package com.learn.config; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.filter.HiddenHttpMethodFilter; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import javax.servlet.Filter; public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMVCConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } protected Class<?>[] getRootConfigClasses() { return new Class[0]; } //乱码处理(只能处理后台接受到的参数乱码问题,返回给前台的json数据不会乱码) @Override protected Filter[] getServletFilters() { CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter(); encodingFilter.setEncoding("UTF-8"); encodingFilter.setForceRequestEncoding(true); HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter(); return new Filter[]{encodingFilter, hiddenHttpMethodFilter}; } }
SpringConfig
package com.learn.config; import com.learn.controller.UserController; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; @Configuration @ComponentScan(value = "com.learn",excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = UserController.class )) public class SpringConfig { }
SpringMVCConfig
package com.learn.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.learn.controller") public class SpringMVCConfig { }
注解方式返回给前台的数据乱码的解决
就是要在 @RequestMapping上加上produces = "text/html;charset=utf-8"
给个实例
package com.learn.controller; import com.learn.entity.Ts; import com.learn.entity.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Arrays; import java.util.List; @Controller public class UserController { //浏览器请求的路径 @RequestMapping(value = "/getdata",produces = "text/html;charset=utf-8") //标识发送的数据为JSON格式 @ResponseBody //如果前端传的参数和后端不一样可以使用注解,@RequestParam public String commonParam(@RequestParam("name") String name, int age) { System.out.println("普通参数传递 name ==> "+name); System.out.println("普通参数传递 age ==> "+age); return "{'module':"+name+"}"; } }