本文在 【从零到一 Springboot+Mybatis_Plus示例】 的基础之上,提出问题分析改进。
首先看一段上文的服务是实现类(NewsServiceImpl)的示例代码:
/** * 添加新闻 * * @param title * @param summary * @return */ public boolean insertNews(String title, String summary) { if (title == null || title.length() < 1) { return false; } News record = new News(); record.setTitle(title); record.setSummary(summary); record.setCreateTime(LocalDateTime.now()); ; return super.save(record); }我们简单分析下上面的代码问题:
上边的代码返回结果只知道添加失败还是成功,如果失败了无法得知具体的错误信息。service方法在执行过程出现异常在哪捕获?在service中需要都加try/catch,如果在controller也需要添加try/catch,代码冗余严重且不易维护。 基于以上问题提出解决方案:在Service方法中的编码顺序是先校验判断,有问题则抛出具体的异常信息,最后执行具体的业务操作,返回成功信息。在统一异常处理类中去捕获异常,无需controller捕获异常,向用户返回统一规范的响应信息。定义统一返回结果实体等 例如下面这样: /** * 添加新闻 * * @param title * @param summary * @return */ public InsertResult insertNews(String title, String summary) { if (title == null || title.length() < 1) { //抛出自定义异常 } News record = new News(); record.setTitle(title); record.setSummary(summary); record.setCreateTime(LocalDateTime.now()); ; return new InsertResult(.....); }系统对异常的处理使用统一的异常处理流程:
自定义异常类型。自定义错误代码及错误信息。对于可预知的异常由程序员在代码中主动抛出,由SpringMVC统一捕获。 可预知异常是程序员在代码中手动抛出本系统定义的特定异常类型,由于是程序员抛出的异常,通常异常信息比较齐全,程序员在抛出时会指定错误代码及错误信息,获取异常信息也比较方便。对于不可预知的异常(运行时异常)由SpringMVC统一捕获Exception类型的异常。不可预知异常通常是由于系统出现bug、或一些不要抗拒的错误(比如网络中断、服务器宕机等),异常类型为RuntimeException类型(运行时异常)。可预知的异常及不可预知的运行时异常最终会采用统一的信息格式(错误代码+错误信息)来表示,最终也会随请求响应给客户端。 异常抛出及处理流程: 在controller、service、dao中程序员抛出自定义异常;springMVC框架抛出框架异常类型统一由异常捕获类捕获异常,并进行处理捕获到自定义异常则直接取出错误代码及错误信息,响应给用户。捕获到非自定义异常类型首先从Map中找该异常类型是否对应具体的错误代码,如果有则取出错误代码和错误信息并响应给用户,如果从Map中找不到异常类型所对应的错误代码则统一为99999错误代码并响应给用户。将错误代码及错误信息以Json格式响应给用户。新建exception包,定义异常类型。
比如发其一个不存在的请求,这样的响应信息在客户端是无法解析。
针对上边的问题其解决方案是:
我们在map中配置HttpRequestMethodNotSupportedException的错误为非法请求(CommonCode.INVALID_REQUEST)。在异常捕获类中对Exception异常进行捕获,并从map中获取异常类型对应的错误代码,如果存在错误代码则返回此错误,否则统一返回99999错误。 修改异常捕获类: package com.qqxhb.mybatis.exception; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.google.common.collect.ImmutableMap; import com.qqxhb.mybatis.model.response.CommonCode; import com.qqxhb.mybatis.model.response.ResponseResult; import com.qqxhb.mybatis.model.response.ResultCode; /** * 统一异常捕获类 * **/ @ControllerAdvice // 控制器增强 public class ExceptionCatch { private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCatch.class); // 定义map,配置异常类型所对应的错误代码 private static ImmutableMap<Class<? extends Throwable>, ResultCode> EXCEPTIONS; // 定义map的builder对象,去构建ImmutableMap protected static ImmutableMap.Builder<Class<? extends Throwable>, ResultCode> builder = ImmutableMap.builder(); // 捕获CustomException此类异常 @ExceptionHandler(CustomException.class) @ResponseBody public ResponseResult customException(CustomException customException) { // 记录日志 LOGGER.error("catch exception:{}", customException.getMessage()); ResultCode resultCode = customException.getResultCode(); return new ResponseResult(resultCode); } // 捕获Exception此类异常 @ExceptionHandler(Exception.class) @ResponseBody public ResponseResult exception(Exception exception) { // 记录日志 LOGGER.error("catch exception:{}", exception.getMessage()); if (EXCEPTIONS == null) { EXCEPTIONS = builder.build();// EXCEPTIONS构建成功 } // 从EXCEPTIONS中找异常类型所对应的错误代码,如果找到了将错误代码响应给用户,如果找不到给用户响应99999异常 ResultCode resultCode = EXCEPTIONS.get(exception.getClass()); if (resultCode != null) { return new ResponseResult(resultCode); } else { // 返回99999异常 return new ResponseResult(CommonCode.SERVER_ERROR); } } static { // 定义异常类型所对应的错误代码 builder.put(HttpRequestMethodNotSupportedException.class, CommonCode.INVALID_REQUEST); } }未设置HttpRequestMethodNotSupportedException的错误码时: 添加错误码之后测试: 源码地址:https://github.com/qqxhb/springboot-mybatis-demo 项目名称:springboot-handle-exception