springboot返回统一数据格式

目录

  • 返回数据格式
  • POM.xml
  • 包路径
  • 核心代码
    • ResultCode.java
    • Result.java
    • ErrorResult.java
    • ServiceException.java
    • JsonUtil.java
    • GlobalExceptionHandler.java
    • ResponseHandler.java
  • 测试代码
    • UserVO.java
    • UserController.java

返回数据格式

{
	"status":10000, // 状态码
	"desc":"成功", // 状态描述
	"data":{} // 实体数据,可能的傎为:null、string、json
}

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.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo1</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>demo1</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-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

包路径

com
  example
    demo
      rest
        advice
          GlobalExceptionHandler.java
          ResponseHandler.java
        ctrl
          UserController.java
        utils
          JsonUtil.java
        vo
          ErrorResult.java
          Result.java
          ResultCode.java
          ServiceException.java
          UserVO.java

核心代码

ResultCode.java

package com.example.demo.rest.vo;

public enum ResultCode {
	
	SUCCESS(0, "成功"),
	
	SYSTEM_ERROR(10000, "系统异常,请稍后重试"),
	
	UNAUTHORIZED(10410, "签名验证失败"),
	
	PARAM_IS_INVALID(10001, "参数无效"),
	
	USER_HAS_EXSISTED(20001, "用户名已存在"),
	
	USER_NOT_FIND(20002, "用户名不存在");

	private Integer code;
	
	private String message;
	
	private ResultCode(Integer code, String message) {
		this.code = code;
		this.message = message;
	}

	public Integer getCode() {
		return code;
	}

	public String getMessage() {
		return message;
	}
	
}

Result.java

package com.example.demo.rest.vo;

public class Result {

	private Integer status;
	
	private String desc;
	
	private Object data;
	
	public Integer getStatus() {
		return status;
	}

	public void setStatus(Integer status) {
		this.status = status;
	}

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	public static Result suc() {
		Result result = new Result();
		result.setResultCode(ResultCode.SUCCESS);
		return result;
	}
	
	public static Result suc(Object data) {
		Result result = new Result();
		result.setResultCode(ResultCode.SUCCESS);
		result.setData(data);
		return result;
	}
	
	public static Result fail(Integer status, String desc) {
		Result result = new Result();
		result.setStatus(status);
		result.setDesc(desc);
		return result;
	}
	
	public static Result fail(ResultCode resultCode) {
		Result result = new Result();
		result.setResultCode(resultCode);
		return result;
	}
	
	private void setResultCode(ResultCode resultCode) {
		this.status = resultCode.getCode();
		this.desc = resultCode.getMessage();
	}
}

ErrorResult.java

package com.example.demo.rest.vo;

public class ErrorResult {

	private Integer status;
	
	private String message;
	
	private String exception;
	
	public Integer getStatus() {
		return status;
	}

	public void setStatus(Integer status) {
		this.status = status;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public String getException() {
		return exception;
	}

	public void setException(String exception) {
		this.exception = exception;
	}
	
	@Override
	public String toString() {
		return "ErrorResult [status=" + status + ", message=" + message + ", exception=" + exception + "]";
	}

	public static ErrorResult fail(ResultCode resultCode, Throwable e, String message) {
		ErrorResult errorResult = ErrorResult.fail(resultCode, e);
		errorResult.setMessage(message);
		return errorResult;
	}
	
	public static ErrorResult fail(ResultCode resultCode, Throwable e) {
		ErrorResult errorResult = new ErrorResult();
		errorResult.setStatus(resultCode.getCode());
		errorResult.setMessage(resultCode.getMessage());
		errorResult.setException(e.getClass().getName());
		return errorResult;
	}
}

ServiceException.java

package com.example.demo.rest.vo;

public class ServiceException extends RuntimeException {

	private static final long serialVersionUID = 2797060340861735113L;

	protected Integer code;
	
	protected String message;

	public ServiceException(ResultCode resultCode) {
		this.code = resultCode.getCode();
		this.message = resultCode.getMessage();
	}

	public ServiceException(ResultCode resultCode, Throwable cause) {
		super(cause);
		this.code = resultCode.getCode();
		this.message = resultCode.getMessage();
	}

	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;
	}
	
}

JsonUtil.java

package com.example.demo.rest.utils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class JsonUtil {
	 
	private static final ObjectMapper objectMapper;
	/** 格式化时间的string */
	private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
	static {
		objectMapper = new ObjectMapper();
		// 去掉默认的时间戳格式
		objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
		// 设置为中国北京时区
		objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		// 空值不序列化
		objectMapper.setSerializationInclusion(Include.NON_NULL);
		// 反序列化时,属性不存在的兼容处理
		objectMapper.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
 
		// 序列化时,日期的统一格式
		objectMapper.setDateFormat(new SimpleDateFormat(DATE_TIME_FORMAT));
 
		objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		// 单引号处理
		objectMapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
	}
 
	/**
	 * json 转换成 Object
	 *
	 * @param json
	 * @param clazz
	 * @return
	 */
	public static <T> T json2Object(String json, Class<T> clazz) {
		try {
			return objectMapper.readValue(json, clazz);
		} catch (IOException e) {
			throw new RuntimeException("解析json错误");
		}
	}
 
	public static <T> T json2Object(String json, TypeReference<T> tr) {
		try {
			return (T)objectMapper.readValue(json, tr);
		} catch (IOException e) {
			throw new RuntimeException("解析json错误", e);
		}
	}
 
	/**
	 * obj 转换成json
	 *
	 * @param entity
	 * @return
	 */
	public static <T> String object2Json(T entity) {
		try {
			return objectMapper.writeValueAsString(entity);
		} catch (IOException e) {
			throw new RuntimeException("转换json错误");
		}
	}
 
	/**
	 * obj对象 转换成树型JSON
	 *
	 * @param obj
	 * @return
	 */
	public static JsonNode object2TreeJson(Object obj) {
		try {
			return objectMapper.valueToTree(obj);
		} catch (Exception e) {
			throw new RuntimeException("转换json错误");
		}
	}
 
	  /**
     * 解码json串成对象
     *
     * @param 
     * @param json
     * @param valueType
     * @return T
     */
    @SuppressWarnings("unchecked")
    public static <T> T decode(String json, Class<?> valueType) {
        try {
            return (T) objectMapper.readValue(json, valueType);
        } catch (Exception e) {
            throw new RuntimeException(json, e);
        }
    }
 
}

GlobalExceptionHandler.java

package com.example.demo.rest.advice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.example.demo.rest.vo.ErrorResult;
import com.example.demo.rest.vo.ResultCode;
import com.example.demo.rest.vo.ServiceException;

@RestControllerAdvice
public class GlobalExceptionHandler {
	private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(Throwable.class)
	public ErrorResult handleThrowable(Throwable e, HttpServletRequest request) {
		ErrorResult error = ErrorResult.fail(ResultCode.SYSTEM_ERROR, e);
		logger.error("URL: {}, 系统异常!", request.getRequestURI(), e);
		return error;
	}
	
	@ExceptionHandler(ServiceException.class)
	public ErrorResult handleServiceException(ServiceException e, HttpServletRequest request) {
		ErrorResult error = new ErrorResult();
		error.setStatus(e.getCode());
		error.setMessage(e.getMessage());
		error.setException(e.getClass().getName());
		logger.warn("URL: {}, 业务异常: {}", request.getRequestURI(), error, e);
		return error;
	}
	
	@ExceptionHandler(BindException.class)
	public ErrorResult handleBindException(BindException e, HttpServletRequest request) {
		ErrorResult error = ErrorResult.fail(ResultCode.PARAM_IS_INVALID, e, e.getAllErrors().get(0).getDefaultMessage());
		logger.warn("URL: {}, 参数校验异常", request.getRequestURI(), e);
		return error;
	}

	@ExceptionHandler(MethodArgumentNotValidException.class)
	public ErrorResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
		ErrorResult error = ErrorResult.fail(ResultCode.PARAM_IS_INVALID, e, e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
		logger.warn("URL: {}, 参数校验异常", request.getRequestURI(), e);
		return error;
	}

	@ExceptionHandler(ConstraintViolationException.class)
	public ErrorResult handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
		StringBuilder builder = new StringBuilder();
		for (ConstraintViolation<?> constraintViolation : e.getConstraintViolations()) {
			builder.append(constraintViolation.getMessage());
		}
		ErrorResult error = ErrorResult.fail(ResultCode.PARAM_IS_INVALID, e, builder.toString());
		logger.warn("URL: {}, 参数校验异常", request.getRequestURI(), e);
		return error;
	}
}

ResponseHandler.java

package com.example.demo.rest.advice;

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import com.example.demo.rest.utils.JsonUtil;
import com.example.demo.rest.vo.ErrorResult;
import com.example.demo.rest.vo.Result;

@ControllerAdvice(basePackages = "com.example.demo.rest")
public class ResponseHandler implements ResponseBodyAdvice<Object> {

	@Override
	public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
		return true;
	}

	@Override
	public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
			Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
			ServerHttpResponse response) {
		if (body instanceof ErrorResult) {
			ErrorResult errorResult = (ErrorResult) body;
			return Result.fail(errorResult.getStatus(), errorResult.getMessage());
		} else if (body instanceof String) {
			return JsonUtil.object2Json(Result.suc(body));
		}
		return Result.suc(body);
	}

}

测试代码

UserVO.java

package com.example.demo.rest.vo;

import java.util.Date;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;

public class UserVO {

	@Min(value = 3)
	private Integer id;
	
	@NotBlank(message = "用户名不能为空")
	private String username;
	
	private String password;
	
	private String email;
	
	private String phone;
	
	private String idCard;
	
	private Byte sex;
	
	private Byte deleted;
	
	private Date updateTime;
	
	private Date createTime;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getIdCard() {
		return idCard;
	}

	public void setIdCard(String idCard) {
		this.idCard = idCard;
	}

	public Byte getSex() {
		return sex;
	}

	public void setSex(Byte sex) {
		this.sex = sex;
	}

	public Byte getDeleted() {
		return deleted;
	}

	public void setDeleted(Byte deleted) {
		this.deleted = deleted;
	}

	public Date getUpdateTime() {
		return updateTime;
	}

	public void setUpdateTime(Date updateTime) {
		this.updateTime = updateTime;
	}

	public Date getCreateTime() {
		return createTime;
	}

	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}

	@Override
	public String toString() {
		return "UserVO [id=" + id + ", username=" + username + ", password=" + password + ", email=" + email
				+ ", phone=" + phone + ", idCard=" + idCard + ", sex=" + sex + ", deleted=" + deleted + ", updateTime="
				+ updateTime + ", createTime=" + createTime + "]";
	}
}

UserController.java

package com.example.demo.rest.ctrl;

import javax.validation.Valid;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.rest.vo.ResultCode;
import com.example.demo.rest.vo.ServiceException;
import com.example.demo.rest.vo.UserVO;

@RestController
@RequestMapping("/user")
public class UserController {

	@GetMapping("getStr")
	public String getStr() {
		return "test";
	}
	
	@GetMapping("getInt")
	public int getInt() {
		return 1;
	}
	
	@GetMapping("/getObject")
	public UserVO getObject() {
		UserVO vo = new UserVO();
		vo.setUsername("xxx");
		return vo;
	}
	
	@GetMapping("/empty")
	public void empty() {
		
	}
	
	@GetMapping("/error")
	public void error() {
		int i = 1 / 0;
	}
	
	@GetMapping("/error2")
	public void error2() {
		Integer.valueOf("aa");
	}
	
	@GetMapping("/error3")
	public void error3() {
		throw new ServiceException(ResultCode.USER_HAS_EXSISTED);
	}
	
	@GetMapping("/error4")
	public void error4() {
		throw new RuntimeException("用户不存在!!");
	}
	
	@GetMapping("/createUser")
	public void createUser(@Valid UserVO userVO) {
		
	}
}

你可能感兴趣的:(springboot,javaweb)