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&#x5F04;&#x6F6E;&#x513F;");
        resultInfo.setBody(map);

        return resultInfo;
    }
</string,></map<string,></map<string,>

今天定义一个注解读返回的 json 进行加密,来运用 HandlerMethodReturnValueHandler

<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 -->
    </relativepath></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;

}
</t>

该类实现 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) {
        //&#x5982;&#x679C;&#x88AB;@ResponseBody&#x6CE8;&#x89E3;&#x4FEE;&#x9970;&#x7684; &#x8FD4;&#x56DE;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&#x6CE8;&#x89E3;&#x6267;&#x884C;&#x5668;
            handlerMethodReturnValueHandler.handleReturnValue(newResultInfo,
                    returnType, mavContainer, webRequest);
        }else{
            handlerMethodReturnValueHandler.handleReturnValue(returnValue,
                    returnType, mavContainer,  webRequest);
        }
    }
}
</string>

注册 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) {
                //&#x5C06;RequestResponseBodyMethodProcessor &#x5B9E;&#x9645;&#x8FD4;&#x56DE;&#x503C;&#x66FF;&#x6362;&#x4E3A;&#x81EA;&#x5B9A;&#x4E49;&#x7684;&#xFF0C;&#x5B9E;&#x9645;&#x6267;&#x884C;&#x4E3A;RequestResponseBodyMethodProcessor
                //&#x91CD;&#x8981;
                HandlerMethodReturnValueHandler handler = new ResponseBodyHandler(returnValueHandler);
                list.add(handler);
            } else {
                list.add(returnValueHandler);
            }
        }
        adapter.setReturnValueHandlers(list);
    }
}
</handlermethodreturnvaluehandler></handlermethodreturnvaluehandler>

编写 Springboot 启动引导类

package com.olive;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * https://cloud.tencent.com/developer/article/1616704
 *
 * @author 2230
 *
 */
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }

}

编写测试 Controller

package com.olive.controller;

import java.util.HashMap;
import java.util.Map;

import com.olive.annotation.Encrypted;
import com.olive.dto.ResultInfo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @Encrypted
    @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&#x5F04;&#x6F6E;&#x513F;");
        resultInfo.setBody(map);

        return resultInfo;
    }

}
</string,></map<string,></map<string,>

通过 HandlerMethodReturnValueHandler 可以对返回的数据进行进一步的封装,减少在业务代码中进行重复的返回值处理。例如,文章中的对返回数据进行统一加密。

Original: https://www.cnblogs.com/happyhuangjinjin/p/16748529.html
Author: BUG弄潮儿
Title: Springboot 之 HandlerMethodReturnValueHandler 运用

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/579784/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 一款吊炸天的AI图片增强工具!

    背景 如果你工作中需要制作文档,PPT,或者给文章配图,或者需要制作视频。一定会有在网上寻找图片素材的经历。 但网上的图质量参差不一,有时候找到了喜欢的图,但是质量不行,分辨率太低…

    Java 2023年6月8日
    066
  • .Net Core 钉钉自定义机器人接入

    接入步骤 获取自定义机器人Webhook 1.选择需要添加机器人的群聊,然后依次单击群设置 > 智能群助手。 2.在机器人管理页面选择自定义机器人,输入机器人名字并选择要发送…

    Java 2023年6月8日
    078
  • 异或的4种堪称神奇的运用场景

    原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。 众所周知,编程语言一般都内置了3种位运算符 &(AND)、 |(OR)、 ~(NOT),用来…

    Java 2023年6月7日
    081
  • 异步线程里的日志不好追踪?小支一招,轻松搞定!

    众所周知,通过唯一的链路id来追踪一次请求的所有日志,对于排查生产问题来说,会是非常给力的。这个比较容易实现。我之前的博客也有多次提及 ▄︻┻┳═一 https://www.cnb…

    Java 2023年6月15日
    063
  • Mongodb使用总结

    Mongodb使用总结 基于内存操作,便于与网站交互 数据库-集合-文档(存储多种数据类型),我们的操作都是基于单文档进行操作,并且通过冗余字段进行操作 嵌入式数组文档减少了对昂贵…

    Java 2023年6月14日
    0102
  • java线程池工作原理和实现原理

    为什么要使用线程池 平时讨论多线程处理,大佬们必定会说使用线程池,那为什么要使用线程池?其实,这个问题可以反过来思考一下,不使用线程池会怎么样?当需要多线程并发执行任务时,只能不断…

    Java 2023年5月29日
    080
  • harbor安装

    Harbor 简介 Docker容器应用的开发和运行离不开可靠的镜像管理,虽然Docker官方也提供了公共的镜像仓库,但是从安全和效率等方面考虑,部署我们私有环境内的Registr…

    Java 2023年6月15日
    090
  • 归并排序求解逆序对

    cpp;gutter:true;</p> <h1>include</h1> <h1>include</h1> <h…

    Java 2023年6月5日
    074
  • 使用python编写简单的api接口

    首先先安装flask模块 接下来编写py文件 执行py文件 访问测试:http://127.0.0.1:8070/testGet?a=12&b=1231223 Origin…

    Java 2023年6月7日
    075
  • 制作自己的Docker镜像

    制作镜像有2种方式,一种是容器转换成镜像,另一种是使用dockerfile创建镜像,一般后者更常用。 使用 docker commit命令将容器转换成镜像 docker commi…

    Java 2023年6月7日
    070
  • Java数据类型 方法 递归调用

    1.基础数据结构 java的基本数据类型有8种,包括6种数字类型、1种字符类型、1种布尔类型。 数字类型 4种 整数类型 byte/ short/ int/ long 2种 浮点数…

    Java 2023年6月9日
    082
  • Centos6.8 下 从零开始 部署 Java Web 应用

    一、硬件信息 CPU: [root@localhost ~]# grep ‘physical id’ /proc/cpuinfo | sort -u | wc -l 2 [root…

    Java 2023年5月29日
    076
  • Spring Security默认的用户登录表单 页面源代码

    Spring Security默认的用户登录表单 页面源代码 <html><head><title>Login Pagetitle>hea…

    Java 2023年5月30日
    056
  • Semaphore实战

    Semaphore信号量计数器。和CountDownLatch,CyclicBarrier类似,是多线程协作的工具类,相对于join,wait,notify方法使用起来简单高效。下…

    Java 2023年6月8日
    043
  • 如何让服务端同时支持WebSocket和SSL加密的WebSocket(即同时支持ws和wss)?

    自从HTML5出来以后,使用WebSocket通信就变得火热起来,基于WebSocket开发的手机APP和手机游戏也越来越多。我的一些开发APP的朋友,开始使用WebSocket通…

    Java 2023年5月30日
    091
  • dubbo和springCloud

    Dubbo 高性能的java RPC框架 架构 init:初始化 async:异步 sync同步 0:需要容器启动例如Tomcat 1:注册ip端口以及一些东西到注册中心 2:订阅…

    Java 2023年6月13日
    061
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球