设为首页 加入收藏

TOP

如何优雅的设计 Java 异常(三)
2018-02-13 12:56:16 】 浏览:783
Tags:如何 优雅 设计 Java 异常
eleteAddress(Integer uid,Integer aid); /** * 查询用户的所有收货地址 * @param uid * @return */ List<Address> listAddresses(Integer uid); }

我们来关注一下实现:

添加收货地址

首先再来看一下之前整理的约束条件:

入参:

  • 用户id
  • 收货地址实体信息

约束:

  • 用户id不能为空,且此用户确实是存在的
  • 收货地址的必要字段不能为空
  • 如果用户还没有收货地址,当此收货地址创建时设置成默认收货地址

先看以下代码实现:

 @Override
public Address createAddress(Integer uid, Address address) {
    //============ 以下为约束条件   ==============
    //1.用户id不能为空,且此用户确实是存在的
    Preconditions.checkNotNull(uid);
    User user = userDao.findOne(uid);
    if(null == user){
        throw new RuntimeException("找不到当前用户!");
    }
    //2.收货地址的必要字段不能为空
    BeanValidators.validateWithException(validator, address);
    //3.如果用户还没有收货地址,当此收货地址创建时设置成默认收货地址
    if(ObjectUtils.isEmpty(user.getAddresses())){
        address.setIsDefault(true);
    }

    //============ 以下为正常执行的业务逻辑   ==============
    address.setUser(user);
    Address result = addressDao.save(address);
    return result;
}

其中,已经完成了上述所描述的三点约束条件,当三点约束条件都满足时,才可以进行正常的业务逻辑,否则将抛出异常(一般在此处建议抛出运行时异常-RuntimeException)。

介绍以下以上我所用到的技术:

  • Preconfitions.checkNotNull(T t)这个是使用Guava中的com.google.common.base.Preconditions进行判断的,因为service中用到的验证较多,所以建议将Preconfitions改成静态导入的方式:
import static com.google.common.base.Preconditions.checkNotNull;

当然Guava的github中的说明也建议我们这样使用。

  • BeanValidators.validateWithException(validator, address);

这个使用了hibernate实现的jsr 303规范来做的,需要传入一个validator和一个需要验证的实体,那么validator是如何获取的呢,如下:

@Configuration
public class BeanConfigs {

@Bean
public javax.validation.Validator getValidator(){
    return new LocalValidatorFactoryBean();
}
}

他将获取一个Validator对象,然后我们在service中进行注入便可以使用了:

 @Autowired     
private Validator validator ;

那么BeanValidators这个类是如何实现的?其实实现方式很简单,只要去判断jsr 303的标注注解就ok了。
那么jsr 303的注解写在哪里了呢?当然是写在address实体类中了:

@Entity
@Setter
@Getter
public class Address {
@Id
    @GeneratedValue
    private Integer id;
    @NotNull
private String province;//省
@NotNull
private String city;//市
@NotNull
private String county;//区
private Boolean isDefault = false;//是否是默认地址

@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="uid")
private User user;
}

写好你需要的约束条件来进行判断,如果合理的话,才可以进行业务操作,从而对数据库进行操作。
这块的验证是必须的,一个最主要的原因是:这样的验证可以避免脏数据的插入。如果读者有正式上线的经验的话,就可以理解这样的一个事情,任何的代码错误都可以容忍和修改,但是如果出现了脏数据问题,那么它有可能是一个毁灭性的灾难。程序的问题可以修改,但是脏数据的出现有可能无法恢复。所以这就是为什么在service中一定要判断好约束条件,再进行业务逻辑操作的原因了。

  1. 此处的判断为业务逻辑判断,是从业务角度来进行筛选判断的,除此之外,有可能在很多场景中都会有不同的业务条件约束,只需要按照要求来做就好。

对于约束条件的总结如下:

  • 基本判断约束(null值等基本判断)
  • 实体属性约束(满足jsr 303等基础判断)
  • 业务条件约束(需求提出的不同的业务约束)

当这个三点都满足时,才可以进行下一步操作

ok,基本介绍了如何做一个基础的判断,那么再回到异常的设计问题上,上述代码已经很清楚的描述如何在适当的位置合理的判断一个异常了,那么如何合理的抛出异常呢?
只抛出RuntimeException就算是优雅的抛出异常吗?当然不是,对于service中的抛出异常,笔者认为大致有两种抛出的方法:

  1. 抛出带状态码RumtimeException异常
  2. 抛出指定类型的RuntimeException异常

相对这两种异常的方式进行结束,第一种异常指的是我所有的异常都抛RuntimeException异常,但是需要带一个状态码,调用者可以根据状态码再去查询究竟service抛出了一个什么样的异常。
第二种异常是指在service中抛出什么样的异常就自定义一个指定的异常错误,然后在进行抛出异常。
一般来讲,如果系统没有别的特殊需求的时候,在开发设计中,建议使用第二种方式。但是比如说像基础判断的异常,就可以完全使用guava给我们提供的类库进行操作。jsr 303异常也可以使用自己封装好的异常判断类进行操作,因为这两种异常都是属于基础判断,不需要为它们指定特殊的异常。但是对于第三点义务条件约束判断抛出的异常,就需要抛出指定类型的异常了。
对于

throw new RuntimeException("找不到当前用户!");

定义一个特定的异常类来进行这个义务异常的判断:

public class NotFindUserException extends RuntimeException
首页 上一页 1 2 3 4 5 6 下一页 尾页 3/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇几个常用的 Git 高级命令 下一篇Spring 中无处不在的 Properties

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目