springmvc 全局异常处理 and 拦截器

文章目录

配置类 SpringMvcInit

java 复制代码
package com.cool.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

"可以被 web项目加载,会初始化ioc容器,会设置 dispatcherServlet的地址"

public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    "设置配置类"
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{MvcConfig.class};
    }

    "配置springmvc内部自带servlet的访问地址"
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

配置类 MvcConfig

java 复制代码
package com.cool.config;

import com.cool.interceptor.MyInterceptor;
import com.cool.interceptor.MyInterceptor1;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@EnableWebMvc
@Configuration
@ComponentScan({"com.cool.controller", "com.cool.error"})
public class MvcConfig implements WebMvcConfigurer {

    /*
        通过configurer.enable()启用默认Servlet处理。
        当请求无法匹配到Spring的控制器时,会回退到Servlet容器的默认Servlet(如:Tomcat的DefaultServlet),
        主要用于,处理静态资源(如HTML、JS、CSS)。

        典型场景:
            配置后,对 /static/** 的请求会先由Spring处理,未匹配则交给容器默认Servlet
    */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 配置方案-1:拦截全部请求
        registry.addInterceptor(new MyInterceptor());


        // 配置方案-2:拦截指定的请求
        // *:任意一层字符串;**:任意多层字符串
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/user/**"); // 拦截 user/ 下的所有请求


        // 配置方案-3:排除拦截
        // 拦截 user/ 下除了 /user/data1 之外的请求地址
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/user/**")
                .excludePathPatterns("/user/data1");


        // 如果有多个拦截器,执行流程是怎样的呢?
        /*
            先声明的优先级高,优先级高的在外层,
            MyInterceptor.preHandle
            MyInterceptor1.preHandle
            OrderController.data
            MyInterceptor1.postHandle
            MyInterceptor.postHandle
            MyInterceptor1.afterCompletion
            MyInterceptor.afterCompletion
        */
        registry.addInterceptor(new MyInterceptor());
        registry.addInterceptor(new MyInterceptor1());
    }
}

全局异常处理器

全局异常处理器 GlobalException 使用了 @RestControllerAdvice,

处理 ArithmeticException 和 Exception。

当 Controller 中的方法抛出这些异常时,会被对应的 @ExceptionHandler 方法捕获并处理。

java 复制代码
package com.cool.error;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器
 *
 * @ControllerAdvice
 *      作用:全局异常发生,就会走此类的方法,可以返回 逻辑视图、转发、重定向
 *
 * @RestControllerAdvice
 *      相当于 @ControllerAdvice 和 @ResponseBody 的组合,
 *      可以直接返回 json 字符串
 *
 */

@RestControllerAdvice
public class GlobalException {

    /*
        发生异常后 -> ControllerAdvice注解的类型 -> @ExceptionHandler(指定的异常) -> 执行handler

        如果,没有找到指定的异常,就会找父类Exception
    */

	"精准匹配算术异常"
    @ExceptionHandler(ArithmeticException.class)
    public Object ArithmeticExceptionHandler(ArithmeticException e){
        // 自定义异常处理即可
        String message = e.getMessage();
        System.out.println("ArithmeticExceptionHandler=" + message);
        return message;
    }

	"兜底所有异常"
    @ExceptionHandler(Exception.class)
    public Object ExceptionHandler(Exception e){
        String message = e.getMessage();
        System.out.println("ExceptionHandler=" + message);
        return message;
    }
}

User实体类 (参数校验)

java 复制代码
package com.cool.pojo;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Past;
import lombok.Data;
import org.hibernate.validator.constraints.Length;

import java.util.Date;

/**
 * name:不为null、不为空字符串
 *      字符串不为空:@NotBlank
 *      集合不为空:@NotEmpty
 *      包装类型不为空:@NotNull
 *
 * password:长度大于6
 */

@Data
public class User {
    @NotBlank
    private String name;

    @Length(min = 6, max = 20)
    private String password;

    @Min(1)
    private int age;

    @Email
    private String email;

    @Past
    private Date birthday;
}

UserController

java 复制代码
package com.cool.controller;

import com.cool.pojo.User;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("user")
public class UserController {

    /**
     * 步骤1:实体类属性添加校验注解
     * 步骤2:handler(@Validated 实体类对象){}
     *       细节:
     *          param、json 校验注解都有效果
     *          只不过,json参数的话,需要用 @RequestBody 修饰形参哦!
     *
     * 这里有个天坑:如果不符合校验规则,会直接向前端抛出异常
     * 解决办法:
     *      handler(@Validated 实体类对象, BindingResult request){}
     *      多加一个 BindingResult request 参数,
     *      此参数,必须紧挨着 @Validated 实体类对象,否则此参数不管用
     */
    @PostMapping("register")
    public Object register(@Validated @RequestBody User user, BindingResult result){
        System.out.println("user= " +  user);

        if(result.hasErrors()){
            // 有错误的话,就不直接返回给前端了,可以在这里自定义内容,返回给前端
            Map data = new HashMap();
            data.put("code", 400);
            data.put("msg", "参数校验异常");
            return data;
        }

        return user;
    }

    @GetMapping("data")
    public String data(){
        // 这个方法,做成,空指针异常
        String name = null;
        name.toString();  // NullPointerException,报错后,就不会执行下面的代码了,就会取异常处理那里
        return "data - ok";
    }

    @GetMapping("data1")
    public String data1(){
        // 这个方法,做成,算数异常
        int i = 1/0;  // ArithmeticException: / by zero
        return "data1 - ok";
    }
}

拦截器 MyInterceptor

java 复制代码
package com.cool.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;


/**
 * 声明好这个类之后,
 * 需要在 MvcConfig 类中注册上
 */
public class MyInterceptor implements HandlerInterceptor {

    /**
     * handler执行之前触发
     * @param request 请求对象
     * @param response 响应对象
     * @param handler 就是我们要调用的方法对象
     * @return true:放行,false:拦截
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("request= " + request + ",response= " + response + ",handler = " + handler);
        System.out.println("MyInterceptor.preHandle");
        return true;
    }

    /**
     * 当 handler 执行完毕后,触发此方法,没有拦截机制了
     * 此方法只有在 preHandle方法 return true 的时候才会被执行
     * @param request
     * @param response
     * @param handler
     * @param modelAndView 返回的视图和共享域的数据对象,如果没有的话,返回null
     * @throws Exception
     *
     * 对 响应结果 的处理
     *
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor.postHandle");
    }

    /**
     * 整体处理完毕后,会触发这个方法
     * @param request
     * @param response
     * @param handler
     * @param ex 如果 handler方法报错了,这个参数就是异常对象
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor.afterCompletion");
    }
}

拦截器 MyInterceptor1

java 复制代码
package com.cool.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;


/**
 * 声明好这个类之后,
 * 需要在 MvcConfig 类中注册上
 */
public class MyInterceptor1 implements HandlerInterceptor {

    /**
     * handler执行之前触发
     * @param request 请求对象
     * @param response 响应对象
     * @param handler 就是我们要调用的方法对象
     * @return true:放行,false:拦截
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor1.preHandle");
        return true;
    }


    /**
     * 当 handler 执行完毕后,触发此方法,没有拦截机制了
     * 此方法只有在 preHandle方法 return true 的时候才会被执行
     * @param request
     * @param response
     * @param handler
     * @param modelAndView 返回的视图和共享域的数据对象,如果没有的话,返回null
     * @throws Exception
     *
     * 对 响应结果 的处理
     *
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor1.postHandle");
    }


    /**
     * 整体处理完毕后,会触发这个方法
     * @param request
     * @param response
     * @param handler
     * @param ex 如果 handler方法报错了,这个参数就是异常对象
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor1.afterCompletion");
    }
}
相关推荐
wangmengxxw1 小时前
SpringAI-mysql
java·数据库·人工智能·mysql·springai
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-数据库设计核心业务方案
java·数据库·spring boot·ddd·tdd
一嘴一个橘子2 小时前
springmvc 参数校验
java
shehuiyuelaiyuehao2 小时前
String的杂七杂八方法
java·开发语言
木井巳2 小时前
【递归算法】计算布尔二叉树的值
java·算法·leetcode·深度优先
2 小时前
java关于时间类
java·开发语言
老蒋每日coding2 小时前
FISCO BCOS 部署Solidity投票智能合约并基于Java SDK 调用智能合约详细指南
java·区块链·智能合约
java1234_小锋2 小时前
Spring里AutoWired与Resource区别?
java·后端·spring
风象南2 小时前
Spring Boot 定时任务多实例互斥执行
java·spring boot·后端