spring boot 对返回值进行加密,之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)
@Documented
public @interface Encrypted {
 
    boolean value() default true;
}

Encrypted 注解,该注解是一个标识注解;如果打上该注解标识加密

统一返回定义

主要包含 code、message 和 body 属性定义

package com.olive.dto;
 
import lombok.Data;
 
import java.io.Serializable;
 
@Data
public class ResultInfo<T> implements Serializable {
 
    public  int 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;
    }
 
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        //如果被@ResponseBody注解修饰的 返回true
        return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class))
                && returnType.hasMethodAnnotation(Encrypted.class);
    }
 
    @Override
    public 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);
        }
    }
}

注册 ResponseBodyHandler 到 controller 返回值处理器里,即添加自己的返回值处理器

package com.olive.config;
 
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
 
import java.util.ArrayList;
import java.util.List;
 
@Configuration
public class WebConfig implements InitializingBean {
 
    @Autowired
    private RequestMappingHandlerAdapter adapter;
 
    @Override
    public void afterPropertiesSet() throws Exception {
        List<HandlerMethodReturnValueHandler> unmodifiableList = adapter.getReturnValueHandlers();
        List<HandlerMethodReturnValueHandler> list = new ArrayList<>(unmodifiableList.size());
        for (HandlerMethodReturnValueHandler returnValueHandler : unmodifiableList) {
            if (returnValueHandler instanceof RequestResponseBodyMethodProcessor) {
                //将RequestResponseBodyMethodProcessor 实际返回值替换为自定义的,实际执行为RequestResponseBodyMethodProcessor
                //重要
                HandlerMethodReturnValueHandler handler = new ResponseBodyHandler(returnValueHandler);
                list.add(handler);
            } else {
                list.add(returnValueHandler);
            }
        }
        adapter.setReturnValueHandlers(list);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值