Java 开源生鲜电商平台 - 异常模块的设计与架构(源码可下载)
说明: 任何一个软件系统都会出现各式各样的异常与错误, 我们需要根据异常的情况进行捕获与分析, 改善自己的代码, 让其更加的稳定的, 快速的运行, 那么作为一个
B2B 的 Java 开源生鲜电商平台, 我们的异常需要思考以下几个维度.
1. 运行的代码异常
说明: 代码在运行的过程中, 难免出现各种异常与错误, 我们采用 Log4j 进行日志的记录.
在分层代码解耦过程中, 我们统一在 Controller 进行异常的捕获与日志记录.
相关的运行的代码异常架构如下:
- /**
- * (商家店铺)商品信息列表
- * @param request
- * @param response
- * @return
- */
- @RequestMapping(value = "/goods/list", method = { RequestMethod.GET})
- public JsonResult goodsList(HttpServletRequest request, HttpServletResponse response) {
- try
- {
- // 业务逻辑处理
- return new JsonResult(JsonResultCode.FAILURE, "系统错误, 请稍后重试","");
- }catch(Exception ex){
- logger.error("[GoodsController][goodsList] exception :",ex);
- return new JsonResult(JsonResultCode.FAILURE, "系统错误, 请稍后重试","");
- }
- }
说明: 由于 spring 的事物控制在 service 层, 所以 service 层不抓取异常. 所有的异常都在 controller 进行抓取, 而且抓取的是任何的异常
异常的记录采用某个类 [] 某个方法[] exception, 这种方式, 然后把所有的异常的堆栈信息进行打印出来, 方便进行查看与分析, 定位等
2. 全局异常
说明: 对于有可能出现的全局异常, 我们采用 Spring 的全局异常处理器, 进行代码的统一处理.
2.1, 对于业务层的异常, 我们采用自定义异常进行获取
核心代码如下:
- /**
- * service 异常, 业务异常继续于当前接口
- *
- */
- public class ServiceException extends RuntimeException {
- private static final long serialVersionUID = 4875141928739446984L;
- /**
- * 错误码
- */
- protected String code;
- /**
- * 错误信息
- */
- protected String message;
- public ServiceException(String code, String message) {
- super();
- this.code = code;
- this.message = message;
- }
- public ServiceException(String code, String message, Throwable t) {
- super();
- this.code = code;
- this.message = message;
- }
- public ServiceException(String message) {
- super(message);
- this.message = message;
- }
- public ServiceException(String message, Throwable t) {
- super(message, t);
- this.message = message;
- }
- public String getCode() {
- return code;
- }
- public void setCode(String code) {
- this.code = code;
- }
- public String getMessage() {
- return message;
- }
- public void setMessage(String message) {
- this.message = message;
- }
- @Override
- public String toString() {
- return "ServiceException [code=" + code + ", message=" + message + "]";
- }
2.2 对于全局的异常, 我们采用 spring 的统一进行处理, 只需要在代码中进行异常的抛出即可
核心代码如下:
- /**
- * 全局异常处理类. 对后台直接抛往前台页面的异常进行封装处理.
- */
- public class ExceptionHandler extends SimpleMappingExceptionResolver {
- private static final Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);
- @Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
- Exception ex) {
- ModelAndView mv = super.doResolveException(request, response, handler, ex);
- String url = webUtils.getPathWithinApplication(request);
- logger.error("controller error.url=" + url, ex);
- /* 使用 response 返回 */
- response.setStatus(HttpStatus.OK.value()); // 设置状态码
- response.setContentType(MediaType.APPLICATION_JSON_VALUE); // 设置 ContentType
- response.setCharacterEncoding("UTF-8"); // 避免乱码
- response.setHeader("Cache-Control", "no-cache, must-revalidate");
- JsonResult jsonResult=new JsonResult(JsonResultCode.FAILURE,"系统错误, 请联系管理员","");
- if(ex instanceof ServiceException)
- {
- ServiceException serviceException=(ServiceException)ex;
- String code=serviceException.getCode();
- String message=serviceException.getMessage();
- jsonResult=new JsonResult(code,message,"");
- }
- try
- {
- PrintWriter printWriter = response.getWriter();
- printWriter.write(JSONObject.fromObject(jsonResult).toString());
- printWriter.flush();
- printWriter.close();
- } catch (IOException e)
- {
- logger.error("与客户端通讯异常:" + e.getMessage(), e);
- }
- logger.error("异常:" + ex.getMessage(), ex);
- return mv;
- }
- }
spring 中还需要加上一段这样的配置:
- <!-- 全局异常处理.-->
- <bean id="exceptionHandler" class="com.netcai.buyer.exception.ExceptionHandler"/>
3. 代码格式方面
说明: 我们控制所有的请求的接口, 都需要返回 JsonResult 对象, 另外, 我们规定 "200" 字符串表示请求成功, 非 "200" 表示失败
相关的代码贴出来, 请大家分享:
- /**
- * Controller 层的 json 格式对象
- */
- public class JsonResult implements java.io.Serializable {
- private static final long serialVersionUID = 1L;
- /**
- * 返回的编码
- */
- private String code;
- /**
- * 返回的信息
- */
- private String message;
- /***
- * 返回的对象
- */
- private Object object;
- public JsonResult() {
- super();
- }
- public JsonResult(String code, String message, Object object) {
- super();
- this.code = code;
- this.message = message;
- this.object = object;
- }
- public String getCode() {
- return code;
- }
- public void setCode(String code) {
- this.code = code;
- }
- public String getMessage() {
- return message;
- }
- public void setMessage(String message) {
- this.message = message;
- }
- public Object getObject() {
- return object;
- }
- public void setObject(Object object) {
- this.object = object;
- }
- }
相关的 JsonResultCode 对象如下:
- /**
- */
- public class JsonResultCode {
- /** 成功 **/
- public static final String SUCCESS="200";
- /** 失败 **/
- public static final String FAILURE="201";
- }
最终形成了一套完整的数据量的处理, 另外还有特殊的情况, 比如: 404,500 等等其他的业务请求, 我们应该如何处理的?
由于我们是运行在 tomcat 下面的, 我们在 web.xml 进行了配置.
代码如下
- <error-page>
- <exception-type>java.lang.Throwable</exception-type>
- <location>/error_500</location>
- </error-page>
- <error-page>
- <exception-type>java.lang.Exception</exception-type>
- <location>/error_404</location>
- </error-page>
- <error-page>
- <error-code>500</error-code>
- <location>/error_500</location>
- </error-page>
- <error-page>
- <error-code>501</error-code>
- <location>/error_500</location>
- </error-page>
- <error-page>
- <error-code>502</error-code>
- <location>/error_500</location>
- </error-page>
- <error-page>
- <error-code>404</error-code>
- <location>/error_404</location>
- </error-page>
- <error-page>
- <error-code>403</error-code>
- <location>/error_404</location>
- </error-page>
- <error-page>
- <error-code>400</error-code>
- <location>/error_404</location>
- </error-page>
我们把可能出现的任何情况都进行了拦截, 然后交给 spring 来处理这种请求, 最终形成一套自己的特殊异常处理
代码如下:
- /**
- * 错误统一处理
- */
- @RestController
- public class ErrorController {
- /**
- * 请求异常 404
- * @return
- * @throws Exception
- */
- @RequestMapping(value = "/error_404", method = { RequestMethod.GET, RequestMethod.POST })
- public JsonResult error_404() throws Exception
- {
- return new JsonResult(JsonResultCode.FAILURE, "404 请求找不到请求", "");
- }
- /**
- * 服务器异常
- * @return JsonResult
- */
- @RequestMapping(value = "/error_500", method = { RequestMethod.GET, RequestMethod.POST })
- public JsonResult error_500()
- {
- return new JsonResult(JsonResultCode.FAILURE, "500 服务器内部错误", "");
- }
- }
总结: 我们通过 3 种情况来进行了所有可能异常的处理, 全局异常, 业务代码异常, 特殊情况异常, 架构封装, 统一的数据返回与处理等等, 进行了完美的结合, 该项目运行一年半以来, 采用这种异常架构后, 从没出现过返回给 app 什么 500 错误或者其他乱七八糟的错误, 依然是正确的 JsonResult 对象, APP 那边也不用处理特殊情况, 一举两得.
Java 开源生鲜电商平台 - 异常模块的设计与架构(源码可下载), 如果需要下载的话, 可以在我的 github 下面进行下载.
来源: https://www.cnblogs.com/jurendage/p/9075219.html