统一结果响应
为了与前端进行数据交互时,能有一个统一的数据结构,一般我们都需要一个统一响应结果类
以下直接上代码,粘贴可用
typescript
package com.kjyfx.response;
import java.io.Serializable;
/**
* 微信公众号:云说Java、Java栈记
* @Created by 墨云
* @Description 统一响应数据
* @Date 2020/8/29 12:33
*/
public class BaseResponse<T> implements Serializable {
private static final long serialVersionUID = 3997124446365032582L;
/**
* 返回消息
*/
private String message;
/**
* 返回对象
*/
private T data;
/**
* 是否成功
*/
private Boolean state;
/**
* 自定义错误码
*/
private Integer code;
/**
* 错误,系统异常
*
* @return result
*/
public static BaseResponse renderError() {
BaseResponse response = new BaseResponse();
response.setState(Boolean.FALSE);
response.setCode(500);
return response;
}
/**
* 错误数据(带消息)
*
* @param msg 需要返回的消息
* @return result
*/
public static BaseResponse renderError(String msg) {
BaseResponse response = BaseResponse.renderError();
response.setMessage(msg);
return response;
}
/**
* 错误数据(带消息)
*
* @param msg 需要返回的消息
* @return result
*/
public static BaseResponse renderError(String msg, Integer code) {
BaseResponse response = BaseResponse.renderError();
response.setMessage(msg);
response.setCode(code);
return response;
}
/**
* 成功数据
*
* @return result
*/
public static BaseResponse renderSuccess() {
BaseResponse response = new BaseResponse();
response.setState(Boolean.TRUE);
response.setCode(200);
return response;
}
/**
* 成功数据(带信息)
*
* @param msg 需要返回的信息
* @return result
*/
public static BaseResponse renderSuccess(String msg) {
BaseResponse response = BaseResponse.renderSuccess();
response.setMessage(msg);
return response;
}
/**
* 成功数据(带数据)
*
* @param obj 需要返回的对象
* @return result
*/
public static BaseResponse renderSuccess(Object obj) {
BaseResponse response = BaseResponse.renderSuccess();
response.setData(obj);
return response;
}
/**
* 成功数据(带数据,带信息)
*
* @param msg 需要返回的信息
* @param obj 需要返回的对象
* @return result
*/
public static BaseResponse renderSuccess(String msg, Object obj) {
BaseResponse response = BaseResponse.renderSuccess();
response.setMessage(msg);
response.setData(obj);
return response;
}
/**
* 失败数据
*
* @return result
*/
public static BaseResponse renderFail() {
BaseResponse response = new BaseResponse();
response.setState(Boolean.FALSE);
response.setCode(500);
return response;
}
/**
* 失败数据(带消息)
*
* @param msg 需要返回的消息
* @return result
*/
public static BaseResponse renderFail(String msg) {
BaseResponse response = BaseResponse.renderFail();
response.setMessage(msg);
return response;
}
/**
* 失败数据(带消息)
*
* @param msg 需要返回的消息
* @param code 自定义错误码
* @return result
*/
public static BaseResponse renderFail(String msg, Integer code) {
BaseResponse response = BaseResponse.renderFail();
response.setMessage(msg);
response.setCode(code);
return response;
}
/**
* 失败数据(带数据,带信息)
*
* @param msg 需要返回的信息
* @param obj 需要返回的对象
* @return result
*/
public static BaseResponse renderFail(String msg, Object obj) {
BaseResponse response = BaseResponse.renderFail();
response.setMessage(msg);
response.setData(obj);
return response;
}
/**
* 失败数据(带数据,带信息)
*
* @param msg 需要返回的信息
* @param obj 需要返回的对象
* @param code 自定义错误码
* @return result
*/
public static BaseResponse renderFail(String msg, Object obj, Integer code) {
BaseResponse response = BaseResponse.renderFail();
response.setMessage(msg);
response.setData(obj);
response.setCode(code);
return response;
}
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;
}
public Boolean getState() {
return state;
}
public void setState(Boolean state) {
this.state = state;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
接下来我们就可以用统一结果响应类进行数据交互
java
@RequestMapping("/getUser")
public BaseResponse getUser(){
SysUser sysUser = new SysUser()
.setId(1000L)
.setAccount("moyun")
.setUserName("墨云");
return BaseResponse.renderSuccess("成功!",sysUser);
}
访问接口:http://localhost:9000/base/sysUser/getUser,得到如下数据,统一的数据结构,也方便前端请求接口之后的统一响应拦截处理
从code状态码跟state查看数据信息就很清晰
json
{
"message": "成功!",
"data": {
"id": 1000,
"account": "moyun",
"password": null,
"userName": "墨云",
"tel": null,
"status": null,
"createUser": null,
"createType": null,
"createTime": null,
"updateTime": null
},
"state": true,
"code": 200
}
一般在实际项目中,见得最多的就是BaseResponse和JsonResult这两个统一响应结果类,命名看个人习惯,内部结构都大同小异
成功结果
,常用以下四个静态方法
ini
BaseResponse.renderSuccess();
BaseResponse.renderSuccess(String msg);
BaseResponse.renderSuccess(Object obj);
BaseResponse.renderSuccess(String msg, Object obj);
业务级错误结果
,常用以下五个静态方法
vbnet
BaseResponse.renderFail();
BaseResponse.renderFail(String msg);
BaseResponse.renderFail(String msg, Integer code);
BaseResponse.renderFail(String msg, Object obj);
BaseResponse.renderFail(String msg, Object obj, Integer code);
系统级错误结果
,可用以下三个静态方法(不常用,只是与业务级错误进行区分)
scss
BaseResponse.renderError();
BaseResponse renderError(String msg);
BaseResponse renderError(String msg, Integer code);
全局异常处理
全局异常处理类主要用于,当服务器出现异常时,将捕获到的异常信息以json数据返给前端。
先自定义一个异常类,继承RuntimeException
java
package com.kjyfx.exception;
/**
* 微信公众号:云说Java、Java栈记
* @author moyun
* @date 2020/12/01
*/
public class MsgException extends RuntimeException{
public MsgException() {
}
public MsgException(String message) {
super(message);
}
public MsgException(String message, Throwable cause) {
super(message, cause);
}
public MsgException(Throwable cause) {
super(cause);
}
protected MsgException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
再定义一个全局异常处理器,可以自行添加其他异常处理
kotlin
package com.kjyfx.exception;
import com.kjyfx.response.BaseResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
/**
* 微信公众号:云说Java、Java栈记
* @author moyun
* @date 2020/12/01
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value = MsgException.class)
public BaseResponse msgExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return BaseResponse.renderFail(e.getMessage());
}
@ExceptionHandler(value = NullPointerException.class)
public BaseResponse nullExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return BaseResponse.renderFail("出现了空指针!");
}
@ExceptionHandler(value = org.springframework.web.servlet.NoHandlerFoundException.class)
public BaseResponse noHandlerFoundExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
logger.error(e.getMessage());
return BaseResponse.renderFail("404,未找到请求地址");
}
@ExceptionHandler(value = IllegalArgumentException.class)
public BaseResponse illegalArgumentExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return BaseResponse.renderFail(e.getMessage());
}
@ExceptionHandler(value = SQLException.class)
public BaseResponse sQLExceptionExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
logger.error(e.getMessage());
return BaseResponse.renderFail("数据库查询异常");
}
}
当我们访问以下接口时,sysUser对象恒为空,此时就会抛出一个MsgException
java
@RequestMapping("/getUser")
public SysUser getUser(){
SysUser sysUser = null;
if(null == sysUser){
throw new MsgException("服务器报了一个错");
}
return new SysUser();
}
此时我们访问接口:http://localhost:9000/base/sysUser/getUser
就会得到以下数据,便是全局异常处理器为我们处理的
json
{
"message": "服务器报了一个错",
"data": null,
"state": false,
"code": 500
}
全局异常处理器最主要的两个注解,
@RestControllerAdvice
:作用于类上,相当于Controller的切面,对异常统一处理,定制,之后再以json格式返给前端
@ExceptionHandler
:统一处理某一类异常,作用于方法上,捕捉到相应异常后,会执行其修饰的方法
例如:执行到第四行的时候肯定会报空指针异常
java
@RequestMapping("/getUser")
public SysUser getUser(){
SysUser sysUser = null;
sysUser.setId(1000L);
return new SysUser();
}
访问接口后,将会得到全局异常处理器返回的数据
json
{
"message": "出现了空指针!",
"data": null,
"state": false,
"code": 500
}
JSON数据处理
对于以上得到的json数据,如果对象属性没有赋值,则会显示为null值,对前端来说这是很不友好的,一不小心整个页面就会瘫痪,接下来我们用SpringBoot自带的Jackson对数据进行转换,将null处理为""空串
创建JacksonConfig配置类:
java
package com.kjyfx.config;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.io.IOException;
/**
* @Description TODO
* 微信公众号:云说Java、Java栈记
* @Date 2020/12/10 22:20
* @Created by moyun
*/
@Configuration
public class JacksonConfig {
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
SerializerProvider serializerProvider = objectMapper.getSerializerProvider();
serializerProvider.setNullValueSerializer(new JsonSerializer<Object>() {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
jsonGenerator.writeString("");
}
});
return objectMapper;
}
}
@Primary:
当Spring容器扫描到某个接口的多个 bean 时,如果某个bean上加了@Primary 注解 ,则这个bean会被优先选用
@ConditionalOnMissingBean:
它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,
它会保证你的bean只有一个,即你的实例只有一个
之后我们重启项目,再访问接口,会得到以下数据,null成功被转成了""空串
json
{
"message": "成功!",
"data": {
"id": 1000,
"account": "moyun",
"password": "",
"userName": "墨云",
"tel": "",
"status": "",
"createUser": "",
"createType": "",
"createTime": "",
"updateTime": ""
},
"state": true,
"code": 200
}