提交 eedfa55f 编写于 作者: zhouweidong's avatar zhouweidong

审计

上级 4dff20d9
......@@ -89,6 +89,11 @@ public class ${item.getCodeName()} extends EntityMP implements Serializable {
/**
* ${defield.getLogicName()}
*/
<#comment>审计注解</#comment>
<#if defield.isEnableAudit()==true && de.getAuditMode()!=0>
<#assign auditExpression=getAuditExpression(defield)>
@${pub.getPKGCodeName()}.util.annotation.Audit(${auditExpression})
</#if>
<#comment>属性默认值</#comment>
<#if defieldano?? && defieldano!='' && defield.isPhisicalDEField()==true>
@DEField(${defieldano})
......@@ -337,6 +342,11 @@ public class ${item.getCodeName()} extends EntityMongo implements Serializable {
<#if defield.isKeyDEField()==true>
@Id()
</#if>
<#comment>审计注解</#comment>
<#if defield.isEnableAudit()==true && de.getAuditMode()!=0>
<#assign auditExpression=getAuditExpression(defield)>
@${pub.getPKGCodeName()}.util.annotation.Audit(${auditExpression})
</#if>
<#comment>属性默认值</#comment>
<#if defieldano?? && defieldano!='' && defield.isPhisicalDEField()==true>
@DEField(${defieldano})
......@@ -501,6 +511,11 @@ public class ${item.getCodeName()} extends EntityClient implements Serializable
/**
* ${defield.getLogicName()}
*/
<#comment>审计注解</#comment>
<#if defield.isEnableAudit()==true && de.getAuditMode()!=0>
<#assign auditExpression=getAuditExpression(defield)>
@${pub.getPKGCodeName()}.util.annotation.Audit(${auditExpression})
</#if>
<#comment>属性默认值</#comment>
<#if defieldano?? && defieldano!='' && defield.isPhisicalDEField()==true>
@DEField(${defieldano})
......@@ -677,6 +692,11 @@ public class ${item.getCodeName()} extends EntityBase implements Serializable {
/**
* ${defield.getLogicName()}
*/
<#comment>审计注解</#comment>
<#if defield.isEnableAudit()==true && de.getAuditMode()!=0>
<#assign auditExpression=getAuditExpression(defield)>
@${pub.getPKGCodeName()}.util.annotation.Audit(${auditExpression})
</#if>
<#comment>属性默认值</#comment>
<#if defieldano?? && defieldano!='' && defield.isPhisicalDEField()==true>
@DEField(${defieldano})
......@@ -823,6 +843,28 @@ public class ${item.getCodeName()} extends EntityBase implements Serializable {
<#return unionKeyResult>
</#function>
<#comment>审计注解</#comment>
<#function getAuditExpression defield>
<#assign defDataType = (defield.getDataType())!"">
<#assign defStdType=srfjavatype(defield.stdDataType)>
<#assign expressionCond="fieldLogicName=\""+ defield.getLogicName()+"\""> //拼接字段逻辑名
<#if defield.getPSCodeList?? && defield.getPSCodeList()??>
<#if ((defield.getPredefinedType())!'')!='LOGICVALID'>
<#assign expressionCond=expressionCond+",dictName=\""+ sys.codeName+"_"+defield.getPSCodeList().codeName+"CodeList"+"\""> //拼接代码表
</#if>
</#if>
<#if defDataType == "DATETIME">//拼接时间
<#assign expressionCond=expressionCond+",fieldType=\"DATETIME\",format=\"yyyy-MM-dd HH:mm:ss\"">//日期时间型
<#elseif defDataType == "DATE">
<#assign expressionCond=expressionCond+",fieldType=\"DATE\",format=\"yyyy-MM-dd\"">//日期型
<#elseif defDataType == "TIME">
<#assign expressionCond=expressionCond+",fieldType=\"TIME\",format=\"HH:mm\"">//时间型
<#elseif defDataType=='PICKUPDATA'&& defStdType=='Timestamp'><#comment>外键值附加数据,数据类型为时间</#comment>
<#assign expressionCond=expressionCond+",fieldType=\"DATETIME\",format=\"yyyy-MM-dd HH:mm:ss\"">//日期时间型
</#if>
<#return expressionCond/>
</#function>
......
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
<changeSet author="Think (generated)" id="1566027230162-1">
<preConditions onFail="MARK_RAN" >
<not>
<tableExists tableName="IBZDATAAUDIT" />
</not>
</preConditions>
<createTable remarks="数据审计" tableName="IBZDATAAUDIT">
<column name="DATAAUDITID" remarks="数据审计标识" type="VARCHAR2(100 BYTE)">
<constraints primaryKey="true" primaryKeyName="SYS_C00115093"/>
</column>
<column name="OPPERSONID" remarks="操作人标识" type="VARCHAR2(100 BYTE)"/>
<column name="OPPERSONNAME" remarks="操作人名称" type="VARCHAR2(100 BYTE)"/>
<column name="AUDITTYPE" remarks="审计行为类型" type="VARCHAR2(60 BYTE)"/>
<column name="OPTIME" remarks="操作时间" type="date"/>
<column name="IPADDRESS" remarks="访问地址" type="VARCHAR2(100 BYTE)"/>
<column name="AUDITOBJECTDATA" remarks="审计对象(表数据)" type="VARCHAR2(100 BYTE)"/>
<column name="AUDITOBJECT" remarks="审计对象(表)" type="VARCHAR2(100 BYTE)"/>
<column name="AUDITINFO" remarks="审计明细" type="CLOB"/>
<column name="ISDATACHANGED" remarks="审计数据是否发生变化" type="INTEGER"/>
</createTable>
</changeSet>
</databaseChangeLog>
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
package ${pub.getPKGCodeName()}.util.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD})
public @interface Audit
{
String fieldLogicName() default "";//字段逻辑名称
String dictName() default "";//代码表名称
String fieldType() default"";//字段类型
String format() default "";//格式化
}
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
package ${pub.getPKGCodeName()}.util.aspect;
import lombok.SneakyThrows;
import ${pub.getPKGCodeName()}.util.annotation.Audit;
import ${pub.getPKGCodeName()}.util.domain.EntityBase;
import ${pub.getPKGCodeName()}.util.helper.DEFieldCacheMap;
import ${pub.getPKGCodeName()}.util.service.IBZDataAuditService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* 实体数据审计切面类
*/
@Aspect
@Component
public class AuditAspect
{
private final ExpressionParser parser = new SpelExpressionParser();
@Autowired
IBZDataAuditService dataAuditService;
/**
* 实体数据建立切面,在成功创建数据后将新增数据内容记录审计日志内(审计明细【AuditInfo】中只记录审计属性变化情况,审计属性在平台属性中配置)
* @param point
*/
@AfterReturning(value = "execution(* ${pub.getPKGCodeName()}.core.*.service.*.create(..))")
@SneakyThrows
public void create(JoinPoint point){
HttpServletRequest request=null;
RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
if(requestAttributes!=null){
request=((ServletRequestAttributes)requestAttributes).getRequest();
}
Object [] args = point.getArgs();
if(ObjectUtils.isEmpty(args) || args.length==0)
return;
Object serviceParam =args[0];
EntityBase entity=(EntityBase)serviceParam;//创建数据
Map<String, Audit> auditFields= DEFieldCacheMap.getAuditFields(entity.getClass());
if(auditFields.size()==0)//是否有审计属性
return;
String idField=DEFieldCacheMap.getDEKeyField(entity.getClass());
Object idValue="";
if(!StringUtils.isEmpty(idField)){
idValue=entity.get(idField);
}
//记录审计日志
dataAuditService.createAudit(request,entity,idValue,auditFields);
return;
}
/**
* 实体数据更新切面,在成功更新数据后将新增数据内容记录审计日志内(审计明细【AuditInfo】中只记录审计属性变化情况,审计属性在平台属性中配置)
* 使用环切【@Around】获取到更新前后的实体数据并进行差异比较,并将差异内容记入审计日志内
* @param point
*/
@Around("execution(* ${pub.getPKGCodeName()}.core.*.service.*.update(..))")
public Object update(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request=null;
RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
if(requestAttributes!=null){
request=((ServletRequestAttributes)requestAttributes).getRequest();
}
Object serviceObj=point.getTarget();
Object args[]=point.getArgs();
if(ObjectUtils.isEmpty(args) || args.length==0)
return point.proceed();
Object arg=args[0];
EntityBase entity= (EntityBase) arg;
Map<String, Audit> auditFields= DEFieldCacheMap.getAuditFields(entity.getClass());
//是否有审计属性
if(auditFields.size()==0)
return point.proceed();
String idField=DEFieldCacheMap.getDEKeyField(entity.getClass());
Object idValue="";
if(!StringUtils.isEmpty(idField)){
idValue=entity.get(idField);
}
if(ObjectUtils.isEmpty(idValue))
return point.proceed();
//获取更新前实体
EntityBase beforeEntity=getEntity(serviceObj,idValue);
//执行更新操作
point.proceed();
//记录审计日志
dataAuditService.updateAudit(request,beforeEntity,serviceObj,idValue,auditFields);
return true;
}
/**
* 实体数据更新切面,在成功更新数据后将新增数据内容记录审计日志内(审计明细【AuditInfo】中只记录审计属性变化情况,审计属性在平台属性中配置)
* 使用环切【@Around】获取要删除的完整数据,并将审计属性相关信息记录到审计日志中
* @param point
* @return
* @throws Throwable
*/
@Around("execution(* ${pub.getPKGCodeName()}.core.*.service.*.remove(..))")
public Object remove(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request=null;
RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
if(requestAttributes!=null){
request=((ServletRequestAttributes)requestAttributes).getRequest();
}
Object serviceObj=point.getTarget();
Object args[]=point.getArgs();
if(ObjectUtils.isEmpty(args) || args.length==0)
return point.proceed();
Object idValue=args[0];
EntityBase entity=getEntity(serviceObj,idValue);
Map<String, Audit> auditFields= DEFieldCacheMap.getAuditFields(entity.getClass());
if(auditFields.size()==0){
return point.proceed();
}
else{
//执行删除操作
point.proceed();
//记录审计日志
dataAuditService.removeAudit(request,entity,idValue,auditFields);
return true;
}
}
/**
* 获取实体
* @param service
* @param id
* @return
*/
@SneakyThrows
private EntityBase getEntity(Object service, Object id){
EntityBase entity=null;
if(!ObjectUtils.isEmpty(service)){
EvaluationContext oldContext = new StandardEvaluationContext();
oldContext.setVariable("service",service);
oldContext.setVariable("id",id);
Expression oldExp = parser.parseExpression("#service.get(#id)");
return oldExp.getValue(oldContext, EntityBase.class);
}
return entity;
}
}
\ No newline at end of file
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
package ${pub.getPKGCodeName()}.util.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Objects;
/**
* 实体[DataAudit] 数据对象
*/
@TableName(value = "IBZDATAAUDIT")
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class IBZDataAudit implements Serializable{
@TableId(value= "dataauditid",type=IdType.UUID)//指定主键生成策略
private String dataauditid;
private String dataauditname;
private String oppersonid;
private String oppersonname;
private String audittype;
private Timestamp optime;
private String ipaddress;
private String auditinfo;
private Object auditobjectdata;
private String auditobject;
private int isdatachanged;
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ TARGET=PSSYSTEM
package ${pub.getPKGCodeName()}.util.helper;
import ${pub.getPKGCodeName()}.util.annotation.Audit;
import ${pub.getPKGCodeName()}.util.annotation.DEField;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
......@@ -25,6 +26,8 @@ public class DEFieldCacheMap {
private static Hashtable<String, Hashtable<String,DEField>> cacheDEField = new Hashtable<>();
private static Hashtable<String, Hashtable<String,Audit>> cacheAuditField = new Hashtable<>();
private static Hashtable<String, String> cacheDEKeyField = new Hashtable<>();
private static Object objLock1=new Object();
......@@ -47,6 +50,7 @@ public class DEFieldCacheMap {
List<Field> list=new ArrayList<Field>();
Hashtable<String,String> keys=new Hashtable<String,String>();
Hashtable<String,DEField> defields=new Hashtable<>();
Hashtable<String, Audit> auditfields=new Hashtable<>();
Hashtable<String,String> dekeyfields=new Hashtable<>();
Field[] fields=clazz.getDeclaredFields();
for(Field field:fields){
......@@ -54,16 +58,21 @@ public class DEFieldCacheMap {
list.add(field);
keys.put(field.getName().toLowerCase(),field.getName());
DEField deField=field.getAnnotation(DEField.class);
Audit auditField=field.getAnnotation(Audit.class);
if(!ObjectUtils.isEmpty(deField)) {
defields.put(field.getName(),deField);
if(deField.isKeyField())
cacheDEKeyField.put(className,field.getName());
}
if(!ObjectUtils.isEmpty(auditField)) {
auditfields.put(field.getName(),auditField);
}
}
cacheMap.put(className, result);
cacheList.put(className,list);
cacheKey.put(className,keys);
cacheDEField.put(className,defields);
cacheAuditField.put(className,auditfields);
return result;
}
}
......@@ -100,6 +109,23 @@ public class DEFieldCacheMap {
}
}
/**
* 从缓存中查询审计属性集合
* @param
* @return
*/
public static <T> Hashtable<String,Audit> getAuditFields(Class<T> clazz) {
String className=clazz.getName();
if(className.indexOf("_$")>0)
className=className.substring(0, className.lastIndexOf("_$"));
if(cacheAuditField.containsKey(className))
return cacheAuditField.get(className);
else{
DEFieldCacheMap.getFieldMap(className);
return cacheAuditField.get(className);
}
}
/**
* 从缓存中查询实体对象主键
* @param
......
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
package ${pub.getPKGCodeName()}.util.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import ${pub.getPKGCodeName()}.util.domain.IBZDataAudit;
public interface IBZDataAuditMapper extends BaseMapper<IBZDataAudit> {
}
\ No newline at end of file
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
package ${pub.getPKGCodeName()}.util.service;
import ${pub.getPKGCodeName()}.util.annotation.Audit;
import ${pub.getPKGCodeName()}.util.domain.EntityBase;
import org.springframework.scheduling.annotation.Async;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* 实体[DataAudit] 服务对象接口
*/
public interface IBZDataAuditService {
@Async
void createAudit(HttpServletRequest request,EntityBase entity,Object idValue,Map<String, Audit> auditFields);
@Async
void updateAudit(HttpServletRequest request, EntityBase beforeEntity, Object serviceObj, Object idValue, Map<String, Audit> auditFields);
@Async
void removeAudit(HttpServletRequest request,EntityBase entity,Object idValue,Map<String, Audit> auditFields);
}
\ No newline at end of file
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册