在一个web项目内,会有很多重复性的代码,如果将共性代码进行提取并规范使用,对后续运维和开发是很有帮助的。下面我们来看一下在一个web项目内有那些部分会出现诸多重复性的代码:
1. model内:id、标记删除、创建时间、创建人、修改时间、修改人等字段
2. service内:根据id查询、新增&修改、删除、分页查询等方法
3. dao内: 根据id查询、新增&修改、删除、分页查询等方法
model
根据当前公司的情况,对model进行了以下抽象:
1. BaseModel 接口,仅包含getId一个方法
2. AbstractBaseModel 抽象类,继承BaseModel接口,提取了创建人、创建时间、修改人、修改时间字段
3. MarkDeleteableModel 抽象类,继承AbstractBaseModel,增加了标记删除标记字段
代码如下:
public interface BaseModel<ID extends Serializable> extends Serializable{
ID getId();
}
/**
* 提取了部分公共字段,可以避免多个实体重复设置这些属性
*/
@MappedSuperclass
public abstract class AbstractBaseModel<ID extends Serializable> implements BaseModel<ID>{
private static final long serialVersionUID = 1195969732659409799L;
@ApiModelProperty(value="创建者ID")
@Column(columnDefinition="int default 0")
private int creator = 0;
@ApiModelProperty(value="创建时间")
@Column(name="create_time")
private Timestamp createTime;
@ApiModelProperty(value="最后修改人")
@Column(columnDefinition="int default 0")
private int updator = 0;
@ApiModelProperty(value="最后修改时间")
@Column(name="update_time")
private Timestamp updateTime;
//省略get set
}
/**
* 需要标记删除的实体继承该类
*/
@MappedSuperclass
public abstract class MarkDeleteableModel<ID extends Serializable> extends AbstractBaseModel<ID>{
private static final long serialVersionUID = -1880548221110317053L;
@ApiModelProperty(value="标记删除字段 0未删除 1已删除 ")
@Column(name = "del", columnDefinition = "tinyint default 0")
private int del = Constants.DEL_NO;
//省略get set
}
@MappedSuperclass用于说明该类不是某个实体,不和数据库的表相对应。
所有的实体皆继承以上三个类中的一个,数据需要标记删除的继承MarkDeleteableModel(如用户)、需要创建时间、修改时间的继承AbstractBaseModel(如角色),其它的实现BaseModel接口(如用户角色关系)
dao
公司项目使用的是spring boot + JPA,所以DAO层的公共操作已经在spring-data-jpa内进行了完善的抽象,如CrudRepository、PagingAndSortingRepository、JpaRepository、JpaSpecificationExecutor等接口,我们自己的DAO只需要根据需要进行继承就可以使用对应的查询方法。
但这里存在一个问题,当我抽取service层代码时肯定需要设置对应的dao,那就希望dao层能有一个统一的接口,如UserDao继承PagingAndSortingRepository和JpaRepository,UserRoleDao继承CrudRepository,虽然满足了对应实体的操作需要,但对service层代码的提取需求冲突,所以为了所有的DAO拥有相同的接口,因此我们可以提供一个公共DAO,满足绝大部分实体所需要的查询操作。
@NoRepositoryBean
public interface BaseDao<T,ID extends Serializable> extends JpaSpecificationExecutor<T>,JpaRepository<T, ID>{
}
- JpaRepository满足基本的增删改查、分页等需求
- JpaSpecificationExecutor满足多可选条件查询需求
service
service层主要提取通用的新增、修改、常用查询方法,这样在创建一个实体的service后,不需要在每个service的接口内都创建一遍这些同样的方法,就可以直接调用其上层方法进行操作。
public interface BaseService<T extends BaseModel<ID>, ID extends Serializable> {