Spring Boot 统一功能处理

news2025/7/16 8:42:50

✏️作者:银河罐头
📋系列专栏:JavaEE

🌲“种一棵树最好的时间是十年前,其次是现在”

目录

  • ⽤户登录权限效验
    • Spring Boot 拦截器
      • 自定义拦截器
      • 将自定义拦截器加入到系统配置
    • 拦截器实现原理
  • 统一异常处理
    • 创建一个异常处理类
    • 创建异常监测的类和处理的方法
  • 统一数据返回格式
    • StringHttpMessageConverter

Spring Boot 统⼀功能处理模块,也是 AOP 的实战环节。

⽤户登录权限效验

Spring Boot 拦截器

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

  1. 创建⾃定义拦截器,实现 HandlerInterceptor 接⼝的 preHandle(执⾏具体⽅法之前的预处理)方 法。
  2. 将⾃定义拦截器加⼊ WebMvcConfigurer 的 addInterceptors ⽅法中。

自定义拦截器

image-20230604164520468

public class LoginInterceptor implements HandlerInterceptor {
    // 调用目标方法之前执行的方法
    // 此方法会返回一个 boolean 类型的值,
    // 返回 true 表示拦截器验证成功,继续走后续流程,执行目标方法;
    // 返回 false 表示拦截器验证失败,后续流程和目标方法不用执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //用户登录校验
        HttpSession session = request.getSession(false);
        if(session != null && session.getAttribute("session_userinfo") != null){
            return true;
        }
        //        response.setStatus(401);
        response.setContentType("application/json;charset=utf8");
//        response.setCharacterEncoding("utf8");
        response.getWriter().println("{\"code\": -1, \"msg\": \"登录失败\", \"data\": \"\"}");
        return false;
    }
}

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

@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")// 拦截所有 url
                .excludePathPatterns("/user/login") // 排除 登录 不拦截
                .excludePathPatterns("/user/reg") // 排除 注册 不拦截
                .excludePathPatterns("/image/**")
        ;
    }
}

验证下拦截功能:

@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/login")
    public String login(){
        return "login";
    }

    @RequestMapping("/index")
    public String index(){
        return "index";
    }

    @RequestMapping("/reg")
    public String reg(){
        return "reg";
    }
}

image-20230604194230354

image-20230604194243430

image-20230604194257433

login() 和 reg() 没有被拦截,index() 被拦截。

拦截器实现原理

正常情况下的调⽤顺序:

image-20230604203530059

然⽽有了拦截器之后,会在调⽤ Controller 之前进⾏相应的业务处理,执⾏的流程如下图所示:

image-20230604203643320

Spring Boot 拦截器的实现原理是基于 Spring MVC 框架的拦截器机制,当客户端发送请求时,请求会经过一系列的组件处理,其中就包括拦截器。

统一异常处理

如果不做统一的异常处理,后端抛异常,返回前端的状态码就是 500。

如果不想返回的是这个 500 状态码,可以对异常做统一处理,降低前端程序员和后端程序员的沟通成本。

创建一个异常处理类

@ControllerAdvice// 随着 spring Boot 项目的启动而启动 + 检测 controller 的异常
public class MyExceptionAdvice {

}

创建异常监测的类和处理的方法

@ControllerAdvice
@ResponseBody
public class MyExceptionAdvice {
    @ExceptionHandler(NullPointerException.class)
    public HashMap<String, Object> doNullPointerException(NullPointerException e){
        HashMap<String, Object> result = new HashMap<>();
        result.put("code",-1);
        result.put("msg","空指针: " + e.getMessage());
        result.put("data",null);
        return result;
    }
}
@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/login")
    public int login(){
        Object obj = null;
        System.out.println(obj.hashCode());
        return 1;
    }
}

image-20230604213539804

但是这里只是处理了"空指针"异常,如果有其他的异常呢?比如"算数异常"

@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/login")
    public int login(){
        int num = 10/0;
        return 1;
    }
}

image-20230604214219365

有一个办法,是再去写一个处理"算数异常"的类,但是异常类型太多,这样很麻烦。

可以写一个类,处理所有异常的父类-“Exception”.

@ControllerAdvice
@ResponseBody
public class MyExceptionAdvice {
    @ExceptionHandler(Exception.class)
    public HashMap<String, Object> doException(Exception e){
        HashMap<String, Object> result = new HashMap<>();
        result.put("code",-1);
        result.put("msg","Exception: " + e.getMessage());
        result.put("data",null);
        return result;
    }
}

image-20230604214702174

  • 如果子类异常(空指针)和父类异常都存在的情况下,出现"空指针"的情况会触发子类还是父类异常处理?
@ControllerAdvice
@ResponseBody
public class MyExceptionAdvice {
    @ExceptionHandler(NullPointerException.class)
    public HashMap<String, Object> doNullPointerException(NullPointerException e){
        HashMap<String, Object> result = new HashMap<>();
        result.put("code",-1);
        result.put("msg","空指针: " + e.getMessage());
        result.put("data",null);
        return result;
    }

    @ExceptionHandler(Exception.class)
    public HashMap<String, Object> doException(Exception e){
        HashMap<String, Object> result = new HashMap<>();
        result.put("code",-1);
        result.put("msg","Exception: " + e.getMessage());
        result.put("data",null);
        return result;
    }
}
@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/login")
    public int login(){
        Object obj = null;
        System.out.println(obj.hashCode());
        return 1;
    }
    @RequestMapping("/login2")
    public int login2(){
        int num = 10/0;
        return 1;
    }
}

image-20230605194818607

优先触发子类异常。

统一数据返回格式

强制性统一数据返回。(在返回数据之前进行数据重写)

统⼀数据返回格式的优点:⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据。 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就⾏了,因为所有接⼝都是这样返回 的。有利于后端技术部⻔的统⼀规范的标准制定,不会出现稀奇古怪的返回内容。

//统一数据格式处理
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;// true => 调用 beforeBodyWrite() 方法
    }

    //返回数据之前进行重写
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 假定标准格式是 HashMap<String, Object> -> {code, msg, data}
        if(body instanceof HashMap) {
            return body;
        }
        HashMap<String, Object> result = new HashMap<>();
        result.put("code", 200);
        result.put("msg","");
        result.put("data",body);
        return result;
    }
}
@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/login")
    public int login(){
        return 1;
    }
    @RequestMapping("/login2")
    public int login2(){
        return 1;
    }

    @RequestMapping("/reg")
    public HashMap<String, Object> reg(){
        HashMap<String, Object> result = new HashMap<>();
        result.put("code",200);
        result.put("msg","");
        result.put("data",1);
        return result;
    }
}

image-20230605203257302

image-20230605203309463

保证始终返回的都是标准的格式。

StringHttpMessageConverter

  • 再来看一个例子:
@RequestMapping("/sayHi")
public String sayHi(){
    return "say hi";
}

image-20230605203828969

//默认异常处理(当具体的异常匹配不到时,会走这个方法)
@ExceptionHandler(Exception.class)
public HashMap<String, Object> doException(Exception e){
    HashMap<String, Object> result = new HashMap<>();
    result.put("code",-1);
    result.put("msg","Exception: " + e.getMessage());
    result.put("data",null);
    return result;
}

返回流程:

1.返回 String

2.统一数据格式处理:String -> HashMap

3.HashMap -> application/json 给前端

报错就是 第 3 步出错了。

image-20230605205752518

到 第 3 步之后就会对原 body 的类型进行判断:

1.是 String -> StringHttpMessageConverter 进行类型转换

就这个例子而言,它就会用第 2 步得到的 HashMap -> String, 就出现类型转换异常。

2.非 String -> HttpMessageConverter 进行类型转换

解决方案:

1.将 StringHttpMessageConverter 转化器去掉。

package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;

@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.removeIf(converter->converter instanceof StringHttpMessageConverter);
    }
}

2.在统一数据重写时,单独处理 String 类型,让其返回一个 String 类型而不是 HashMap.

//返回数据之前进行重写
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
       // 假定标准格式是 HashMap<String, Object> -> {code, msg, data}
        if(body instanceof HashMap) {
            return body;
        }
        HashMap<String, Object> result = new HashMap<>();
        result.put("code", 200);
        result.put("msg","");
        result.put("data",body);
        if(body instanceof String){
//            return "{\"code\": 200, \"msg\": \"\", \"data\": \"" + body + "\"}";
            //将对象转换成 json 字符串
            return objectMapper.writeValueAsString(result);
        }
        return result;
    }

image-20230605213253457

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

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

相关文章

金融投资心得(个人领悟篇)

金融投资心得 前言金融还是要参与的如何参与金融始终相信中国经济把控风险选股技巧不赚最后一块"铜板"多学习&#xff0c;学会筛选有用消息 其它思考推荐学习我的投资 前言 本人从2015年开始接触金融&#xff0c;不知不觉跟金融已经打了8年交道了&#xff0c;一路走…

基于STM32的智能饮水机系统设计

一、项目背景 随着智能化的迅速发展&#xff0c;人们对于生活中的各类设备也越来越有智能化的需求&#xff0c;其中智能饮水机是一种比较常见的设备。智能饮水机不仅可以提供饮用水&#xff0c;还可以通过智能化的技术满足人们对于水质、水温、出水量等方面的需求。因此&#…

深入浅出:单链表的实现和应用

&#x1f331;博客主页&#xff1a;青竹雾色间. &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 ✨人生如寄&#xff0c;多忧何为 ✨ 目录 前言 单链表的基本概念 节点 头节点 尾节点 单链表的基本操作 创建单链表 头插法&#xff1a; 尾插法&#…

OpenGL蓝宝书第九章学习笔记:片段着色器和帧缓存

前言 本篇在讲什么 OpenGL蓝宝书第九章学习笔记之片段着色器和帧缓存 本篇适合什么 适合初学OpenGL的小白 本篇需要什么 对C语法有简单认知 对OpenGL有简单认知 最好是有OpenGL超级宝典蓝宝书 依赖Visual Studio编辑器 本篇的特色 具有全流程的图文教学 重实践&am…

Node服务器 - koa框架

1 koa的基本使用 2 koa的参数解析 3 koa响应和错误 4 koa静态服务器 5 koa的源码解析 6 和express对比 koa的基本使用过程 const Koa require(koa)// 创建app对象 const app new Koa()// 注册中间件(middleware) // koa的中间件有两个参数: ctx/next app.use((ctx, next…

Apple Vision Pro:空间计算的未来已来,你准备好了吗?

“ 正如iPhone带我们进入移动计算时代&#xff0c;Apple Vision Pro将带我们进入空间计算时代。” 我虽然没有亲身体验&#xff0c;但观看了许多国内外第一批体验者的体验分享&#xff0c;看得出来&#xff0c;这些体验者都十分兴奋&#xff0c;根据他们的描述&#xff0c;我…

Mac安装zookeeper

文章目录 1.下载zookeeper安装包2.解压安装包3.修改配置文件4.启动服务端5.启动客户端 1.下载zookeeper安装包 https://archive.apache.org/dist/zookeeper/ 选择需要的版本下载 下载的时候要注意下载已经编译好的二进制版本 2.解压安装包 将下载的安装包解压到你想要的位…

基于Faster RCNN时间钢铁表面的缺陷检测

目标检测在许多行业中都有许多实际应用。大多数时候,在工业环境中,物体检测目标很小。因此,有效地训练目标检测模型变得非常困难。其中一个问题是钢材表面缺陷检测。即使使用深度学习,也很难高精度地解决问题。在本文中,我们将使用 PyTorch 库训练 Faster RCNN 对象检测模…

【3DsMAX】从零开始建房(5)

目录 1. 制作护栏 2. 制作梯子 3. 制作二层窗户 1. 制作护栏 选中顶部三条边线 点击“利用所选内容创建图形” 选择线性 此时我们就成功的创建了一个二维样条线 选中样条线上其中的一个点&#xff0c;移动点使线条缩短 缩小一点 渲染 同样的方法再制作一根 新建一个圆柱体 …

浅谈Spring Cloud OpenFeign

OpenFeign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用OpenFeign&#xff0c;可以做到使用HTTP请求访问远程服务&#xff0c;就像调用本地方法一样的&#xff0c;开发者完全感知不到这是在调用远程方法&#xff0c;更感知不到在访问HTTP请求。 Spring Cloud OpenFe…

临期食品电商 APP 的设计与开发

摘 要 &#xff1a; 在移动互联网和电子商务产业的快速发展中&#xff0c;越来越多的消费者开始慢慢的接触网上购 物&#xff0c;互联网经济的全面动员将席卷全球&#xff0c;各种电商应用将在时代的浪潮中层出不穷。在未来各国的 不断发展中互联网很可能会成为销售各种货物的…

在线商城前台开发环境配置

一、项目配置 node 15.14.0 官网下载 https://nodejs.org/zh-cn/download/releases npm 7.7.6 下载node后自动安装npm&#xff0c;如果版本不对就更换对应版本 npm install react7.7.6 下载项目源码 链接&#xff1a;https://www.123pan.com/s/bT07Vv-WICcv.html 解压到一…

【P50】JMeter 汇总报告(Summary Report)

文章目录 一、汇总报告&#xff08;Summary Report&#xff09;参数说明二、准备工作三、测试计划设计 一、汇总报告&#xff08;Summary Report&#xff09;参数说明 可以查看事务或者取样器在某个时间范围内执行的汇总结果 使用场景&#xff1a;用于评估测试结果 使用频率…

java boot将一组yml配置信息装配在一个对象中

其实将一组yml数据封进一个对象中才是以后的主流开发方式 我们创建一个springboot项目 找到项目中的启动类所在目录 在同目录下创建一个类 名字你们可以随便取 我这里直接叫 dataManager 然后 在yml中定义这样一组数据信息 然后 我们在类中定义三个和这个配置信息相同的字段…

全志V3S嵌入式驱动开发(触摸屏驱动)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 所谓的触摸屏&#xff0c;其实就是在普通的lcd屏幕之上&#xff0c;再加一层屏而已。这个屏是透明的&#xff0c;这样客户就可以看到下面lcd屏幕的…

想要提高办公效率,可以采用表单自定义工具

当前&#xff0c;随着社会的进步和科技的发展&#xff0c;表单自定义工具逐渐在现代化办公场所中得到重用和喜爱。因为它的灵活、简便、易操作等优势特性&#xff0c;使得其突破了传统表单制作工具的局限&#xff0c;成为广大中大型企业实现流程化管理和数字化进程的得力助手。…

UnityVR--组件5--Animation动画

目录 新建动画Animation Animation组件解释 应用举例1&#xff1a;制作动画片段 应用举例2&#xff1a;添加动画事件 Animator动画控制器 应用举例3&#xff1a;在Animator中设置动画片段间的跳转 本篇使用的API&#xff1a;Animation、Animator以及Animator类中的SetFlo…

程序语言排行榜有哪些

程序语言排名 程序语言排行NO.1Java Java是基于类的面向对象的编程语言&#xff0c;拥有跨平台、面向对象、泛型编程的特性&#xff0c;广泛应用于企业级Web应用开发和移动应用开发。任职于Sun Microsystems的詹姆斯高斯林等人于1990年代初开发Java语言的雏形&#xff0c;最初被…

超低功耗待机血压计语音IC方案,智能提示NV080C-S8

随着我国步入21世纪的步伐和改革开放的不断深入&#xff0c;我国医疗水平和人民的生活水平不断提高&#xff0c;致使我国已经成为了全球老龄化为严重的国家&#xff0c;老年人占据的比重越来越大&#xff0c;一些常见的却不容易治愈的老年性疾病的预防工作已成为现今确保老年人…

LVM逻辑卷元数据丢失恢复案例 —— 筑梦之路

Lvm常见的故障主要是pv出现异常&#xff0c;有以下几种情况 一个是pv所在的磁盘发生了lvm的元数据损坏一个是系统无法识别到pv所在的磁盘一个是系统异常&#xff0c;断电等导致重启后盘符发生变化&#xff0c;也就是系统识别的磁盘uuid发生变化&#xff0c;但是wwid还是可以对应…