后台在接收前端请求数据的时候,后端处理完需要对前端请求的ajax或者H5页面的跳转做统一的返回处理,同时也需要对可能造成的异常进行全局统一处理,使当程序运行异常的时候ajax返回统一的异常码,H5请求跳转到统一的错误提示页面。
1、先对全局正常返回类进行包装
@RestControllerAdvice(basePackages = {"com.xxx.xxx.v2"})
public class ControllerResponseAdvice implements ResponseBodyAdvice<Object> {
private static final Logger logger = LoggerFactory.getLogger(ControllerResponseAdvice.class);
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return !(methodParameter.getParameterType().isAssignableFrom(ResultVo.class)
|| methodParameter.hasMethodAnnotation(NotControllerResponseAdvice.class));
}
@Override
public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if (returnType.getGenericParameterType().equals(String.class)) {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(new ResultVo(data));
} catch (Exception e) {
e.printStackTrace();
}
}
return new ResultVo(data);
}
}
ResultVo 为统一返回的包装类方便前台统一解析。
public class ResultVo {
private int code;
private String msg;
private Object data;
public ResultVo(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public ResultVo(Object data) {
this.code = ResultCode.SUCCESS.getCode();
this.msg = ResultCode.SUCCESS.getMsg();
this.data = data;
}
public ResultVo(ResultCode resultCode, Object data) {
this.code = resultCode.getCode();
this.msg = resultCode.getMsg();
this.data = data;
}
public ResultVo(ResultCode resultCode) {
this.code = resultCode.getCode();
this.msg = resultCode.getMsg();
this.data = null;
}
}
NotControllerResponseAdvice.class 这个类是一个注解,意思是忽略返回包装类,大概类似通信接口直接返回 success 就行了,需要要状态吗和返回数据体。注解这边写的可以先忽略注释掉。
这样的话当请求一个controller的时候在没有成功异常返回的都是正常的统一包装体了
@RestController
@RequestMapping("/textApi")
public class TextApi {
@Autowired
LoanService loanService;
@RequestMapping("/queryLoan")
public Loan queryLoan(){
return loanService.queryById(40L);
}
@RequestMapping("/queryPage")
public ModelAndView queryPage(){
return new ModelAndView("/error");
}
}
可以看到代码里面直接返回的实体类,但前端接口返回的是在面自动加了ResultVo。
后面还需要对可能的异常做一下统一返回的处理,模拟逻辑错误可以把 int i = 1/0;这行代码的注释放开进行模拟。 首先创建一个全局异常类的拦截处理,对异常进项包装返回前端
@Slf4j
@RestControllerAdvice(basePackages = {"com.xxx.xxx.v2"})
public class GlobalExceptionHandlerV2 {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandlerV2.class);
private static final String APPLICATION_JSON = "application/json";
private static final String XML_HTTP_REQUEST = "XMLHttpRequest";
private static final String JSON_SUFFIX = ".json";
private static final String XML_SUFFIX = ".xml";
private static final int INDEX_NOT_FOUND = -1;
@ExceptionHandler(value = Exception.class)
ModelAndView MethodArgumentNotValidExceptionHandler(Exception e, HttpServletRequest request){
if(isAjaxRequest(request)){
ModelAndView modelAndView=new ModelAndView(new MappingJackson2JsonView());
modelAndView.addObject(new ResultVo(ResultCode.VALIDATE_ERROR, e.getMessage()));
e.printStackTrace();
return modelAndView;
}else{
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg",e.getMessage());
modelAndView.setViewName("/error");
e.printStackTrace();
return modelAndView;
}
}
public static boolean isAjaxRequest(HttpServletRequest request) {
String accept = request.getHeader("accept");
if (accept != null && accept.contains(APPLICATION_JSON)) {
return true;
}
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.contains(XML_HTTP_REQUEST)) {
return true;
}
String uri = request.getRequestURI();
if (inStringIgnoreCase(uri, JSON_SUFFIX, XML_SUFFIX)) {
return true;
}
String ajax = request.getParameter("__ajax");
return inStringIgnoreCase(ajax, "json", "xml");
}
public static boolean inStringIgnoreCase(String str, String... searchStrings) {
if (str != null && searchStrings != null) {
for (String s : searchStrings) {
if (str.equalsIgnoreCase(StringUtils.trim(s))) {
return true;
}
}
}
return false;
}
}
这里面进行了请求是否为ajax的判断,若是前端为ajax则返回统一的JSON格式,若是H5的页面跳转则跳到统一的error页面,其中 MappingJackson2JsonView这个类需要了解一下。
这个就进行的错误的统一返回包装了,前端获取到数据判断下code 不为约定的成功就是代表数据有问题了。
这个总体可以理解为两个流程: 1、先实现数据的统一返回。 2、全局controller的异常处理。
|