装饰SpringMVC的适配器实现响应自动包装

文章目录

    • 1.common-tool-starter
        • 1.目录结构
        • 2.ResultWrapper.java
    • 2.common-web-starter
        • 1.目录结构
        • 2.IgnoredResultWrapper.java 自定义注解,忽略对返回结果的自动包装
        • 3.ReturnValueHandlersDecorator.java 对适配器进行扩展的装饰器
        • 4.WebAutoConfiguration.java 将装饰器注入容器
    • 3.common-web-starter-demo
        • 1.WebController.java 测试三种使用方式
        • 2.测试
          • 1.第一种:直接使用自动包装成功结果
          • 2.第二种:使用 @IgnoredResultWrapper注解忽略掉自动包装
          • 3.第三种:直接使用ResultWrapper来自己封装结果

1.common-tool-starter

1.目录结构

CleanShot 2025-01-06 at 18.36.32@2x

2.ResultWrapper.java
package com.sunxiansheng.tool.response;import lombok.Data;import java.io.Serializable;/*** Description: 通用响应封装类,通过枚举来获取code和message** @Author sun* @Create 2024/10/11* @Version 1.0*/
@Data
public class ResultWrapper<T> implements Serializable {private static final long serialVersionUID = 1L;// 是否成功private boolean success;// 响应代码private int code;// 响应消息private String message;// 响应数据private T data;// 私有构造器,防止外部直接创建private ResultWrapper() {}// 使用内部建造者类进行对象构建public static class Builder<T> {private boolean success;private int code;private String message;private T data;// ============================== 链式调用设置建造者对象 ==============================public Builder<T> success(boolean success) {this.success = success;return this;}public Builder<T> code(int code) {this.code = code;return this;}public Builder<T> message(String message) {this.message = message;return this;}public Builder<T> data(T data) {this.data = data;return this;}// ============================== 链式调用设置建造者对象 ==============================// ============================== 构建ResultWrapper对象 ==============================public ResultWrapper<T> build() {ResultWrapper<T> result = new ResultWrapper<>();result.success = this.success;result.code = this.code;result.message = this.message;result.data = this.data;return result;}// ============================== 构建ResultWrapper对象 ==============================}// ============================== 快捷方法 ==============================public static <T> ResultWrapper<T> ok() {return new Builder<T>().success(true).code(RespBeanEnum.SUCCESS.getCode()).message(RespBeanEnum.SUCCESS.getMessage()).build();}public static <T> ResultWrapper<T> ok(T data) {return new Builder<T>().success(true).code(RespBeanEnum.SUCCESS.getCode()).message(RespBeanEnum.SUCCESS.getMessage()).data(data).build();}public static <T> ResultWrapper<T> ok(T data, String message) {return new Builder<T>().success(true).code(RespBeanEnum.SUCCESS.getCode()).message(message).data(data).build();}public static <T> ResultWrapper<T> fail() {return new Builder<T>().success(false).code(RespBeanEnum.ERROR.getCode()).message(RespBeanEnum.ERROR.getMessage()).build();}public static <T> ResultWrapper<T> fail(String message) {return new Builder<T>().success(false).code(RespBeanEnum.ERROR.getCode()).message(message).build();}public static <T> ResultWrapper<T> fail(int code, String message) {return new Builder<T>().success(false).code(code).message(message).build();}public static <T> ResultWrapper<T> fail(int code, String message, T data) {return new Builder<T>().success(false).code(code).message(message).data(data).build();}public static <T> ResultWrapper<T> fail(RespBeanEnum respBeanEnum) {return new Builder<T>().success(false).code(respBeanEnum.getCode()).message(respBeanEnum.getMessage()).build();}// ============================== 快捷方法 ==============================
}

2.common-web-starter

1.目录结构

CleanShot 2025-01-06 at 18.37.27@2x

2.IgnoredResultWrapper.java 自定义注解,忽略对返回结果的自动包装
package com.sunxiansheng.web.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** Description: 忽略对返回结果的自动包装** @Author sun* @Create 2025/1/6 15:58* @Version 1.0*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoredResultWrapper {}
3.ReturnValueHandlersDecorator.java 对适配器进行扩展的装饰器
package com.sunxiansheng.web.config;import com.sunxiansheng.tool.response.ResultWrapper;
import com.sunxiansheng.web.annotation.IgnoredResultWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
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 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;/*** Description: 装饰器** @Author sun* @Create 2025/1/6 14:40* @Version 1.0*/
@Slf4j
public class ReturnValueHandlersDecorator implements InitializingBean {/*** 注入适配器,可以获取*/@Resourceprivate RequestMappingHandlerAdapter requestMappingHandlerAdapter;@Overridepublic void afterPropertiesSet() {List<HandlerMethodReturnValueHandler> returnValueHandlers = requestMappingHandlerAdapter.getReturnValueHandlers();// 因为默认List<HandlerMethodReturnValueHandler>是不可修改列表,所以需要给他转换成一个可修改的列表assert returnValueHandlers != null;List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(returnValueHandlers);// 装饰一下然后重新设置this.decorateHandlers(handlers);// 将装饰后的handlers替换原来的不可变列表requestMappingHandlerAdapter.setReturnValueHandlers(handlers);}private void decorateHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {if (returnValueHandler instanceof RequestResponseBodyMethodProcessor) {// 找到RequestResponseBodyMethodProcessorControllerReturnValueHandler controllerReturnValueHandler = new ControllerReturnValueHandler(returnValueHandler);// 找到在原列表中的索引位置int index = returnValueHandlers.indexOf(returnValueHandler);// 将装饰后的HandlerMethodReturnValueHandler放到原来的位置returnValueHandlers.set(index, controllerReturnValueHandler);}}}private static class ControllerReturnValueHandler implements HandlerMethodReturnValueHandler {// 拿到被装饰的对象private final HandlerMethodReturnValueHandler handler;public ControllerReturnValueHandler(HandlerMethodReturnValueHandler handler) {this.handler = handler;}/*** 保持跟原生的一致** @param returnType* @return*/@Overridepublic boolean supportsReturnType(MethodParameter returnType) {return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class);}@Overridepublic void handleReturnValue(Object o, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest) throws Exception {IgnoredResultWrapper methodAnnotation = methodParameter.getMethodAnnotation(IgnoredResultWrapper.class);// 如果有IgnoredResultWrapper注解,就不进行包装,走原来的逻辑if (Objects.nonNull(methodAnnotation)) {handler.handleReturnValue(o, methodParameter, modelAndViewContainer, nativeWebRequest);return;}// 如果返回值是ResultWrapper类型,也不进行包装,走原来的逻辑if (o instanceof ResultWrapper) {handler.handleReturnValue(o, methodParameter, modelAndViewContainer, nativeWebRequest);return;}// 其余情况,进行包装log.info("Controller返回值已被自动包装,如果上传文件,请加@IgnoredResultWrapper注解取消自动包装!");ResultWrapper<Object> ok = ResultWrapper.ok(o);handler.handleReturnValue(ok, methodParameter, modelAndViewContainer, nativeWebRequest);}}
}
4.WebAutoConfiguration.java 将装饰器注入容器
    /*** 注入对返回结果增强的装饰器** @return*/@Bean@ConditionalOnMissingBeanpublic ReturnValueHandlersDecorator returnValueHandlersDecorator() {return new ReturnValueHandlersDecorator();}

3.common-web-starter-demo

1.WebController.java 测试三种使用方式
package com.sunxiansheng.web.controller;import com.sunxiansheng.tool.response.ResultWrapper;
import com.sunxiansheng.web.annotation.IgnoredResultWrapper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** Description: 测试** @Author sun* @Create 2024/10/4 22:56* @Version 1.0*/
@RestController
public class WebController {/*** 第一种方式:直接使用自动包装成功结果** @return*/@RequestMapping("/method1")public String method1() {return "method1";}/*** 第二种方式:使用 @IgnoredResultWrapper注解忽略掉自动包装** @return*/@IgnoredResultWrapper@RequestMapping("/method2")public String method2() {return "method2";}/*** 第三种方式:直接使用ResultWrapper来自己封装结果** @return*/@RequestMapping("/method3")public ResultWrapper<String> method3() {return ResultWrapper.fail("method3");}
}
2.测试
1.第一种:直接使用自动包装成功结果

CleanShot 2025-01-06 at 18.40.09@2x

2.第二种:使用 @IgnoredResultWrapper注解忽略掉自动包装

CleanShot 2025-01-06 at 18.40.48@2x

3.第三种:直接使用ResultWrapper来自己封装结果

CleanShot 2025-01-06 at 18.41.18@2x

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/68311.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在Spring Boot项目中高效集成Spring Security

1 Spring Security 介绍 Spring Security 是一个功能强大且高度可定制的安全框架,专为保护基于Java的应用程序而设计。它不仅提供了认证(Authentication)和授权(Authorization)的功能,还支持防止各种常见的安全攻击模式。本文将详细介绍Spring Security的主要特点、功能…

代码随想录算法训练营第三十七天-动态规划-完全背包-377. 组合总和 Ⅳ

这是一道与上一题几乎一样的题目不同点是在上一题是组合&#xff0c;这道题是排列所以就要用先循环背包&#xff0c;内循环为物品来实现排列效果总结&#xff1a; 对纯完全背包&#xff0c;求装满这个背包的最大价值&#xff0c;或者问能不能装满这个背包&#xff0c;那么两层f…

Go优雅实现redis分布式锁

前言 高可用方案一般会部署多实例&#xff0c;会存在对共享资源并发读写的业务&#xff0c;为了保证读写的正确&#xff0c;通常会引入分布式锁&#xff0c;本文将介绍如何使用redis设计一个优雅的Go分布式锁。 设计 redis分布式锁是借助SETNX来实现&#xff0c;可能会遇到一…

HPO3:提升模型性能的高效超参数优化工具

引言 在当今快速发展的数据科学和机器学习领域中&#xff0c;超参数优化&#xff08;Hyperparameter Optimization, HPO&#xff09;是构建高性能模型不可或缺的一环。为了简化这一复杂过程&#xff0c;恒通网络科技团队推出了HPO3模块——一个专为Python开发者设计的强大库&a…

全球AI模型百科全书,亚马逊云科技Bedrock上的100多款AI模型

今天小李哥给大家介绍的是亚马逊云科技上的AI模型管理平台Amazon Bedrock上的Marketplace&#xff0c;这是亚马逊云科技在今年re:Invent发布的一个全新功能&#xff0c;将亚马逊的电商基因带到了其云计算平台&#xff0c;让我们能够通过Amazon Bedrock访问100多种流行、新兴和专…

CentOS7使用源码安装PHP8教程整理

CentOS7使用源码安装PHP8教程整理 下载安装包解压下载的php tar源码包安装所需的一些依赖扩展库安装前的配置修改配置文件1、进入php8的安装包 配置环境变量开机自启启动服务创建软连接常见问题1、checking for icu-uc > 50.1 icu-io icu-i18n... no2、configure: error: Pa…

Ubuntu二进制部署K8S 1.29.2

本机说明 本版本非高可用&#xff0c;单Master&#xff0c;以及一个Node 新装的 ubuntu 22.04k8s 1.29.3使用该文档请使用批量替换 192.168.44.141这个IP&#xff0c;其余照着复制粘贴就可以成功需要手动 设置一个 固定DNS&#xff0c;我这里设置的是 8.8.8.8不然coredns无法…

Jetson Xavier NX (ARM) 使用 PyTorch 安装 Open3D-ML 指南

由于 Jetson 为 ARM64 (aarch64) 的系统架构&#xff0c;所以不能用 pip install 直接安装&#xff0c;需要通过源码编译。 升级系统 JetPack 由于 Open3D-ML 目前只支持 CUDA 10.0 以及 CUDA 11.*&#xff0c;并且 JetPack 的 CUDA 开发环境只有10.2、11.4以及12.2&#xff0…

npm常见报错整理

npm install时报UNMET PEER DEPENDENCY 现象 npm install时报UNMET PEER DEPENDENCY,且执行npm install好几遍仍报这个。 原因 不是真的缺少某个包,而是安装的依赖版本不对,警告你应该安装某一个版本。 真的缺少某个包。 解决 看了下package.json文件,我的react是有的…

单片机-STM32 WIFI模块--ESP8266 (十二)

1.WIFI模块--ESP8266 名字由来&#xff1a; Wi-Fi这个术语被人们普遍误以为是指无线保真&#xff08;Wireless Fidelity&#xff09;&#xff0c;并且即便是Wi-Fi联盟本身也经常在新闻稿和文件中使用“Wireless Fidelity”这个词&#xff0c;Wi-Fi还出现在ITAA的一个论文中。…

“AI质量评估系统:智能守护,让品质无忧

嘿&#xff0c;各位小伙伴们&#xff01;今天咱们来聊聊一个在现代社会中越来越重要的角色——AI质量评估系统。你知道吗&#xff1f;在这个快速发展的时代&#xff0c;产品质量已经成为企业生存和发展的关键。而AI质量评估系统&#xff0c;就像是我们的智能守护神&#xff0c;…

sqlite3 学习笔记

文章目录 前言SQL的概念与表格相关的操作i.创建表格&#xff08;增&#xff09;ii 删除表格&#xff08;删&#xff09;iii 更改表格&#xff08;改&#xff09;iv 查询表格&#xff08;查&#xff09; 与记录相关的操作i 插入记录ii 删除记录iii 查询记录iv 修改记录 Linux中使…

Swing使用MVC模型架构

什么是MVC模式? MVC是一组英文的缩写,其全名是Model-View-Controller,也就是“模型-视图-控制器”这三个部分组成。这三个部分任意一个部分发生变化都会引起另外两个发生变化。三者之间的关系示意图如下所示: MVC分为三个部分,所以在MVC模型中将按照此三部分分成三…

壁纸设计过程中如何增加氛围感

在壁纸设计过程中&#xff0c;增加氛围感是提升整体视觉效果和情感传达的关键。以下是一些具体的方法和技巧&#xff0c;帮助你在设计中营造出强烈的氛围感&#xff1a; 一、色彩运用 选择主题色&#xff1a; 根据你想要传达的情感选择主色调。例如&#xff0c;温暖的色调&…

【学习笔记】深度学习网络-深度前馈网络(MLP)

作者选择了由 Ian Goodfellow、Yoshua Bengio 和 Aaron Courville 三位大佬撰写的《Deep Learning》(人工智能领域的经典教程&#xff0c;深度学习领域研究生必读教材),开始深度学习领域学习&#xff0c;深入全面的理解深度学习的理论知识。 在之前的文章中介绍了深度学习中用…

Excel分区间统计分析(等步长、不等步长、多维度)

在数据分析过程中&#xff0c;可能会需要统计不同数据区间的人数、某个数据区间的平均值或者进行分组区间统计&#xff0c;本文从excel函数到数据透视表的方法&#xff0c;从简单需求到复杂需求&#xff0c;采用不同的方法进行讲解&#xff0c;尤其是通过数据透视表的强大功能大…

二叉搜索树中的众数(力扣501)

根据二叉树的特性&#xff0c;我们使用中序遍历&#xff0c;确保是从小到大遍历各个节点。为了方便计数&#xff0c;我们使用双指针法&#xff0c;一旦发现当前且节点和前一个节点相同(指的是按照中序遍历的顺序的前一个)&#xff0c;则累加该数字的次数。将出现次数最多的数字…

【趋势】《2024—2026金融科技十大趋势预测》一览

本白皮书基于新华三在金融行业的前沿实践和IDC的全球研究成果,深入分析了金融科技领域的十大关键趋势,旨在为金融机构提供前瞻性的战略指导和业务创新的参考。 导言 当前,在地缘政治冲突加剧、商业经济市场环境高度不确定、数字化业务加速发展的背景下,金融行业处于深度变…

私域流量池构建与转化策略:以开源链动2+1模式AI智能名片S2B2C商城小程序为例

摘要&#xff1a;随着互联网技术的快速发展&#xff0c;流量已成为企业竞争的关键资源。私域流量池&#xff0c;作为提升用户转化率和增强用户粘性的有效手段&#xff0c;正逐渐受到企业的广泛关注。本文旨在深入探讨私域流量池构建的目的、优势及其在实际应用中的策略&#xf…

电子应用设计方案105:智能家庭AI拖把系统设计

智能家庭 AI 拖把系统设计 一、引言 智能家庭 AI 拖把系统旨在为用户提供更高效、便捷和智能化的地面清洁解决方案&#xff0c;减轻家务劳动负担。 二、系统概述 1. 系统目标 - 自动清洁地面&#xff0c;包括吸尘、拖地和擦干功能。 - 智能识别地面材质和污渍程度&#xff0c…