当前位置: 首页 > article >正文

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

1.全局异常处理

使用ControllerAdvice与ExceptionHandler注解

/**
 * 全局异常处理程序
 *
 * @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注解,这个注解上可以指定时间格式和时区
/**
 * @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.跨域问题

@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
/**
 * 登录拦截器
 *
 * @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.添加拦截器,使用拦截器

/**
 * 登录拦截器配置类
 *
 * @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

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) {
    }
}

第二步:扫描监听器

@ServletComponentScan("cn.lgc.blog.listenter")//扫描servlet监听器
public class BlogApp {
    public static void main(String[] args) {
        SpringApplication.run(BlogApp.class, args);
    }
}

http://www.kler.cn/news/321651.html

相关文章:

  • Brave编译指南2024 MacOS篇-获取源码(三)
  • 如何解决: Java商城系统开发过程中 开发难度大和时间紧的问题
  • python-rpc-windows服务器C#项目远程调用Linux服务器上的python脚本
  • 数据库常见概念
  • React学习笔记(2.0)
  • 【rust】 基于rust编写wasm,实现markdown转换为html文本
  • Lab1 Xv6 and Unix utilities
  • 推荐、nlp、算法题等相关复习(0922-0929)
  • 计算机毕业设计宠物领养网站我的发布领养领养用户信息/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序
  • HalconDotNet实现OCR详解
  • 比较 Python Web 框架:Django、FastAPI 和 Flask
  • 如何使用 ChatGPT 生成万字长文?
  • verilog中非阻塞多个if 优先级判断。
  • 介绍与部署 Zabbix 监控系统
  • C#知识|基础知识点巩固拾遗
  • MySQL基础知识(二)
  • FBX福币连续2天破万亿,沪指重回3000点,后续怎么走?
  • 学习Java(三)
  • js发送邮件至指定邮箱功能实现方式和技巧?
  • 【系统架构设计师】专题:软件工程基础
  • 2024年9月27日历史上的今天大事件早读
  • 面向对象的三大特性:封装、继承、多态
  • AI/LLM 大模型入门指南
  • 探索EasyCVR视频融合平台:在视频编解码与转码领域的灵活性优势
  • 2024!再见前端!
  • TypeScript 设计模式之【备忘录模式】
  • 搜索插入位置
  • R包compareGroups详细用法
  • MySQL_插入、更新和删除数据
  • Android中大量使用建造者模式(Builder Pattern)的原因可以归结为以下几点: