14个文本转图像AI API
SpringBoot无侵入式实现接口统一返回JSON格式
2024-12-18
现在基本项目都实现统一返回JSON,但需要每个接口都设置,那有没有全局设置呢?今天就介绍如何无侵入式的实现API接口统一JSON格式返回响应
常见方式
1.定义结果码枚举
@Data
public enum ResultCode {
SUCCESS("0000","成功"),
FAIL("10001","操作失败");
/** 结果码 */
private String code;
/** 结果码描述 */
private String message;
ResultCode(String code, String message) {
this.code = code;
this.message = message;
}
}
2.定义返回结果类
@Data
public class Result<T> {
/** 结果码 */
private String code;
/** 结果码描述 */
private String message;
/** 返回参数 */
private T data;
private Result(ResultCode resultCode, T data) {
this.code = resultCode.getCode();
this.message = resultCode.getMessage();
this.data = data;
}
/** 成功返回结果码和描述 */
public static Result<Void> success() {
return new Result<Void>(ResultCode.SUCCESS, null);
}
/** 成功返回结果码,描述和返回参数 */
public static <T> Result<T> success(T data) {
return new Result<T>(ResultCode.SUCCESS, data);
}
/** 成功返回结果码,描述和返回参数 */
public static <T> Result<T> success(ResultCode resultCode, T data) {
if (resultCode == null) {
return success(data);
}
return new Result<T>(resultCode, data);
}
/** 异常返回结果码和描述 */
public static <T> Result<T> failure() {
return new Result<T>(ResultCode.FAIL, null);
}
/** 异常返回结果码,描述 */
public static <T> Result<T> failure(ResultCode resultCode) {
return failure(resultCode, null);
}
/** 异常返回结果码,描述和返回参数 */
public static <T> Result<T> failure(ResultCode resultCode, T data) {
if (resultCode == null) {
return new Result<T>(ResultCode.FAIL, data);
}
return new Result<T>(resultCode, data);
}
}
3.控制层
@RestController
public class HelloController {
@GetMapping("/test")
public Result hello() {
HashMap<String, Object> info = new HashMap<>();
info.put("name","一安未來");
info.put("addr","北京");
return Result.success(ResultCode.SUCCESS,info);
}
}
4.接口测试
如果还有接口test2、test3、test4…..,即每个接口都必须返回Result对象,这也是目前大多数项目正在使用的方式
优化一
1.继承@ResponseBody
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@ResponseBody
public @interface ResponseResultBody {
}
2.实现ResponseBodyAdvice
ResponseBodyAdvice 接口允许在执行 @ResponseBody 或 ResponseEntity 控制器方法之后,但在使用 HttpMessageConverter 写入响应体之前自定义响应,进行功能增强。通常用于加密,签名,统一数据格式等
相应的也有RequestBodyAdvice接口,针对所有以@RequestBody的参数,在读取请求body之前或者在body转换成对象之前可以做相应的增强
@Slf4j
@RestControllerAdvice
public class ResponseResultBodyAdvice implements ResponseBodyAdvice<Object> {
private static final Class<? extends Annotation> ANNOTATION_TYPE = ResponseResultBody.class;
/**
* 1、选择是否执行 beforeBodyWrite 方法,返回 true 执行,false 不执行.
* 2、通过supports方法,可以选择对哪些类或方法的 Response 进行处理,其余的则不处理。
* @param returnType:返回类型
* @param converterType:转换器
* @return :返回 true 则下面的 beforeBodyWrite 执行,否则不执行
* /
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ANNOTATION_TYPE) || returnType.hasMethodAnnotation(ANNOTATION_TYPE);
}
/**
* 对 Response 处理的具体执行方法
* @param body:响应对象(response)中的响应体
* @param returnType:控制器方法的返回类型
* @param selectedContentType:通过内容协商选择的内容类型
* @param selectedConverterType:选择写入响应的转换器类型
* @param request:当前请求
* @param response:当前响应
* @return :返回传入的主体或修改过的(可能是新的)主体
* /
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return convert(convert(body), selectedConverterType);
}
private Result<?> convert(Object body) {
//兼容返回是Result类型
if (body instanceof Result) {
return (Result<?>) body;
}
return Result.success(body);
}
private Object convert(Result<?> result, Class<? extends HttpMessageConverter<?>> selectedConverterType) {
//兼容返回是String类型
if (selectedConverterType == StringHttpMessageConverter.class && result.getData() instanceof String) {
return "{\"code\":\"" + result.getCode() + "\",\"message\":\"" + result.getMessage() + "\",\"data\":\"" + result.getData() + "\"}";
}
return result;
}
}
3.控制层
@RestController
@ResponseResultBody
public class HelloController {
@GetMapping("/test")
public Result hello() {
HashMap<String, Object> info = new HashMap<>();
info.put("name","一安未來");
info.put("addr","北京");
return Result.success(ResultCode.SUCCESS,info);
}
@GetMapping("/test2")
public Object hello2() {
HashMap<String, Object> info = new HashMap<>();
info.put("name","一安未來");
info.put("addr","北京");
return info;
}
}
4.接口测试
至此,即使返回Object也可以统一JSON格式了, 不用每个返回都返回Result对象
优化二
使用@ExceptionHandler可以用来统一处理方法抛出的异常返回JSON格式
自定义异常处理类
@Data
public class ResultException extends Exception{
ResultCode resultCode;
public ResultException() {
this(ResultCode.FAIL);
}
public ResultException(ResultCode resultCode) {
super(resultCode.getMessage());
this.resultCode = resultCode;
}
}
改造ResponseResultBodyAdvice
类
ResponseBodyAdvice 接口允许在执行 @ResponseBody 或 ResponseEntity 控制器方法之后,但在使用 HttpMessageConverter 写入响应体之前自定义响应,进行功能增强。通常用于加密,签名,统一数据格式等
相应的也有RequestBodyAdvice接口,针对所有以@RequestBody的参数,在读取请求body之前或者在body转换成对象之前可以做相应的增强
@Slf4j
@RestControllerAdvice
public class ResponseResultBodyAdvice implements ResponseBodyAdvice<Object> {
private static final Class<? extends Annotation> ANNOTATION_TYPE = ResponseResultBody.class;
/**
* 1、选择是否执行 beforeBodyWrite 方法,返回 true 执行,false 不执行.
* 2、通过supports方法,可以选择对哪些类或方法的 Response 进行处理,其余的则不处理。
* @param returnType:返回类型
* @param converterType:转换器
* @return :返回 true 则下面的 beforeBodyWrite执行,否则不执行
* /
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ANNOTATION_TYPE) || returnType.hasMethodAnnotation(ANNOTATION_TYPE);
}
/**
* 对 Response 处理的具体执行方法
* @param body:响应对象(response)中的响应体
* @param returnType:控制器方法的返回类型
* @param selectedContentType:通过内容协商选择的内容类型
* @param selectedConverterType:选择写入响应的转换器类型
* @param request:当前请求
* @param response:当前响应
* @return :返回传入的主体或修改过的(可能是新的)主体
* /
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return convert(convert(body), selectedConverterType);
}
private Result<?> convert(Object body) {
if (body instanceof Result) {
return (Result<?>) body;
}
return Result.success(body);
}
private Object convert(Result<?> result, Class<? extends HttpMessageConverter<?>> selectedConverterType) {
if (selectedConverterType == StringHttpMessageConverter.class && result.getData() instanceof String) {
return "{\"code\":\"" + result.getCode() + "\",\"message\":\"" + result.getMessage() + "\",\"data\":\"" + result.getData() + "\"}";
}
return result;
}
/**
* 提供对标准Spring MVC异常的处理
*/
@ExceptionHandler(Exception.class)
public final ResponseEntity<Result<?>> exceptionHandler(Exception ex, WebRequest request) {
log.error("ExceptionHandler: {}", ex.getMessage());
HttpHeaders headers = new HttpHeaders();
if (ex instanceof ResultException) {
return this.handleResultException((ResultException) ex, headers, request);
}
// TODO: 这里可以自定义其他的异常拦截
return this.handleException(ex, headers, request);
}
/**
* 对ResultException类返回返回结果的处理
*/
protected ResponseEntity<Result<?>> handleResultException(ResultException ex, HttpHeaders headers, WebRequest request) {
Result<?> body = Result.failure(ex.getResultCode());
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
return this.handleExceptionInternal(ex, body, headers, status, request);
}
/**
* 异常类的统一处理
*/
protected ResponseEntity<Result<?>> handleException(Exception ex, HttpHeaders headers, WebRequest request) {
Result<?> body = Result.failure();
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
return this.handleExceptionInternal(ex, body, headers, status, request);
}
protected ResponseEntity<Result<?>> handleExceptionInternal(
Exception ex, Result<?> body, HttpHeaders headers, HttpStatus status, WebRequest request) {
if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST);
}
return new ResponseEntity<>(body, headers, status);
}
}
文章转自微信公众号@一安未来
同话题下的热门内容