SpringBoot + SpringDataJpa 通用审核逻辑
场景
最近再写一个sql 模拟数据的一个小工具,里面涉及到了提交表数据的审核、提交字段数据的审核,以及一些关键字的审核,而这些审核逻辑都是相同的,假设一个一个写的话,那么会基本同样的代码写多次,这样的代码不符合代码重用原则,也就是代码冗余,所以这篇文章主要是基于 SpringBoot+SpringDataJpa实现统一审核逻辑的代码。
代码
统一审核信息
@Data
@MappedSuperclass
public abstract class BaseAuditEntity implements Serializable {
@Enumerated(EnumType.STRING)
@ApiModelProperty("审核状态")
private AuditStateEnums auditState = AuditStateEnums.waiting;
@ApiModelProperty("审核时间")
private LocalDateTime auditTime;
@ApiModelProperty("意见")
private String verdict;
}
表信息实体类
@Data
@Entity
@ApiModel("表信息")
@Where(clause = "deleted = false")
@EqualsAndHashCode(callSuper = true)
@EntityListeners(AuditingEntityListener.class)
public class TableInfo extends BaseAuditEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Id;
@ApiModelProperty("用户Id")
private String userId;
@ApiModelProperty("表名")
private tableName;
@ApiModelProperty("表注释")
private tableComment;
@ApiModelProperty("字段信息")
private List<Feild> feildInfo;
@CreatedDate
@ApiModelProperty("创建时间")
private LocalDateTime createdAt;
@ApiModelProperty("是否删除")
private boolean deleted;
}
字段信息实体类
@Data
@ApiModel("字段信息")
@Entity(name = "field_info")
@Where(clause = "deleted = false")
@EqualsAndHashCode(callSuper = true)
@EntityListeners(AuditingEntityListener.class)
public class FieldInfo extends BaseAuditEntity {
private static final long serialVersionUID = 1L;
@Id
@ApiModelProperty("主键")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ApiModelProperty("用户id")
private String userId;
@ApiModelProperty("字段名称")
private String fieldName;
@ApiModelProperty("内容")
@Convert(converter = FieldConverter.class)
private Field fieldContent;
@ApiModelProperty("是否删除")
private boolean deleted = false;
@CreatedDate
@ApiModelProperty("创建时间")
private LocalDateTime createdAt;
}
Base Repository 统一审核mapper
@NoRepositoryBean
public interface BaseAuditRepository<T extends BaseAuditEntity, ID extends Serializable> extends JpaRepository<T, ID> {
/**
* 审核
*
* @param id id
* @param s1 审核后状态
* @param s2 审核前状态
* @param verdict 审核意见
* @return int 是否成功
*/
@Modifying
@Transactional(rollbackFor = {Exception.class, RuntimeException.class})
@Query("update #{#entityName} t set t.auditState = :s1, t.verdict = :verdict where t.id = :id and t.auditState = :s2")
int audit(ID id, AuditStateEnums s1, AuditStateEnums s2, String verdict);
}
TableInfoRepository
public interface TableInfoRepository extends BaseAuditRepository<TableInfo, Long> {
}
FieldInfoRepository
public interface FieldInfoRepository extends BaseAuditRepository<TableInfo, Long> {
}
AuditService 通用审核service
public interface AuditService<T extends BaseAuditEntity, ID extends Serializable> {
/**
* 获取审核持久化mapper
*
* @return BaseAuditRepository<T, ID>
*/
BaseAuditRepository<T, ID> getRepository();
/**
* 审核
*
* @param id 审核id
* @param event 审核事件
* @param verdict 意见
* @return Boolean 是否成功
*/
default Boolean audit(ID id, AuditEventEnums event, String verdict) {
BaseAuditRepository<T, ID> repository = this.getRepository();
if (repository == null) {
throw new BusinessException("未找到审核持久化mapper");
}
switch (event) {
case accept:
return this.accept(repository, id);
case reject:
return this.reject(repository, id, verdict);
default:
throw new BusinessException("未找到审核事件");
}
}
/**
* 审核通过
*
* @param repository mapper
* @param id 审核id
* @return Boolean 是否成功
*/
default Boolean accept(BaseAuditRepository<T, ID> repository, ID id) {
int row = repository.audit(id, AuditStateEnums.accepted, AuditStateEnums.waiting, null);
if (1 != row) {
throw new BusinessException("审核失败");
}
return true;
}
/**
* 审核拒绝
*
* @param repository mapper
* @param id 审核id
* @param verdict 意见
* @return Boolean 是否成功
*/
default Boolean reject(BaseAuditRepository<T, ID> repository, ID id, String verdict) {
int row = repository.audit(id, AuditStateEnums.rejected, AuditStateEnums.waiting, verdict);
if (1 != row) {
throw new BusinessException("审核失败");
}
return true;
}
}
TableInfoService
public interface TableInfoService extends AuditService {
}
FieldInfoService
public interface FieldInfoService extends AuditService {
}
TableInfoServiceImpl
public class TableInfoServiceImpl implements TableInfoService {
@Resource
private TableInfoRepository tableInfoRepository;
@Override
public BaseAuditRepository<FieldInfo, Long> getRepository() {
return fieldInfoRepository;
}
}
FieldInfoServiceImpl
public class FieldInfoServiceImpl implements FieldInfoService {
@Resource
private FieldInfoRepository fieldInfoRepository;
@Override
public BaseAuditRepository<FieldInfo, Long> getRepository() {
return fieldInfoRepository;
}
}
main
public class Application {
@Resource
private TableInfoService tableInfoService;
public Boolean audit(Long id, AuditEventEnums event){
return this.tableInfoService.audit(id, event);
}
}
备注
因为每个实体类都有审核字段 (审核状态、审核时间、审核意见),所以创建了一个BaseAuditEntity 审核抽象类,需要审核的实体类需要继承。
因为每个实体类中审核时都要操作数据库,但是在操作数据库时需要使用实体类对应的mapper,所以创建了BaseAuditRepository用来实现统一管理继承方法的mapper,但是要注意,在接口上需要打上@NoRepositoryBean 注解,假如不打这个注解的话,那么在启动的时候会报错 BaseAuditEntity is not mapped
他会找BaseAuditEntity 中是否有@Entity注解,但是BaseAuditEntity并不是一张表,所以我们不需要创捷这个接口的示例。最后所有的Repository都要继承BaseAuditRepository中的audit审核方法用于后面直接调用。
创建了 AuditSerivce 统一审核服务代码,这个主要就是审核的逻辑代码,但是要注意,这个service中有个getRepository();方法,这个方法是可以指定对应的Repository。
这样就完成了一个基于SpringBoot+SpringDataJpa的统一审核代码!