#springmvc springmvc简介 大部分java应用都是web应用,表现层是web应用最为重要的部分。Spring为表现层提供了一个优秀的web框架——SpringMVC。和众多其他web框架一样,它是基于mvc的设计理念,此外,它采用了松散耦合可插拔组件结构,比其他mvc框架更具有扩展性和灵活性。
SpringMVC通过一套MVC注解,让POJO(Plain Ordinary Java Object,简单的Java对象)成为处理请求的处理器,无需实现任何接口,同时,SpringMVC还支持REST风格的URL请求。此外,SpringMVC在数据绑定、视图解析、本地化处理以及静态资源处理上都有许多不俗的表现。
它在框架设计、扩展性、灵活性等方法全面超越的Struts、WebWork等MVC框架,从原来的追赶者一跃成为了MVC的领跑者。
SpringMVC框架围绕DispatcherServlet这个核心展开,DispatcherServlet是SpringMVC框架的总导演、总策划,它负责拦截请求并将其分派给相应的处理器。
springmvc入门 1.创建maven工程
记得添加webapp目录
2.添加打包方式和引入依赖
3.添加日志和springmvc配置文件
4.添加视图
在WEB-INF下创建一个views目录,在views目录下添加一个hello.jsp。
5.配置前端控制器
在web.xml中配置DispatcherServlet控制器:
6.创建自定义处理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Controller public class HelloController { @RequestMapping ("/show1.do" ) public ModelAndView test1 () { ModelAndView mv = new ModelAndView(); mv.setViewName("/WEB-INF/views/hello.jsp" ); mv.addObject("msg" ,"Hello Word!" ); return mv; } }
7.开启注解扫描
8.访问localhost:8080/show1.do
springmvc架构
用户发送请求至前端控制器DispatcherServlet
DispatcherServlet手动请求调用HandlerMapping处理器映射器
处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
执行处理器(Controller,也叫后端控制器)
Controller执行完成返回ModelAndView
HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
DispatcherServlet将ModelAndView传给ViewReslover视图解析器
ViewReslover解析后返回具体View
DispatcherServlet对View进行渲染视图(将模型数据填充到视图中)
DisparcherServlet响应给用户
DispatcherServlet :前端控制器
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcher是整个流程控制中心,由它调用其他组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性
HandlerMapping :处理器映射器
HandlerMapping 负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现了不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等
HandlerAdapter :处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
Handler :处理器
它就是我们开发中要编写的具体业务处理器,由DispatcherServlet把用户请求转发到Handler。由Handler对具体的用户请求进行处理
View Resolver :视图解析器
View Resolver 负责处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后掉View进行渲染将处理结果通过页面展示给用户。
View :视图
Springmvc框架提供了很多的View视图类型的支持,包括:jstlView,freemarkerView,pdfView等,我们最常用的视图就是html。一般情况下需要通过页面标签将模型数据通过页面展示给用户,需要根据业务需求开发具体页面
默认加载的组件:
我们在配置文件中只配置DispatcherServlet,缺能正常运行,说名springmvc的执行流程中需要配置映射器和适配器,而两个springmvc框架帮我们默认配置完成了,因此无需用户手动配置
在控制器DispatcherServlet中:有一行默认配置,控制器会读取该默认的资源文件DispatcherServlet.properties
1 2 3 4 5 6 7 org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
为了方便起见我们在配置文件中做出如下修改
视图解析器框架默认的InternalResourceViewResolver,该视图解析器支持jsp视图的解析
1 2 3 4 5 6 7 <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/views/" > </property > <property name ="suffix" value =".jsp" > </property > </bean >
视图名称需要在处理器的方法中使用ModelAndView进行封装后返回,如果视图名称名为hello,那么最终返回的jsp视图地址为:
“/WEB-INF/views/hello.jsp”
最终jsp的物理地址为:前缀+视图名称+后缀
小结 springmvc的使用步骤:
1.配置web.xml
配置前端控制器
tomcat启动时初始化
指定springmvc的配置文件的位置
2.编写springmvc的配置文件
开启包扫描
配置mvc注解驱动:注册各种功能,使用spring推荐的映射器和适配器和消息转化器
配置视图解析器:指定如果去查找视图
3.编写自定义处理器
将处理器装配到容器中
编写请求的url映射关系:@ResquestMapping(“xxx”):来映射要执行的方法
在@RequestMapping(“xxx”)下编写方法处理具体的业务逻辑,返回一个ModelAndView,其中可以封装视图名称和数据
#RequestMapping映射请求 1.简介
标准url映射
Ant风格的映射:(0个或多个字符)、?(单个字符)、** (0个或多个路径)
Rest风格的映射:占位符
限定请求方法的映射:get post put delete
限定参数的映射:限定那些请求参数可以访问
2.标准URL映射 @RequestMapping(value = “xxx”)
在springmvc众多Controller以及每个Controller的众多方法中,请求是如何映射到具体的处理方法上的呢?
它可以定义在方法上,也可以定义在类上.
3.Ant风格的映射(通配符) ?:通配一个字符
*:通配任意多个字符,可以是0个,可以是1个,可以是多个.但是最好和其他字符一起使用
**:通配任意多个路径
4.Rest风格(占位符)的映射 @RequestMapping(value = “hello/{name}/{id}”)
请求url:http://localhost:8080/hello/zhangsan/1001.do
注意:占位符的主要应用是用来接受url中的参数
比如:@PathVariable(“userid”) Long id , @PathVariable(“name”) String name 获取对应的参数
注意:@PathVariable(“key”) 中的key必须和对应的占位符的参数名一致,而方法形参的参数可任意取。
如果传递的参数类型和接受参数的形参类型不一致,则会自动转换,如果转换出错,(例如:id传了abc字符串,方法形参使用Long来接受参数)则会报400错误(参数列表错误 )
5.限定请求方法的映射 限定单个请求方法
@RequestMapping(value = “x”, method = RequestMethod.POST)
限定多个请求方法
@RequestMapping(value = “x”, method = {RequestMethod.POST, RequestMethod.GET})
6.限定请求参数的映射 @RequestMapping(value= “”, params= “”)
params = “userId” : 请求参数中必须带有userId
params = “!userId” : 请求参数中不能包含userId
params = “userId = 1” :请求参数中必须包含userId并且值必须为1
params = “userId ! = 1” : 请求的所有参数中如果有userId必须不为1 ,参数中可以不包含userId
params = {“userId”, “name”} :请求参数中必须有userId,name 参数
7.组合注解 @GetMapping:相当于@RequestMapping (method =RequestMethod.GET)
@PostMapping:相当于@RequestMapping(method= RequestMethod.POST)
@PutMapping:相当于@RequestMapping(method= RequestMethod.PUT)
@DeleteMapping:相当于@RequestMapping(method= RequestMethod.DELETE)
也可以在注解中限定请求参数,用法和之前的一样。
#返回值类型 1.返回值是String类型 1 2 3 4 5 6 7 @RequestMapping (value="show" )public String test (Model model) { model.addAttribute("msg" , "优化后的代码" ); return "hello" ; }
2.返回值是void类型 1 2 3 4 5 6 @RequestMapping ("show" )@ResponseStatus (value=HttpStatus.OK)public void test (Model model) { System.out.println("返回值是void" ); }
#接受数据及数据绑定
接收servlet的内置对象
接收占位符请求路径中的参数
接收普通的请求参数
获取cookie参数
基本数据类型的绑定
pojo对象绑定
集合绑定
1.接收Servlet的内置对象 1 2 3 4 5 6 @RequestMapping (value="show19" ) public String test19 (Model model, HttpServletRequest request, HttpServletResponse response, HttpSession session) { model.addAttribute("msg" , request+"<br/>" +response+"<br/>" +session); return "hello" ; }
2.接收普通的请求参数 @RequestParam(value = “”, required = true/false, defaultValue = “”)
1.value: 参数名
2.required:是否必须, 默认为true,标识请求参数中必须包含该参数,如果不包含则抛出异常
3.defaultValue:默认参数值,如果设置了该值,required = true 将失效(即使手动设置了也会失效),自动为false,如果请求中不包含该参数则使用默认值
@RequestParam和@PathVariable的区别 :
@RequestParam比@PathVariable的区别是不需要在注解中使用占位符{xxx}
不设置required属性,那么默认提交参数name,因为required默认为true
1 2 3 4 5 6 @RequestMapping (value="show20" )public String test20 (Model model,@RequestParam(value="name" ) String name) { model.addAttribute("msg" , "使用@RequestParam接收到的参数为:" +name); return "hello" ; }
只有当手动设置了required为false时,才可以不用传递参数
1 2 3 4 5 6 @RequestMapping (value="show20" )public String test20 (Model model,@RequestParam(value="name" ,required=false ) String name) { model.addAttribute("msg" , "使用@RequestParam接收到的参数为:" +name); return "hello" ; }
3.defaultValue属性 如果设置了defaultValue属性,那么表示可以不用传递参数,一旦不传递参数,就使用默认值
1 2 3 4 5 @RequestMapping (value="show20" )public String test20 (Model model,@RequestParam(value="name" ,defaultValue="lisi" ) String name) { model.addAttribute("msg" , "使用@RequestParam接收到的参数为:" +name); return "hello" ; }
一旦设置了默认值,那么required = true 就失效了,那怕手动设置required为true页没用,照样可以不传递参数
小结:只有配置了defaultValue属性,required属性就失效了
4.传统方式获取cookie 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @RequestMapping (value = "show21" )public String test21 (Model model, HttpServletRequest request) { Cookie[] cookies = request.getCookies(); if (cookies!=null ) { for (Cookie cookie : cookies) { if (cookie.getName().equalsIgnoreCase("jsessionid" )) { model.addAttribute("msg" , "jsessionid:" + cookie.getValue()); } } } return "hello" ; }
5.注解方式获取cookie 注意:@CookieValue(“JSESSION”)必须大写
1 2 3 4 5 6 @RequestMapping (value = "show22" )public String test22 (Model model, @CookieValue("JSESSIONID" ) String jsessionid) { model.addAttribute("msg" , "jsessionid:" + jsessionid); return "hello" ; }
notes:
如果是清除Chrome缓存后发送请求,此时cookie中没用数据,因此页无法在参数中使用注解获取jsession,那就会报400
此时当cookie中没有该属性时,可以设置参数非必须或者设置一个默认即可
1 2 3 4 5 6 @RequestMapping (value = "show22" )public String test22 (Model model, @CookieValue(value="JSESSIONID" ,required = false ) String jsessionid) { model.addAttribute("msg" , "jsessionid:" + jsessionid); return "hello" ; }
6.基本数据类型的绑定 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @RequestMapping ("show23" )public String test23 (Model model, @RequestParam("name" ) String name, @RequestParam ("age" ) Integer age, @RequestParam ("isMarry" ) Boolean isMarry, @RequestParam ("income" ) Float income, @RequestParam ("interests" ) String[] interests) { System.out.println(name); System.out.println(age); System.out.println(isMarry); System.out.println(income); System.out.println(Arrays.toString(interests)); return "hello" ; }
7.pojo对象的绑定 SpringMVC会将请求参数名和pojo实体类中属性名(set 方法) 进行自动匹配如果名称一致,将把值填充到对象的属性中,并且支持级联(user.dept.id)
例如:自己编写User属性,idea在生成isMarry的setter和getter方法的时候会变成setMarry而非setIsMarry,需要手动更改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class User { private String name; private Integer age; private Boolean isMarry; private Float income; private String [] interests; public String getName () { return name; } public void setName (String name) { this .name = name; } public Integer getAge () { return age; } public void setAge (Integer age) { this .age = age; } public Boolean getIsMarry () { return isMarry; } public void setIsMarry (Boolean isMarry) { this .isMarry = isMarry; } public Float getIncome () { return income; } public void setIncome (Float income) { this .income = income; } public String[] getInterests() { return interests; } public void setInterests (String[] interests) { this .interests = interests; } @Override public String toString () { return "User [name=" + name + ", age=" + age + ", isMarry=" + isMarry + ", income=" + income + ", interests=" + Arrays.toString(interests) + "]" ; } }
1 2 3 4 5 @RequestMapping (value="show24" )public String test24 (Model model,User user) { model.addAttribute("msg" ,user); return "hello" ; }
当自动讲数据封装到User对象中之后,如果还想单独获取某个或几个参数,可以单独设置形参获取。
集合的绑定
1 2 3 4 5 @RequestMapping (value="show25" )public String test25 (Model model,@RequestParam("ids" ) List<Long> ids) { model.addAttribute("msg" ,"打印参数:" +ids.toString()); return "hello" ; }
集合元素中为pojo,这个时候用一个UserVO来包装List集合:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class UserVO { private List<User> users; public List<User> getUsers () { return users; } public void setUsers (List<User> users) { this .users = users; } @Override public String toString () { return "UserVO [users=" + users + "]" ; } }
Controller方法
1 2 3 4 5 @RequestMapping (value="show26" )public String test26 (Model model,UserVO userVO) { model.addAttribute("msg" ,"打印参数:" +userVO); return "hello" ; }
#jstl标签的使用 springmvc虽然有自己的标签库,但是其使用并不方便,因此几乎没有人使用,甚至没有人知道其存在。因而一般还是使用的jstl标签。
JSTL:标准标签库
JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,SQL标签。
1 2 3 4 5 <dependency > <groupId > jstl</groupId > <artifactId > jstl</artifactId > <version > 1.2</version > </dependency >
找一个jsp页面,将其头信息复制该userList.jsp中:
1 <%@ page contentType ="text/html;charset=UTF-8" language ="java" %>
引入jstl核心标签库:
1 <%@ taglib prefix ="c" uri ="http://java.sun.com/jsp/jstl/core" %>
Json springmvc提供了一种更为简便的方式传递数据。
@ResponseBody 是把Controller方法返回值转化为JSON,称为序列化
当一个处理请求的方法标记为@ResponseBody时,表示该方法需要输出其他视图(json、xml),springmvc会通过默认的json转化器转化输出。
@RequestBody 是把接收到的JSON数据转化为Pojo对象,称为反序列化
转换json的常用方式: 1、 Gson
Google的工具,功能强大,但是效率稍逊。
2、 Fastjson
阿里的工具,效率高,但是功能稍逊。
3、 jackson
springmvc内置的转换工具,功能和效率都有不俗的表现,在世界范围内使用较广。
引入依赖 1 2 3 4 5 6 <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.9.4</version > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @RequestMapping (value="show28" )@ResponseBody public List<User> test28 () { List<User> list = new ArrayList<User>(); for (int i = 0 ;i< 20 ;i++) { User user = new User(); user.setId(i+1L ); user.setUsername("zhangsan" +i); user.setName("张三" +i); user.setAge(18 ); list.add(user); } return list; }
报错:在使用jackson转换json数据时需要消息转换器HttpMessageConverter的支持,该消息转换器默认并没有开启。
1 2 <mvc:annotation-driven > </mvc:annotation-driven >
使用pojo接收接送数据 @RequestBody:接收一个json并且转换成一个对象。 接收一个json数据并反序列化为一个user对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 @RequestMapping (value="show29" )public String test29 (Model model,@RequestBody User user) { model.addAttribute("msg" , user); return "hello" ; }
使用String接收json数据 1 2 3 4 5 @RequestMapping(value="show30") public String test30(Model model,@RequestBody String user) { model.addAttribute("msg", user); return "hello"; }
解决中文乱码问题 原因:使用的消息转换器换成了StringHttpMessageConverter,该转换器中使用的默认的编码为ISO_8859_1:
解决方案:
修改消息转换器中的编码集
将注解驱动修改如下: 1、 设置String的消息转换器 2、 该消息转换器中有一个构造函数可以设置编码集,因此只要直接赋值即可。
1 2 3 4 5 6 7 8 <mvc:annotation-driven > <mvc:message-converters > <bean class ="org.springframework.http.converter.StringHttpMessageConverter" > <constructor-arg index ="0" value ="utf-8" > </constructor-arg > </bean > </mvc:message-converters > </mvc:annotation-driven >
@RestController 有时如果在一个Contoller中所有的方法都是用来响应json格式数据的,那么如果有多个方法,就需要在多个方法上使用@ResponseBody,这样太麻烦,springmvc提供了一个@RestController,将该注解使用在Controller类上,那么该controller中的所有方法都默认是响应json格式的数据了。
#文件上传 添加依赖 1 2 3 4 5 6 <dependency > <groupId > commons-fileupload</groupId > <artifactId > commons-fileupload</artifactId > <version > 1.3.1</version > </dependency >
配置文件上传解析器 需要在springmvc的配置文件中配置一个文件上传解析器(在spring-web包下),并且设置其解析器的某些参数,如上传文件大小和编码集等。
在springmvc-servlet.xml中配置: 注意:必须配置id属性,并且名称固定为multipartResolver,否则无法使用.
1 2 3 4 5 6 7 <bean id ="multipartResolver" class ="org.springframework.web.multipart.commons.CommonsMultipartResolver" > <property name ="maxUploadSize" value ="5242880" > </property > <property name ="defaultEncoding" value ="utf-8" > </property > </bean >
defaultEncoding:用来设置上传文件名称的参数,如果不设置的话,问题如下:
保存的图片会出现乱码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @RequestMapping ("show31" )public String test31 (Model model,@RequestParam("file" ) MultipartFile file) throws Exception { if (file!=null ) { file.transferTo(new File("d://upload//" +file.getOriginalFilename())); } model.addAttribute("msg" , "上传成功!" ); return "hello" ; }
但是如果上传图片过大就会报500的错误
如此的话,用户体验不好,我们应该自定义一个错误页面来告诉用户,哪里出问题了。 这是有一个处理器异常解析器抛出的错误,在请求到达我们自定义的Controller之前就抛出了异常。
自定义一个处理器异常解析器: 1、自定义处理器异常解析器实现HandlerExceptionResolver
2、 在springmvc-servlet.xml中注册自定义的处理器异常解析器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class MyHandlerExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView mv = new ModelAndView(); if (ex instanceof MaxUploadSizeExceededException) { mv.addObject("msg" ,"上传文件大小不得超过5个字节" ); mv.setViewName("hello" ); } return mv; } }
1 2 3 <!--装配自定义处理器错误解析器--> <bean class="cn.itcast.exception.MyHandlerExceptionResolver"></bean>
当上传多个的时候后台使用数据接收遍历循环 1 2 3 4 5 6 7 8 9 10 @RequestMapping ("show32" )public String test32 (Model model,@RequestParam("files" ) MultipartFile[] files) throws Exception { for (MultipartFile file : files) { if (file!=null ) { file.transferTo(new File("d://upload//" +file.getOriginalFilename())); } } model.addAttribute("msg" , "上传成功" ); return "hello" ; }
#转发和重定向 返回值为字符串时,默认为视图名称。当返回值字符串是以”forward:”或者”redirect:”开头,则会被认为是转发或者重定向。
使用方式如下:
转发:forward:/hello/show.do(绝对路径)或者forward:show.do(相对路径)
重定向:redirect:/hello/show.do(绝对路径)或者redirect:show.do(相对路径)
/:表示绝对路径,指的是localhost:8080/springmvc(项目名称可以省略)
不带/:表示相对路径,相对于当前请求的路径
如果当前请求是:localhost:8080/springmvc(项目名称可以省略)/hello/show32
那么不带/:表示localhost:8080/springmvc(项目名称可以省略)/hello/
forward
redirect
拦截器 HandlerExecutionChain是一个执行链,当请求到达DispatchServlet时,DispatchServlet根据请求路径到HandlerMapping查询具体的Handler,从HandlerMapping返回执行链给DispatcherServlet,其中包含了一个具体的Handler对象和Interceptors(拦截器集合)。
拦截器一般用于对处理器进行预处理和后处理。
应用场景:
1、权限检查:如登录检测,进入处理器前检测用户是否登录,如果没有登陆直接返回到登录页面。
2、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,统计处理器执行使用了多少时间。
springmvc的拦截器接口(HandlerInterceptor)定义了三个方法:
n preHandle调用Handler之前执行,称为预处理回调方法
返回值:true表示放行,后续业务逻辑继续执行
false表示被拦截,后续业务逻辑不再执行,但之前返回true的拦截器的请求完成回调方法会倒叙执行
n postHandle调用Handler之后执行,称为后处理回调方法
n afterCompletion视图渲染完成之后执行,可以称为请求完成回调方法
拦截器的配置过程:
1、 编写自定义拦截器实现HandlerInterceptor
2、 在springmvc-servlet.xml中注册自定义拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class MyInterceptor1 implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor1,预处理回调方法正在执行" ); return true ; } @Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("MyInterceptor1,后处理回调方法正在执行" ); } @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("MyInterceptor1,请求完成回调方法正在执行" ); } }
配置自定义拦截器
1 2 3 4 5 6 7 8 9 /: 表示绝对路径: http://localhost:8080/springmvc /*:表示绝对路径下的任意一级路径: http://localhost:8080/springmvc/xxx /**:表示绝对路径下的任意多级目录: http://localhost:8080/springmvc/xxx http://localhost:8080/springmvc/xxx/xxx/xxx 注意:之所以请求url中看不到springmvc,是因为在pom.xml中配置了tomcat插件,配置了path为/而省略了项目名称springmvc 在springmvc-servlet.xml中配置自定义的拦截器,/**:拦截所有请求
1 2 3 4 5 6 7 8 <mvc:interceptors > <mvc:interceptor > <mvc:mapping path ="/**" /> <bean class ="com.qiezicy.interceptor.MyInterceptor1" > </bean > </mvc:interceptor > </mvc:interceptors >
当有多个拦截器时
1 2 3 4 5 6 7 8 9 10 11 12 13 <mvc:interceptors > <mvc:interceptor > <mvc:mapping path ="/**" /> <bean class ="com.qiezicy.interceptor.MyInterceptor1" > </bean > </mvc:interceptor > <mvc:interceptor > <mvc:mapping path ="/**" /> <bean class ="com.qiezicy.interceptor.MyInterceptor2" > </bean > </mvc:interceptor > </mvc:interceptors >
小结:
拦截器的预处理回调方法依次执行, 后处理回调方法和请求完成回调方法倒序执行 当预处理回调方法返回false时,后续的拦截器以及Handler方法不再执行,但它前面的预处理回调方法返回值为true的拦截器的请求完成回调方法会倒序执行。 请求完成回调方法会在视图渲染完成之后才去执行。
中断拦截器的预处理回调方法
当有多个拦截器的时候,
中断第一个拦截器的预处理回调方法,将第一个拦截器的预处理回调方法返回值设置为false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class MyInterceptor1 implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor1,预处理回调方法正在执行" ); return false ; } @Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("MyInterceptor1,后处理回调方法正在执行" ); } @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("MyInterceptor1,请求完成回调方法正在执行" ); } }
结果:后续方法不再执行
中断第二个拦截器的预处理回调方法(先将第一个恢复)
将第二个拦截器的预处理回调方法返回值设置为false:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 Public class MyInterceptor2 implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor2,预处理回调方法正在执行" ); return false ; } @Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("MyInterceptor2,后处理回调方法正在执行" ); } @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("MyInterceptor2,请求完成回调方法正在执行" ); } }
结果:
执行测试:执行完连个预处理回调方法后,倒叙执行请求完成回调方法,由于第二个连接器的预处理回调方法返回false,因此自定义处理器不再执行,然后开始倒叙执行请求完成回调方法,并且没有机会执行第二个拦截器的请求完成回调方法,而是从第一个拦截器的请求完成回调方法开始执行。
#POST和GET乱码解决(tomcat7) 在使用Post提交请求参数的时候,一旦参数是中文的,那么controller中获取到的数据数据就会乱
编写自定义处理器 1 2 3 4 5 @RequestMapping ("show36" )public String test36 (@RequestParam("name" ) String name) { System.out.println(name); return "hello" ; }
当传来参数是中文时,会产生乱码
解决方案: 手动配置post请求编码过滤器
Spring-web给我们提供了解决post请求编码的过滤器:
1 2 3 4 5 6 7 8 9 10 11 12 13 <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 >
解决get请求乱码文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <plugins > <plugin > <groupId > org.apache.tomcat.maven</groupId > <artifactId > tomcat7-maven-plugin</artifactId > <configuration > <port > 8080</port > <path > /</path > <uriEncoding > utf-8</uriEncoding > </configuration > </plugin > </plugins >