视图解析: 返回字符串:
controller 方法返回字符串也称为逻辑视图名,通过视图解析器解析为物理视图地址。
物理视图地址 = 视图解析器前缀 + 逻辑视图名 + 视图解析器后缀
1 2 3 4 5 6 7 8 <bean id ="viewResolver" class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/pages/" /> <property name ="suffix" value =".jsp" /> <property name ="contentType" value ="text/html;charset=UTF-8" /> </bean >
1 2 3 4 5 @RequestMapping("/saveAccount") public String saveAccount (User user) { System.out.println(user); return "success" ; }
最终返回的物理视图地址:/WEB-INF/pages/ + success + .jsp = /WEB-INF/pages/success.jsp
返回void?
很少用,默认会查找请求路径结尾的jsp资料
1 2 3 4 @RequestMapping("/void") public void returnVoid () { System.out.println("返回值void..." ); }
会报404,即便是空值返回也会被视图解析为 void.jsp,当然如果你设置了视图解析器的话
ModelAndView
ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值。
两个重要的方法:
1 2 3 4 5 6 7 8 9 10 11 12 public ModelAndView addObject (String attributeName, @Nullable Object attributeValue) { getModelMap().addAttribute(attributeName, attributeValue); return this ; }
1 2 3 4 5 6 7 8 public void setViewName (@Nullable String viewName) { this .view = viewName; }
返回值可以直接通过el表达式获取
controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @RequestMapping(value = "/model/view",method = RequestMethod.GET) public ModelAndView modelAndView (ModelAndView modelAndView) { System.out.println("测试 modelAndView..." ); User user = new User(); user.setName("tom" ); user.setAge(22 ); modelAndView.addObject("clazz" ,"大数据" ); modelAndView.addObject("user" ,user); modelAndView.setViewName("success" ); return modelAndView; }
jsp:
1 2 3 4 5 6 7 8 <body> <h2>sccess</h2> class: ${clazz} username: ${user.name} age: ${user.age} </body>
json返回
主要使用@ResponseBody注解
该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的 数据如:json、xml 等,默认转为json格式,再通过 Response 响应给客户端 。使用json格式的数据进行交互,也是目前前后端分离开发最主要的方式。
Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换,需要加入 jackson 的包(如果已经添加过,不要重复添加)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <jackson-version > 2.11.0</jackson-version > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > ${jackson-version}</version > </dependency > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-core</artifactId > <version > ${jackson-version}</version > </dependency > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-annotations</artifactId > <version > ${jackson-version}</version > </dependency >
用法:
1 2 3 4 5 6 7 8 9 10 11 12 @RequestMapping(value = "/testResponseBody",method = RequestMethod.POST) public @ResponseBody User testResponseBody () { System.out.println("使用 @ResponseBody响应json数据 ..." ); User user = new User(); user.setId(1001 ); user.setMoney(100.1F ); user.setName("tom" ); user.setAge(22 ); return user; }
实际上就是在返回值前面添加约束注解,但是因为要返回值嘛,所以必须要限制访问方式为post请求
拦截器 简介 Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对请求进行预处理和后处理。用户可以自己定义一些拦截器来实现特定的功能。谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,都是基于AOP编程思想的体现,都能实现权限检查、日志记录等,但是也有区别,例如:
使用范围不一样
过滤器是 servlet规范中的一部分,只能用于web工程中。
拦截器是 SpringMVC框架自己的,只有使用了 SpringMVC框架的工程才能用。
规范不同:
Filter实在servlet规范中定义的,是servlet容器支持的。
拦截器(interceptor)是在Spring容器内的,是Spring框架支持的。
使用资源不同
拦截器是Spring的组件,因此能够使用Spring里的任何资源、对象,而Filter不能
深度不同
Filter只在servlet前后起作用,
拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用更具有弹性,因此在Spring架构中优先使用拦截器
如何自定义拦截器?
编写一个普通类实现 HandlerInterceptor 接口
配置拦截器
测试运行结果:
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 public class HelloInterceptor implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle...controller之前执行" ); return true ; } @Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle...jsp之前执行" ); } @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion...jsp 之后执行" ); } }
继承抽象类不会报错,但是要重写他的三个方法分别是上面的三种
返回true表示允许请求通过
prehandle表示在请求到来之前
posthandle表示在controller执行之后,jsp之前
afterhandle表示在jsp(视图)之后执行
为什么需要在请求到来之前还有个拦截器呢,这个怎么用?答:因为在jsp页面中可以 用 <%%> 这个里面直接写java代码,执行相应的逻辑
创建新项目找不到模板了,maven东西太多了:org.apache.maven.archetypes:maven-archetype-webapp
在springmvc.xml中
1 2 3 4 5 6 7 8 9 <mvc:interceptors > <mvc:interceptor > <mvc:mapping path ="/**" /> <bean id ="helloInterceptor" class ="com.ls.intereptor.interectorooo" > </bean > </mvc:interceptor > </mvc:interceptors >
/** 这个是过滤所有的controller的意思
什么时候用到?
prehandle
错误拦截示例
1 2 3 4 5 @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { request.getRequestDispatcher("WEB-INF/error.jsp" ).forward(request,response); return false ; }
返回值特点
该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,可以返回到其他页面,后续的Interceptor 和Controller 都不会再执行;
当返回值为true 时,如果还有别的interceptor实力的话,就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
作用
可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。典型的应用场景:登录拦截、权限校验
posthandle
1 2 3 4 5 6 7 8 9 10 @Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { modelAndView.addObject("token" ,"CZXY-2020-07-03" ); System.out.println("postHandle..." ); }
执行时机
preHandle 方法的返回值为true 时才能被调用,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,
postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行
作用
可以在这个方法中对Controller 处理之后的ModelAndView 对象和request、response进行操作。
afterCompletion
1 2 3 4 5 6 7 8 @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion...controller之后执行" ); }
执行时机
当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。
该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。
作用
这个方法的主要作用是用于进行资源清理 、记录日志信息等工作。
拦截器指定配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <mvc:interceptors > <mvc:interceptor > <mvc:mapping path ="/**" /> <mvc:exclude-mapping path ="/login" /> <bean id ="helloInterceptor1" class ="com.ls.mvc.interceptor.HelloInterceptor" > </bean > </mvc:interceptor > <mvc:interceptor > <mvc:mapping path ="/user/**" /> <bean id ="helloInterceptor2" class ="com.ls.mvc.interceptor.HelloInterceptor2" > </bean > </mvc:interceptor > <mvc:interceptor > <mvc:mapping path ="/user/list" /> <bean id ="helloInterceptor3" class ="com.ls.mvc.interceptor.HelloInterceptor3" > </bean > </mvc:interceptor > </mvc:interceptors >
我们不想用所有拦截器一起生效,只想要我们使用的生效,可以看上面。
不需要拦截的静态资源? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <mvc:resources location ="/js/" mapping ="/**/*.js" /> <mvc:resources location ="/css/" mapping ="/**/*.css" /> <mvc:resources location ="/assets/" mapping ="/assets/**" /> <mvc:resources location ="/images/" mapping ="/images/**" cache-period ="360000" /> <mvc:interceptors > <mvc:interceptor > <mvc:mapping path ="/**" /> <mvc:exclude-mapping path ="/**/fonts/*" /> <mvc:exclude-mapping path ="/**/*.css" /> <mvc:exclude-mapping path ="/**/*.js" /> <mvc:exclude-mapping path ="/**/*.png" /> <mvc:exclude-mapping path ="/**/*.gif" /> <mvc:exclude-mapping path ="/**/*.jpg" /> <mvc:exclude-mapping path ="/**/*.jpeg" /> <bean class ="com.czxy.mvc.interceptor.HelloInterceptor" > </bean > </mvc:interceptor > </mvc:interceptors >
在springmvc.xml中加上静态资源放行配置,某个拦截器执行的时候
/**代表第一层所有目录
<mvc:exclude-mapping path=”/user/toadd”/> 这个标签是一个过滤器的放行标签,参数里面填写完其他的请求,其他的请求也会被放行
放行不一定在配置中设置,也可以在程序里面写
多个拦截器执行顺序?
简单来说就是,prehandle按照配置顺序来,也就是 A B C,在执行完controller之后,posthandle 与 aftercompletion过滤规则都是,C B A