SpringBoot—统一功能处理

这篇具有很好参考价值的文章主要介绍了SpringBoot—统一功能处理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

利用 AOP 的思想对一些特定的功能进行统一的处理, 包括

  • 使用拦截器实现用户登录权限的统一校验
  • 统一异常的处理
  • 统一数据格式的返回

🔎小插曲(通过一级路由调用多种方法)


通过一级路由调用多种方法, 需要保证这些方法的请求类型各不相同(GET, POST, PUT…)

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

🔎使用拦截器实现用户登录权限的统一校验


使用 Spring AOP 可以实现统一拦截, 但 Spring AOP 的使用较为复杂, 包括

  1. 定义拦截的规则(切点表达式)较为复杂
  2. 在切面类中拿到 HttpSession 较为复杂

于是 Pivotal 公司针对上述情况开发出 Spring 拦截器

Spring 拦截器的使用🍂

  1. 自定义拦截器
    • 实现 HandlerInterceptor 接口
    • 重写 preHandler 方法, 在方法中编写业务代码
  2. 将自定义拦截器添加至配置文件中, 并设置拦截的规则

自定义拦截器


SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

将自定义拦截器添加至配置文件中


  • addPathPatterns, 表示需要拦截的 URL
    (/*表示一级路由, /**表示所有的请求)
  • excludePathPatterns, 表示不需要拦截的 URL
    SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

拦截器的实现原理


调用方法时, 发现 DispatcherServlet

Dispatcher → 调度器

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

所有方法都会执行 DispatcherServlet 中的 doDispatch—调度方法

拦截器(doDispatch)的实现源码🌰

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
     HttpServletRequest processedRequest = request;
     HandlerExecutionChain mappedHandler = null;
     boolean multipartRequestParsed = false;
     WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

     try {
         try {
             ModelAndView mv = null;
             Object dispatchException = null;

             try {
                 processedRequest = this.checkMultipart(request);
                 multipartRequestParsed = processedRequest != request;
                 mappedHandler = this.getHandler(processedRequest);
                 if (mappedHandler == null) {
                     this.noHandlerFound(processedRequest, response);
                     return;
                 }

                 HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                 String method = request.getMethod();
                 boolean isGet = HttpMethod.GET.matches(method);
                 if (isGet || HttpMethod.HEAD.matches(method)) {
                     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                     if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                         return;
                     }
                 }

                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                     return;
                 }

                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                 if (asyncManager.isConcurrentHandlingStarted()) {
                     return;
                 }

                 this.applyDefaultViewName(processedRequest, mv);
                 mappedHandler.applyPostHandle(processedRequest, response, mv);
             } catch (Exception var20) {
                 dispatchException = var20;
             } catch (Throwable var21) {
                 dispatchException = new NestedServletException("Handler dispatch failed", var21);
             }

             this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
         } catch (Exception var22) {
             this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
         } catch (Throwable var23) {
             this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
         }

     } finally {
         if (asyncManager.isConcurrentHandlingStarted()) {
             if (mappedHandler != null) {
                 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
             }
         } else if (multipartRequestParsed) {
             this.cleanupMultipart(processedRequest);
         }

     }
}

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

当返回结果为 false 时, 拦截器将不会进行后续操作

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

applyPreHandle 的源码🌰

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
        HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
        if (!interceptor.preHandle(request, response, this.handler)) {
            this.triggerAfterCompletion(request, response, (Exception)null);
            return false;
        }
    }

    return true;
}

分析源码🍂

在 applyPreHandle 中会获取所有的拦截器 HandlerInterceptor, 并执行 HandlerInterceptor 中的 preHandle 方法

即自定义拦截器中重写的 preHandle 方法

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

统⼀访问前缀添加


统⼀访问前缀的添加有 2 种方式

  1. 重写 configurePathMatch( )
  2. 在配置文件中添加

重写 configurePathMatch( ) 🍂

@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
    configurer.addPathPrefix("/bibubibu", c -> true);
}
  • /bibubibu, 要添加的统一前缀
  • c -> true, 所有请求均添加统一前缀

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

在配置文件中添加🍂

server:
  servlet:
    context-path: /bibubibu

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

🔎统一异常的处理


统一异常的处理, 利用 2 个注解

  1. @ControllerAdvice → 感知异常
  2. @ExceptionHandler → 处理异常

未设置异常处理🍂

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

NullPointerException

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

ArithmeticException

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

设置异常处理🍂

@ControllerAdvice
@ResponseBody
public class MyExceptionHandler {

    /**
    * 拦截所有空指针异常, 进行统一数据格式的返回
    * @author bibubibu
    * @date 2023/7/9
    */
    @ExceptionHandler(NullPointerException.class)
    public HashMap<String, Object> nullPointerException(NullPointerException e) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("status", -1);
        map.put("data", null);
        map.put("msg", "NullPointerException" + e.getMessage()); // 错误码的描述信息
        return map;
    }

    /**
    * 拦截所有算数异常, 进行统一数据格式的返回
    * @author bibubibu
    * @date 2023/7/9
    */
    @ExceptionHandler(ArithmeticException.class)
    public HashMap<String, Object> arithmeticException(ArithmeticException e) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("status", -1);
        map.put("data", null);
        map.put("msg", "ArithmeticException" + e.getMessage()); // 错误码的描述信息
        return map;
    }

    /**
    * 拦截所有异常, 进行统一数据格式的返回
    * @author bibubibu
    * @date 2023/7/9
    */
    @ExceptionHandler(Exception.class)
    public HashMap<String, Object> exception(Exception e) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("status", -1);
        map.put("data", null);
        map.put("msg", "Exception" + e.getMessage());
        return map;
    }
}

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

NullPointerException

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

ArithmeticException

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

🔎统一数据格式的返回


统一数据格式返回的优点


  1. 方便前端程序员更好的接收和解析后端数据接口返回的数据
  2. 降低前端程序员和后端程序员的沟通成本, 按照某个格式实现即可, 因为所有接口都是这样返回的
  3. 有利于项目统一数据的维护和修改
  4. 有利于后端技术部门统一规范的标准制定, 不会出现奇怪的返回内容

统一数据格式返回的实现


统一数据格式的返回, 利用注解 @ControllerAdvice + ResponseBodyAdvice(接口) 实现

未设置统一数据格式的返回🍂

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

    @RequestMapping("get-num")
    public Integer getNumber() {
        return (int) (Math.random() * 10 + 1);
    }

}

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

设置统一数据格式的返回🍂

  1. 自定义类(ResponseAdvice), 添加 @ControllerAdvice 注解
  2. 实现 ResponseBodyAdvice 接口, 重写 supports() 与 beforeBodyWrite()

supports() 类似于一个开关
当返回值为 true 时, 开启 beforeBodyWrite() 中编写的相关功能
当返回值为 false 时, 关闭 beforeBodyWrite() 中编写的相关功能

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("status", 200);
        map.put("data", body); // 此处的 Body 是 String 类型会出错
        map.put("msg", "");
        return map;
    }
}

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

当方法的返回值类型为 String 时

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

    @RequestMapping("/get-user")
    public String getUser() {
        System.out.println("执行 getUser()");
        return "getUser~~";
    }

}

当调用方法的返回值类型为 String 时, 设置统一数据格式的返回🍂

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

类型转换异常

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

解决方法

当调用方法的返回值类型为 String 时, 利用 jackson 完成类型转换

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    // 利用 jackson 转换 String
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("status", 200);
        map.put("data", body); // 此处的 Body 是 String 类型会出错
        map.put("msg", "");
        // 判断 Body 是否为 String 类型
        if(body instanceof String) {
            // 是 String 类型, 将 map 转换为 Json 格式
            try {
                return objectMapper.writeValueAsString(map);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
}

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端

🔎总结


  1. 用户登录权限的统一校验 → 实现 HandlerInterceptor 接口 + 重写 preHandler 方法 + 将自定义拦截器添加至配置文件中(实现 WebMvcConfigurer 接口)
  2. 统一访问前缀的添加 → 重写 configurePathMatch( ) / 在配置文件中添加
  3. 统一异常的处理 → 利用注解 @ControllerAdvice + @ExceptionHandler
  4. 统一数据格式的返回 → 利用注解 @ControllerAdvice + 实现接口 ResponseBodyAdvice

🌸🌸🌸完结撒花🌸🌸🌸

SpringBoot—统一功能处理,JavaEE,spring boot,java,后端文章来源地址https://www.toymoban.com/news/detail-538399.html

到了这里,关于SpringBoot—统一功能处理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring Boot】拦截器与统一功能处理

    博主简介:想进大厂的打工人 博主主页: @xyk: 所属专栏: JavaEE进阶   上一篇文章我们讲解了Spring AOP是一个基于面向切面编程的框架,用于将某方面具体问题集中处理,通过代理对象来进行传递,但使用原生Spring AOP实现统一的拦截是非常繁琐的。而在本节,我们将使用一种

    2024年02月14日
    浏览(29)
  • 【Spring Boot】拦截器与统一功能处理:统一登录验证、统一异常处理与统一数据返回格式

     Spring AOP是一个基于面向切面编程的框架,用于将横切性关注点(如日志记录、事务管理)与业务逻辑分离,通过代理对象将这些关注点织入到目标对象的方法执行前后、抛出异常或返回结果时等特定位置执行,从而提高程序的可复用性、可维护性和灵活性。但使用原生Sp

    2024年02月16日
    浏览(34)
  • 【Spring】SpringBoot 统一功能处理

    在日常使用 Spring 框架进行开发的时候,对于一些板块来说,可能需要实现一个相同的功能,这个功能可以是验证你的登录信息,也可以是其他的,但是由于各个板块实现这个功能的代码逻辑都是相同的,如果一个板块一个板块进行添加的话,开发效率就会很低,所以 Spring

    2024年01月18日
    浏览(33)
  • 【Spring Boot统一功能处理】统一异常处理,统一的返回格式,@ControllerAdvice简单分析,即将走进SSM项目的大门! ! !

    前言: 大家好,我是 良辰丫 ,在上一篇文章中我们已经学习了一些统一功能处理的相关知识,今天我们继续深入学习这些知识,主要学习统一异常处理,统一的返回格式,@ControllerAdvice简单分析.💌💌💌 🧑个人主页:良辰针不戳 📖所属专栏:javaEE进阶篇之框架学习 🍎励志语句:生

    2024年02月16日
    浏览(33)
  • Spring Boot 统一功能处理(拦截器实现用户登录权限的统一校验、统一异常返回、统一数据格式返回)

    目录 1. 用户登录权限校验 1.1 最初用户登录权限效验 1.2 Spring AOP 用户统⼀登录验证 1.3 Spring 拦截器 (1)创建自定义拦截器 (2)将自定义拦截器添加到系统配置中,并设置拦截的规则 1.4 练习:登录拦截器 (1)实现 UserController 实体类 (2)返回的登录页面:login.html (3)实

    2024年02月12日
    浏览(34)
  • 【JavaEE】Spring全家桶实现AOP-统一处理

    【JavaEE】AOP(2) 在前面的Spring AOP的学习之中,Spring AOP去实现AOP,虽然比较灵活,可以实现很多想法,但是也有一些现实的问题: 没办法获取到HttpRequest,一些功能难以实现 进而无法获取HttpSession对象,这样登录校验功能就无法实现 我们要对⼀部分方法进行拦截,而另⼀部

    2024年02月11日
    浏览(24)
  • Spring Boot 优雅实现统一数据返回格式+统一异常处理+统一日志处理

            在我们的项目开发中,我们都会对数据返回格式进行统一的处理,这样可以方便前端人员取数据,当然除了正常流程的数据返回格式需要统一以外,我们也需要对异常的情况进行统一的处理,以及项目必备的日志。         在项目开发中返回的是json格式的数据

    2024年01月19日
    浏览(32)
  • Spring Boot实现统一异常处理的技术解析

    引言 在软件开发过程中,异常处理是非常重要的一环。一个好的异常处理机制可以帮助我们更好地定位问题,提高代码的可维护性和稳定性。Spring Boot作为一款轻量级的Java开发框架,提供了一种简单而高效的方式来实现统一异常处理。本文将详细介绍如何使用Spring Boot实现统

    2024年01月21日
    浏览(29)
  • Spring Boot 统一数据返回格式 分析 和 处理

    目录 实现统一数据格式  测试   原因分析  解决方案 🎥 个人主页:Dikz12 📕格言:吾愚多不敏,而愿加学 欢迎大家👍点赞✍评论⭐收藏 统⼀的数据返回格式使⽤ @ControllerAdvice 和 ResponseBodyAdvice 的⽅式实现; @ControllerAdvice : 表⽰控制器通知类. 比如:添加类 ResponseAdvic

    2024年04月08日
    浏览(40)
  • Spring统一功能处理

    获取参数复杂 AOP的规则相对简单 2.1.1. 自定义拦截器 新建interceptor文件夹 2.1.2. 将自定义拦截器加入到系统配置 新建config文件夹 2.1.3. 业务代码 方法1 方法2 2.3.1. 总体思路 2.3.2. 部分源码分析 拦截器是基于AOP实现的 (AOP基于动态代理(JDK|CGLIB)) 参考上一节 拦截器的应用 对于下面

    2024年02月11日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包