SpringBoot-全局处理异常,时间格式,跨域,拦截器,监听器

1.全局异常处理

使用ControllerAdvice与ExceptionHandler注解

java 复制代码
/**
 * 全局异常处理程序
 *
 * @author 
 * @date 
 */
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public JsonResult handleException(Exception e) {
        e.printStackTrace();
        return JsonResult.error(e.getMessage());
    }

    /**
     * 处理业务异常
     *
     * @param e
     * @return {@link JsonResult}
     */
    @ExceptionHandler(BusinessException.class)
    public JsonResult handleBusinessException(BusinessException e) {
        e.printStackTrace();
        return JsonResult.error(e.getMessage());
    }

    /**
     * handle 方法参数无效异常
     *
     * @param e e
     * @return {@link JsonResult}
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public JsonResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        e.printStackTrace();
        return JsonResult.error(e.getBindingResult().getFieldError().getDefaultMessage());
    }

}

2.全局时间格式处理

配合第一种@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")联合使用了,哪些字段需要特殊对待的,就可以单独使用这个@JsonFormat注解进行处理了。

  • 如果是后台接收前端的时间数据,前端传递string类型的时间数据,后端要转换成的Date类型数据,可以使用@DateTimeFormat注解来接收参数
  • 如果后端向前端传递数据,默认是返回时间戳,如果想要优雅的格式,可以在模型的Date字段或get方法上使用@JsonFormat注解,这个注解上可以指定时间格式和时区
java 复制代码
/**
 * @description: 日期时间全局格式化
 * @auth: wujiangbo
 * @date: 2022-03-09 17:38
 */
@JsonComponent
public class LocalDateTimeSerializerConfig {

    @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
    private String pattern;

    /**
     * Date 类型全局时间格式化
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilder() {
        return builder -> {
            TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");//获取时区
            DateFormat df = new SimpleDateFormat(pattern);//设置格式化模板
            df.setTimeZone(tz);
            builder.failOnEmptyBeans(false)
                    .failOnUnknownProperties(false)
                    .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                    .dateFormat(df);
        }; }

    /**
     * LocalDate 类型全局时间格式化
     */
    @Bean
    public LocalDateTimeSerializer localDateTimeDeserializer() {
        return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern));
    }

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return builder -> builder.serializerByType(LocalDateTime.class, localDateTimeDeserializer());
    }
}

3.跨域问题

java 复制代码
@Configuration
/**
 * 告诉浏览器,我允许哪些服务器访问,哪些请求方式访问,是否运行携带请求头
 */
public class GlobalCorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        //1.添加CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        //2.允许的域,不要写*,否则cookie就无法使用了
        //config.addAllowedOriginPattern("*");
        config.addAllowedOriginPattern("http://127.0.0.1:8081");
        config.addAllowedOriginPattern("http://localhost:8081");
        config.addAllowedOriginPattern("http://127.0.0.1:80");
        config.addAllowedOriginPattern("http://localhost:80");
        config.addAllowedOriginPattern("http://127.0.0.1");
        config.addAllowedOriginPattern("http://localhost");

        //3.是否允许发送Cookie信息
        config.setAllowCredentials(true);
        //4.允许的请求方式
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        //5.允许的头信息
        config.addAllowedHeader("*");

        //6.添加映射路径,我们拦截一切请求
        UrlBasedCorsConfigurationSource configSource = new
                UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);
        //7.返回新的CorsFilter.
        return new CorsFilter(configSource);
    }
}

4. 配置拦截器

如何定义SpringMVC的拦截器

SpringMVC 的拦截器主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、判断登录等功能上

第1步,定义拦截器:可以实现 HandlerInterceptor 接口来自定义拦截器,接口定义了三个方法,preHandler方法是在请求到达处理器之前执行,postHandler方法是在请求经过处理器之后、解析试图之前执行,afterCompletion方法是在视图渲染之后、返回客户端之前执行

第2步,配置拦截器:在springmvc的配置文件xml中或配置类中,配置所有拦截路径,以及需要放行的路径

SpringMVC的执行原理

  1. DispatcherServlet:请求打过来由DispatcherServlet处理,它是 SpringMVC 中的前端控制器(中央控制器), 负责接收 Request 并将 Request 转发给对应的处理组件
  2. HandlerMapping:HandlerMapping 维护了 url 和 Controller(Handler)的 映 射关系 。 DispatcherServlet 接 收 请求, 然 后 从 HandlerMapping 查找处理请求的Controller(Handler),标注了@RequestMapping 的每个 method 都可以看成是一个 Handler,HandlerMapping 在请求到达之后, 它的作用便是找到请求相应的处理器 Handler 和 Interceptors。
  3. HandlerAdapter:SpringMVC通过HandlerAdapter对Handler进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。它的作用就是按照特定的规则去执行 Controller (Handler)
  4. Handler : Controller (Handler)负责处理请求,Controller 执行后并返回 ModelAndView 对象,其中包括了数据模型和逻辑视图,ModelAndView 是封装结果 视图的组件。Handler把结果返回给HandlerAdapter,HandlerAdapter把结果返回给DispatcherServlet前端控制器。
  5. ViewResolver:DispatcherServlet收到ModelAndView,调用视图解析器(ViewResolver)来解析HandlerAdapter传递的ModelAndView。Handler执行完成后返回的是逻辑视图,也就是视图名字,一个String ,还有一个Model就是数据模型,封装成ModelAndView。ViewResolver视图解析的作用就是根据视图名,把本地模板文件(比如:xx.jsp;xx.ftl)解析为View视图对象。View用来渲染视图,也就是负责把Handler返回的数据模型model,填充到模板(jsp;ftl)形成html格式的静态内容。
  6. 最后就是把生成的html通过response写给浏览器,浏览器进行html渲染展示。

1.创建拦截器

  1. HandlerInterceptor是接口,我们可以实现该接口来定义拦截器,
  2. HandlerInterceptorAdapter是抽象类,它实现了HandlerInterceptor接口的子接口AsyncHandlerInterceptor,我们可以继承该类来定义拦截器,它简化拦截器的实现,默认preHandler返回true
java 复制代码
/**
 * 登录拦截器
 *
 * @author 
 * @date 
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 前置拦截器
     *
     * @param request  请求
     * @param response 响应
     * @param handler  处理器
     * @return boolean
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");
        Boolean tag = false;
        if (token == null) {
            token = request.getParameter("token");
            tag = true;
        }
        Object tokenObj = redisTemplate.opsForValue().get(token);
        //token为null,说明没有登录,跳转到登录页面
        if (tokenObj == null) {
            responseMessage(response);
            if (tag) {
                response.sendRedirect("http://127.0.0.1/pages/login/login.html");
            }
            return false;
        }
        return true;
    }

    /**
     * 被拦截后的响应消息
     *
     * @param response 响应
     * @throws IOException ioexception
     */
    private static void responseMessage(HttpServletResponse response) throws IOException {
        //告诉浏览器响应数据类型
        response.setContentType("application/json;charset=UTF-8");
        //设置响应数据
        PrintWriter writer = response.getWriter();
        writer.write("{\"code\": \"403\", \"success\": false, \"msg\": \"请先登录\"}");
    }
}

2.添加拦截器,使用拦截器

java 复制代码
/**
 * 登录拦截器配置类
 *
 * @author 
 * @date 2023/12/18
 */
@Configuration
public class LoginInterceptorConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //启用登录拦截器
        registry.addInterceptor(loginInterceptor)
                //拦截所有请求
                .addPathPatterns("/**")
                //登录放行
                .excludePathPatterns("/login/**");
    }
}

5.集成Servllet组件,配置监听器

第一步:继承ServletContextListener

java 复制代码
public interface ServletContextListener extends EventListener {

    //当servlet初始化上下文容器时触发
    public default void contextInitialized(ServletContextEvent sce) {
        	// 获取Servlet上下文
            ServletContext servletContext = sce.getServletContext();
            // 获取springMVC上下文
            WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
    }

	//当servlet销毁上下文容器时触发
    public default void contextDestroyed(ServletContextEvent sce) {
    }
}

第二步:扫描监听器

java 复制代码
@ServletComponentScan("cn.lgc.blog.listenter")//扫描servlet监听器
public class BlogApp {
    public static void main(String[] args) {
        SpringApplication.run(BlogApp.class, args);
    }
}
相关推荐
鲤籽鲲几秒前
C# Random 随机数 全面解析
android·java·c#
荆州克莱6 分钟前
mysql中局部变量_MySQL中变量的总结
spring boot·spring·spring cloud·css3·技术
zquwei19 分钟前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
TT哇25 分钟前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
火烧屁屁啦1 小时前
【JavaEE进阶】初始Spring Web MVC
java·spring·java-ee
w_31234541 小时前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安1 小时前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA1 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
北辰浮光1 小时前
[spring]XML配置文件标签
xml·spring
Q_19284999061 小时前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端