SpringBoot+SpringDataJpa general audit logic

SpringBoot + SpringDataJpa general audit logic

Scene

Recently I wrote a small tool for sql simulation data, which involves the review of submitted table data, review of submitted field data, and review of some keywords, and these review logics are the same. Assuming that they are written one by one, then Basically, the same code will be written multiple times. Such code does not comply with the principle of code reuse, that is, code redundancy. Therefore, this article is mainly based on the code of unified audit logic based on SpringBoot + SpringDataJpa.

Code

Unified review information

@Data
@MappedSuperclass
public abstract class BaseAuditEntity implements Serializable {<!-- -->
    @Enumerated(EnumType.STRING)
    @ApiModelProperty("Audit Status")
    private AuditStateEnums auditState = AuditStateEnums.waiting;
    @ApiModelProperty("Audit time")
    private LocalDateTime auditTime;
    @ApiModelProperty("opinion")
    private String verdict;
}

Table information entity class

@Data
@Entity
@ApiModel("Table information")
@Where(clause = "deleted = false")
@EqualsAndHashCode(callSuper = true)
@EntityListeners(AuditingEntityListener.class)
public class TableInfo extends BaseAuditEntity {<!-- -->
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Id;
@ApiModelProperty("UserId")
private String userId;
@ApiModelProperty("table name")
private tableName;
@ApiModelProperty("Table annotation")
private tableComment;
@ApiModelProperty("field information")
private List<Feild> feildInfo;
@CreatedDate
@ApiModelProperty("Creation time")
private LocalDateTime createdAt;
@ApiModelProperty("Delete")
private boolean deleted;
}

Field information entity class

 @Data
@ApiModel("field information")
@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("primary key")
    @GeneratedValue(strategy = GenerationType. IDENTITY)
    private Long id;
    @ApiModelProperty("userid")
    private String userId;
    @ApiModelProperty("field name")
    private String fieldName;
    @ApiModelProperty("Content")
    @Convert(converter = FieldConverter. class)
    private Field fieldContent;
    @ApiModelProperty("Delete")
    private boolean deleted = false;
    @CreatedDate
    @ApiModelProperty("Creation time")
    private LocalDateTime createdAt;
}

Base Repository unified audit mapper

@NoRepositoryBean
public interface BaseAuditRepository<T extends BaseAuditEntity, ID extends Serializable> extends JpaRepository<T, ID> {<!-- -->
/**
     * review
     *
     * @param id id
     * @param s1 status after review
     * @param s2 status before review
     * @param verdict review opinion
     * @return int whether successful
     */
    @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 general audit service

public interface AuditService<T extends BaseAuditEntity, ID extends Serializable> {<!-- -->
    /**
     * Get audit persistence mapper
     *
     * @return BaseAuditRepository<T, ID>
     */
    BaseAuditRepository<T, ID> getRepository();

    /**
     * review
     *
     * @param id audit id
     * @param event audit event
     * @param verdict opinion
     * @return Boolean whether it was successful
     */
    default Boolean audit(ID id, AuditEventEnums event, String verdict) {<!-- -->
        BaseAuditRepository<T, ID> repository = this.getRepository();
        if (repository == null) {<!-- -->
            throw new BusinessException("Audit persistence mapper not found");
        }
        switch (event) {<!-- -->
            case accept:
                return this.accept(repository, id);
            case reject:
                return this.reject(repository, id, verdict);
            default:
                throw new BusinessException("Audit event not found");
        }
    }

    /**
     * examination passed
     *
     * @param repository mapper
     * @param id audit id
     * @return Boolean whether it was successful
     */
    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("Audit failed");
        }
        return true;
    }

    /**
     * Review rejected
     *
     * @param repository mapper
     * @param id audit id
     * @param verdict opinion
     * @return Boolean whether it was successful
     */
    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("Audit failed");
        }
        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;
\t
public Boolean audit(Long id, AuditEventEnums event){<!-- -->
return this.tableInfoService.audit(id, event);
}
}

Remarks

Because each entity class has audit fields (audit status, audit time, audit opinion), a BaseAuditEntity audit abstract class is created, and the entity classes that need to be audited need to inherit.
Because each entity class needs to operate the database when auditing, but when operating the database, it is necessary to use the mapper corresponding to the entity class, so BaseAuditRepository was created to implement the mapper for unified management of inheritance methods, but it should be noted that @ needs to be marked on the interface. NoRepositoryBean annotation. If this annotation is not marked, an error BaseAuditEntity is not mapped will be reported at startup. It will look for the @Entity annotation in BaseAuditEntity, but BaseAuditEntity is not a table, so we do not An example of Chuangjie’s interface is needed. Finally, all Repositories must inherit the audit method in BaseAuditRepository for direct calling later.
The AuditSerivce unified audit service code was created. This is mainly the audit logic code. However, it should be noted that there is a getRepository(); method in this service. This method can specify the corresponding Repository.
This completes a unified review code based on SpringBoot + SpringDataJpa!