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..");;
    }
}

在springmvc.xml中注册拦截器:

    <!--注册拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/login"/>
            <bean class="com.zi.interceptor.MyInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

②通过实现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.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.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..");;
    }

拦截器执行顺序

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

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;
    }
}

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;
    }
}

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

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

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.jsp</prop>
                <prop key="java.lang.NullPointerException">redirect://error2.jsp</prop>
            </props>
        </property>
    </bean>

②配置类方式【零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;
    }
}

注意:还需在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;
    }
}

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" %>
<html>
<head>
    <title>Title</title>
    <script src="js/jquery-3.4.1.js"></script>
    <script>
        $(function(){
            $.ajax({
                url:"demo1",
                type:"get",
                data:"name=zhangsan&hiredate=2022-7-28",
                success:function (result){
                    console.log(result)
                }
            })
        })
    </script>
</head>
<body>

</body>
</html>

EmpController.java:

@Controller
public class EmpController {

    @RequestMapping("/demo1")
    @ResponseBody
    public Emp demo1(Emp emp){
        System.out.println(emp);
        return emp;
    }
}

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

④@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>

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;
    }
}

⑤@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. 前端解决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 = '<ul>';
    for(var i = 0; i < data.length; i++)
    {
        html += '<li>' + data[i] + '</li>';
    }
    html += '</ul>';
    
    $('#divCustomers').html(html); 
});
</script>
</body>
</html>

第三种方案:通过过滤器

/*请求地址白名单 *代表所有*/
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")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值