Springboot 之 HandlerMethodReturnValueHandler 運用

簡介現在項目中大部分采用前后端分離的架構 , 采用這種架構的項目,在返回數據時,幾乎都是采用返回 json 格式的數據 。而 spring 中返回 json 格式的數據一般采用 @RestController 或者 @ResponseBody 注解 。代碼樣例
@ResponseBody@RequestMapping("/reqBody")public ResultInfo<Map<String, Object>> reqBody(){ResultInfo<Map<String, Object>> resultInfo = new ResultInfo<>();resultInfo.setCode(200);resultInfo.setMessage("success");Map<String, Object> map = new HashMap<>();map.put("userId", 100);map.put("tenantId", 1001);map.put("userName", "bug弄潮兒");resultInfo.setBody(map);return resultInfo; }今天定義一個注解讀返回的 json 進行加密 , 來運用 HandlerMethodReturnValueHandler
pom.xml 文件引入依賴<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.olive</groupId> <artifactId>springmvc-response-body</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springmvc-response-body</name> <url>http://maven.apache.org</url> <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.14</version><relativePath /> <!-- lookup parent from repository --> </parent> <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target> </properties> <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.14</version></dependency> </dependencies></project>定義加密注解package com.olive.annotation;import java.lang.annotation.*;@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Encrypted {boolean value() default true;}Encrypted 注解,該注解是一個標識注解;如果打上該注解標識加密
統一返回定義主要包含 code、message 和 body 屬性定義
package com.olive.dto;import lombok.Data;import java.io.Serializable;@Datapublic class ResultInfo<T> implements Serializable {publicint code;public String message;private T body;private boolean encrypt;}自定義 ResponseBodyHandler該類實現 HandlerMethodReturnValueHandler 類,主要對@RestController 或者 @ResponseBody 注解進行解析
package com.olive.config;import com.alibaba.fastjson2.JSON;import com.olive.annotation.Encrypted;import com.olive.dto.ResultInfo;import org.springframework.core.MethodParameter;import org.springframework.core.annotation.AnnotatedElementUtils;import org.springframework.util.Base64Utils;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.context.request.NativeWebRequest;import org.springframework.web.method.support.HandlerMethodReturnValueHandler;import org.springframework.web.method.support.ModelAndViewContainer;import java.nio.charset.StandardCharsets;public class ResponseBodyHandler implements HandlerMethodReturnValueHandler {protected final HandlerMethodReturnValueHandler handlerMethodReturnValueHandler;public ResponseBodyHandler(HandlerMethodReturnValueHandler handlerMethodReturnValueHandler){this.handlerMethodReturnValueHandler = handlerMethodReturnValueHandler;}@Overridepublic boolean supportsReturnType(MethodParameter returnType) {//如果被@ResponseBody注解修飾的 返回truereturn (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class))&& returnType.hasMethodAnnotation(Encrypted.class);}@Overridepublic void handleReturnValue(Object returnValue,MethodParameter returnType,ModelAndViewContainer mavContainer,NativeWebRequest webRequest) throws Exception {if(returnValue instanceof ResultInfo){ResultInfo<?> resultInfo = (ResultInfo<?>)returnValue;ResultInfo<String> newResultInfo = new ResultInfo<>();newResultInfo.setCode(resultInfo.getCode());newResultInfo.setMessage(resultInfo.getMessage());newResultInfo.setEncrypt(true);newResultInfo.setBody(Base64Utils.encodeToString(JSON.toJSONString(resultInfo.getBody()).getBytes(StandardCharsets.UTF_8)));//ResponseBody注解執行器handlerMethodReturnValueHandler.handleReturnValue(newResultInfo,returnType, mavContainer, webRequest);}else{handlerMethodReturnValueHandler.handleReturnValue(returnValue,returnType, mavContainer,webRequest);}}}

推薦閱讀