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

2.ResultWrapper.java
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.目录结构

2.IgnoredResultWrapper.java 自定义注解,忽略对返回结果的自动包装
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 对适配器进行扩展的装饰器
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 {
/**
* 注入适配器,可以获取
*/
@Resource
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
@Override
public 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) {
// 找到RequestResponseBodyMethodProcessor
ControllerReturnValueHandler 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
*/
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class);
}
@Override
public 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 将装饰器注入容器
java
/**
* 注入对返回结果增强的装饰器
*
* @return
*/
@Bean
@ConditionalOnMissingBean
public ReturnValueHandlersDecorator returnValueHandlersDecorator() {
return new ReturnValueHandlersDecorator();
}
3.common-web-starter-demo
1.WebController.java 测试三种使用方式
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.第一种:直接使用自动包装成功结果

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

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