• SpringMVC拦截器、异常、其他注解


    1 SpringMVC拦截器

    SpringMVC中的拦截器主要用于拦截用户请求并做出相应的处理。比如:权限验证、记录请求信息的日志、判断用户是否登录等。
    在这里插入图片描述

    1.1 实现拦截器的两种方法

    ①实现HandlerInterceptor接口或继承该接口的实现类(如HandlerInterceptorAdapter)
    MyInterceptor.java

    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandler....");
            return true;//返回true表示放行,可以继续到达handler*
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            /*handler处理单元返回ModelAndView时候进行拦截*/
            System.out.println("postHandler...");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            /*页面渲染完毕,但是还没有给浏览器响应数据*/
            System.out.println("afterCompletion..");;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在springmvc.xml中注册拦截器:

        
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/login"/>
                <bean class="com.zi.interceptor.MyInterceptor">bean>
            mvc:interceptor>
        mvc:interceptors>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ②通过实现WebRequestInterceptor接口或继承该接口的实现类

    1.2 拦截器、过滤器区别

    1.拦截器是SpringMVC的,过滤器是java的servlet的
    2.拦截器不依赖servlet,由Spring容器初始化的,过滤器依赖于servlet容器,由servlet容器初始化
    3.拦截器只能对.action、.do这类似的请求起作用,而过滤器可以对几乎所有请求起作用(包括对静态资源的访问)
    4.拦截器可以访问action上下文、值栈里面的对象,而过滤器不能
    5.在action的生命周期中,拦截器可以被多次调用,而过滤器只能在容器初始化时被调用一次
    6.拦截器可以获取IOC容器中的各个bean,而过滤器不方便获取;在拦截器中注入一个service,可以调用业务逻辑

    1.3 拦截器的三个方法及作用

    1.3.1 preHandle

        /**
         *
         * @param request 请求对象
         * @param response 响应对象
         * @param handler 目标要调用的Handler
         * @return 返回true表示放行
         * @throws Exception
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //在请求到达我们定义的handler之前执行的
            System.out.println("preHandler....");
            //设置请求和响应的编码【防止乱码】
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
            //判断是否登录,如果没有登录直接拦截
    //        User user = (User) request.getSession().getAttribute("user");
    //        if(null == user){
    //            response.sendRedirect("index.jsp");
    //        }
    //        return false;
            return true;//返回true表示放行,可以继续到达handler*
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    1.3.2 postHandle

        /**
         *
         * @param request
         * @param response
         * @param handler
         * @param modelAndView controller响应的结果,视图和数据
         * @throws Exception
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            /*handler处理单元返回ModelAndView时候进行拦截*/
            System.out.println("postHandler...");
            //控制数据
            Map<String, Object> map = modelAndView.getModel();
            String msg = (String) map.get("msg");
            String newMsg = msg.replaceAll("脏话", "**");
            map.put("msg", newMsg);
    //        modelAndView.setViewName("success");
            //控制视图
    //        modelAndView.setViewName("/testDemo");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    1.3.3 afterCompletion

        /**
         * 无论controller是否出现异常都会执行的操作,类似于finally
         * 通常用来完成资源释放等操作
         * @param request
         * @param response
         * @param handler
         * @param ex
         * @throws Exception
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            /*页面渲染完毕,但是还没有给浏览器响应数据*/
            System.out.println("afterCompletion..");;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    拦截器执行顺序

    多个拦截器同时存在时,执行的顺序由配置顺序决定. 先配置谁, 谁就先执行.多个拦截器想象成"反弹"

    2 SpringMVC异常

    在Java中异常包括两类:预期异常(检查型异常)和运行时异常
    系统的dao、service、controller出现都向上throws Exception,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:

    在这里插入图片描述

    2.1 SpringMVC异常处理的具体实现

    2.1.1 使用@ExceptionHandler注解(只能处理当前controller中异常)

    DemoExceptionController02.java:

    @Controller
    public class DemoExceptionController02 {
    
        @RequestMapping("/test01")
        public String test01(){
            int i = 1 / 0;
            return "success";
        }
    
        @RequestMapping("/test02")
        public String test02(){
            String str = null;
            int length = str.length();
            return "success";
        }
    
        @ExceptionHandler(value = {ArithmeticException.class})//处理数学异常
        public ModelAndView handlerException(){
            ModelAndView mv = new ModelAndView();
            mv.setViewName("fail");
            return mv;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2.1.2 使用@ControllerAdvice+@ExceptionHandler(优先级低于局部)

    @ControllerAdvice
    public class ExceptionHandler01 {
    
        @ExceptionHandler(value = ArithmeticException.class)
        public ModelAndView handlerException(){
            ModelAndView mv = new ModelAndView();
            mv.setViewName("index");
            return mv;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    注意:还需要再applicationContext.xml中配置扫描:

    <context:component-scan base-package="com.zi.exceptionhandler">context:component-scan>
    
    • 1

    2.1.3 使用SimpleMappingExceptionResolver

    ①XML方式
    需要再springmvc.xml中配置:

        
        <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" id="exceptionResolver">
            <property name="exceptionMappings">
                <props>
                    <prop key="java.lang.ArithmeticException">redirect://error1.jspprop>
                    <prop key="java.lang.NullPointerException">redirect://error2.jspprop>
                props>
            property>
        bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ②配置类方式【零XML配置】
    ExceptionConfig.java:

    @Configuration
    public class ExceptionConfig {
    
        @Bean
        public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
            SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
            Properties prop = new Properties();
            prop.put("java.lang.NullPointerException", "error1.jsp");
            prop.put("java.lang.ArithmeticException", "error2.jsp");
            resolver.setExceptionMappings(prop);
            return resolver;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    注意:还需在applicationContext.xml中配置包扫描

    2.1.4 自定义类HandlerExceptionResolver【实现接口】

    ExceptionHandler02.java:

    /**
     * 全局异常
     */
    @Configuration
    public class ExceptionHandler02 implements HandlerExceptionResolver {
    
        @Override
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
            ModelAndView mv = new ModelAndView();
            if(ex instanceof NullPointerException){
                mv.setViewName("error1");
            }
            if(ex instanceof ArithmeticException){
                mv.setViewName("error2");
            }
            mv.addObject("msg", ex);
            return mv;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3 SpringMVC其他注解

    ① @GetMapping、@PostMapping

    例:@GetMapping = @RequestMapping + method = GET

    ②@RestController【相当于类中所有方法都加上@ResponseBody】

    如果我们在一个controller中,想要返回json格式的数据,而不是通过返回String,从而对应视图,就需要添加@ResponseBody

    ③@JsonFormat

    作用:处理响应json数据的处理
    属性:
    pattern:指定响应时间日期的格式
    TImezone:执行响应的时区

    testJson.jsp:
    【注意:ajax中的type与method区别:method是jQuery1.9之后推出的新属性】

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        </span>Title<span class="token filehandle symbol">
        <script src="js/jquery-3.4.1.js">
        
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    EmpController.java:

    @Controller
    public class EmpController {
    
        @RequestMapping("/demo1")
        @ResponseBody
        public Emp demo1(Emp emp){
            System.out.println(emp);
            return emp;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    最终结果:
    在这里插入图片描述

    ④@RequestBody

    用于获取请求体json格式的字符串内容。直接使用得到是 key=value&key=value…结构的数据,get 请求方式不适用。

    testJson.jsp
    【注意加上contenType,并且方式为post】

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
        <script src="js/jquery-3.4.1.js"></script>
        <script>
            var jsonObj = {name:"lisi", hiredate:"2035-9-5"}
            var jsonStr = JSON.stringify(jsonObj);//'{"name":"lisi", "hiredate":"2035-9-5"}'
            $(function(){
                $.ajax({
                    url:"demo1",
                    method:"post",
                    data:jsonStr,
                    contentType:"application/json",//需要指定否则会报415【Unsupported Media Type】
                    success:function (result){
                        console.log(result)
                    }
                })
            })
        </script>
    </head>
    <body>
    
    </body>
    </html>
    
    
    • 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

    EmpController

    @Controller
    public class EmpController {
    
        @RequestMapping(value = "/demo1", method = RequestMethod.POST)
        @ResponseBody
        public Emp demo1(@RequestBody(required = false) Emp emp){//required = false 表明emp参数可以没有
            System.out.println(emp);
            return emp;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ⑤@CrossOrigin

    作用:解决ajax请求之间的跨域问题

    浏览器有一个同源策略的约定。同源(同一个域):两个页面具有相同的协议protocol、主机host、端口号port
    http://127.0.0.1:8080/zi/index.jsp 基础
    https://127.0.0.1:8080/zi/index.jsp 协议不同
    http://192.168.3.34:8080/zi/index.jsp IP不同
    http://127.0.0.1:8080/zi/index.jsp IP不同
    http://127.0.0.1:9090/zi/index.jsp 端口不同
    http://localhost:8080/zi/index.jsp IP不同

    属性:
    orgins:允许可访问的域列表IP
    maxAge:准备响应前的缓存持续的最大时间(秒为单位)
    代码:

    @Controller
    @CrossOrigin(value = "http:domain.com", maxAge = 6000)
    public class EmpController {
    
        @RequestMapping(value = "/demo1", method = RequestMethod.POST)
        @ResponseBody
        public Emp demo1(@RequestBody(required = false) Emp emp){//required = false 表明emp参数可以没有
            System.out.println(emp);
            return emp;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    拓展:
    解决跨域问题的三种方案:

    1. 前端解决jsonp
    2. 后端解决:@CrossOrigin
    3. 后端解决:通过过滤器
      第一种方案jsonp:
    DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>JSONP 实例title>
        <script src="https://cdn.static.runoob.com/libs/jquery/1.8.3/jquery.js">script>    
    head>
    <body>
    <div id="divCustomers">div>
    <script>
    $.getJSON("https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=?", function(data) {
        
        var html = '
      '; for(var i = 0; i < data.length; i++) { html += '
    • ' + data[i] + '
    • '
      ; } html += '
    '
    ; $('#divCustomers').html(html); });
    script> body> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    第三种方案:通过过滤器

    /*请求地址白名单 *代表所有*/
    resp.setHeader("Access-Control-Allow-Origin", "*")
    /*请求方式白名单*/
    resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
    resp.setHeader("Access-Control-Max-Age", "3600")
    resp.setHeader("Access-Control-Allow-Header", "x-requried-with")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    static
    Android开发第二步(全屏嵌套H5页面)
    530. 二叉搜索树的最小绝对差
    子进程变成孤儿进程
    Java-反射
    elk安装篇之 Kibana安装
    数组、单链表和双链表介绍以及双向链表的C/C++实现
    MongoDB基础【学习笔记】
    Nginx的请求时间限制(如周一到周五可以访问)
    软件测试 app自动化02 Appium常用的元素定位工具 元素的属性 元素定位方法
  • 原文地址:https://blog.csdn.net/weixin_45565886/article/details/126005042