一.创建SpringMVC步骤
1. 创建web项目,导入SpringMVC相关坐标
<packaging>war</packaging> <dependencies> <!--springMVC坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.5.RELEASE</version> </dependency> <!--servlet坐标--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--jsp坐标--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>compile</scope> </dependency> </dependencies> |
2. 配置SpringMVC前端控制器 DispathcerServlet(注:也就是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"> <!--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:spring-mvc.xml</param-value> </init-param> <!--在应用启动时,就完成servlet的实例化及初始化操作--> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <!--/会匹配到所有的访问路径,但是不会匹配到像*.jsp这样的方法url /login /add /update /a.jsp--> <!--/和/*的区别--> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> |
3. 配置SpringMVC核心文件spring-mvc.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--配置注解扫描--> <context:component-scan base-package="com.yang.controller"/> </beans> |
4. 编写Controller类和视图页面
UserController.java
public class UserController{ public String quick(){ System.out.println("quick running....."); return "/WEB-INF/pages/success.jsp"; } } |
/WEB-INF/pages/ success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>success</title> </head> <body> <h3>请求成功!</h3> </body> </html> |
5. 也可以使用注解配置Controller类中业务方法的映射地址
@Controller public class UserController { @RequestMapping("/quick") public String quick() { System.out.println("quick running....."); return "/WEB-INF/pages/success.jsp"; } } |
二.SpringMVC的执行流程
1. 用户发送请求至前端控制器DispatcherServlet。 2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。 3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如 果有则生成)一并返回给DispatcherServlet。 4. DispatcherServlet调用HandlerAdapter处理器适配器。 5. HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。 6. Controller执行完成返回ModelAndView。 7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。 8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器。 9. ViewReslover解析后返回具体View。 10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。 11. DispatcherServlet将渲染后的视图响应响应用户 |
三.SpringMVC组件解析
1. 前端控制器:DispatcherServlet 用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的 中心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。 2. 处理器映射器:HandlerMapping HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器 实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。 3. 处理器适配器:HandlerAdapter 通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型 的处理器进行执行。 4. 处理器:Handler【**开发者编写**】 它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。 5. 视图解析器:ViewResolver View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物 理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给 用户。 6. 视图:View 【**开发者编写**】 SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、 pdfView等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--配置注解扫描--> <context:component-scan base-package="com.yang.controller"/> <!--处理器映射器和处理器适配器功能增强--> <mvc:annotation-driven></mvc:annotation-driven> <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans> |
四.SpringMVC注解解析
@Controller
SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使用@Controller注解标注的话,就需要使用:
<!--配置注解扫描--> <context:component-scan base-package="com.yang.controller"/> |
@RequestMapping
* 作用: 用于建立请求 URL 和处理请求方法之间的对应关系 * 位置: 1.类上:请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。 它出现的目的是为了使我们的URL可以按照模块化管理: 用户模块 /user/add /user/update /user/delete ... 账户模块 /account/add /account/update /account/delete 2.方法上:请求URL的第二级访问目录,和一级目录组成一个完整的 URL 路径。 * 属性: 1.value:用于指定请求的URL。它和path属性的作用是一样的 2.method:用来限定请求的方式 3.params:用来限定请求参数的条件 例如:params={"accountName"} 表示请求参数中必须有accountName pramss={"money!100"} 表示请求参数中money不能是 |
五.SpringMVC的请求
1. 请求参数类型介绍
客户端请求参数的格式是: name=value&name=value……
服务器要获取请求的参数的时候要进行类型转换,有时还需要进行数据的封装.
SpringMVC可以接收如下类型的参数:基本类型参数,对象类型参数,数组类型参数.集合类型参数.
2. 中文乱码过滤器
post请求时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤。
<!--配置全局过滤的filter--> <filter> <filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
3.自定义类型转换器
SpringMVC 默认已经提供了一些常用的类型转换器;例如:客户端提交的字符串转换成int型进行参数设置,日期格式类型要求为:yyyy/MM/dd 不然的话会报错,对于特有的行为,SpringMVC提供了自定义类型转换器方便开发者自定义处理。
<form action="${pageContext.request.contextPath}/user/converterParam"> 生日:<input type="text" name="birthday"> <input type="submit" value="自定义类型转换器"> </form> |
public class DateConverter implements Converter<String, Date> { // s就是表单传递过来的请求参数 2012-12-12 @Override public Date convert(String s) { // 将日期字符串转换成日期对象,进行返回 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date date = null; try { date = simpleDateFormat.parse(s); } catch (ParseException e) { e.printStackTrace(); } return date; } } |
<!--处理器映射器和适配器增强--> <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation- driven> <!--自定义转换器配置--> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.yang.converter.DateConverter"></bean> </set> </property> </bean> |
@RequestMapping("/converterParam") public String converterParam(Date birthday) { System.out.println(birthday); return "success"; } |
4.相关注解
@RequestParam
当请求的参数name名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定
<a href="${pageContext.request.contextPath}/user/findByPage?pageNo=2"> 分页查询 </a> |
/* @RequestParam() 注解 ? efaultValue 设置参数默认值 ?name 匹配页面传递参数的名称 ? equired 设置是否必须传递参数,默认值为true;如果设置了默认值,值自动改为false */ @RequestMapping("/findByPage") public String findByPage(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "5") Integer pageSize) { System.out.println(pageNum); System.out.println(pageSize); return "success"; } |
@RequestHeader
获取请求头的数据。
@RequestMapping("/requestHead") public String requestHead(@RequestHeader("cookie") String cookie) { System.out.println(cookie); return "success"; } |
@CookieValue
获取cookie中的数据。
@RequestMapping("/cookieValue") public String cookieValue(@CookieValue("JSESSIONID") String jesessionId) { System.out.println(jesessionId); return "success"; } |
5. 获取Servlet相关API
SpringMVC也可以用原生的Servlet
SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:
@RequestMapping("/servletAPI") public String servletAPI(HttpServletRequest request, HttpServletResponse response, HttpSession session) { System.out.println(request); System.out.println(response); System.out.println(session); return "success"; } |
六.SpringMVC的响应
1.响应方式介绍
页面跳转
* 返回字符串逻辑视图
* void原始ServletAPI
* ModelAndView
返回数据
* 直接返回字符串数据
*将对象或集合转为json返回
2. 返回字符串逻辑视图
直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转到指定页面
@RequestMapping("/returnString") public String returnString() { return "success"; } |
3. void原始ServletAPI
我们可以通过request、response对象实现响应
@RequestMapping("/returnVoid") public void returnVoid(HttpServletRequest request, HttpServletResponse response) throws Exception { // 1.通过response直接响应数据 response.setContentType("text/html;charset=utf-8"); response.getWriter().write("阳哥"); request.setAttribute("username", 牛气冲天); // 2.通过request实现转发 request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response); // 3.通过response实现重定向 response.sendRedirect(request.getContextPath() + "/index.jsp"); } |
4.转发和重定向
forward转发: return "forward:/WEB-INF/pages/success.jsp";
redirect重定向: return "redirect:/index.jsp";
5. ModelAndView
Controller中方法创建并返回ModelAndView对象,并且设置视图名称
@RequestMapping("/returnModelAndView1") public ModelAndView returnModelAndView1() { /* Model:模型作用封装数据 ? ?View:视图作用展示数据 ?*/ ModelAndView modelAndView = new ModelAndView(); //设置模型数据 modelAndView.addObject("username", " yang"); //设置视图名称 modelAndView.setViewName("success"); return modelAndView; } |
七.静态资源访问的开启
当有静态资源需要加载时,比如jquery文件,通过谷歌开发者工具抓包发现,没有加载到jquery文件,原因是SpringMVC的前端控制器DispatcherServlet的url-pattern配置的是 /(缺省),代表对所有的静态资源都进行处理操作,这样就不会执行Tomcat内置的DefaultServlet处理,我们可以通过以下两种方式指定放行静态资源:
方式一:
<!--在springmvc配置文件中指定放行资源--> <mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/img/**" location="/img/"/> |
方式二:
<!--在springmvc配置文件中开启DefaultServlet处理静态资源--> <mvc:default-servlet-handler/> |
八.ajax异步交互
Springmvc默认用MappingJackson2HttpMessageConverter对json数据进行转换,需要加入
jackson的包;同时使用 <mvc:annotation-driven />(对应的spring-mvc.xml中配置即可)。
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.0</version> </dependency> |
1. @RequestBody
该注解用于Controller的方法的形参声明,当使用ajax提交并指定contentType为json形式时,通过HttpMessageConverter接口转换为对应的POJO对象。
<script src="${pageContext.request.contextPath}/js/jquery-3.5.1.js"></script> <%--ajax异步交互--%> <button id="btn1">ajax异步提交</button> <script> $("#btn1").click(function () { let url = '${pageContext.request.contextPath}/user/ajaxRequest'; let data = '[{"id":1,"username":"张三"},{"id":2,"username":"李四"}]'; $.ajax({ type: 'POST', url: url, data : data, contentType : 'application/json;charset=utf-8', success: function (resp) { alert(JSON.stringify(resp)); } }) }) </script>
|
@RequestMapping(value = "/ajaxRequest") public void ajaxRequest(@RequestBody List<User>list) {
System.out.println(list); } |
2. @ResponseBody
该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端。
/* @RequestMapping produces = "application/json;charset=utf-8" 响应返回数据的mime类型和编码,默认为 json */ @RequestMapping(value = "/ajaxRequest") @ResponseBody public List<User> ajaxRequest(@RequestBody List<User> list) { ?System.out.println(list); ?return list; } |
九.RESTful风格
1.什么是restful风格
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP 协议里面四个表示操作方式的动。
GET:读取(Read)
POST:新建(Create)
PUT:更新(Update)
DELETE:删除(Delete)
2.代码实现
@PathVariable
用来接收RESTful风格请求地址中占位符的值
@RestController
RESTful风格多用于前后端分离项目开发,前端通过ajax与服务器进行异步交互,我们处理器通常返
回的是json数据所以使用@RestController来替代@Controller和@ResponseBody两个注解。
// @Controller @RestController public class RestFulController { @GetMapping(value = "/user/{id}") // 相当于 @RequestMapping(value = "/user/{id}",method = RequestMethod.GET) // @ResponseBody public String get(@PathVariable Integer id) { return "get:" + id; } @PostMapping(value = "/user") // @ResponseBody public String post() { return "post"; } @PutMapping(value = "/user") // @ResponseBody public String put() { return "put"; } @DeleteMapping(value = "/user/{id}") // @ResponseBody public String delete(@PathVariable Integer id) { return "delete:"+ id; } } |
十.文件上传
1.文件上传三要素
*表单项 type="file"
*表单的提交方式 method="POST"
*表单的enctype属性是多部分表单形式 enctype=“multipart/form-data"
2.单文件上传
2.1导入fileupload和io坐标
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
2.2配置文件上传解析器
<!--文件上传解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设定文件上传的最大值为MB,*1024*1024 --> <property name="maxUploadSize" value="5242880"></property> <!-- 设定文件上传时写入内存的最大值,如果小于这个参数不会生成临时文件,默认为--> <property name="maxInMemorySize" value="40960"></property> </bean>
|
2.3编写文件上传代码
<form action="${pageContext.request.contextPath}/fileUpload" method="post" enctype="multipart/form-data"> 名称:<input type="text" name="username"> <br> 文件:<input type="file" name="filePic"> <br> <input type="submit" value="单文件上传"> </form> |
@RequestMapping("/fileUpload") public String fileUpload(String username, MultipartFile filePic) throws IOException { System.out.println(username); // 获取文件名 String originalFilename = filePic.getOriginalFilename(); //保存文件 filePic.transferTo(new File("d:/upload/"+originalFilename)); return "success"; } |
3.文件上传
<form action="${pageContext.request.contextPath}/filesUpload" method="post" enctype="multipart/form-data"> 名称:<input type="text" name="username"> <br> 文件:<input type="file" name="filePic"> <br> 文件:<input type="file" name="filePic"> <br> <input type="submit" value="多文件上传"> </form> |
@RequestMapping("/filesUpload") public String filesUpload(String username, MultipartFile[] filePic) throws IOException { System.out.println(username); for (MultipartFile multipartFile : filePic) { // 获取文件名 String originalFilename = multipartFile.getOriginalFilename(); // 保存到服务器 multipartFile.transferTo(new File("d:/upload/" + originalFilename)); } return "success"; } |
十一.异常
1.异常处理思路
第一种方式: 一种是当前方法捕获处理(try-catch),这种处理方式会造成业务代码和异常处理代码的耦合。
第二种方式: 另一种是自己不处理,而是抛给调用者处理(throws),调用者再抛给它的调用者,也就是一直向上抛。在这种方法的基础上,衍生出了SpringMVC的异常处理机制。
2.自定义异常处理器
2.1创建异常处理器类实现HandlerExceptionResolver
public class GlobalExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("error", ex.getMessage()); modelAndView.setViewName("error"); return modelAndView; } } |
2.2配置异常处理器
@Component public class GlobalExecptionResovler implements HandlerExceptionResolver {} |
bean id="globalExecptionResovler" class="com.yang.exception.GlobalExecptionResovler"></bean> |
2.3编写异常页面
2.4测试跳转到异常页面
3.web的处理异常机制
写好重用错误页面
<!--处理异常--> <error-page> <error-code>500</error-code> <location>/500.jsp</location> </error-page> <!--处理异常--> <error-page> <error-code>404</error-code> <location>/404.jsp</location> </error-page> |
十二.拦截器
1. 拦截器(interceptor)的作用
Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
2.快速入门步骤如下
2.1创建拦截器类实现HandlerInterceptor接口
public class MyInterceptor1 implements HandlerInterceptor {
/* preHandle: 在目标方法执行之前进行拦截 return false:不放行 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle1....");
return true; } /* postHandle: 在目标方法执行之后,视图对象返回之前,执行的方法 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle1...."); }
/* afterCompletion:在流程都执行完成后,执行的方法 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion1....");
} }
|
2.2配置拦截器
<!--配置拦截器--> <mvc:interceptors> <mvc:interceptor> <!--对哪些资源执行拦截操作--> <mvc:mapping path="/**"/> <bean class="com.yang.interceptor.MyInterceptor1"/> </mvc:interceptor> </mvc:interceptors> |
2.3测试拦截器的拦截效果
编写Controller,发请求到controller,跳转页面
@Controller public class TargetController { @RequestMapping("/target") public String targetMethod() { System.out.println("目标方法执行了..."); return "success"; } } |
2.4编写jsp页面测试
3.拦截器链
开发中拦截器可以单独使用,也可以同时使用多个拦截器形成一条拦截器链。开发步骤和单个拦截器是一样的,只不过注册的时候注册多个,注意这里注册的顺序就代表拦截器执行的顺序。同上,再编写一个MyHandlerInterceptor2操作。
4.拦截器方法说明总结
方法名 | 说明 |
preHandle | 方法将在请求处理之前进行调用,该方法的返回值是布尔值Boolen类型的,当它返回为false时,表示请求结束,后续的Interecptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor的preHandle方法 |
postHandle | 该方法是在当前请求进行处理后被调用,前提是preHandle方法的返回值为true时才能被调用,且它会在DisatherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView进行操作 |
afterCompletion | 该方法将在整个请求结束后,也就是在DispathcerServlet渲染了对应的视图之后执行,前提是preHandle方法的返回值为true是才能被调用 |
(注:拦截器链的postHandle,afterCompletion后链比前链早,可自行测试)