设为首页 加入收藏

TOP

如何优雅的设计 Java 异常(二)
2018-02-13 12:56:16 】 浏览:779
Tags:如何 优雅 设计 Java 异常
n)。一般来讲,如果没有特殊的要求,我们建议使用RuntimeException异常。

场景介绍和技术选型

架构描述

正如我们所知,传统的项目都是以MVC框架为基础进行开发的,本文主要从使用restful风格接口的设计来体验一下异常处理的优雅。
我们把关注点放在restful的api层(和web中的controller层类似)和service层,研究一下在service中如何抛出异常,然后api层如何进行捕获并且转化异常。
使用的技术是:spring-boot,jpa(hibernate),mysql,如果对这些技术不是太熟悉,读者需要自行阅读相关材料。

业务场景描述

选择一个比较简单的业务场景,以电商中的收货地址管理为例,用户在移动端进行购买商品时,需要进行收货地址管理,在项目中,提供一些给移动端进行访问的api接口,如:添加收货地址,删除收货地址,更改收货地址,默认收货地址设置,收货地址列表查询,单个收货地址查询等接口。

构建约束条件

ok,这个是设置好的一个很基本的业务场景,当然,无论什么样的api操作,其中都包含一些规则:

添加收货地址:
入参:

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

约束:

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

删除收货地址:
入参:

  • 用户id
  • 收货地址id

约束:

  • 用户id不能为空,且此用户确实是存在的
  • 收货地址不能为空,且此收货地址确实是存在的
  • 判断此收货地址是否是用户的收货地址
  • 判断此收货地址是否为默认收货地址,如果是默认收货地址,那么不能进行删除

更改收货地址:
入参:

  • 用户id
  • 收货地址id

约束:

  • 用户id不能为空,且此用户确实是存在的
  • 收货地址不能为空,且此收货地址确实是存在的
  • 判断此收货地址是否是用户的收货地址

默认地址设置:
入参:

  • 用户id
  • 收货地址id

约束:

  • 用户id不能为空,且此用户确实是存在的
  • 收货地址不能为空,且此收货地址确实是存在的
  • 判断此收货地址是否是用户的收货地址

收货地址列表查询:
入参:

  • 用户id

约束:

  • 用户id不能为空,且此用户确实是存在的

单个收货地址查询:
入参:

  • 用户id
  • 收货地址id

约束:

  • 用户id不能为空,且此用户确实是存在的
  • 收货地址不能为空,且此收货地址确实是存在的
  • 判断此收货地址是否是用户的收货地址

约束判断和技术选型

对于上述列出的约束条件和功能列表,我选择几个比较典型的异常处理场景进行分析:添加收货地址,删除收货地址,获取收货地址列表。
那么应该有哪些必要的知识储备呢,让我们看一下收货地址这个功能:
添加收货地址中需要对用户id和收货地址实体信息就行校验,那么对于非空的判断,我们如何进行工具的选择呢?传统的判断如下:

/**
 * 添加地址
 * @param uid
 * @param address
 * @return
 */
public Address addAddress(Integer uid,Address address){
    if(null != uid){
        //进行处理..
    }
    return null;
}

上边的例子,如果只判断uid为空还好,如果再去判断address这个实体中的某些必要属性是否为空,在字段很多的情况下,这无非是灾难性的。
那我们应该怎么进行这些入参的判断呢,给大家介绍两个知识点:

  1. Guava中的Preconditions类实现了很多入参方法的判断
  2. jsr 303的validation规范(目前实现比较全的是hibernate实现的hibernate-validator)
    如果使用了这两种推荐技术,那么入参的判断会变得简单很多。推荐大家多使用这些成熟的技术和jar工具包,他可以减少很多不必要的工作量。我们只需要把重心放到业务逻辑上。而不会因为这些入参的判断耽误更多的时间。

如何优雅的设计java异常

domain介绍

根据项目场景来看,需要两个domain模型,一个是用户实体,一个是地址实体.
Address domain如下:

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

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

User domain如下:

@Entity
@Data
public class User {
    @Id
   @GeneratedValue
   private Integer id;
   private String name;//姓名

    @OneToMany(cascade= CascadeType.ALL,mappedBy="user",fetch = FetchType.LAZY)
        private Set<Address> addresses;
}

ok,上边是一个模型关系,用户-收货地址的关系是1-n的关系。上边的@Data是使用了一个叫做lombok的工具,它自动生成了Setter和Getter等方法,用起来非常方便,感兴趣的读者可以自行了解一下。

dao介绍

数据连接层,我们使用了spring-data-jpa这个框架,它要求我们只需要继承框架提供的接口,并且按照约定对方法进行取名,就可以完成我们想要的数据库操作。
用户数据库操作如下:

@Repository
public interface IUserDao extends JpaRepository<User,Integer> {

}

收货地址操作如下:

@Repository
public interface IAddressDao extends JpaRepository<Address,Integer> {

}

正如读者所看到的,我们的DAO只需要继承JpaRepository,它就已经帮我们完成了基本的CURD等操作,如果想了解更多关于spring-data的这个项目,请参考一下spring的官方文档,它比不方案我们对异常的研究。

Service异常设计

ok,终于到了我们的重点了,我们要完成service一些的部分操作:添加收货地址,删除收货地址,获取收货地址列表.
首先看我的service接口定义:

public interface IAddressService {

/**
 * 创建收货地址
 * @param uid
 * @param address
 * @return
 */
Address createAddress(Integer uid,Address address);

/**
 * 删除收货地址
 * @param uid
 * @param aid
 */
void d
首页 上一页 1 2 3 4 5 6 下一页 尾页 2/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇几个常用的 Git 高级命令 下一篇Spring 中无处不在的 Properties

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目