SpringBoot统一功能处理

我们要实现以下3个目标:

  1. 统一用户登录权限
  2. 统一数据格式返回
  3. 统一异常处理

1.用户的登录权限校验

1.1Spring AOP用户统一登录验证问题

@Aspect
@Component
public class UserAspect {
    // 定义切点controller包下、子孙包下所有类的所有方法
    @Pointcut("execution(* com.example.demo.controller..*.*(..))")
    public void pointcut(){}

    //前置方法
    @Before("pointcut()")
    public void doBefore() {
        System.out.println("Before开始执行!");
    }

    //环绕方法
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        Object obj = null;
        System.out.println("Around方法开始执行");
        try {
            obj=joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("Around方法执行结束");
        return obj;
    }

}

在以上Spring AOP的切面中实现用户登录权限校验的功能,有以下几个问题:

  1. 没办法获取到HttpSession对象
  2. 我们要对一部分方法进行拦截,而另一部分方法不拦截,我们是很难定义的。

1.3Spring拦截器

对于以上问题Spring中提供了具体的实现拦截器:HandlerInterceptor,拦截器的实现分为以下连两个步骤:

  1. 创建自定义拦截器:实现HandlerInterceptor接口的preHandle方法(执行具体方法之前预处理)
  2. 自定义拦截器加入WebMvcConfigurer的addInterceptors方法中

1.3.1自定义拦截器

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        HttpSession session = request.getSession(false);
        if(session != null && session.getAttribute("userinfo") != null) {
            return true;
        }
        response.setStatus(401);
        return false;
    }
}

1.3.2将自定义拦截器加入到系统配置

@Configuration
public class AppConfig implements WebMvcConfigurer {
    //添加拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") //拦截所有接口
                .excludePathPatterns("/art/param11"); //排除一些接口
    }
}
  • addPathPatterns:表示需要拦截的URL,**表示拦截任意方法
  • excludePathPatterns:表示需要排除的URL

说明:以上拦截规则可以拦截此项目中使用的URL,包括静态文件

排除所有的静态资源

@Configuration
public class AppConfig implements WebMvcConfigurer {
    //添加拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") //拦截所有接口
                .excludePathPatterns("/art/param11") //排除一些接口
                .excludePathPatterns("/**/*.js")
                .excludePathPatterns("/**/*.css")
                .excludePathPatterns("/**/*.jpg")
                .excludePathPatterns("login.html")
                .excludePathPatterns("/**/login"); 
    }
}

1.4拦截器实现原理

有了拦截器之后,执行流程如下图所示:

 1.4.1实现源代码分析

所有的Controller执行都会通过一个调度器DispatcherServlet来实现,这一点可以从Spring Boot控制台的打印信息看出来,如下图所示(我们必须触发拦截功能):

 而所有的方法都会执行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);
            }

        }
    }

我们发现在开始执行Controller之前,会先调用预处理方法applyPreHandle,而这个方法就是获取实现HandlerInterceptor接口的所有所有类,并调用preHandler方法。

2.统一异常处理

统一异常处理使用的是@ControllerAdvice + @ExceptionHandler来实现的,@ControllerAdvice表示控制器通知类,@ExceptionHandler是异常处理器,两个结合表示当出现异常的时候执行某个通知,也就是执行了某个方法事件,具体代码实现如下:

@ControllerAdvice
public class ErrorAdive {
    
    @ExceptionHandler(Exception.class) 
    @ResponseBody
    public Object handler(Exception e) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("state", 0);
        map.put("data", null);
        map.put("msg", e.getMessage());
        return map;
    }
}

PS:方法名和返回值可以自定义,重要的是@ControllerAdvice和ExceptionHandler()

我们可以针对不同的异常设置不同的注解,这将返回不同的结果。

@ControllerAdvice
public class ErrorAdive {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object handler(Exception e) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("state", 0);
        map.put("data", null);
        map.put("msg", e.getMessage());
        return map;
    }

    @ExceptionHandler(NullPointerException.class)
    @ResponseBody
    public Object nullPointerExceptionAdvice(NullPointerException e) {
        HashMap<String, Object> ret = new HashMap<>();
        ret.put("state", 0);
        ret.put("msg", "空指针异常");
        ret.put("data", null);
        return ret;
    }

}

当有多个异常通知的时候,匹配顺序为当前类及其子类向上依次匹配。

3.统一数据返回格式

3.1为什么需要统一数据返回格式?

统一数据返回格式有以下优点:

  1. 方便前端程序员更好的接收和解析后端数据接口返回的数据
  2. 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就行了
  3. 有利于项目统一的数据的维护和修改
  4. 有利于后端技术部门的统一规范的标准制定

3.2统一数据返回格式的实现

统一的数据格式返回可以使用@ControllerAdvice + @ResponseBodyAdvice的方法实现,具体实现代码如下:

@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> result = new HashMap<>();
        result.put("state", 1);
        result.put("msg", "");
        result.put("data", body);
        return result;
    }
}

4.总结

  • 登录校验使用WebMvcConfigurer + HandlerInterceptor实现,
  • 统一异常处理使用@ControllerAdvice + @ExceptionHandler 来实现
  • 统一的返回值处理使用@ControllerAdvice + ResponseBodyAdvice来实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/55935.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

浅析大数据时代下的视频技术发展趋势以及AI加持下视频场景应用

视频技术的发展可以追溯到19世纪初期的早期实验。到20世纪初期&#xff0c;电视技术的发明和普及促进了视频技术的进一步发展。 1&#xff09;数字化&#xff1a;数字化技术的发明和发展使得视频技术更加先进。数字电视信号具有更高的清晰度和更大的带宽&#xff0c;可以更快地…

【李宏毅机器学习·学习笔记】Deep Learning General Guidance

本节课可视为机器学习系列课程的一个前期攻略&#xff0c;这节课主要对Machine Learning 的框架进行了简单的介绍&#xff1b;并以training data上的loss大小为切入点&#xff0c;介绍了几种常见的在模型训练的过程中容易出现的情况。 课程视频&#xff1a; Youtube&#xff1…

青少年软件编程(Python六级)等级考试试卷(2022年9月)

青少年软件编程&#xff08;Python六级&#xff09;等级考试试卷&#xff08;2022年9月&#xff09; 第 1 题 单选题 以下关于Python二维数据的描述中&#xff0c;错误的是&#xff1f;&#xff08; &#xff09; A. 表格数据属于二维数据&#xff0c;由整数索引的数据构成 …

Appium+python自动化(二十八)- 高级滑动(超详解)

高级溜冰的滑动 滑动操作一般是两点之间的滑动&#xff0c;这种滑动在这里称其为低级的溜冰滑动&#xff1b;就是上一节给小伙伴们分享的。然而实际使用过程中用户可能要进行一些多点连续滑动操作。如九宫格滑动操作&#xff0c;连续拖动图片移动等场景。那么这种高级绚丽的溜…

银河麒麟V10 飞腾 Qt环境搭建

采用在线安装方式&#xff1a; 1、在线安装qt组件 sudo apt-get install qt5-* 2、在线安装qt creator sudo apt-get install qtcreator 以上简单两步安装完成后&#xff0c;新建项目已经可以编译过&#xff0c;但ClangCodeModel会报错如下图 the code model could not parse …

docker—springboot服务通信

文章目录 docker—springboot服务通信一、方式1、host 二、坑点末、参考资料 docker—springboot服务通信 一、方式 1、host 步骤&#xff1a; host文件增加域名解析&#xff1a; 127.0.0.1 rabbitmqapplication.yml&#xff1a; application.yml中&#xff0c;连接方式使用…

matlab使用教程(7)—基本画图函数

1.创建绘图 plot 函数具有不同的形式&#xff0c;具体取决于输入参数。 • 如果 y 是向量&#xff0c; plot(y) 会生成 y 元素与 y 元素索引的分段线图。 • 如果有两个向量被指定为参数&#xff0c; plot(x,y) 会生成 y 对 x 的图形。 使用冒号运算符创建从 0 至 2…

python-网络爬虫.BS4

BS4 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库&#xff0c; 它能够通过你喜欢的转换器实现惯用的文档导航、查找、修改文档的方 式。 Beautiful Soup 4 官方文档&#xff1a;https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/ 帮助手册&…

devops(前端)

1.前言 前端的打包流程和后端的流程是一样的&#xff0c;只是打包的环境和制作的镜像有所不同&#xff0c;前端需要使用nodejs环境打包&#xff0c;镜像也是使用nginx镜像&#xff0c;因为用的是k8s的pod运行镜像&#xff0c;还需要使用configmap挂载nginx的配置&#xff0c;一…

CDH基于Kerberos开启身份验证实践总结

CDH基于Kerberos开启身份验证实践总结 前言简介Kerberos是什么Kerberos解决什么问题 Kerberos基本概念Kerberos认证流程Kerberos基本配置principalkeytabkrb5.confkdc.confkadm5.aclkerberos数据库 访问示例数据库访问信息 其他kerberos常用命令[Git Bash支持make命令](https:/…

【计算机网络】11、网络连通性:ping、traceroute、nslookup

文章目录 一、ping1.1 禁 ping 二、traceroute三、nslookup3.1 非交互模式3.2 交互模式 注意&#xff0c;测试网络连通性时&#xff0c;有的机器无法 ping 通&#xff0c;但可能 telnet 能通。不要因为无法 ping 通就放弃尝试。 一、ping 1.1 禁 ping 禁 ping 是通过忽略 IC…

SpringBoot 统⼀功能处理

目录 前言 1.⽤户登录权限效验 1.1、最初⽤户登录效验 1.2、Spring AOP ⽤户统⼀登录验证的问题 1.3、Spring 拦截器 了解 创建一个 Spring 拦截器 的流程 1、 创建自定义拦截器&#xff0c;实现 HandlerInterceptor 接⼝的preHandle&#xff08;执⾏具体⽅法之前的预处理…

day17 | 654.最大的二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

文章目录 一、最大的二叉树二、合并二叉树三、二叉搜索树中的搜索四、验证二叉搜索树 一、最大的二叉树 654.最大的二叉树 构建二叉树的题目&#xff0c;都用前序遍历。 因为我们一定要先构建根节点&#xff0c;才能继续向后构建。 递归函数的参数和返回值&#xff1a; Tree…

【MyBatis】MyBatis把空字符串转换成0的问题处理方案(96)

先看问题: Postman入参: MyBatis采用map循环插入: // Mapper接口层void addPar(Param(value "question") Map<String, Object> paramMap);<!-- 新增&#xff1a;参数 --><insert id"addPar" parameterType"map">INSERT IGNO…

小研究 - JVM 垃圾回收方式性能研究(一)

本文从几种JVM垃圾回收方式及原理出发&#xff0c;研究了在 SPEC jbb2015基准测试中不同垃圾回收方式对于JVM 性能的影响&#xff0c;并通过最终测试数据对比&#xff0c;给出了不同应用场景下如何选择垃圾回收策略的方法。 目录 1 引言 2 垃圾回收算法 2.1 标记清除法 2.2…

构建语言模型:BERT 分步实施指南

学习目标 了解 BERT 的架构和组件。了解 BERT 输入所需的预处理步骤以及如何处理不同的输入序列长度。获得使用 TensorFlow 或 PyTorch 等流行机器学习框架实施 BERT 的实践知识。了解如何针对特定下游任务(例如文本分类或命名实体识别)微调 BERT。为什么我们需要 BERT? 正…

使用docker部署Wordpress

文章目录 1.创建网络2.创建volume存储3.拉取镜像4.创建mysql容器mysql修改密码 5.创建wordpress容器6.访问localhost:80就可以直接使用啦 1.创建网络 docker network create --subnet172.18.0.0/24 pro-net2.创建volume存储 # mysql 存储 docker volume create volume_mysql…

怎么才能远程控制笔记本电脑?

为什么选择AnyViewer远程控制软件&#xff1f; 为什么AnyViewer是远程控制笔记本电脑软件的首选&#xff1f;以下是选择AnyViewer成为笔记本电脑远程控制软件的主要因素。 跨平台能力 AnyViewer作为一款跨平台远程控制软件&#xff0c;不仅可以用于从一台Windows电…

如何制作VR全景地图,VR全景地图可以用在哪些领域?

引言&#xff1a; 随着科技的迅速进步&#xff0c;虚拟现实&#xff08;VR&#xff09;技术正逐渐渗透到各个领域。VR全景地图作为其中的重要应用之一&#xff0c;为人们提供了身临其境的全新体验。 一.什么是VR全景地图&#xff1f; VR全景地图是一种利用虚拟现实技术&…

PHP8的数据类型-PHP8知识详解

在PHP8中&#xff0c;变量不需要事先声明&#xff0c;赋值即声明。 不同的数据类型其实就是所储存数据的不同种类。在PHP8.0、8.1中都有所增加。以下是PHP8的15种数据类型&#xff1a; 1、字符串&#xff08;String&#xff09;&#xff1a;用于存储文本数据&#xff0c;可以使…