无侵入式 统一返回JSON格式接口开发demo
参考
https://github.com/galaxy-sea/galaxy-blogs/tree/master/code/responseResult
自己copy了一份发现使用eureka或者直接引入如下依赖,接口浏览器访问返回xml格式结果
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
如图:
百度一下,Eureka依赖自动引入的
所以只需要在eureka依赖中使用 排除该依赖就行。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
具体统一json代码实现如下:
==========================================
ResponseResultBody.java
package com.wwy.newapi.result;
import org.springframework.web.bind.annotation.ResponseBody;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@ResponseBody
public @interface ResponseResultBody {
}
==========================================
ResponseResultBodyAdvice.java
package com.wwy.newapi.result;
import java.lang.annotation.Annotation;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import org.springframework.web.util.WebUtils;
import com.wwy.newapi.result.exception.ResultException;
import lombok.extern.slf4j.Slf4j;
/**
* 使用这个注解就可以返回统一的json格式, 用于类和方法上
* @author wangwenying
*
*/
@Slf4j
@RestControllerAdvice
public class ResponseResultBodyAdvice implements ResponseBodyAdvice<Object> {
private static final Class<? extends Annotation> ANNOTATION_TYPE = ResponseResultBody.class;
/** 判断类或者方法是否使用了 @ResponseResultBody */
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ANNOTATION_TYPE) || returnType.hasMethodAnnotation(ANNOTATION_TYPE);
}
/** 当类或者方法使用了 @ResponseResultBody 就会调用这个方法 */
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof Result) {
return body;
}
return Result.success(body);
}
/**
* 提供对标准Spring MVC异常的处理
*
* @param ex the target exception
* @param request the current request
*/
@ExceptionHandler(Exception.class)
public final ResponseEntity<Result<?>> exceptionHandler(Exception ex, WebRequest request) {
HttpHeaders headers = new HttpHeaders();
if (ex instanceof ResultException) {
return this.handleResultException((ResultException) ex, headers, request);
}
// TODO: 2019/10/05 galaxy 这里可以自定义其他的异常拦截
return this.handleException(ex, headers, request);
}
/** 对ResultException类返回返回结果的处理 */
protected ResponseEntity<Result<?>> handleResultException(ResultException ex, HttpHeaders headers, WebRequest request) {
Result<?> body = Result.failure(ex.getResultStatus());
HttpStatus status = ex.getResultStatus().getHttpStatus();
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);
}
/**
* org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler#handleExceptionInternal(java.lang.Exception, java.lang.Object, org.springframework.http.HttpHeaders, org.springframework.http.HttpStatus, org.springframework.web.context.request.WebRequest)
* <p>
* A single place to customize the response body of all exception types.
* <p>The default implementation sets the {@link WebUtils#ERROR_EXCEPTION_ATTRIBUTE}
* request attribute and creates a {@link ResponseEntity} from the given
* body, headers, and status.
*/
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);
}
}
==========================================
Result.java
package com.wwy.newapi.result;
/**
* 后端返回给前端的json格式
* todo 返回格式参考 org.springframework.boot.web.servlet.error.DefaultErrorAttributes
*
* @author galaxy
* @date 2019/10/05 16:19
*/
public class Result<T> {
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
/** 业务错误码 */
private Integer code;
/** 信息描述 */
private String message;
/** 返回参数 */
private T data;
private Result(ResultStatus resultStatus, T data) {
this.code = resultStatus.getCode();
this.message = resultStatus.getMessage();
this.data = data;
}
/** 业务成功返回业务代码和描述信息 */
public static Result<Void> success() {
return new Result<Void>(ResultStatus.SUCCESS, null);
}
/** 业务成功返回业务代码,描述和返回的参数 */
public static <T> Result<T> success(T data) {
return new Result<T>(ResultStatus.SUCCESS, data);
}
/** 业务成功返回业务代码,描述和返回的参数 */
public static <T> Result<T> success(ResultStatus resultStatus, T data) {
if (resultStatus == null) {
return success(data);
}
return new Result<T>(resultStatus, data);
}
/** 业务异常返回业务代码和描述信息 */
public static <T> Result<T> failure() {
return new Result<T>(ResultStatus.INTERNAL_SERVER_ERROR, null);
}
/** 业务异常返回业务代码,描述和返回的参数 */
public static <T> Result<T> failure(ResultStatus resultStatus) {
return failure(resultStatus, null);
}
/** 业务异常返回业务代码,描述和返回的参数 */
public static <T> Result<T> failure(ResultStatus resultStatus, T data) {
if (resultStatus == null) {
return new Result<T>(ResultStatus.INTERNAL_SERVER_ERROR, null);
}
return new Result<T>(resultStatus, data);
}
}
==========================================
ResultStatus.java
package com.wwy.newapi.result;
import org.springframework.http.HttpStatus;
public enum ResultStatus {
SUCCESS(HttpStatus.OK, 200, "OK"),
BAD_REQUEST(HttpStatus.BAD_REQUEST, 400, "Bad Request"),
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 500, "Internal Server Error"),
;
/** 返回的HTTP状态码, 符合http请求 */
private HttpStatus httpStatus;
/** 业务异常码 */
private Integer code;
/** 业务异常信息描述 */
private String message;
ResultStatus(HttpStatus httpStatus, Integer code, String message) {
this.httpStatus = httpStatus;
this.code = code;
this.message = message;
}
public HttpStatus getHttpStatus() {
return httpStatus;
}
public void setHttpStatus(HttpStatus httpStatus) {
this.httpStatus = httpStatus;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
==========================================
WebMvcConfiguration.java
package com.wwy.newapi.result;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author changjinwei
* @date 2020/11/10
*/
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
/**
* // 这里是修复 com.galaxy.controller.HelloResultController.testString 方法, 解决方案有两个
* // 1。 重写 org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse)
* // 2。 实现WebMvcConfigurer或者继承WebMvcConfigurationSupport 重写 #extendMessageConverters(java.util.List)方法,
* // 第二个方法实现如下
*/
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(converter -> converter instanceof StringHttpMessageConverter);
}
}
==========================================
ResultException.java
package com.wwy.newapi.result.exception;
import com.wwy.newapi.result.ResultStatus;
/**
* 业务异常类
*
* @author galaxy
* @date 2019/10/05 16:19
*/
@SuppressWarnings("serial")
public class ResultException extends Exception {
/**
* 业务异常信息信息
*/
ResultStatus resultStatus;
public ResultException() {
this(ResultStatus.INTERNAL_SERVER_ERROR);
}
public ResultStatus getResultStatus() {
return resultStatus;
}
public void setResultStatus(ResultStatus resultStatus) {
this.resultStatus = resultStatus;
}
public ResultException(ResultStatus resultStatus) {
super(resultStatus.getMessage());
this.resultStatus = resultStatus;
}
}
==========================================
HelloResultController.java
package com.wwy.newapi.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.wwy.newapi.result.ResponseResultBody;
import com.wwy.newapi.result.Result;
import com.wwy.newapi.result.exception.ResultException;
/**
* @author galaxy
* @date 2019/10/05 16:19
*/
@RestController
@RequestMapping("/helloResult")
@ResponseResultBody
public class HelloResultController {
private static final HashMap<String, Object> INFO;
static {
INFO = new HashMap<String, Object>();
INFO.put("name", "galaxy");
INFO.put("age", "70");
}
@GetMapping("hello")
public HashMap<String, Object> hello() {
return INFO;
}
@GetMapping("result")
public Result<Map<String, Object>> helloResult() {
return Result.success(INFO);
}
@GetMapping("helloError")
public HashMap<String, Object> helloError() throws Exception {
throw new Exception("helloError");
}
@GetMapping("helloMyError")
public HashMap<String, Object> helloMyError() throws Exception {
throw new ResultException();
}
@GetMapping(value = "testString")
public String testString() {
return "helloString";
}
@GetMapping(value = "testInt")
public Integer testInt() {
return 123;
}
}
==========================================
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.galaxy</groupId>
<artifactId>response-result</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>response-result</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
结果如下: