Controller异常统一处理

在Spring中,通常会有一个Controller类,它会处理来自客户端的请求。比如,
客户端想要访问一个用户的信息,也许只是一个展示用户资料的前台发来的请求。

那么,你会在Controller里面写这样一个方法:

@RequestMapping(value={/id},method=RequestMethod.GET)
public @ResponseBody Item ItemID
(@PathVariable long id){
    //@PathVariable 为路径参数
    return ItemRepository.findOne(id);

}

很棒,如果数据库存在ID=参数id的用户,那么这个请求会执行的很完美。
为了程序的健壮性,假如这个用户不存在呢?你也许会想到从数据库中
把用户资料取出来,然后判断对象的引用是否为空!这很好,但并不是一个很完美的解决方案—-因为错误处理代码与业务执行逻辑耦合!

耦合度高的代码会在以后的维护中是一个噩梦

那么,接下来,就是一个错误处理的解决方案,它能够把错误处理的逻辑提取出来,对所有出现某个特定异常的Controller中的方法进行异常处理。

耦合度更低的解决方案

异常描述对象+异常类+异常处理方法(句柄)+重构后的Ccntroller中的方法

异常描述对象是一个普通的Java对象–POJO,它存储描述异常的信息

Error.java

   public class Error{

    private int code;
    private String message;
    public Error(int code,String message){
      this.code=code;
      this.message=message;
    }
    public int getCode(){

    }
   public String getMessage(){

   }
}

异常类-ItemNotFoundException

@ResponseStatus(value=HttpStatus.NOT_FOUND,
                  reason="Item not found")
public class ItemNotFoundException 
             extends RuntimeException{
    //这是一个普通的异常类,带有请求失败响应值404,继承未检查异常
    //所以你不被强制去catch它
}

一个异常处理句柄,是当请求处理方法出现异常时能够被调用的异常处理方法,当然,在此情况下为ItemNotFouindHandler.java,@ExceptionHandler注解代表这是一个异常处理句柄,注解中传递的异常类

//表示这个句柄处理ItemNotFoundException
@ExceptionHandler(ItemNotFoundException.class)
//表示这个句柄处理时,请求响应值会被设定为HttpStatus.NOT_FOUND-404
@ResponseStatus(HttpStatus.NOT_FOUND)
public Error ItemNotFound(ItemNotFoundException e){
     long Item=e.getItemId();
     return new Error(4,"Item["+ItemId+"] not Found");
}

这一切都妥妥的了,接下来,终于可以重构我们的方法来把讨厌的异常处理去掉,
这跟我们想在Controller类ItemID()中的实现的逻辑完全没有关系好不啦!

扫描二维码关注公众号,回复: 2842960 查看本文章

请求处理方法

  @RequestMapping(value={/id},method=RequestMethod.GET)
public @ResponseBody Item ItemID(@PathVariable long id){
    //@PathVariable 为路径参数,比如/item/23456,23456就是id
     //跟参数/item?id=23456不一样
    Spittle item=ItemRepository.findOne(id);
     if(item==null){ throw new ItemNotFoundException(id);}
     return item;
}

以上这就是重构后的代码。除了抛出一个异常之外,好像没有任何异常处理代码。
听起来,好像没有省下多少工作量,但是注意当一个Controller中的方法多的时候
,你要对**这个**Controller类中的方法中出现的此类异常都加一个这样的处理,这样的固定模式代码应该被提取出来。

这个Controller被加粗的原因是,这个模式可能出现在多个Controller类中,而我们上述的解决方案,异常处理句柄方法ItemNotFoundException()只能对它所在的类出现的ItemNotFoundException类异常进行处理,这对我们想要的作用域–所有Controller中出现的ItemNotFoundException异常进行处理来说,太小了!

作用域更广的Advising Controller

Spring 3.2+引入的Advising Controller类能够处理所有Controller中出现的ItemNotFoundException,太棒了!

@ControllerAdvice  //表示这是一个Advising Controller
public class ItemControllerAdvice{

    //处理ItemNotFoundException的异常处理句柄
    @ExceptionHandler(ItemNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Error ItemNotFound(ItemNotFoundException e){
       long Item=e.getItemId();
       return new Error(4,"Item["+ItemId+"] not Found");
    }   

    @ExceptionHandler(ItemExpiredException.class)
    public String ItemExpiredHandler(){
         return "error/ItemExpired";
    }
}

那么按照以上的思路来讲,你应该能够提取一定的设计模式,好的设计模式简洁,
强大,好维护!你会发现你最好将所有关于Item实体的异常全部写在一个Advise Controller类中,哈哈,unbelivable,异常处理本质上是一种面向切面的编程思想,当然,Spring引入@ControllerAdvice是为了防止糟糕的切面命名吧,这种比较特定的切面注解也能够闻名知其义!

猜你喜欢

转载自blog.csdn.net/qq_33745102/article/details/80100831