在java 中,我们常常需要对接口返回的数据进行统一的封装,如调用接口异常的时候,我们不希望直接在后台报错,而是需要给前端或者友好提示是什么异常。又或者在处理分页请求的时候,我们可能需要对数据进行统一的封装(返回总条数,数据集等),对于这个需求,我们可以使用ResponseBodyAdvice 这个接口实现。
以下是几个效果图
1.
2.
3.
4.
5.
ResponseBodyAdvice 是 spring 框架中提供的一个接口,其有两个方法,如下:
supports :返回参数是一个boolean类型的数据,表示是否进行响应特殊处理
beforeBodyWrite:表示需要进行特殊处理的时候,需要做的具体处理逻辑
由此可见,通过这两个方法,我们就可以对响应体进行封装。
1.我们新建一个配置类,实现ResponseBodyAdvice 接口,具体代码如下:
package com.xhw.demo.config;
import com.github.pagehelper.Page;
import com.xhw.demo.exception.ResponseErrorBody;
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 java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author: XiaTian
* @create-time 16:17 2021/11/19
*/
@ControllerAdvice
public class ResponseConfig implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter methodParameter,
Class<? extends HttpMessageConverter<?>> aClass) {
Class<?> clazz = methodParameter.getParameterType();
if (clazz.equals(String.class) || clazz.equals(ResponseErrorBody.class)){
return false;
}
// todo 可以配置 需要放过的路由等,自行定义
return true;
}
@Override
public Object beforeBodyWrite(Object o,
MethodParameter methodParameter,
MediaType mediaType,
Class<? extends HttpMessageConverter<?>> aClass,
ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {
Class<?> clazz = methodParameter.getParameterType();
Map rtnMap = new HashMap(3 << 1);
rtnMap.put("status","ok");
rtnMap.put("timestamp",new Date());
if (clazz.equals(Page.class)){
// 对分页的请求进行特殊处理
Page page = (Page)o;
rtnMap.put("data",page.getResult());
rtnMap.put("total",page.getTotal());
rtnMap.put("pageNum",page.getPageNum());
rtnMap.put("pageSize",page.getPageSize());
return rtnMap;
}
rtnMap.put("data",o);
return rtnMap;
}
}
2.controller 类
package com.xhw.demo.controller;
import com.github.pagehelper.PageHelper;
import com.xhw.demo.entity.User;
import com.xhw.demo.exception.AuthException;
import com.xhw.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
/**
* @author: XiaTian
* @create-time 15:30 2021/11/19
// */
@Controller
@ResponseBody
public class TestController {
@Autowired
private UserMapper userMapper;
/**
* 此接口中 抛出了一个 自定义 认证 异常
* @return
*/
@RequestMapping("/test01")
public String test01(){
throw new AuthException();
}
/**
* 次接口 返回的是一个字符串, 在 ResponseConfig 中,
* 我们 不对 返回类型是 String 类型的接口做出做出处理(前提是此接口没有抛出异常)
* @return
*/
@RequestMapping(value = "/test02",method = RequestMethod.GET)
public String test02(){
return "test02";
}
/**
* 此接口返回的是一个 User 对象
* @return
*/
@RequestMapping(value = "/test03",method = RequestMethod.GET)
public User test03(){
return new User(1,"user_001","法半夏");
}
/**
* 此接口 必须一个参数
* @param param
*/
@RequestMapping(value = "/test04",method = RequestMethod.GET)
public void test04(@RequestParam Integer param){
}
/**
* 此接口是一个分页请求
* @return
*/
@RequestMapping(value = "/test05",method = RequestMethod.GET)
public List<User> test05(){
PageHelper.startPage(1,10);
return userMapper.getUserList();
}
}
3. 实体User
package com.xhw.demo.entity;
import lombok.Data;
/**
* @author: XiaTian
* @create-time 17:52 2021/11/19
*/
@Data
public class User {
private Integer id;
private String uid;
private String username;
public User(Integer id, String uid, String username) {
this.id = id;
this.uid = uid;
this.username = username;
}
}
4. 关于异常的类
4.1 自定义 AuthException
package com.xhw.demo.exception;
/**
* 自定义异常
* @author: XiaTian
* @create-time 16:09 2021/11/19
*/
public class AuthException extends RuntimeException{
public AuthException(){}
public AuthException(String message){
super(message);
}
}
4.2 异常枚举类ExceptionEnum
package com.xhw.demo.exception;
/**
* @author: XiaTian
* @create-time 16:10 2021/11/19
*/
public enum ExceptionEnum {
/**
* 认证异常
*/
AUTH_EXCEPTION(1001,"接口认证失败"),
/**
* 缺少请求参数
*/
MISSING_REQUEST_PARAM_EXCEPTION(2001,"缺少请求参数"),
/**
* 请求方法不支持
*/
REQUEST_METHOD_NOT_SUPPORT(2002,"请求方法不支持");
/**
* 响应码
*/
private Integer code;
/**
* 响应消息
*/
private String message;
ExceptionEnum(Integer code,String message){
this.code = code;
this.message = message;
}
public Integer getCode(){
return this.code;
}
public String getMessage() {
return this.message;
}
}
4.3 异常处理类
package com.xhw.demo.exception;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author: XiaTian
* @create-time 16:14 2021/11/19
*/
@ControllerAdvice
@ResponseBody
public class ExceptionHandlerClass {
/**
* 自定义 exception, 认证异常
* @return
*/
@ExceptionHandler(AuthException.class)
public ResponseErrorBody authExceptionHandler(){
return new ResponseErrorBody(ExceptionEnum.AUTH_EXCEPTION.getCode(),
ExceptionEnum.AUTH_EXCEPTION.getMessage());
}
/**
* 缺少请求参数
* @return
*/
@ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseErrorBody missingParamHandler(){
return new ResponseErrorBody(ExceptionEnum.MISSING_REQUEST_PARAM_EXCEPTION.getCode(),
ExceptionEnum.MISSING_REQUEST_PARAM_EXCEPTION.getMessage());
}
/**
* 请求方法不支持
* @return
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ResponseErrorBody requestMethodExceptionHandler(){
return new ResponseErrorBody(ExceptionEnum.REQUEST_METHOD_NOT_SUPPORT.getCode(),
ExceptionEnum.REQUEST_METHOD_NOT_SUPPORT.getMessage());
}
}
4.4 异常响应体类 ResponseErrorBody
package com.xhw.demo.exception;
/**
* 异常响应体
*
* @author: XiaTian
* @create-time 16:13 2021/11/19
*/
public class ResponseErrorBody {
/**
* 返回码
*/
private Integer code;
/**
* 返回消息
*/
private String message;
public ResponseErrorBody(Integer code, String message) {
this.code = code;
this.message = message;
}
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;
}
}
5. UserMapper 类
package com.xhw.demo.mapper;
import com.xhw.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @author: XiaTian
* @create-time 19:15 2021/11/19
*/
@Mapper
public interface UserMapper {
List<User> getUserList();
}
6. UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xhw.demo.mapper.UserMapper" >
<select id="getUserList" resultType="com.xhw.demo.entity.User">
SELECT * FROM user
</select>
</mapper>