注解的介绍 ControllerAdvice ControllerAdvice注解是Spring3。2中新增的注解,学名是Controller增强器,作用是给Controller控制器添加统一的操作或处理。 这里ControllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行切面环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的。ControllerAdvice是在类上声明的注解,其用法主要有三点:1。结合方法型注解ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。 2。结合方法型注解InitBinder,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的。 3。结合方法型注解ModelAttribute,表示其注解的方法将会在目标Controller方法执行之前执行。 从上面的讲解可以看出,ControllerAdvice的用法基本是将其声明在某个bean上,然后在该bean的方法上使用其他的注解来指定不同的织入逻辑。不过这里ControllerAdvice并不是使用AOP的方式来织入业务逻辑的,而是Spring内置对其各个逻辑的织入方式进行了内置支持。针对声明ExceptionHandler、InitBinder或ModelAttribute方法的类的ComponentExceptionHandler,InitBinder在多个Controller类之间共享。 使用ControllerAdvice注解的类可以明确声明为Springbean或通过类路径扫描自动检测。所有此类bean都根据Ordered语义或OrderPriority声明进行Ordered,Ordered语义优先于OrderPriority声明。然后在运行时按该顺序应用ControllerAdvicebean。但是请注意,实现PriorityOrderedControllerAdvicebean的PriorityOrdered不高于实现OrderedControllerAdvicebean。此外,Ordered不适用于范围内的ControllerAdvice例如,如果这样的bean已被配置为请求范围或会话范围的bean。对于处理异常,ExceptionHandler将在第一个具有匹配异常处理程序方法的通知中被选择。对于模型的属性和数据绑定初始化,ModelAttribute和InitBinder方法将遵循ControllerAdvice秩序。 注意:对于ExceptionHandler方法,在特定建议bean的处理程序方法中,根异常匹配将优先于仅匹配当前异常的原因。但是,与较低优先级建议bean上的任何匹配(无论是根还是原因级别)相比,更高优先级建议上的原因匹配仍然是首选。因此,请在具有相应顺序的优先建议bean上声明您的主要根异常映射。 默认情况下,ControllerAdviceControllerAdvice中的方法全局应用于所有控制器。使用诸如annotations、basePackageClasses和basePackages(或其别名value)之类的选择器来定义目标控制器的更窄子集。如果声明了多个选择器,则应用布尔OR逻辑,这意味着所选控制器应至少匹配一个选择器。请注意,选择器检查是在运行时执行的,因此添加许多选择器可能会对性能产生负面影响并增加复杂性。 ExceptionHandler拦截异常并统一处理 配合ExceptionHandler注解结合使用,当异常抛到controller层时,可以对异常进行统一的处理,规定返回的json格式或者跳转到指定的错误页面等。 ExceptionHandler的作用主要在于声明一个或多个类型的异常,当符合条件的Controller抛出这些异常之后将会对这些异常进行捕获,然后按照其标注的方法的逻辑进行处理,从而改变返回的视图信息。 用于处理特定处理程序类和或处理程序方法中的异常的注解。 使用此注解注释的处理程序方法允许具有非常灵活的签名。它们可能具有以下类型的参数,按任意顺序排列: 异常参数:声明为一般异常或更具体的异常。如果注解本身没有通过其value()缩小异常类型,这也可用作映射提示 代码实现 自定义异常自定义一个异常类,用于处理我们发生的业务异常authorPromsing(张有博)version1。0。0since2021112720:14publicclassBizExceptionextendsRuntimeException{privatestaticfinallongserialVersionUID1L;错误码protectedStringerrorC错误信息protectedStringerrorMpublicBizException(){super();}publicBizException(FrontResulterrorInfoInterface){super(errorInfoInterface。getCode());this。errorCodeerrorInfoInterface。getMessage();this。errorMsgerrorInfoInterface。getMessage();}publicBizException(FrontResulterrorInfoInterface,Throwablecause){super(errorInfoInterface。getCode(),cause);this。errorCodeerrorInfoInterface。getCode();this。errorMsgerrorInfoInterface。getMessage();}publicBizException(StringerrorMsg){super(errorMsg);this。errorMsgerrorM}publicBizException(StringerrorCode,StringerrorMsg){super(errorCode);this。errorCodeerrorCthis。errorMsgerrorM}publicBizException(StringerrorCode,StringerrorMsg,Throwablecause){super(errorCode,cause);this。errorCodeerrorCthis。errorMsgerrorM}publicStringgetErrorCode(){returnerrorC}publicvoidsetErrorCode(StringerrorCode){this。errorCodeerrorC}publicStringgetErrorMsg(){returnerrorM}publicvoidsetErrorMsg(StringerrorMsg){this。errorMsgerrorM}publicStringgetMessage(){returnerrorM}OverridepublicThrowablefillInStackTrace(){}} 统一异常处理 importcom。tfjy。arbackend。enumtool。ResultCodeEimportcom。tfjy。arbackend。enumtool。ResutlMsgEimportcom。tfjy。arbackend。util。FrontRimportorg。slf4j。Limportorg。slf4j。LoggerFimportorg。springframework。web。bind。annotation。ControllerAimportorg。springframework。web。bind。annotation。ExceptionHimportorg。springframework。web。bind。annotation。ResponseBimportjavax。servlet。http。HttpServletRimportjava。io。IOEimportjava。net。InetAimportjava。net。UnknownHostEimportjava。sql。SQLE统一异常处理authorPromsing(张有博)version1。0。0since2021112720:14ControllerAdvice使用该注解表示开启了全局异常的捕获publicclassGlobalExceptionHandler{privatestaticfinalLoggerloggerLoggerFactory。getLogger(GlobalExceptionHandler。class);处理自定义的业务异常paramreqparamereturnExceptionHandler(valueBizException。class)ResponseBodypublicFrontResultbizExceptionHandler(HttpServletRequestreq,BizExceptione){logger。error(URL:req。getRequestURL()。toString());logger。error(HTTPMETHOD:req。getMethod());logger。error(发生业务异常!原因是:{},e。getErrorMsg());returnFrontResult。getExceptionResult(e。getErrorCode(),e。getErrorMsg());}处理空指针的异常paramreqparamereturnExceptionHandler(valueNullPointerException。class)ResponseBodypublicFrontResultexceptionHandler(HttpServletRequestreq,NullPointerExceptione){logger。error(URL:req。getRequestURL()。toString());logger。error(HTTPMETHOD:req。getMethod());logger。error(发生空指针异常!原因是:,e);returnFrontResult。getExceptionResult(ResultCodeEnum。FAIL。getCode(),ResutlMsgEnum。EXECUTEFAIL。getMsg());}处理索引越界异常paramreqparamereturnExceptionHandler(valueIndexOutOfBoundsException。class)ResponseBodypublicFrontResultexceptionHandler(HttpServletRequestreq,IndexOutOfBoundsExceptione){logger。error(URL:req。getRequestURL()。toString());logger。error(HTTPMETHOD:req。getMethod());logger。error(索引越界异常!原因是:,e);returnFrontResult。getExceptionResult(ResultCodeEnum。FAIL。getCode(),ResutlMsgEnum。EXECUTEFAIL。getMsg());}处理类未找到异常paramreqparamereturnExceptionHandler(valueClassNotFoundException。class)ResponseBodypublicFrontResultexceptionHandler(HttpServletRequestreq,ClassNotFoundExceptione){logger。error(URL:req。getRequestURL()。toString());logger。error(HTTPMETHOD:req。getMethod());logger。error(发生类未找到异常!原因是:,e);returnFrontResult。getExceptionResult(ResultCodeEnum。FAIL。getCode(),ResutlMsgEnum。EXECUTEFAIL。getMsg());}处理SQL异常paramreqparamereturnExceptionHandler(valueSQLException。class)ResponseBodypublicFrontResultexceptionHandler(HttpServletRequestreq,SQLExceptione){logger。error(URL:req。getRequestURL()。toString());logger。error(HTTPMETHOD:req。getMethod());logger。error(发生SQL异常!原因是:,e);returnFrontResult。getExceptionResult(ResultCodeEnum。FAIL。getCode(),ResutlMsgEnum。EXECUTEFAIL。getMsg());}处理IO异常paramreqparamereturnExceptionHandler(valueIOException。class)ResponseBodypublicFrontResultexceptionHandler(HttpServletRequestreq,IOExceptione){logger。error(URL:req。getRequestURL()。toString());logger。error(HTTPMETHOD:req。getMethod());logger。error(发生IO异常!原因是:,e);returnFrontResult。getExceptionResult(ResultCodeEnum。FAIL。getCode(),ResutlMsgEnum。EXECUTEFAIL。getMsg());}处理其他异常paramreqparamereturnExceptionHandler(valueException。class)ResponseBodypublicFrontResultexceptionHandler(HttpServletRequestreq,Exceptione){logger。error(URL:req。getRequestURL()。toString());logger。error(HTTPMETHOD:req。getMethod());logger。error(未知异常!原因是:,e);returnFrontResult。getExceptionResult(ResultCodeEnum。FAIL。getCode(),ResutlMsgEnum。EXECUTEFAIL。getMsg());}} 前端返回值类 importcom。tfjy。arbackend。enumtool。ResultCodeEimportlombok。AllArgsCimportlombok。Dimportlombok。NoArgsCDataAllArgsConstructorNoArgsConstructorpublicclassFrontResult{结果状态码privateS响应结果描述privateS返回数据privateO静态方法,返回前端实体结果paramcode状态码parammessage消息paramdata数据return前端实体结果publicstaticFrontResultbuild(Stringcode,Stringmessage,Objectdata){returnnewFrontResult(code,message,data);}返回成功的结果实体parammessage消息paramdata数据return实体publicstaticFrontResultgetSuccessResult(Stringmessage,Objectdata){FrontResultresultnewFrontResult();result。codeResultCodeEnum。SUCCESS。getCode();result。result。}返回无需data的成功结果实体parammessage消息内容return返回结果publicstaticFrontResultgetSuccessResultOnlyMessage(Stringmessage){FrontResultresultnewFrontResult();result。codeResultCodeEnum。SUCCESS。getCode();result。result。}获取一个异常结果paramcode错误码parammessage自定义异常信息returnFrontResultpublicstaticFrontResultgetExceptionResult(Stringcode,Stringmessage){FrontResultresultnewFrontResult();result。codecode。isEmpty()?ResultCodeEnum。CODEEXCEPTION。getCode():result。messagemessage。isEmpty()?ResultCodeEnum。CODEEXCEPTION。getMsg():}}importlombok。AllArgsCAllArgsConstructorpublicenumResultCodeEnum{请求成功SUCCESS(0000),请求失败FAIL(1111),EXCEL导入失败EXCELFAIL(1000),userID为空IDNULL(1001),前端传的实体为空MODELNULL(1002),更新失败UPDATEFAIL(1011),参数为空PARAMERROR(400),代码内部异常CODEEXCEPTION(500,代码内部异常);状态码privateSpublicStringgetCode(){}ResultCodeEnum(Stringcode){this。}privateSpublicStringgetMsg(){}}publicenumResutlMsgEnum{查询成功FINDSUCCESS(查询成功!),查询失败FINDFAIL(查询失败!),更新成功UPDATESUCCESS(更新成功),更新失败UPDATEFAIL(更新成功),SENDSUCCESS(发送成功),SENDFAIL(发送失败);privateSResutlMsgEnum(Stringmsg){this。}publicStringgetMsg(){}} 测试用例测试用例authorPromsing(张有博)version1。0。0since202111299:05Api(tags{测试controller})RequestMapping(valuetestController)RestControllerpublicclassTestController{ApiOperation(value测试null)GetMapping(valuegetNull)publicFrontResultgetNull(){intlength0;Slengthname。length();returnFrontResult。build(ResultCodeEnum。SUCCESS。getCode(),ResutlMsgEnum。EXECUTESUCCESS。getMsg(),length);}} 其他异常同理,也可以捕获。完美,没问题。全局统一异常处理设置成功。