当前位置: 首页 > news >正文

【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;}


http://www.lryc.cn/news/164043.html

相关文章:

  • 分布式数据库-架构真题(二十六)
  • MyWebServer开发日记-socket
  • 图书管理信息系统分析与设计
  • Charles基础使用指南
  • Android12之/proc/pid/status参数含义(一百六十五)
  • UMA 2 - Unity Multipurpose Avatar☀️三.给UMA设置默认服饰Recipes
  • uniapp-小程序登录授权框
  • Unity 性能优化Shader分析处理函数:ShaderUtil.GetShaderGlobalKeywords用法
  • 第一百四十一回 如何添加程序启动页
  • 从零开始的PICO教程(4)--- UI界面绘制与响应事件
  • IntelliJ IDEA 远程调试 Tomcat
  • 谷粒商城----认证服务
  • Mediasoup源码介绍
  • GIS入门,WKT格式详解
  • Qt之postEvent
  • 1976~2020年青藏高原典型冰川及冰湖遥感监测数据集
  • 时序预测 | MATLAB实现LSSVM最小二乘支持向量机时间序列预测未来
  • windows10 使用WSL2安装原生docker
  • jupylab pandas按条件批量处理xls数据
  • RJ45水晶头网线顺序出错排查
  • 【洛谷 P1115】最大子段和 题解(贪心算法)
  • uni-app--》基于小程序开发的电商平台项目实战(一)
  • 入门人工智能 —— 学习一门编程语言 python 基础代码编写和运算符介绍(1)
  • 【java安全】CommonsBeanUtils1
  • JVM优化(OOM,内存溢出),查看线程快照,堆内存情况等问题
  • git 给分支添加描述
  • SpringBoot+Vue 整合websocket实现简单聊天窗口
  • PCB layout在布线上的设计规范有哪些?
  • 喜报丨迪捷软件入选浙江省2023年省级产业数字化服务商
  • verilog写rom,采用端口排序顺序例化