第一节 拦截器的简介

1、遇到的问题

在之前学习Servlet的时候,我们学习了过滤器的知识。过滤器的作用是保护请求的服务器资源,在请求资源被执行之前,如果请求地址符合拦截范围,则会先执行过滤器。过滤器的执行时机,是在Servlet之前执行的。但是在使用了SpringMVC后,Servlet只有一个了,也就是DisptcherServlet。那么,如果我们仍然使用过滤器来完成请求的拦截,因为过滤器是在Servlet之前执行的,就会造成,过滤器会拦截DispatcherServlet所有的请求。那么,如果我们有部分请求不想被拦截,怎么办?

1 解决方案机制

拦截器使用

2 理解示意图

拦截器和异常处理 - 图1

3 拦截器的概念

Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义。
1.通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。

  1. 通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。

两者不同点是:
1.WebRequestInterceptor的入参WebRequest是包装了HttpServletRequest 和HttpServletResponse的,通过WebRequest获取Request中的信息更简便。
2.WebRequestInterceptor的preHandle是没有返回值的,说明该方法中的逻辑并不影响后续的方法执行,所以这个接口实现就是为了获取Request中的信息,或者预设一些参数供后续流程使用。
3.HandlerInterceptor的功能更强大也更基础,可以在preHandle方法中就直接拒绝请求进入controller方法。

4 拦截器和过滤器的区别

①拦截器SpringMVC的,而过滤器是servlet的。
  ②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
  ③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
  ④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
  ⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不太方便,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

6、代码实现

6.1 编写一个普通类实现

接口

public class HandlerInterceptorDemo1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
System.out.println(“preHandle 拦截器拦截了”);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler ModelAndView modelAndView) throws Exception {
System.out.println(“postHandle 方法执行了”);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse
response, Object handler, Exception ex) throws Exception {
System.out.println(“afterCompletion 方法执行了”);
}
}

6.2配置拦截器




class=“com.bjsxt.controller.interceptor.HandlerInterceptorDemo1”>

第二节 拦截器内容详解

1、preHandle方法

执行时机
再进入控制单元方法之前执行
如何调用
按拦截器定义顺序调用
具体作用
如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去 进行处理,则返回 true。 如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。
参数详解
HttpServletRequest arg0,拦截的请求的request对象
HttpServletResponse arg1, 拦截的请求的response对象
Object arg2 封存了单元方法对象的HandleMethod对象
代码实现

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse resp, Object o) throws Exception {
//作用一: 进行中文乱码的处理
//request.setCharacterEncoding(“utf-8”);
//作用二 :进行页面的升级和页面的跳转
//resp.sendRedirect(request.getContextPath()+”/error.jsp”);
_System.**_out
.println(“preHandle—-“+o);
//作用三 :登录用户权限的校验
return true**;
}

2、postHandle方法

执行时机
在进行数据处理和做出响应之间进行这个方法的调用
如何调用
在拦截器链内所有拦截器返成功调用
具体作用
在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用,
在该方法中对用户请求 request 进行处理。
参数详解
HttpServletRequest arg0, 拦截的请求的request对象
HttpServletResponse arg1, 拦截的请求的response对象
Object arg2, 封存了单元方法对象的HandleMethod对象
ModelAndView arg3 封存了单元方法的返回值资源路径和请求转到的Map数据
代码实现

@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
//作用一: 进行后期页面跳转页面维护修改的操作
//modelAndView.setViewName(“main2”);
//作用二:进行恶意字符的替换
_Map map = modelAndView.getModel();
//登陆失败枪支
String str = (String) map.get(“msg”);
if(str.contains(“枪支”)){
//登陆失败
_String str2 = str.replaceAll(
“枪支”, );
map.put(“msg”,str2);
}
System.out.println(“postHandle—-“);
}

5 afterCompletion方法

执行时机
在进行页面渲染的时候执行_如何调用
按拦截器定义逆序调用
具体作用
在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
参数详解
HttpServletRequest arg0, 拦截的请求的request对象
HttpServletResponse arg1, 拦截的请求的response对象
Object arg2, 封存了单元方法对象的HandleMethod对象
Exception arg3 存储了责任链的异常信息
代码实现

public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println(“afterCompletion—-“);
}

第三节 多个拦截器的执行顺序

1、多个拦截器执行顺序

多个拦截器同时存在时, 执行的顺序由配置顺序决定. 先配置谁, 谁就先执行.多个拦截器可以理解为拦截器栈, 先进后出(后进先出), 如图所示:
拦截器和异常处理 - 图2

6 代码实现

[1]拦截器 1 的代码

public class HandlerInterceptorDemo1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
System.out.println(“拦截器 1:preHandle 拦截器拦截了”);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(“拦截器 1:postHandle 方法执行了”);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(“拦截器 1:afterCompletion 方法执行了”);
} }

[2]拦截器二的代码

public class HandlerInterceptorDemo2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(“拦截器 2:preHandle 拦截器拦截了”);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(“拦截器 2:postHandle 方法执行了”);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse
response, Object handler, Exception ex) throws Exception {
System.out.println(“拦截器 2:afterCompletion 方法执行了”);
} }

[3]拦截器配置





class=“com.sxt.controller.interceptor.HandlerInterceptorDemo1”>



id=“handlerInterceptorDemo2”
class=“com.sxt.controller.interceptor.HandlerInterceptorDemo2”>

[4]执行结果
拦截器和异常处理 - 图3

第四节SpringMVC中异常处理

1、SpringMVC异常简介

系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息, 后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理,如下图
拦截器和异常处理 - 图4

2、异常处理具体实现

a、使用@ExceptionHandler注解处理异常

@ExceptionHandler(value = {java.lang.ArithmeticException.class,java.lang.NullPointerException.class})
public ModelAndView handlerArithmeticException(Exception e){
System.out.println(e);
ModelAndView mv = new ModelAndView();
mv.addObject(“msg”,e);
mv.setViewName(“error1”);
return mv;}

缺点:只能处理当前Controller中的异常。

b、使用:@ControllerAdvice+@ExceptionHandler

/*
全局异常处理器,如果我们即配置类局部异常处理器有配置了全局异常处理器,这个时候走局部异常处理器
*/
@ControllerAdvice
public class GloableException {
@ExceptionHandler(value = {java.lang.ArithmeticException.class,java.lang.NullPointerException.class})
public ModelAndView handlerArithmeticException(Exception e){
System.out.println(e);
ModelAndView mv = new ModelAndView();
mv.addObject(“msg”,e);
mv.setViewName(“error1”);
return mv;
}
}

c、使用:SimpleMappingExceptionResolver

/*
全局异常
*/
@Configurationpublic class GloableException2 {
@Bean
public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties prop = new Properties();
prop.put(“java.lang.NullPointerException”,”error1”);
prop.put(“java.lang.ArithmeticException”,”error2”);
resolver.setExceptionMappings(prop);
return resolver;
}
}

d、自定义的HandlerExceptionResolve

/*
全局异常
HandlerExceptionResolve
/
@Configurationpublic class GloableException3 implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
ModelAndView mv = new ModelAndView();
if(e instanceof NullPointerException){
mv.setViewName(“error1”);
}
if(e instanceof ArithmeticException){
mv.setViewName(“error2”);
}
mv.addObject(“msg”,e);
return mv;
}}

SpringMVC中注解完善

1、@PostMapping

作用:
指定当前发送请求的方式只可以是post请求
属性:
和@RequestMapping中属性一致
代码实现

@PostMapping(“/userControllerA”)public String userControllerA(){
return “forward:/success.jsp”;
}

2、@GetMapping

作用:
指定当前发送请求的方式只可以是get请求
属性:
和@RequestMapping中属性一致
代码实现:

| @GetMapping(“/userControllerA”)public String userControllerA(){

  1. return "forward:/success.jsp";<br />} |

| —- |

3、@RestController

作用:
书写到类上,代表该类中所有控制单元方法均是ajax响应 相当于@ResponseBody+@Controller
属性:
其中的属性和@Controller中一样
代码实现:

@RestController
public class UserController {
}

4、@JsonFormat

作用:
处理响应json 数据的处理
属性:
pattern :指定响应时间日期的格式
Timezone:指定响应的时区,否则会有8个小时的时间差
代码实现:

@DateTimeFormat(pattern = “yyyy-MM-dd”)@JsonFormat(pattern = “yyyy-MM-dd” ,timezone=”GMT+8”)private Date birth;

5、@RequestBody

作用:
用于获取请求体json格式的字符串内容。直接使用得到是 key=value&key=value…结构的数据,get 请求方式不适用。
属性:
required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值 为 false,get 请求得到是 null。
实现:

$(function () {
var jso={name:“zs”,pwd:“123”};
var s = JSON.stringify(jso);
$.ajax({
type:“post”,
url:“bj”,
data:s,
contentType:“application/json”,
})
})
@RequestMapping(“/useRequestBody”)
public String useRequestBody(@RequestBody(required=false) String body){
System.out.println(body);
return “sxt”;
}

6、@CrossOrigin

6.1什么是跨域

出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
http://127.0.0.1:8080/sxt/index.jsp基础
https://127.0.0.1:8080/sxt/index.jsp 协议不一样
http://192.168.24.11:8080/sxt/index.jsp IP不一致
http://127.0.0.1:8888/sxt/index.jsp 端口不一致
http://localhost:8080/sxt/index.jsp IP不一致
作用:
解决ajax请求之间的跨域问题
属性:
origins : 允许可访问的域列表IP
maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。
代码实现:

@CrossOrigin(origins = “http://domain2.com“, maxAge = 3600)
@RestController
@RequestMapping(“/account”)public class AccountController {
@GetMapping(“/{id}”)
public Account retrieve(@PathVariable Long id) { }
}

拦截器和异常处理 - 图5