异常方案和实践

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mengdonghui123456/article/details/81132723

 

一、Java异常简介

 

        异常是程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行。异常处理,是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况(即超出程序正常执行流程的某些特殊条件)。

       Java提供了更加优秀的解决办法:异常处理机制。异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。

       Throwable类是Java异常类型的顶层父类,一个对象只有是 Throwable 类的(直接或者间接)实例,它才是一个异常对象,才能被异常处理机制识别。JDK中内建了一些常用的异常类,当然我们也可以自定义异常。

                                                     JDK内建异常体系

 

二、异常分类和异常罗列

 

异常分类

根据现有异常情况,将项目中的所有异常划分为三类:

JAVA内建异常:指程序运行过程发生非预料的错误,比如数据库连接异常、空指针等人为未检测出的异常。

业务自定义异常:指模块中阻碍正常逻辑进行的对外抛出的错误信息。囊括现有项目设计出的所有的异常状态码

 

模块

异常码

异常描述

 

 wave-odin-workflow

MAX_NUM_ERROR

最大负载数错误

MISSION_EXIST

任务已存在

MAX_NUM_ERROR

最大负载数错误

PROCESSOR_NOT_FOUND

处理机不存在

PROCESSOR_NOT_EXIST

处理机信息不存在

DISCERN_RECORD_NOT_FOUNT

识别记录无法找到

EXIST_ACTIVE_WORKFLOW

存在激活的工作流

MISSION_PERSONNEL_ASSOCIATE_EXIST

任务人员关系已经存在

MISSION_CAMERA_ASSOCIATE_EXIST

任务摄像机关系已经存在

MONITOR_DOOR_GROUP_PERSONNEL_ASSOCIATE_EXIST

门禁组人员关系已经存在

CAMERA_NOT_FOUNT

摄像机信息无法找到

MONITOR_DOOR_GROUP_MISSION_ASSOCIATE_EXIST

门禁组任务关系已经存在

MONITOR_DOOR_GROUP_NOT_FOUNT

门禁组信息无法找到

MISSION_NOT_FOUNT

无法找到任务信息

JOB_RECORD_EXIST

工作记录已存在

 NOT_FOUND_PROCESSOR

处理机超负载

PERSONNEL_GROUP_NOT_FOUNT

人员组信息无法找到

PERSONNELGROUP_PERSONNEL_ASSOCIATE_EXIST

人员组和人员关联关系已经存在

PERSONNEL_GROUP_MISSION_ASSOCIATE_EXIST

人员组任务关联已存在

MONITOR_DOOR_GROUP_ALREADY_ACTIVE

门禁组已经激活

MONITOR_DOOR_GROUP_ALREADY_BACKOUT

门禁组已经挂起

WORK_FLOW_JOB_RECORD_UNFOUND

没有找到工作记录

NOT_FOUND_CAMERA_DEVEICE

该任务未分配摄像机

PERSONNEL_EXIST

人员信息已存在

PERSONNEL_GROUP_ALREADY_BACKOUT

人员组已经挂起

PERSONNEL_GROUP_ALREADY_ACTIVE

人员组已经激活

 

 

 

 

模块

异常码

异常描述

wave-odin-sentry

MISSION_PERSONNEL_ASSOCIATE_EXIST

任务人员关系已经存在

MISSION_CAMERA_ASSOCIATE_EXIST

任务摄像机关系已经存在

MONITOR_DOOR_GROUP_MISSION_ASSOCIATE_EXIST

门禁组任务关系已经存在

MONITOR_DOOR_GROUP_NOT_FOUNT

门禁组信息无法找到

MONITOR_DEVICE_EXIST

控制器信息已存在

MONITOR_DEVICE_NOT_EXIST

门禁控制器不存在

MONITOR_DOOR_DEVICE_NOT_EXIST

门禁设备不存在

 

 

 

 

 

模块

异常码

异常描述

 

wave-odin-vidicon

CAMERA_DEVICE_EXIST

摄像机设备已经存在

CAMERA_DEVICE_NOT_EXIST

设备信息不存在

CAMERA_ATTENDANCE_NO_RELATION

设备考勤没有关联信息

CAMERA_DEVICE_EXIST_RELATION

设备存在关联关系

CAMERA_NOT_FOUNT

摄像机信息无法找到

 

 

 

模块

异常码

异常描述

 

 wave-centimani-storage

STORAGE_FAILED

存储失败

IMAGE_NOT_FOUNT

图片未找到

STORAGE_FASTDFS_FAILED

FASTDFS存储失败

OSS_DATA_READ_FAILED

OSS读取异常

 

 

 

模块

异常码

异常描述

 

wave-centimani-authority

CONNECT_TIME_OUT

连接超时

NOT_FOUND

api_key和api_secret不匹配

STORAGE_OSS_FAILED

OSS存储异常

AUTHENTICATION_ERROR

api_key和api_secret不匹配

AUTHORIZATION_ERROR

api_key 没有调用本 API 的权限

API_NOT_FOUND

所调用的 API 不存在

 

 

 

模块

异常码

异常描述

 

wave-argus-faceDetect

 

 

 

 

 

 

 

模块

异常码

异常描述

 

wave-argus-faceSet

FACESET_UPDATED

FaceSet更新成功

FACESET_CREATED

FACESET创建成功

FACESET_ADDED

FACESET添加成功

FACESET_UPDATED

FaceSet更新成功

FACESET_CREATED

FACESET添加重复!

FACESET_ADDED

FACESET添加重复!

QUOTA_EXCEEDED

FaceSet存储上限

FACESET_NOT_EMPTY

FaceSet不为空,不能删除

INVALID_OUTER_ID

outer_id无效

INVALID_FACESET_TOKEN

faceset_token无效

NEW_OUTER_ID_EXIST

提供的new_outer_id与已有outer_id重复

INVALID_FACE_TOKENS_SIZE

face_token数量达到上限

FACE_TOKEN_QUOTA_EXCEEDED

face_token数量达到上线

FACESET_QUOTA_EXCEEDED

FaceSet数量达到上限,不能继续创建FaceSet

FACESET_EXIST

FACESET_EXIST已经存在

FACETOKEN_EXIST

face_token已经存在不能重复添加

EMPTY_FACESET

Faceset中没有face_token

EMPTY_FACESET_FEATURE

请确保传入的face_token和Faceset中face_token具有定位信息

FEATURE_RESULT_UNFOUND

请确保传入的face_token具有定位信息

START_OUT_OF_BOUND

请确保传入的start具有信息

INVALID_FACE_TOKEN

face_token无效

 

 

 

模块

异常码

异常描述

 

wave-argus-bioAssay

 

 

 

 

 

 

 

模块

异常码

异常描述

 

wave-argus-faceFeature

 

 

 

 

 

 

模块

异常码

异常描述

 

wave-argus-faceRecognize

 

 

 

 

 

 

网关参数校验异常对于网关传入参数的校验所引起的异常

异常码

异常描述

COEXISTENCE_ARGUMENTS

同时传入了要求是二选一或多选一的参数。

BAD_ARGUMENTS

某个参数解析出错

MISSING_ARGUMENTS

缺少某个必选参数

INVALIDPARAMETER

无效参数

IMAGE_ERROR_UNSUPPORTED_FORMAT

对应的图像无法正确解析

IMAGE_FILE_TOO_LARGE

上传的图片文件太大

IMAGE_DOWNLOAD_TIMEOUT

下载图片超时

CONCURRENCY_LIMIT_EXCEEDED

并发数超过限制

INVALID_IMAGE_URL

无法从指定的image_url下载图片

INVALID_IMAGE_SIZE

客户上传的图像像素尺寸太大或太小

 

 

    

 

 

 

 

三、自定义异常类设计

         基于该异常方案的流程讲解图:

                          

      

 

 

         自定义业务异常类是继承于RuntimeException,指程序运行时不符合业务逻辑时,抛出的自定义错误信息。目前只有BusinessException。

         校验异常类同样是继承RuntimeException,目前有MethodArgumentNotValidExcption。

       

 

实施步骤:    

网关处理步骤:

1. 添加网关校验配置:

1.1.添加pom依赖: 网关校验的时候因为是Spring源生框架需要依赖hibernate-validator的api进行校验,所以需要在pom中增加依赖(如是springboot则不需要增加)

              <dependency>

                       <groupId>org.hibernate</groupId>

                       <artifactId>hibernate-validator</artifactId>

                       <version>5.3.5.Final</version>

        </dependency>

1.2添加注解:因为引用了validator依赖,所以需要通过@Validated、@Valid注解开启校验。

 

package com.wave.odin.net.controller;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.validation.Valid;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.validation.annotation.Validated;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.RestController;

 

import com.wave.odin.net.service.PersonnelService;

 

/**

 * @author Mango

 * @date 2018年6月14日

 * @version 1.0 Description:人员数据管理

 */

@Validated

@RestController

@RequestMapping("/personnel")

public class testController {

 

         /**

          * 人员数据管理

          */

         @Autowired

         PersonnelService personnelService;

 

         /**

          * 1.异常效验

          *

          * @param query

          * @param request

          * @param response

          * @return

          * @throws Exception

          */

         @RequestMapping(value = { "/test" }, method = RequestMethod.POST, produces = { "text/html;charset=UTF-8" })

         @ResponseBody

         public String getInfoFoa(@RequestBody @Valid TestVo vo, HttpServletRequest request, HttpServletResponse response)

                            throws Exception {

 

                   return personnelService.test();

         }

}

 

 

 

注:①@Validated、@Valid 注解开启hibernate-validator校验功能;

 2.添加异常返回类/全局异常捕获类:

 2.1.异常返回类:BussinessException

                          <dependency>

                            <groupId>com.wave.centimani</groupId>

                            <artifactId>wave-centimani-tool</artifactId>

                            <version>1.0.1</version>

                 </dependency>

 

2.2.全局捕获类:

通过@ControllerAdvice,我们可以将控制器的全局配置放置在同一个位置,注解了@Controller的类的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上,这对所有注解了@RequestMapping的控制器内的方法有效。

@ExceptionHandler:配置全局异常处理。

 

 

全局异常捕获类。

package com.wave.odin.net.controller;

 

import javax.validation.ConstraintViolationException;

 

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.http.HttpStatus;

import org.springframework.web.bind.MethodArgumentNotValidException;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.ResponseStatus;

 

/**

 * 全局异常拦截

 * @author B250M-J

 *  日期:2018年7月10日

 */

@ControllerAdvice

public class ExceptionHandle {

         private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);

 

         /**

          * 处理exception类型异常以及其子类,起到兜底的作用,主要是非自定义异常

          * @param e

          * @return

          */

         @ExceptionHandler(value = Exception.class)

         @ResponseBody

         public String handler(Exception e) {

                   if (e instanceof Exception) {

 

                            String excption = e.toString();

                            String[] excptions = excption.split(":");

 

                            return ResultUtil.errorInfo(excptions[1].replace("/", ""), excptions[0], "0000000000000000000000000000000");

 

                   } else {

                            logger.info("[系统异常] {}", e);

                            return ResultUtil.errorInfo("-1", "服务出差了,程序员小哥哥正在召唤!", "0000000000000000000000000000000");

                   }

         }

 

         /**

          * 处理业务异常,属于自定义异常范围

          * @param e

          * @return

          */

         @ExceptionHandler(value = BussinessException.class)

         @ResponseBody

         public String handlers(BussinessException e) {

                   if (e instanceof BussinessException) {

 

                            BussinessException bussinessException = (BussinessException) e;

 

                            return ResultUtil.errorInfo(bussinessException.getDescption(), bussinessException.getName(),

                                               bussinessException.getRequestId());

 

                   } else {

                            logger.info("[系统异常] {}", e);

 

                            return ResultUtil.errorInfo("-1", "未知错误", "0000000000000000000000000000000");

                   }

         }

 

         /**

          * @Validated + @RequestBody 注解但是没有在绑定的数据对象后面跟上 Errors 类型的参数声明的话,Spring MVC

          *            框架会抛出 MethodArgumentNotValidException 异常。 捕捉方法参数的校验异常

          * @param e

          * @return

          */

         @ExceptionHandler(ConstraintViolationException.class)

         @ResponseBody

         @ResponseStatus(HttpStatus.BAD_REQUEST)

         public String handleValidationException(ConstraintViolationException e) {

 

                   return ResultUtil.errorInfo(e.getConstraintViolations().stream()

                                     .map(message -> message.getInvalidValue() + ":" + message.getMessage() + "<br/>")

                                     .reduce("", (s0, s1) -> s0 + s1), "BAD_Arguments", "0000000000000000000000000000000");

 

         }

 

         /**

          * 捕捉方法参数的校验异常

          * @param e

          * @return

          */

         @ExceptionHandler(MethodArgumentNotValidException.class)

         @ResponseBody

         @ResponseStatus(HttpStatus.BAD_REQUEST)

         public String handleValidationException(MethodArgumentNotValidException e) {

 

                   e.getBindingResult().getAllErrors().stream().map(message -> message.getDefaultMessage() + "\n").reduce("",

                                     (s0, s1) -> s0 + s1); //

                   return ResultUtil.errorInfo(e.getBindingResult().getAllErrors().stream()

                                     .map(message -> message.getDefaultMessage() + "\n").reduce("", (s0, s1) -> s0 + s1), "BAD_Arguments",

                                     "0000000000000000000000000000000");

 

         }

 

}

        

 

 

各个模块处理步骤:

在需要业务逻辑判断出错的地方抛出异常类:BussinessException(errorCode,requestId)。

例如:判断,如果age<14则抛出异常

 

                   /**

          * 异常测试

          *

          * @return

          */

         public String test() throws Exception {

                   int age = 1;

                   if (age < 14) {

 

                            // int a =1/0; 抛java内建异常

 

                            // 抛自定义异常

                       throw new BussinessException(EnumErrorsDesBase.API_NOT_FOUND, "1524654321575241241212");

 

                   } else if (age > 20) {

                            System.out.println("333333333");

                   }

                   return "555555555";

         }

 

 

 

 

[1] 基于该异常方案的流程讲解     

图:常规请求流程

 

 

 

       网关配置:

  1. pom中添加依赖jar;[2]  网关校验的时候因为是Spring源生框架需要依赖hibernate-validator的api进行校验,所以需要在pom中增加依赖(如是springboot则不需要增加);
  2. 创建异常配置类;[3] 对于异常的捕获需要创建异常返回类、全局异常捕获类。
  3. 网关配置注解;[4] 因为引用了validator依赖,所以需要通过@Validated、@Valid注解开启校验。

       模块配置:

  1. 模块配置实践;[5] 只需要抛出异常类(BussniessException)并且在构造函数中补充异常code和reqeustId;

       效果:

  1. 实验效果;

步骤如下:

步骤1

              <dependency>

                       <groupId>org.hibernate</groupId>

                       <artifactId>hibernate-validator</artifactId>

                       <version>5.3.5.Final</version>

        </dependency>

 

 

 

步骤2:

 

异常类:

package com.wave.odin.net.controller;

/**

 * 自定义:业务返回异常类

 * @author loaf

 *2018年7月10日14

 */

public class BussinessException extends RuntimeException {

 

       private String descption;

       private String name;

       private String requestId;

 

       public BussinessException(EnumErrorsDesBase resultEnum, String requestId) {

 

              this.descption = resultEnum.getDescription();

              this.name = resultEnum.getName();

              this.requestId = requestId;

 

       }

 

       public String getDescption() {

              return descption;

       }

 

       public void setDescption(String descption) {

              this.descption = descption;

       }

 

       public String getName() {

              return name;

       }

 

       public void setName(String name) {

              this.name = name;

       }

 

       public String getRequestId() {

              return requestId;

       }

 

       public void setRequestId(String requestId) {

              this.requestId = requestId;

       }

 

}

 

 

 

 

 

 

 

异常返回类

package com.wave.odin.net.controller;

 

import com.fasterxml.jackson.core.JsonProcessingException;

import com.wave.centimani.tool.tojson.JacksonJsonUntil;

 

/**

 * http请求返回处理类

 * 2018年7月10日14

 * @author loaf

 *

 */

public class ResultUtil {

 

       /**

        * 异常时才会调用此类的方法

        * @param descption

        * @param name

        * @param requestId

        * @return

        */

       public static String errorInfo(String descption, String name, String requestId) {

              FaildResultVo result = new FaildResultVo();

              result.setErrorCode(name);

              result.setErrorCodeDesc(descption);

              result.setRequestId(requestId);

              result.setRequestStatus("Fail");

              result.setTimeUsed(100);

 

              String results = "";

              try {

                     results = JacksonJsonUntil.objectToJson(result);

              } catch (JsonProcessingException e) {

                     e.printStackTrace();

              }

 

              return results;

       }

}

 

 

 

 

 

 

 

全局异常捕获类。

package com.wave.odin.net.controller;

 

import javax.validation.ConstraintViolationException;

 

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.http.HttpStatus;

import org.springframework.web.bind.MethodArgumentNotValidException;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.ResponseStatus;

 

/**

 * 全局异常拦截

 * @author B250M-J

 *  日期:2018年7月10日

 */

@ControllerAdvice

public class ExceptionHandle {

         private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);

 

         /**

          * 处理exception类型异常以及其子类,起到兜底的作用,主要是非自定义异常

          * @param e

          * @return

          */

         @ExceptionHandler(value = Exception.class)

         @ResponseBody

         public String handler(Exception e) {

                   if (e instanceof Exception) {

 

                            String excption = e.toString();

                            String[] excptions = excption.split(":");

 

                            return ResultUtil.errorInfo(excptions[1].replace("/", ""), excptions[0], "0000000000000000000000000000000");

 

                   } else {

                            logger.info("[系统异常] {}", e);

                            return ResultUtil.errorInfo("-1", "服务出差了,程序员小哥哥正在召唤!", "0000000000000000000000000000000");

                   }

         }

 

         /**

          * 处理业务异常,属于自定义异常范围

          * @param e

          * @return

          */

         @ExceptionHandler(value = BussinessException.class)

         @ResponseBody

         public String handlers(BussinessException e) {

                   if (e instanceof BussinessException) {

 

                            BussinessException bussinessException = (BussinessException) e;

 

                            return ResultUtil.errorInfo(bussinessException.getDescption(), bussinessException.getName(),

                                               bussinessException.getRequestId());

 

                   } else {

                            logger.info("[系统异常] {}", e);

 

                            return ResultUtil.errorInfo("-1", "未知错误", "0000000000000000000000000000000");

                   }

         }

 

         /**

          * @Validated + @RequestBody 注解但是没有在绑定的数据对象后面跟上 Errors 类型的参数声明的话,Spring MVC

          *            框架会抛出 MethodArgumentNotValidException 异常。 捕捉方法参数的校验异常

          * @param e

          * @return

          */

         @ExceptionHandler(ConstraintViolationException.class)

         @ResponseBody

         @ResponseStatus(HttpStatus.BAD_REQUEST)

         public String handleValidationException(ConstraintViolationException e) {

 

                   return ResultUtil.errorInfo(e.getConstraintViolations().stream()

                                     .map(message -> message.getInvalidValue() + ":" + message.getMessage() + "<br/>")

                                     .reduce("", (s0, s1) -> s0 + s1), "BAD_Arguments", "0000000000000000000000000000000");

 

         }

 

         /**

          * 捕捉方法参数的校验异常

          * @param e

          * @return

          */

         @ExceptionHandler(MethodArgumentNotValidException.class)

         @ResponseBody

         @ResponseStatus(HttpStatus.BAD_REQUEST)

         public String handleValidationException(MethodArgumentNotValidException e) {

 

                   e.getBindingResult().getAllErrors().stream().map(message -> message.getDefaultMessage() + "\n").reduce("",

                                     (s0, s1) -> s0 + s1); //

                   return ResultUtil.errorInfo(e.getBindingResult().getAllErrors().stream()

                                     .map(message -> message.getDefaultMessage() + "\n").reduce("", (s0, s1) -> s0 + s1), "BAD_Arguments",

                                     "0000000000000000000000000000000");

 

         }

 

}

        

 

 

步骤3:

 

package com.wave.odin.net.controller;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.validation.Valid;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.validation.annotation.Validated;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.RestController;

 

import com.wave.odin.net.service.PersonnelService;

 

/**

 * @author Mango

 * @date 2018年6月14日

 * @version 1.0 Description:人员数据管理

 */

@Validated

@RestController

@RequestMapping("/personnel")

public class testController {

 

         /**

          * 人员数据管理

          */

         @Autowired

         PersonnelService personnelService;

 

         /**

          * 1.异常效验

          *

          * @param query

          * @param request

          * @param response

          * @return

          * @throws Exception

          */

         @RequestMapping(value = { "/test" }, method = RequestMethod.POST, produces = { "text/html;charset=UTF-8" })

         @ResponseBody

         public String getInfoFoa(@RequestBody @Valid TestVo vo, HttpServletRequest request, HttpServletResponse response)

                            throws Exception {

 

                   return personnelService.test();

         }

}

 

 

 

注:①@Validated、@Valid 注解开启hibernate-validator校验功能;

 

步骤4:

 

              /**

          * 异常测试

          *

          * @return

          */

         public String test() throws Exception {

                   int age = 1;

                   if (age < 14) {

 

                            // int a =1/0; 抛java内建异常

 

                            // 抛自定义异常

                       throw new BussinessException(EnumErrorsDesBase.API_NOT_FOUND, "1524654321575241241212");

 

                   } else if (age > 20) {

                            System.out.println("333333333");

                   }

                   return "555555555";

         }

 

 

 

 

步骤5:

1.自定义业务异常类捕获:

2.网关校验异常捕获:

3.java内建异常捕获: 

 

 

 

 

 

 

 


换个标题,可以类似于:该异常方案基于Spring源生框架的全流程讲解

什么原因

为什么需要创建异常配置类

目的是什么

目的是什么

猜你喜欢

转载自blog.csdn.net/mengdonghui123456/article/details/81132723