对于⽇常的开发过程中出现的异常,我把它分为两种,
⼀种是需要给前端返回的异常,这种异常通常有⼊参格式、字段缺少、以及相关的业务异常,需要明确的告诉前端出现了什么问题,前端才好处理,
⽽另⼀种异常例如空指针、连接超时、io异常,这类型的异常不需要前端知晓,统⼀返回服务器异常即可。所以我们需要捕获异常,对异常进⾏分类,然后再将封装成固定的格式返回给前端。
⾸先第⼀步个⾃定义⼀个ExceptionMap,这⾥其实啥也没实现就是改了个名字,这样在代码的可读性上能增加不少(我觉得)。其实不做这⼀步直接⽤HashMap也⾏。我们都知道异常的抛出是冒泡的形式抛出的,现在要做的就是捕获,获取异常的内容,ExceptionMap就是⽤来异常被捕获后将异常的信息转化成⼀个map,后续再进⾏格式化和返回
/**
* ⾃定义HashMap的ExceptionMap controller抛出的异常被处理成ExceptionMap * @author xuwang
* @date 2019年5⽉29⽇ 15:04:49 */
public class XcCuisineExceptionMap extends HashMap {}
第⼆步需要继承Exception实现⼀个新的业务Exception类,
这样做有两个⽤处,⼀个是可以⾃定义异常的内容,⼀个是可以和其他异常区分出来
/**
* @ClassName: XcCuisineBusinessException * @ClassNameExplain: * @Description: * @author xuwang
* @date 2019年05⽉31⽇ 10:34:00 * */
public class XcCuisineBusinessException extends Exception { private static final long serialVersionUID = 1; private int code;
private String errorMsg;
public XcCuisineBusinessException(int code, String errorMsg) { super(errorMsg); this.code = code;
this.errorMsg = errorMsg; }
public XcCuisineBusinessException(int code, String errorMsg, Throwable throwable) { super(errorMsg, throwable); this.code = code;
this.errorMsg = errorMsg; }
public int getCode() { return code; }
public String getErrorMsg() { return errorMsg; }}
第三步实现⼀个ControllerAdvice,这⼀步的⽬的主要就是捕获全局异常,所有从Controller抛出的异常都能在这捕获到,在ExceptionHandler中,根据getClass().getName()区分出业务异常,和服务器异常,将异常变成⼀个拥有code和message的XcCuisineExceptionMap
这⾥还额外判断了⼀个MethodArgumentNotValidException ,MethodArgumentNotValidException是使⽤@Valid对⼊参⾥字段进⾏后,字段不符合规则出现的异常,这种也属于业务异常,但是没法抛出变成XcCuisineBusinessException,就在这判断了⼀下。
/**
* @ClassName: XcCuisineControllerAdvice * @ClassNameExplain: * @Description:
* @author xuwang
* @date 2019年05⽉31⽇ 10:34:00 * */
@ControllerAdvice
public class XcCuisineControllerAdvice {
static final Logger logger = LoggerFactory.getLogger(XcCuisineControllerAdvice.class);
/**
* 全局异常捕捉处理 * @param ex * @return */
@ResponseBody
@ExceptionHandler(value = Exception.class) public Map errorHandler(Exception ex) {
Map map = new XcCuisineExceptionMap();
if(ex.getClass().getName().equals(XcCuisineBusinessException.class.getName())){ XcCuisineBusinessException bex = (XcCuisineBusinessException) ex; map.put(\"code\ map.put(\"msg\
}else if(ex.getClass().getName().equals(MethodArgumentNotValidException.class.getName())){ MethodArgumentNotValidException mex = (MethodArgumentNotValidException) ex; StringBuffer sb = new StringBuffer();
List sb.append(error.getObjectName()); sb.append(\"对象的\"); sb.append(error.getField()); sb.append(\"字段\"); sb.append(translationString(error.getDefaultMessage())); } map.put(\"code\ map.put(\"msg\ }else { map.put(\"code\ map.put(\"msg\ } return map; } /** * @Title: translationString * @TitleExplain: * @Description: 对字符串进⾏转译 解决报错中出现json关键字符 导致json序列化失败的问题 * @param * @return java.lang.String * @version * @author */ private String translationString(String string){ String temp = GsonUtil.toJson(string); return temp.substring(1, temp.length()-1); } } 第四步是在创建转化器,我的这个转换器其实对⼊参和反参都进⾏了转换,因为在我的项⽬⾥⼊参也是有标准的,不过这⾥没写太多,在writeInternal中,反参如果是XcCuisineExceptionMap,直接就转换成JSON字符串返回,这⾥还在正常返回的内容中添加了code和message,做到了反参的标准化{code:\"\ /** * @author xuwang * @ClassName: GsonHttpMessageConverter * @ClassNameExplain: Gson转换器 * @Description: * @date 2019年05⽉30⽇ 20:13:04 */ public class GsonHttpMessageConverter extends AbstractHttpMessageConverter { private final static String CODE_KEY = \"code\"; private final static String MSG_KEY = \"msg\"; private final static String DATA_KEY = \"data\"; private final static String CONTENT_TYPE_KEY = \"Content-Type\"; public GsonHttpMessageConverter() { super(new MediaType(\"application\ } @Override protected boolean supports(Class aClass) { //返回true表⽰⽀持所有的类 return true; } /** * 处理请求内容 * @param aClass * @param httpInputMessage * @return * @throws IOException * @throws HttpMessageNotReadableException */ @Override protected Object readInternal(Class aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException { //取出requestBody中内容 String json = StreamUtils.copyToString( httpInputMessage.getBody(), httpInputMessage.getHeaders().getContentType().getCharset()); //打印⼊参 logger.debug(aClass+\" request json : \\n\" + json); if(StringUtils.isNotEmpty(json) && json.trim().startsWith(\"{\") && json.trim().endsWith(\ return GsonUtil.json2Bean(json, aClass); }else{ //TODO throw new RequestFormatException(\"请求格式不正确\"); return json; } } /** * 处理响应内容 * @param o * @param httpOutputMessage * @throws IOException * @throws HttpMessageNotWritableException */ @Override protected void writeInternal(Object o, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException { Class oClass = o.getClass(); String json = \"\"; if(oClass.getName().equals(XcCuisineExceptionMap.class.getName())){ //判断如果是抛出来的异常直接转换为json字符串 json = GsonUtil.toJson(o); }else { Map result.put(CODE_KEY, Constant.CORRECT_CODE); //设置msg result.put(MSG_KEY, Constant.CORRECT_MSG); //设置data result.put(DATA_KEY, o == null ? \"\" : o); json = GsonUtil.toJson(result); }; logger.debug(\"response json : \\n\" + json); httpOutputMessage.getHeaders().add(CONTENT_TYPE_KEY, \"application/json\"); httpOutputMessage.getBody().write(json.getBytes(\"UTF-8\")); }} 最后是注册这个转换器 @EnableWebMvc@Configuration public class MvcConfig implements WebMvcConfigurer { @Override public void configureMessageConverters( List converters.add(createGsonHttpMessageConverter()); } @Bean public GsonHttpMessageConverter createGsonHttpMessageConverter() { //注⼊⾃定义转换器 return new GsonHttpMessageConverter(); } } 到此就完成了。 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- sceh.cn 版权所有 湘ICP备2023017654号-4
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务