【SpringBoot】统一功能处理
目录
🎃1 拦截器
🎀1.1 拦截器的代码实现
🎨1.2 拦截器的实现原理
🧶2 拦截器应用——登录验证
🦺3 异常统一处理
🎭4 统一数据返回格式
🧤4.1 为什么需要统一数据返回格式
🧣4.2 统一返回对象
👘4.3 统一数据处理(强制执行)
本篇文章介绍 Spring Boot 的统一功能处理模块,也就是 AOP 的实战环节。
1 拦截器
没有登录的情况下,会跳转到登录页面。
1.1 拦截器的代码实现
Spring 提供了具体的实现拦截器:HandlerInterceptor,拦截器的实现分为以下两个步骤:
1. 创建自定义拦截器,实现 HandlerInterceptor 接口,重写 preHandle 方法。(执行具体方法之前的预处理)。
2. 将自定义拦截器加入 WebMvcConfigurer 的 addInterceptors 方法中。
package com.example.demo.configuration;import com.example.demo.common.AppVar;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/*** 自定义拦截器*/
@Component
public class UserInterceptor implements HandlerInterceptor {/*** 返回 true -> 拦截器验证成功,继续执行后续的方法* false -> 拦截器验证失败,不会执行后续的目标方法* @param request* @param response* @param handler* @return* @throws*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("do UserInterceptor"); // 拦截时候会打印// 业务方法HttpSession session = request.getSession(false);if(session != null &&session.getAttribute(AppVar.SESSION_KEY) != null){// 用户已经登录了return true; // 继续执行后续流程}// 未登录的情况,跳转到 百度response.sendRedirect("https://www.baidu.com");return false;}
}
package com.example.demo.common;/*** 全局变量*/
public class AppVar {// Session Keypublic static final String SESSION_KEY = "SESSION_KEY";
}
package com.example.demo.configuration;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 将自定义拦截器加入到系统配置* 有两种写法* 一是 new 一个 UserInterceptor 对象* 二是 注入的方式*/
@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") // 登录页面不拦截.excludePathPatterns("/user/login") // 注册页面不拦截;}
}
* 一级路由,** 所有路由。
/user 就是一级路由,/user/reg 是二级路由。
addPathPatterns 表示需要拦截的 URL,** 表示拦截所有方法
excludePathPattern 表示需要排除的 URL
package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/getuser")public String getUser(){System.out.println("do getUser()");return "getuser";}@RequestMapping("/reg")public String reg(){System.out.println("do reg()");return "reg";}@RequestMapping("/login")public String getlogin(){System.out.println("do login()");return "login";}
}
输出:
do UserInterceptor
do reg()
do login()
1.2 拦截器的实现原理
正常情况下的调用顺序:
有了拦截器之后,在调用 controller 之前,会执行拦截器,如果为 true,则继续执行后续程序,如果为 false,则跳转相关页面。
2 拦截器应用——登录验证
package com.example.demo.configuration;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 将自定义拦截器加入到系统配置* 有两种写法* 一是 new 一个 UserInterceptor 对象* 二是 注入的方式*/
@Configurationpublic class AppConfig implements WebMvcConfigurer {@Autowiredprivate UserInterceptor userInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// registry.addInterceptor(new UserInterceptor());registry.addInterceptor(userInterceptor).addPathPatterns("/**") // 拦截所有请求.excludePathPatterns("/user/reg") // 登录页面不拦截.excludePathPatterns("/reg.html").excludePathPatterns("/login.html").excludePathPatterns("/css/**").excludePathPatterns("/editor.md/**").excludePathPatterns("/img/**").excludePathPatterns("/js/**").excludePathPatterns("/user/login") // 注册页面不拦截.excludePathPatterns("/image/**") // image 文件下所有的图片格式拦截;}
}
除了注册页面、登录页面之外,其余页面都会跳转到百度。
3 异常统一处理
@RequestMapping("/reg")public String reg(){System.out.println("do reg()");Object obj = null;System.out.println(obj.hashCode());return "reg";}
如果每个页面都出现异常,可不可以统一处理呢?
出现的所有异常按照统一的格式返回:
package com.example.demo.common;import lombok.Data;/*** 统一返回对象*/
@Data
public class ResultAjax {private int code; // 状态码private String msg; // 状态码的描述信息private Object data; // 返回数据
}
异常统一处理时,需要两个注解。一个是 @ControllerAdvice / @RestControllerAdvice ,另一个是 @ExceptionHandler(Exception.class) 统一返回对象。
package com.example.demo.configuration;import com.example.demo.common.ResultAjax;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice
public class ExceptionAdvice {@ExceptionHandler(NullPointerException.class)public ResultAjax doNullPointerException(NullPointerException e){ResultAjax resultAjax = new ResultAjax();resultAjax.setCode(-1);resultAjax.setMsg("空指针异常:"+e.getMessage());resultAjax.setData(null);return resultAjax;}
}
再举一个算术异常的例子:
由于所有的异常都继承自 Exception,所以 @ExceptionHandler(Exception.class) 里面的异常类不用写那么详细也可以:
@RequestMapping("/login")public String login(){System.out.println("do login()");int num = 10 / 0;return "login";}
@ExceptionHandler(Exception.class)public ResultAjax doException(Exception e){ResultAjax resultAjax = new ResultAjax();resultAjax.setCode(-1);resultAjax.setMsg("异常:"+e.getMessage());resultAjax.setData(null);return resultAjax;}
4 统一数据返回格式
4.1 为什么需要统一数据返回格式
统⼀数据返回格式的优点有很多,⽐如以下⼏个:
1. ⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据。
2. 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就⾏了,因为所有接⼝都是这样返回 的。
3. 有利于项⽬统⼀数据的维护和修改。
4. 有利于后端技术部⻔的统⼀规范的标准制定,不会出现稀奇古怪的返回内容。
4.2 统一返回对象
对 ResultAjax 这个类进行改造,添加两种方法,一是成功之后返回的数据,二是失败之后返回的数据。
package com.example.demo.common;import lombok.Data;/*** 统一返回对象*/
@Data
public class ResultAjax {private int code; // 状态码private String msg; // 状态码的描述信息private Object data; // 返回数据/*** 成功时返回* @param data* @return*/public static ResultAjax success(Object data){ResultAjax resultAjax = new ResultAjax();resultAjax.setCode(200);resultAjax.setMsg("");resultAjax.setData(data);return resultAjax;}public static ResultAjax success(String msg, Object data){ResultAjax resultAjax = new ResultAjax();resultAjax.setCode(200);resultAjax.setMsg(msg);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(data);return resultAjax;}}
package com.example.demo.controller;import com.example.demo.common.ResultAjax;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/getuser")public ResultAjax getUser(){System.out.println("do getUser()");return ResultAjax.success("getuser");}@RequestMapping("/reg")public ResultAjax reg(){System.out.println("do reg()");return ResultAjax.success("reg");}@RequestMapping("/login")public ResultAjax login(){System.out.println("do login()");return ResultAjax.success("login");}
}
4.3 统一数据处理(强制执行)
如果就是有人不按要求返回 ResultAjax 这一格式呢?比如下面这样:
@RequestMapping("getnum")public int getNum(){System.out.println("getNum()");return 1;}
这时就可以对返回的数据进行统一处理,这是强制执行的。
使用:
1. @ControllerAdvice
2. 实现 ResponseBodyAdvice 接口,并重写它的两个方法,supports 必须返回 true,beforeBodyWrite 方法中进行重新判断和重写操作。
package com.example.demo.configuration;import com.example.demo.common.ResultAjax;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;@ControllerAdvice
public class ResponAdvice implements ResponseBodyAdvice {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType,MediaType selectedContentType,Class selectedConverterType,ServerHttpRequest request,ServerHttpResponse response) {// 已经包装好的对象// body 是 ResultAjax 的格式if(body instanceof ResultAjax){return body;}// 对字符串进行判断和处理// 重新封装成 ResultAjax 的格式return ResultAjax.success(body);}
}
@RequestMapping("/getstr")public String getStr(){System.out.println("getStr()");return "whoooooo~~";}
如果返回的是 String,而不是 int 类型,会报错。在把 String 转化成 json格式的时候报错了。所以对于返回类型是 String 的话,需要单独处理。不使用 String 解析引擎,而是手动转成 json。
package com.example.demo.configuration;import com.example.demo.common.ResultAjax;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;@ControllerAdvice
public class ResponAdvice implements ResponseBodyAdvice {
// springboot 框架自动注入@Autowiredprivate ObjectMapper objectMapper;@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType,MediaType selectedContentType,Class selectedConverterType,ServerHttpRequest request,ServerHttpResponse response) {// 已经包装好的对象// body 是 ResultAjax 的格式if(body instanceof ResultAjax){return body;}// 对字符串进行判断和处理// 手动转换成 json 格式if(body instanceof String){ResultAjax resultAjax = ResultAjax.success(body);try {return objectMapper.writeValueAsString(resultAjax);} catch (JsonProcessingException e) {e.printStackTrace();}}return ResultAjax.success(body);}
}
如果返回的是对象呢?
@RequestMapping("/usermsg")public User usermsg(){User user = new User();user.setId(263);user.setName("柳飘飘");user.setPassword("96134");return user;}
相关文章:

【SpringBoot】统一功能处理
目录 🎃1 拦截器 🎀1.1 拦截器的代码实现 🎨1.2 拦截器的实现原理 🧶2 拦截器应用——登录验证 🦺3 异常统一处理 🎭4 统一数据返回格式 🧤4.1 为什么需要统一数据返回格式 🧣4.2 统…...
分布式数据库-架构真题(二十六)
构件组装成软件系统的过程分为三个不同的层次()。(2018年) 初始化、互连和集成连接、集成和演化定制、集成和扩展集成、扩展和演化 答案:C (2018年)CORBA服务端构件模型中,&#x…...
MyWebServer开发日记-socket
打算把 tinyWebServer 重写成跨平台(Windows and Linux)的。 这里首先需要跨平台的 sokcet,主要参考 尹圣雨 的 TCP/IP 网络编程 来着: 代码写的有些笨,欢迎批评: 首先是一个 socket 类,主要…...

图书管理信息系统分析与设计
一、系统开发的可行性分析 (一)系统背景.必要性及意义 随着社会经济的迅速发展和科学技术的全面进步,计算机事业的飞速发展,以计算机与通信技术为基础的信息系统正处于蓬勃发展的时期。随着经济文化水平的显著提高,人…...
Charles基础使用指南
##Charles 基本使用指南 Charles 在本地构建一个HTTP代理服务器,可以实现对HTTP、HTTPS请求的抓取,也就是我们常说的抓包,以及对请求响应的修改等。 Charles 官网地址 https://www.charlesproxy.com/ ###一、移动端的抓包实现 1. PC端开启…...

Android12之/proc/pid/status参数含义(一百六十五)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...

UMA 2 - Unity Multipurpose Avatar☀️三.给UMA设置默认服饰Recipes
文章目录 🟥 项目基础配置🟧 给UMA配置默认服饰Recipes🟨 设置服饰Recipes属性🟥 项目基础配置 将 UMA_DCS 预制体放到场景中创建空物体,添加DynamicCharacterAvatar 脚本,选择 HumanMaleDCS作为我们的基本模型配置默认Animator 🟧 给UMA配置默认服饰Recipes 服饰Re…...

uniapp-小程序登录授权框
微信官方文档 不弹出授权框原因 因为版本问题,目前的最新的版本是不支持 wx.getUserInfo 去主动弹出授权框 只能引导用户去点击 butten 去授权 解决方法 我的思路是参考了其他的微信微信小程序, 就是跳转到我的页面的时候 在钩子函数内去触发一个封装的模态框,状…...

Unity 性能优化Shader分析处理函数:ShaderUtil.GetShaderGlobalKeywords用法
Unity 性能优化Shader分析处理函数:ShaderUtil.GetShaderGlobalKeywords用法 点击封面跳转下载页面 简介 Unity 性能优化Shader分析处理函数:ShaderUtil.GetShaderGlobalKeywords用法 在Unity开发中,性能优化是一个非常重要的方面。一个常见…...
第一百四十一回 如何添加程序启动页
文章目录 概念介绍使用方法示例代码 我们在上一章回中介绍了如何解决BLE包中的错误的内容,本章回中将介绍如何添加程序启动页.闲话休提,让我们一起Talk Flutter吧。 概念介绍 程序启动页就是点击手机桌面上的程序启动图标后显示的页面,也叫s…...

从零开始的PICO教程(4)--- UI界面绘制与响应事件
从零开始的PICO教程(4)— UI界面绘制与响应事件 文章目录 从零开始的PICO教程(4)--- UI界面绘制与响应事件一、前言1、大纲2、教程示例 二、具体步骤1、PICO VR环境配置2、XR的UI Canvas画布创建与调整(1)C…...

IntelliJ IDEA 远程调试 Tomcat
准备工作 明确远程服务器的 IP 地址,比如我是:192.168.92.128 关掉服务器防火墙:service iptables stop 本地 Remote Server 配置 添加 Remote Server,如下图 复制 Remote Server 自动生成的 JVM 参数,等下有用&…...
谷粒商城----认证服务
一、短信验证码(阿里云短信服务) Data ConfigurationProperties(prefix "spring.cloud.alicloud.sms") Component public class SmsComponent {private String host;private String path;private String skin;private String sign;private S…...

Mediasoup源码介绍
一、Mediasoup 整体结构 整个Mediasoup库通过Nodejs管理,比如整体逻辑、worker、router、producer、consumer...都是通过JS进行管理的。 其底层的数据传输是通过C部分进行控制的,通过NodeJs来控制C部分,以实现整体的数据传输效 二、Mediasou…...
GIS入门,WKT格式详解
WKT介绍 WKT是Well-known Text的缩写,它是一种用于描述地理空间几何对象的文本格式。 WKT是一种开放的国际标准,由Open Geospatial Consortium(OGC)定义和维护。 WKT是一种标准的表示方法,可以用来描述点、线、面等地理空间对象的形状和位置。通过使用一系列的坐标点和关…...
Qt之postEvent
基本介绍 postEvent方法所属类为QCoreApplication,完整声明如下: [static] void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority Qt::NormalEventPriority) 该方法的作用是将要发送的事件推送到对应线程的事件队列中&…...

1976~2020年青藏高原典型冰川及冰湖遥感监测数据集
冰川面积是反应气候变化最直接的指标之一。在全球变暖的大背景下,对于评估冰川融化造成的生态、全球气候变化和水资源价值评价等问题十分重要。本文针对受西风和印度洋夏季风影响下的青藏高原冰川及其末端冰湖的变化特征,制作了近44年来时相相对连续的冰…...

时序预测 | MATLAB实现LSSVM最小二乘支持向量机时间序列预测未来
时序预测 | MATLAB实现LSSVM最小二乘支持向量机时间序列预测未来 目录 时序预测 | MATLAB实现LSSVM最小二乘支持向量机时间序列预测未来预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现LSSVM时间序列预测未来(最小二乘支持向量机); 2.运行环境Mat…...
windows10 使用WSL2安装原生docker
1.升级WSL2 我的 win10 wsl默认版本是1,先要升级WSL2不然不支持systemd(后台守护进程) 双击直接安装就行,安装包网上都能找到: Microsoft.WSL_1.3.17.0_x64_ARM64.msixbundle 执行 wsl --version 显示这样成功了: C:\Users\xx>wsl --version WSL …...
jupylab pandas按条件批量处理xls数据
批量处理xls表数据 引入相关包 import pandas as pd import xlrd import numpy as np# 去掉jupyleb警告 import warnings warnings.filterwarnings("ignore")from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...