文章目录
一、springMVC 4.2.4 架构图:
1、运行流程 :
1、用户向服务器发送请求,请求被Spring 前端控制DispatcherServlet捕获。(DispatcherServlet#doDispatch)
2、前端控制器DispatcherServlet将请求交给处理器映射HandlerMapping,处理器映射依据URL进行决策,选择合适的处理器(即controller的方法)。(DispatcherServlet#getHandler)
3、将处理器 和 拦截器数组 及拦截器索引 组成一个处理器执行链返回前端控制器。
4、前端控制根据处理器找到合适的适配器 (HandlerAdapter就是执行处理器的对象)。(DispatcherServlet#getHandlerAdapter)
此时将开始执行拦截器的 preHandler(…)方法【安装配置顺序正向执行】 (mappedHandler.applyPreHandle)
5、使用HandlerAdapter执行控制层处理器方法。
提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring
将帮你做一些额外的工作:
a) HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
b) 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
c) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
d) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
6、Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。
7、此时将开始执行拦截器的 postHandle(…)方法【安装配置逆序执行】(mappedHandler.applyPostHandle)
8、根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据逻辑视图转发和重定向 以及配置的视图解析器 选择合适视图解析器。
9、据Model和View,来渲染视图(DispatcherServlet#render)。
10、渲染视图完毕执行拦截器的 afterCompletion(…)方法【逆向】。 (mappedHandler.triggerAfterCompletion)
11、将渲染结果返回给客户端
springmvc的三大组件:处理器映射器、处理器适配器、视图解析器
二、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">
<!--过滤器按照编写顺序执行,编码过滤器必须放在最前面-->
<!--配置全局乱码过滤器,解决post和get乱码-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param><!--初始化参数:即构造参数或者属性set设置-->
<!--设置request请求接收参数编码-->
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<!--设置请求和响应都设置为UTF-8-->
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--设置restFul风格PUT/delete等请求方式过滤器-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--上下文加载springMVC配置文件路径-->
<!--classpath:指src/main/java 或 resource路径;具体可查看target/项目/WEB-INFO/classes目录-->
<!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的 src/main/resources -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!-- 将启动控制DispatcherServlet的初始化时间提前到服务器启动时-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<!--设置springMVC的核心控制器所能处理的请求的请求路径,
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径,但是/不能匹配.jsp请求路径的请求
因为jsp请求需要tomcat处理(/*可匹配)-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 由于springMVC IOC容器依赖注入需要spring IOC 容器,并且由于设置了服务一启动
DispatcherServlet就初始化。一初始化就是启动springMVC IOC容器,并且spring IOC容器需要
设置spring容器为parent(调用DispatcherServlet#initWebApplicationContext就初始化SpringMVC容器),
所以使用ServletContext监听器监听DispatcherServlet初始化之前必须启动spring容器。
作用:初始化spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--Spring配置文件默认位置和名称:/WEB-INF/applicationContext.xml
可通过上下文参数自定义Spring配置文件的位置和名称-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</context-param>
</web-app>
1、url-pattern标签中使用/和/*的区别:
-
/ 所匹配的请求可以是 /login 或 .html 或 .js 或 .css 方式的请求路径,但是/不能匹配.jsp请求路径的请求,因此就可以避免在访问jsp页面时,该请求被DispatcherServlet处理,从而找不到相应的页面。
-
/* 则能够匹配所有请求,例如在使用过滤器时,若需要对所有请求进行过滤,就需要使用 /* 的写法
2、监听器 过滤器 和 servlet 执行顺序
监听器 – > 过滤器 – > servlet
3、classpath:路径
指src/main/java 或 src/main/resources 路径;具体可查看target/项目/WEB-INFO/classes目录
三、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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--组件扫描-->
<context:component-scan base-package="xiao"/>
<!--开启注解驱动:处理ajax请求/视图控制直接跳转/json数据/静态资源-->
<mvc:annotation-driven/>
<!--视图控制器,当前路径直接跳转页面不经过控制层-->
<mvc:view-controller path="/" view-name="index"/>
<!--设置默认servlet(因为tomcat容器配置了)处理静态资源,例如html、js、css、jpg
若只设置该标签,则只能访问静态资源,其他请求则无法访问此时必须设置<mvc:annotation-driven/>解决问题-->
<mvc:default-servlet-handler/>
<!-- 开启mvc注解驱动 -->
<!-- <mvc:annotation-driven>
<mvc:message-converters>
<!– 处理响应中文内容乱码 –>
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="UTF-8" />
<property name="supportedMediaTypes">
<list>
<value>text/html</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>-->
<!-- 配置Thymeleaf视图解析器 -->
<bean id="viewResolver"
class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<!--输出的编码为 UTF-8-->
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean
class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>
<!--拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="xiao.intercept.FirstIntercept"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
四、controller控制器
1、域对象有request、session、ServletContext ,这些都可以传输数据。
2、由于DispatherServlet底层就是servlet,所以依然传输数据时HttpServletReques、 HttpServletResponse,当然可以从request中获取到session和ServletContext 对象。
3、controller类中的方法接收参数类型,HttpServletRequest 、HttpServletResponse、 HttpSession、Model/ModelMap
ModelMap是Model接口的实现类使用效果一样,都会封装成ModelAndView。
4、Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的
5、控制器方法可以自动绑定参数到 实体类、数组。
1、 使用注解@controller
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import xiao.entity.Person;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Controller
public class HelloController {
@RequestMapping("/")
public String index(HttpServletRequest request){
HttpSession session = request.getSession();
return "index";
}
@RequestMapping("/hello")
public String hello(Model model){
//org.springframework.validation.support.BindingAwareModelMap
System.out.println(model.getClass().getName());
return "success";
}
//ant 风格匹配 ?:表示任意的单个字符 *:表示任意的0个或多个字符 **:表示任意层数的任意目录
@RequestMapping("/hello?")
public String helloAnt(){
return "success";
}
@GetMapping("/demo/path/{pathValue}")
public String pathVa(@PathVariable String pathValue){
System.out.println("路径参数 pathValue = " + pathValue);
return "success";
}
@GetMapping("/demo/param")
public String param(@RequestParam String param ,
@RequestHeader(value = "Referer",required = false) String referer,//获取请求头
@CookieValue("JSESSIONID") String jsessionId){//获取cookie
System.out.println("简单参数绑定 param = " + param);
System.out.println("请求头 referer = " + referer);
System.out.println("请求头cookie jsessionId = " + jsessionId);
return "success";
}
@PostMapping("/demo/entity")
public String entity(Person person){
System.out.println("实体类 entity 参数绑定 person = " + person);
return "success";
}
}
2、json交互
1、导入jackson的依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
2、SpringMVC的配置文件中设置开启mvc的注解驱动
<!--开启mvc的注解驱动-->
<mvc:annotation-driven />
3、在控制器方法的形参位置,设置json格式的请求参数要转换成的java类型(实体类或map)的参
数,并使用@RequestBody注解标识
①RequestBody
绑定在方法上,用于接收HTTP请求的json、xml格式数据通过springMVC的HttpMessageConverter转换成java对象。
②ResponseBody
将数据转换成json,反馈给客户端
// 商品修改提交json信息,响应json信息
@RequestMapping("/editItemSubmit_RequestJson")
public @ResponseBody Items editItemSubmit_RequestJson(@RequestBody Items items) throws Exception {
System.out.println(items);
return items;
}
五、视图
- SpringMVC视图的种类很多,默认有转发视图和重定向视图
- 当工程引入jstl 的依赖,转发视图会自动转换为 JstlView
- 若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视图解析器解析之后所得到的是ThymeleafView
1、 ThymeleafView
@RequestMapping("/")
public String index(HttpServletRequest request){
HttpSession session = request.getSession();
return "index";
}
指定逻辑视图名,经过视图解析器解析为html物理路径:/WEB-INF/index.html
2、 重定向视图 RedirectView
return “redirect:/hello”; //重定向到 /hello请求中,相当于response.sendRedirect()。地址发生变化,由客户端发起。产生了一对新request、response,之前的request数据丢失。
@GetMapping("/redirect")
public String testRedirectView(RedirectAttributes redirectModel){
//重定向将参数以路径拼接方式发送 /redirect?redirectValue2=重定向数据保存了
redirectModel.addAttribute("redirectValue2","重定向数据保存了==2");
//重定向将参数隐藏发送
redirectModel.addFlashAttribute("redirectValue3","重定向数据保存了==3");
//重定向视图
return "redirect:/hello";
}
@RequestMapping("/hello")
public String hello(Model model,HttpServletRequest request){
//org.springframework.validation.support.BindingAwareModelMap
System.out.println(model.getClass().getName());
System.out.println(request.getParameterMap());
//model接收addFlashAttribute从定向参数,request接收addAttribute参数
System.out.println("redirectValue3= " + model.containsAttribute("redirectValue3"));
return "success";
}
3、 转发视图 InternalResourceView
SpringMVC中默认的转发视图是InternalResourceView
转发,同一个request,并且请求的地址不变还是/forward
@GetMapping("/forward")
public String testForwardView(){
//转发视图
return "forward:/hello";
}
4、处理jsp页面转发视图 和 渲染视图 需要 InternalResourceView
由于springMVC.xml中配置了ThymeleafViewResolver 视图解析器,所以默认的视图就是 Thymeleaf 视图。
如果想要使用 jsp,就需使用 InternalResourceViewResolver 解析器。
六、文件上传和下载
文件上传和下载都是文件复制的过程,都是通过IO流将数据传输。
1、文件下载
ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文
@GetMapping("downImg/{imgName}")//下载文件
public ResponseEntity<byte[]> downImg(@PathVariable String imgName,
HttpSession session) throws IOException {
//获取应用上下文
ServletContext context = session.getServletContext();
String realPath = context.getRealPath("/img") + File.separator + imgName + ".png";
InputStream inputStream = new FileInputStream(realPath);
//available() 获取文件字节长度
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes);
//创建HttpHeaders对象设置响应头信息
MultiValueMap<String, String> headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename=" + imgName + ".png");
return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
}
2、文件上传
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency
②在SpringMVC的配置文件中添加配置:
<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>
<form th:action="@{/restFul01/uploadFile}" th:method="post" enctype="multipart/form-data">
文件:<input th:type="file" name="multipartFile">
<input th:type="submit" th:value="文件上传">
</form>
控制层 multipartFile参数必须和前端的 file的value一致,文件上传要求form表单的请求方式必须为post,并且添加属性enctype=“multipart/form-data”
@PostMapping("/uploadFile")//文件上传
public String uploadFile(MultipartFile multipartFile,HttpSession session) throws IOException {
String filename = multipartFile.getOriginalFilename();
String fileType = filename.substring(filename.lastIndexOf("."));
ServletContext context = session.getServletContext();
String realPath = context.getRealPath("upload");
File file = new File(realPath);
if(!file.exists()){
file.mkdir();
}
String filePath = realPath + File.separator + filename;
multipartFile.transferTo(new File(filePath));
return "success";
}
七、拦截器
1、SpringMVC中的拦截器需要实现HandlerInterceptor
Public class HandlerInterceptor1 implements HandlerInterceptor{
/**
* controller方法执行前调用此方法
* 返回true表示继续执行,返回false中止执行
* 这里可以加入登录校验、权限拦截等(校验用户是否有访问内容的权限)
*/
@Override
Public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
Return false;
}
/**
* controller方法执行后但未返回视图前调用此方法
* 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
*/
@Override
Public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
/** controller方法执行后且视图渲染视图后调用此方法
* 这里可得到执行controller时的异常信息
* 这里可记录操作日志,资源清理等
*/
@Override
Public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:
<!--拦截器 -->
<mvc:interceptors>
<!--多个拦截器,顺序执行 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.zixue.springmvc.filter.HandlerInterceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.zixue.springmvc.filter.HandlerInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
运行流程(按顺序执行,如果前面中false,后面无法执行)
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor2..postHandle..
HandlerInterceptor1..postHandle..
HandlerInterceptor2..afterCompletion..
HandlerInterceptor1..afterCompletion..
2、拦截器 与 过滤器 的区别
浏览器 --> 过滤器 -->前端控制器DispatcherServlet --> 拦截器 --> controller的方法 --> 拦截器
filter过滤器用于资源拦截,
SpringMVC中的拦截器用于拦截控制器方法的执行
八、异常处理器
1、基于配置的异常处理
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver
HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver (默认) 和 SimpleMappingExceptionResolver
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!--
properties的键表示处理器方法执行过程中出现的异常
properties的值表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面
-->
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
<!-- exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享 -->
<property name="exceptionAttribute" value="ex"></property>
</bean>
2、基于注解的异常处理
@ControllerAdvice
public class ExceptionController {
@ExceptionHandler(ArithmeticException.class)//处理的异常
public String handleArithmeticException(Throwable ex, Model model){
model.addAttribute("ex",ex);
//跳转页面
return "error";
}
}
九、本测试使用的 index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>=========首页======</h1>
<a th:href="@{/hello}">HelloWorld</a><br/>
<a th:href="@{/error1}">异常处理跳转</a><br/>
<a href="/hello">测试绝对链接路径</a><br/>
<a th:href="@{/helloa}">测试ant风格路径</a><br/>
<a th:href="@{/demo/param(param=测试参数为中文)}">简单参数绑定 param 和 注解获取请求头、cookie信息</a><br/>
<a th:href="@{/demo/path/人品测试}">测试路径参数</a><br/>
<form th:action="@{/demo/entity}" method="post">
姓名:<input th:type="text" name="name"> <br>
年龄:<input th:type="text" name="age"> <br>
<input type="submit" value="记入">
</form>
<h1>=========测试视图======</h1>
<a th:href="@{/viewDemo/forward}">转发视图</a><br/>
<a th:href="@{/viewDemo/redirect}">重定向视图</a><br/>
<h1>=========restFul风格请求测试======</h1>
<form th:action="@{/restFul01/1}" method="post">
<input th:type="hidden" name="_method" value="put"> <br>
<input type="submit" value="put请求">
</form>
<h1>=========文件上传下载======</h1>
<a th:href="@{/restFul01/downImg/image-2022}">图片下载</a><br/>
<form th:action="@{/restFul01/uploadFile}" th:method="post" enctype="multipart/form-data">
文件:<input th:type="file" name="multipartFile">
<input th:type="submit" th:value="文件上传">
</form>
</body>
</html>