SpringBoot统一功能处理(AOP思想实现)(统一用户登录权限验证 / 异常处理 / 数据格式返回)

主要是三个处理:

        1、统一用户登录权限验证;

        2、统一异常处理;

        3、统一数据格式返回。

目录

一、用户登录权限校验

🍅  1、使用拦截器

        🎈 1.1自定义拦截器

        🎈 1.2 设置自定义拦截器

        🎈创建controller类,并且运行项目

 🍅 2、拦截器原理

二、统一异常处理

三、统一数据返回

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

🍅 统一数据返回格式

       🎈定义同已返回类型

       🎈 同以数据处理

        🎈业务类


一、用户登录权限校验

🍅  1、使用拦截器

可以对一部分方法进行拦截,而另一部分不拦截。

        🎈 1.1自定义拦截器

/*
* 全局变量
* */
public class AppVar {
//    Session key
    public static final String SESSION_KEY = "SESSION KEY";
}

/*
* 自定义拦截器
* 返回true -> 表示拦截器验证成功,继续指定后续方法
* 返回false -> 表示验证失败,不会执行后续的方法了
* */
@Component
public class UserInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
//        业务方法
        HttpSession session = request.getSession(false);
        if (session!=null &&
                session.getAttribute(AppVar.SESSION_KEY)!=null){
//            用户已经登录
            return true;
        }
        return false;
    }
}

        🎈 1.2 设置自定义拦截器

将自定义拦截器设置当前项目的配置文件中,并且设置拦截规则。

拦截器要注入到Spring中才能运行,他是伴随着Spring的启动而启动的

@Configuration
public class AppConfig implements WebMvcConfigurer {
    @Autowired
    private UserInterceptor userInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(new UserInterceptor());
        registry.addInterceptor(userInterceptor)
                .addPathPatterns("/**")    //("/**")表示拦截所有的请求
                .excludePathPatterns("/user/reg")//表示过滤拦截,不拦截(/user/reg)
                .excludePathPatterns("/user/login");//表示过滤拦截,不拦截("/user/login")
    }
}

        🎈创建controller类,并且运行项目


@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/getuser")
    public String getUser(){
        System.out.println("do getUser()");
        return "user";
    }

    @RequestMapping("/reg")
    public String reg(){
        System.out.println("do reg()");
        return "reg";
    }

    @RequestMapping("/login")
    public String login(){
        System.out.println("do login()");
        return "login";
    }
}

其中:

  • addPathPatterns:表示要拦截的url,“/**”表示拦截任意方法
  • elcludePathPatterns:表示需要排除的URL
  • 以上得拦截规则可以拦截URL,包括静态文件(图片文件、JS、CSS等),一般拦截静态文件的时候,我们可以把这些静态文件分类放在static文件中

 🍅 2、拦截器原理

在使用拦截器之前

 

 

使用拦截器之后:会在调用Controller之前进行相应的业务处理

实现原理源码分析:

          所有的controller指定都会通过一个调度器DispatcherServlet来实现,

 

所有的请求都会执行DispatcherServlet中的doDispatcher方法,在doDispatcher会执行一系列的事件,该事件是在执行拦截器之前的,如果该事件返回false,后续就不会执行Controller。

以下是doDispatcher中的一部分代码,发现在执行controller之前都会追先执行预处理

// 调⽤预处理【重点】

 if (!mappedHandler.applyPreHandle(processedRequest, respon
se)) {
 return;
 }
 // 执⾏ Controller 中的业务

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

那么,关于预处理⽅法 applyPreHandle方法:从上面的源码可以看出,着和我们之前定义的拦截器相似,着就是拦截器的实现原理

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex

                = i++) {
            // 获取项⽬中使⽤的拦截器 HandlerInterceptor

            HandlerInterceptor interceptor = (HandlerInterceptor)this.intercep
            torList.get(i);
            if (!interceptor.preHandle(request, response, this.handler)) {
                this.triggerAfterCompletion(request, response, (Exception)null

                );
                return false;
            }
        }
        return true;
    }

二、统一异常处理

统一异常处理:就是指常规的异常,统一处理。

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

首先认为构造一个空指针异常:

 @RequestMapping("/reg")
    public String reg(){
        System.out.println("do reg()");
        Object obj = null;
        System.out.println(obj.hashCode());
        System.out.println();
        System.out.println("do reg()");
        return "reg";
    }

报错了: 这种直接给你报错的方式并不直观,所以我们可以进行统一的异常处理,返回直观的数据。

 然后我们进行统一异常处理:

        首先定义一个统一的返回对象:

@Data
public class ResultAjax {
    private int code;   //状态码
    private String msg; //状态码的描述信息
    private Object data;//返回数据
}

        然后定义异常管理器:

@RestControllerAdvice
public class ExceptionAdvice {

    @ExceptionHandler(NullPointerException.class)
    public ResultAjax doNullPointerException(NullPointerException e){
        ResultAjax resultAjax = new ResultAjax();
        //错误的信息使用-1描述状态码
        resultAjax.setCode(-1);
        resultAjax.setMsg("空指针异常:"+ e.getMessage());
        resultAjax.setData(null);
        return resultAjax;
    }
}

这时候就会返回状态的描述信息:


 也可以直接使用NullPointerException的父类

@ExceptionHandler(Exception.class)
    public ResultAjax doException(Exception e){
        ResultAjax resultAjax = new ResultAjax();
        resultAjax.setCode(-1);
        resultAjax.setMsg("空指针异常:"+ e.getMessage());
        resultAjax.setData(null);
        return resultAjax;
    }

三、统一数据返回

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

统一数据返回格式的优点(为什么要统一):

  • 方便程序员更好的接收和解析后端数据接口返回的数据
  • 降低前端程序源和后端程序员的沟通成本,按照找某个格式实现,所有接口都这样返回
  • 有利于项目统一数据的维护和修改
  • 有利于后端技术部分的统一规范的标准制定,不会出现稀奇古怪的返回内容

🍅 统一数据返回格式

       🎈定义同已返回类型

@Data
public class ResultAjax {
    private int code;   //状态码
    private String msg; //状态码的描述信息
    private Object data;//返回数据

    /*
    * 返回成功
    * */
    public static ResultAjax success(Object data){
        ResultAjax resultAjax = new ResultAjax();
        resultAjax.setCode(200);
        resultAjax.setMsg("");
        resultAjax.setData(data);
        return resultAjax;
    }


    /*
    * 返回失败
    * */
    public static ResultAjax fail(int code,String msg){
        ResultAjax resultAjax = new ResultAjax();
        resultAjax.setCode(code);
        resultAjax.setMsg(msg);
        resultAjax.setData(null);
        return resultAjax;
    }

    public static ResultAjax fail(int code,String msg,Object data){
        ResultAjax resultAjax = new ResultAjax();
        resultAjax.setCode(code);
        resultAjax.setMsg(msg);
        resultAjax.setData(null);
        return resultAjax;
    }
}

              🎈 同以数据处理

统一数据处理(强制执行):

  1. @ControllerAdvice
  2. 实现ResponseBodyAdvice接口,并且重写它其中的两个方法,supports必须返回true,beforeBodyWrite方法进行重新判断和重写操作
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    /*
    * 默认翻会true的时候
    * 才会执行beforeBodyWrite方法
    * */
    @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) {
        //已经包装好的对象
        if (body instanceof ResultAjax){
            return body;
        }
//        没有包装
        return ResultAjax.success(body);

    }
}

        🎈业务类

@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/login")
    public ResultAjax login(){
        System.out.println("do login()");
        return ResultAjax.success("login");
    }
    
    @RequestMapping("/getnum")
    public int getNum(){
        return 1;
    }
}

其中login没有定义返回类型,getNum定义了返回类型,返回结果分别如下:

 

注意:

        如果定义的返回值类型是String,那么会报错

  @RequestMapping("/getstring")
    public String getString(){
        return "qqq";
    }

那么可以对String类型作出单独处理:

@Autowired
    private ObjectMapper objectMapper;

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class selectedConverterType,
                                  ServerHttpRequest request,
                                  ServerHttpResponse response) {
        //已经包装好的对象
        if (body instanceof ResultAjax){
            return body;
        }
//        对字符串进行单独处理
        if (body instanceof String){
            ResultAjax resultAjax = ResultAjax.success(body);
            try {
                return objectMapper.writeValueAsString(resultAjax);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
//        没有包装
        return ResultAjax.success(body);
    }

返回结果:

 

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

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

相关文章

SSM项目-博客系统

在线体验项目&#xff1a;登陆页面 项目连接&#xff1a;huhublog_ssm: 个人博客系统 技术栈&#xff1a;SpringBoot、SpringMVC、Mybatis、Redis、JQuery、Ajax、Json (gitee.com) 1.项目技术点分析 SpringBoot、SpringWeb(SpringMVC)、MyBatis、MySQL(8.x)、Redis(存储验…

JSP实训项目设计报告—MVC简易购物商城

JSP实训项目设计报告—MVC简易购物商城 文章目录 JSP实训项目设计报告—MVC简易购物商城设计目的设计要求设计思路系统要求单点登录模块商品展示模块购物车展示模块 概要设计Model层View层Controller层 详细设计Model层View层登录界面系统主界面 Controller层 系统运行效果项目…

【驱动开发day8作业】

作业1&#xff1a; 应用层代码 #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h>int main(int…

CVE-2022-23134(Zabbix setup 访问控制登录绕过)

目录 一、题目 二、进入题目 一、题目 靶标介绍&#xff1a; Zabbix Sia Zabbix是拉脱维亚Zabbix SIA&#xff08;Zabbix Sia&#xff09;公司的一套开源的监控系统。该系统支持网络监控、服务器监控、云监控和应用监控等。 Zabbix 存在安全漏洞&#xff0c;该漏洞源于在初始…

为什么要选择文件传输软件?有哪些最佳高速文件传输软件?

是否经历过这样的场景&#xff0c;正在努力地完成工作任务&#xff0c;但是由于制作的数据无法及时传送给合作伙伴&#xff0c;工作流程被打断了&#xff1f;这听起来很令人沮丧&#xff0c;对吧&#xff1f;可是&#xff0c;这种情况在现实中并不罕见。 因此&#xff0c;需要…

数据结构——搜索二叉树

文章目录 一. 概念二. 二叉搜索树的操作1.查找2.插入3.删除&#xff08;重点&#xff09;4.遍历5.拷贝构造与析构 三.二叉搜索树的递归实现1.递归查找2.递归插入3.递归删除 四.二叉搜索树的性能分析五.二叉树搜索的应用六.源码 前言&#xff1a; 本章我们将认识一种新的二叉树—…

Spring Boot配置文件与日志文件

1. Spring Boot 配置文件 我们知道, 当我们创建一个Spring Boot项目之后, 就已经有了配置文件存在于目录结构中. 1. 配置文件作用 整个项目中所有重要的数据都是在配置文件中配置的&#xff0c;比如: 数据库的连接信息 (包含用户名和密码的设置) ;项目的启动端口;第三方系统的调…

【chrome扩展开发】vue-i18n使用问题及解决方案

记录chrome扩展开发时调用vue-i18n的一些问题和解决方法 环境 vue: ^3.3.4vue-i18n: ^9.2.2vite: ^4.4.8 错误1 Uncaught (in promise) EvalError: Refused to evaluate a string as JavaScript because unsafe-eval is not an allowed source of script in the following Con…

vi 编辑器入门到高级

vi 编辑器的初级用法vi 编辑器的工作模式1. 命令模式2. 文本输入模式3. 状态行vi 工作模式切换存储缓冲区 vi 编辑器命令1. 启动 vi2. 文本输入3. 退出 vi4. 命令模式下的 光标移动5. 命令模式下的 文本修改6. 从 命令模式 进入 文本输入模式7. 搜索字符串8. vi 在线帮助文档 v…

云原生Kubernetes:阿里云托管k8s集群ACK创建和使用

目录 一、理论 1.容器服务Kubernetes版 2.ACK Pro版集群概述 3.CKA版本说明 二、实验 1.创建专有版Kubernetes集群 三、问题 1.依赖检查未通过 一、理论 1.容器服务Kubernetes版 &#xff08;1&#xff09;概念 阿里云容器服务Kubernetes版&#xff08;Alibaba Cloud…

mysql转sqlite3

在项目中需要将mysql迁移到sqlite3中&#xff0c;此时需要作数据转换 准备工作 下载mysql2sqlite转换工具 https://github.com/dumblob/mysql2sqlite/archive/refs/heads/master.zip 下载sqlite3 https://www.sqlite.org/download.html 转换 命令行中输入如下命令 1、cd …

Vue——webpack

webpack 一、Install1.全局安装2.局部安装 二、总结1.打包2.定义脚本3.配置文件定义&#xff08;webpack.config.js)4.项目重新加载依赖5.webpack打包Css6.style-loader 一、Install 1.全局安装 npm install webpack webpack-cli -g2.局部安装 以项目为单位&#xff0c;一个项…

skywalking日志收集

文章目录 一、介绍二、添加依赖三、修改日志配置1. 添加链路表示traceId2. 添加链路上下文3. 异步日志 四、收集链路日志 一、介绍 在上一篇文章skywalking全链路追踪中我们介绍了在微服务项目中使用skywalking进行服务调用链路的追踪。 本文在全链路追踪的基础上&#xff0c…

QT生成Debug和Release发布版后,运行exe缺少dll问题

在QT Creator生成debug和release的exe执行文件后&#xff0c;运行时&#xff0c;报错缺少*.dll.解决办法1&#xff1a; 在系统环境变量中添加D:\Qt\Qt5.13.2\Tools\mingw730_64\bin后&#xff0c;即可运行。 当使用此方法时&#xff0c;将exe拷贝到其他电脑中运行时&#xff0c…

科技感响应式管理系统后台登录页ui设计html模板

做了一个科技感的后台管理系统登录页设计&#xff0c;并且尝试用响应式布局把前端html写了出来&#xff0c;发现并没有现象中的那么容易&#xff0c;chrome等标准浏览器都显示的挺好&#xff0c;但IE11下面却出现了很多错位&#xff0c;兼容起来还是挺费劲的&#xff0c;真心不…

《吐血整理》高级系列教程-吃透Fiddler抓包教程(36)-掌握Fiddler中FiddlerScript用法你会有多牛逼-上

1.简介 Fiddler是一款强大的HTTP抓包工具&#xff0c;它能记录所有客户端和服务器的http和https请求&#xff0c;允许你监视&#xff0c;设置断点&#xff0c;甚至修改输入输出数据. 使用Fiddler无论对开发还是测试来说&#xff0c;都有很大的帮助。Fiddler提供的功能基本上能…

全网最全Linux 运行jar包的几种方式

一、Linux 运行jar包的几种方式 方式一&#xff1a; java -jar xxx.jar 最常用的启动jar包命令&#xff0c;特点&#xff1a;当前ssh窗口被锁定&#xff0c;可按CTRL C打断程序运行&#xff0c;或直接关闭窗口&#xff0c;程序退出 方式二&#xff1a; java -jar xxx.jar &…

复原 IP 地址——力扣93

文章目录 题目描述回溯题目描述 回溯 class Solution{public:static constexpr int seg_count=4<

使用Python + Flask搭建web服务

示例脚本 from flask import Flask# 获取一个实例对象 app Flask(__name__)# 1、注册 app.route(/reg, methods[get]) def reg():return {code: 200,msg: reg ok!}# 2、登录 app.route(/login, methods[get]) def login():return login ok&#xff01;if __name__ __main__:…

防火墙第五次作业

1. 什么是恶意软件&#xff1f; 恶意软件官方的一个定义&#xff1a;恶意软件 (Malware) 从“恶意”(malicious) 和“软件”(software) 这两个词合并而来&#xff0c;是一个通用术语&#xff0c;可以指代病毒、蠕虫、特洛伊木马、勒索软件、间谍软件、广告软件和其他类型的有害…