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

主要是三个处理:

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

        2、统一异常处理;

        3、统一数据格式返回。

目录

一、用户登录权限校验

🍅  1、使用拦截器

        🎈 1.1自定义拦截器

        🎈 1.2 设置自定义拦截器

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

 🍅 2、拦截器原理

二、统一异常处理

三、统一数据返回

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

🍅 统一数据返回格式

       🎈定义同已返回类型

       🎈 同以数据处理

        🎈业务类


一、用户登录权限校验

🍅  1、使用拦截器

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

        🎈 1.1自定义拦截器

/*
* 全局变量
* */
public class AppVar {
//    Session keypublic static final String SESSION_KEY = "SESSION KEY";
}/*
* 自定义拦截器
* 返回true -> 表示拦截器验证成功,继续指定后续方法
* 返回false -> 表示验证失败,不会执行后续的方法了
* */
@Component
public class UserInterceptor implements HandlerInterceptor {@Overridepublic 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 {@Autowiredprivate UserInterceptor userInterceptor;@Overridepublic 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++) {// 获取项⽬中使⽤的拦截器 HandlerInterceptorHandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.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方法* */@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic 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类型作出单独处理:

@Autowiredprivate ObjectMapper objectMapper;@Overridepublic 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);}

返回结果:

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一零六七、JVM梳理

JVM&#xff1f; Java虚拟机&#xff0c;可以理解为Java程序的运行环境&#xff0c;可以执行Java字节码&#xff08;Java bytecode&#xff09;并提供了内存管理、垃圾回收、线程管理等功能 java内存区域划分?每块内存中都对应什么? 方法区&#xff1a;类的结构信息、常量池、…

Typescript+vite+sass手把手实现五子棋游戏(放置类)

Typescriptvitesass手把手实现五子棋游戏&#xff08;放置类&#xff09; 下面有图片和gif可能没加载出来 上面有图片和gif可能没加载出来 导言 最近练习Typescript&#xff0c;觉得差不多了&#xff0c;就用这个项目练练手&#xff0c;使用Typescript纯面向对象编程。 开源…

马斯克收购AI.com域名巩固xAI公司地位;如何评估大型语言模型的性能

&#x1f989; AI新闻 &#x1f680; AI拍照小程序妙鸭相机上线商业工作站并邀请摄影师进行内测 摘要&#xff1a;AI拍照小程序妙鸭相机将上线面向商业端的工作站&#xff0c;并邀请摄影师进行模板设计的内测。妙鸭相机希望为行业提供更多生态产品&#xff0c;扩大行业规模&a…

在java中如何使用openOffice进行格式转换,word,excel,ppt,pdf互相转换

1.首先需要下载并安装openOffice,下载地址为&#xff1a; Apache OpenOffice download | SourceForge.net 2.安装后&#xff0c;可以测试下是否可用&#xff1b; 3.build.gradle中引入依赖&#xff1a; implementation group: com.artofsolving, name: jodconverter, version:…

安卓4G核心板开发板_MTK6785/MT6785(Helio G95)安卓手机主板方案

联发科MTK6785&#xff08;Helio G95&#xff09;安卓核心板采用八核 CPU 具有两个强大的 Arm Cortex-A76 处理器内核&#xff0c;主频高达 2.05GHz&#xff0c;外加六个 Cortex-A55 高效处理器。其强大的图形性能由 Arm Mali-G76 MC4 提供&#xff0c;速度可提升至 900MHz 。 …

【云原生】K8S二进制搭建二:部署CNI网络组件

目录 一、K8S提供三大接口1.1容器运行时接口CRI1.2云原生网络接口CNI1.3云原生存储接口CSI 二、Flannel网络插件2.1K8S中Pod网络通信2.2Overlay Network2.3VXLAN2.4Flannel 三、Flannel udp 模式的工作原理3.1ETCD 之 Flannel 提供说明 四、vxlan 模式4.1Flannel vxlan 模式的工…

无向图-已知根节点求高度

深搜板子题&#xff0c;无向图&#xff0c;加边加两个&#xff0c;dfs输入两个参数变量&#xff0c;一个是当前深搜节点&#xff0c;另一个是父节点&#xff08;避免重复搜索父节点&#xff09;&#xff0c;恢复现场 ///首先完成数组模拟邻接表#include<iostream> #incl…

记一次 HTTPS 抓包分析和 SNI 的思考

日常听说 HTTPS 是加密协议&#xff0c;那现实中的 HTTPS 流量&#xff0c;是真的完全加密吗&#xff1f; ——答案是&#xff0c;不一定。原因嘛&#xff0c;抓个包就知道了。 我们用 curl 命令触发一下&#xff1a; curl -v https://s-api.37.com.cn/api/xxx * Trying 1…

python 常见数据类型和方法

不可变数据类型 不支持直接增删改 只能查 str 字符串 int 整型 bool 布尔值 None None型特殊常量 tuple 元组(,,,)回到顶部 可变数据类型&#xff0c;支持增删改查 list 列表[,,,] dic 字典{"":"","": ,} set 集合("",""…

Flutter 文件上传(七牛云)简单封装

前言&#xff1a;记录了七牛云上传图片的简单封装、若有不足 欢迎指正。 开始前准备&#xff1a; A、七牛sdk版本一定要和dart版本相对应&#xff08;推荐用any方式、让其自己去匹配&#xff09;&#xff1b; qiniu_flutter_sdk: any B、七牛上传文件所需的参数&#xff1a; …

GPIO实验

一、GPIO GPIO&#xff08;General-purpose input/output&#xff09;即通用型输入输出&#xff0c;GPIO可以控制连接在其之上的引脚实现信号的输入和输出 芯片的引脚与外部设备相连&#xff0c;从而实现与外部硬件设备的通讯、控制及信号采集等功能 LED实验步骤 最终目的&am…

windows 同时安装 Mysql 5.7 和8.0

下载链接 https://dev.mysql.com/downloads/mysql/ 推荐下载 MSI&#xff0c;可以通过图像化界面配置 8.1 版本 安装5.7 系统安装两个MySQL 怎么访问 都是mysql&#xff0c;所以环境变量 配置&#xff0c;只能一个生效&#xff0c;生效就是谁靠前谁生效 cmd 录入 services.m…

Linux用户管理

一、linux用户&#xff1a;username/UID Linux用户分为以下几种 root用户&#xff1a;UID为0&#xff0c;也称超级用户&#xff0c;权限最高。系统用户&#xff1a;UID为1~999&#xff0c;也称虚拟用户、伪用户、假用户&#xff0c;是系统自身拥有的用户&#xff0c;比如bin、…

SpringBoot+SSM实战<一>:打造高效便捷的企业级Java外卖订购系统

文章目录 项目简介项目架构功能模块管理端用户端 技术选型用户层网关层应用层数据层工具 项目优缺点结语 黑马程序员最新Java项目实战《苍穹外卖》&#xff1a;让你轻松掌握SpringBootSSM的企业级开发技巧项目简介 《苍穹外卖》是一款为餐饮企业&#xff08;餐厅、饭店&#x…

C++ 类的继承与派生

1.继承关系举例 交通工具的分类如下图所示&#xff1a; 这个分类树反映了交通工具的派生关系&#xff0c;最高层是抽象程度最高的&#xff0c;是最具有普遍和一般意义的概念&#xff0c;下层具有了上层的特性&#xff0c;同时加入了自己的新特征&#xff0c;而最下层是最为具…

[CKA]考试之PersistentVolumeClaims

由于最新的CKA考试改版&#xff0c;不允许存储书签&#xff0c;本博客致力怎么一步步从官网把答案找到&#xff0c;如何修改把题做对&#xff0c;下面开始我们的 CKA之旅 题目为&#xff1a; Task 创建一个名字为pv-volume的pvc&#xff0c;指定storageClass为csi-hostpath-…

HTML中元素和标签有什么区别?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 标签&#xff08;Tag&#xff09;⭐元素&#xff08;Element&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&a…

Leetcode-每日一题【剑指 Offer 17. 打印从1到最大的n位数】

题目 输入数字 n&#xff0c;按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3&#xff0c;则打印出 1、2、3 一直到最大的 3 位数 999。 示例 1: 输入: n 1输出: [1,2,3,4,5,6,7,8,9] 说明&#xff1a; 用返回一个整数列表来代替打印 n 为正整数 解题思路 前置知识 M…

kubernetes基于helm部署gitlab

kubernetes基于helm部署gitlab 这篇博文介绍如何在 Kubernetes 中使用helm部署 GitLab。 先决条件 已运行的 Kubernetes 集群负载均衡器&#xff0c;为ingress-nginx控制器提供EXTERNAL-IP&#xff0c;本示例使用metallb默认存储类&#xff0c;为gitlab pods提供持久化存储&…

将word每页页眉单独设置

在进行论文排版的时候&#xff0c;总是会出现页眉的页码设置问题&#xff0c;比如出现奇数或偶数页码一致&#xff0c;尝试将前面页码改掉&#xff0c;后面再修改前面也进行了变动&#xff0c;将每页页眉单独设置&#xff1a; &#xff08;1&#xff09;在第一页的最后一行输入…