Spring MVC 统一处理异常值AOP
* 思想 |
下班后,站在熙熙攘攘的地铁上,看到一个帖子,技术和思想的重要性。一位楼主的话让我感受很深刻:论技术和思想的重要性,他说到他的开发水平不是很高,但是他认为他所具有的思想是很不错的,他谈到对自己手下的员工的高要求,让他们在写出来的代码不至于那样的笨重,他说他很严格,但是还是有人愿意跟着他,为什么呢?因为可以收获很多。然后开始制定接口,约束大家如何写代码。
看着文章,不由得想到了我的领导,顺手写下评论:“感恩我有一个和您很像的领导”。前两周做了一个开发demo,以便让后续的开发更加的高效,项目经理审代码的时候提了一个要求,我们的异常处理可以不在controller中处理吗,boss提了这么个建议,我便去落实,我知道答案肯定是可以的。
* 代码分析 |
我们用的框架有SpringMVC,给大家分享一下controller中的代码:
/**
* 根据id查找Foo
*
* @param id 主键id
* @return ItooResult Foo集合
* @author viola
* @since 1.0.0 2018-10-18 14:35:27
*/
@ApiOperation(value = "根据id查询Foo", notes = "请输入主键id进行查询")
@GetMapping(value = {"/findFooModelById/{id}"})
public ItooResult findFooModelById(@ApiParam(value = "主键id", required = true) @PathVariable String id) {
FooModel fooModel = null;
try {
fooModel = fooService.queryFooModelById(id);
} catch (Exception e) {
return ItooResult.build(ItooResult.SUCCESS, "查询成功", fooModel);
}
return ItooResult.build(ItooResult.SUCCESS, "查询成功", fooModel);
}
当然上面的代码大家看着已经很不错了,大家看到经过已经是被封装过的了。但是我们的每个方法中都要进行异常的捕获和处理,是不是显得很麻烦,这样也不符合我们开发的过程中多关注业务实现。下面是优化后的代码:
/**
* 根据id查找Foo
*
* @param id 主键id
* @return ItooResult Foo集合
* @author viola
* @since 1.0.0 2018-10-18 14:35:27
*/
@ApiOperation(value = "根据id查询Foo", notes = "请输入主键id进行查询")
@GetMapping(value = {"/findFooModelById/{id}"})
public ItooResult findFooModelById(@ApiParam(value = "主键id", required = true) @PathVariable String id) {
FooModel fooModel = fooService.queryFooModelById(id);
return ItooResult.build(ItooResult.SUCCESS, "查询成功", fooModel);
}
给人的感觉是不是简单了很多,这便是一个团队整体素质的体现。
* @Around |
我的实现方式是通过横切处理的,@Around增强处理是较为强大的处理,它近似等于Before和AfterReturning的总和。@Around既可在执行目标方法之前织入增强动作,也可在执行目标方法之后织入增强动作。@Around甚至可以绝地目标方法什么时候执行,如何执行,更甚这可以完全阻止目标方法的执行。
@Around功能虽然强大,但通常在线程安全的环境下使用,因此,如果可以用Before和AfterReturning就能解决问题的,就没有必要使用Around。但是我们拦截controller需要改变目标返回值,因此需要用Around。
当定义一个Around增强处理时,需要的一个形参必须是ProceedingJopinPoint类型,在增强处理方法体内,调用ProceedingJoinPoint的proceed方法才会执行目标方法------这就是@Around增强处理可以完全控制目标方法执行时机、如何执行的关键;如果程序没有调用ProceedingJoinPoint的proceed方法,则目标方法不会执行。
如下是拦截异常的方法实现:
@Aspect
public class ExceptionIntercept {
private static final Logger logger = LoggerFactory.getLogger(AfterReturningAspect.class);
//配置切面
@Pointcut("execution(* com.dmsdbj.itoo.*.provider.controller.*.*(..))")
public void declareJoinPointExpression() {
}
//增强方法
@Around("declareJoinPointExpression()")
public Object handleControllerMethod(ProceedingJoinPoint pjp) {
try {
ItooResult itooResult = (ItooResult)pjp.proceed(pjp.getArgs());
return itooResult;
} catch (Throwable var4) {
if("true".equals(this.clazzMap.get("aop.printexception.enable"))) {
logger.info("执行Controller异常: " + pjp.getSignature() + ", 异常信息:" + var4);
throw new ItooRuntimeException(var4);
} else {
return ItooResult.build("1111", "异常");
}
}
}
}
spring.xml中进行如下配置:
<!-- 启动对@AspectJ注解的支持 -->
<aop:aspectj-autoproxy/>
<!--统一处理controller的异常-->
<bean class="com.dmsdbj.itoo.tool.aspect.ExceptionIntercept"/>