需求:根据注解自动插入到操作日志
CREATE TABLE notice
(
id
bigint(20) NOT NULL AUTO_INCREMENT,
title
varchar(255) DEFAULT NULL,
status
int(11) DEFAULT NULL,
PRIMARY KEY (id
)
)
CREATE TABLE logrecord
(
id
bigint(20) NOT NULL AUTO_INCREMENT,
username
varchar(255) DEFAULT NULL,
type
varchar(255) DEFAULT NULL,
remark
varchar(255) DEFAULT NULL,
tableName
varchar(255) DEFAULT NULL,
param
text,
foreignKeyId
bigint(20) DEFAULT NULL,
date
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id
)
)
依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>lib</directory>
<targetPath>BOOT-INF/lib/</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
</resources>
</build>
@Data
public class LogRecord {
private Long id;
private String username;
private String type;
private Date date;
private String tableName;
private String remark;
private String param;
private Long foreignKeyId;
}
@Data
public class Notice {
private int id;
private String title;
/**
* 状态:1保存;2发布
*/
private int status;
private List<LogRecord> logRecords=new ArrayList<>();
}
public interface NoticeMapper {
void add(Notice notice);
void delete(Long id);
List<Notice> search(Notice notice);
}
public interface LogRecordMapper {
void add(LogRecord logRecord);
}
<mapper namespace="com.study.dao.NoticeMapper">
<resultMap id="resultMap" type="com.study.bean.Notice">
<id column="id" property="id"/>
<result column="title" property="title"/>
<result column="status" property="status"/>
<collection property="logRecords" select="getLogRecordsNotice" column="id"> </collection>
</resultMap>
<insert id="add" keyProperty="id" useGeneratedKeys="true">
insert into notice(title,status) values (#{title},#{status})
</insert>
<delete id="delete">
delete from notice where id=#{id}
</delete>
<select id="search" resultMap="resultMap">
select id,title,status from notice
</select>
<select id="getLogRecordsNotice" resultType="com.study.bean.LogRecord">
select id,username,type,tableName,param,foreignKeyId,date,remark from logrecord where tableName='notice' and foreignKeyId=#{id}
</select>
</mapper>
<mapper namespace="com.study.dao.LogRecordMapper">
<insert id="add" keyProperty="id" useGeneratedKeys="true">
insert into logrecord(username,type,tableName,param,foreignKeyId,date,remark) values (#{username},#{type},#{tableName},#{param},#{foreignKeyId},#{date},#{remark})
</insert>
</mapper>
@Service
public class LogRecordService {
@Autowired
private LogRecordMapper logRecordMapper;
public void add(LogRecord logRecord){
logRecordMapper.add(logRecord);
}
}
@Service
public class NoticeService {
@Autowired
private NoticeMapper noticeMapper;
@Autowired
private DataSourceTransactionManager manager;
/**
*切换
*/
@ToLog(tableName = "notice")
public void addMethod(Notice notice){
add1(notice);
}
@Transactional
public void add1(Notice notice) {
noticeMapper.add(notice);
}
@Transactional
public void add2(Notice notice) {
noticeMapper.add(notice);
}
@Transactional
@ToLog(tableName = "notice",type = "删除")
public void delete(Long id) {
noticeMapper.delete(id);
}
public List<Notice> search(Notice notice) {
return noticeMapper.search(notice);
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Documented
public @interface ToLog {
String type() default "新增";
String tableName() default "0";
}
@Aspect
@Component
@Slf4j
public class LogAOP {
public static final ThreadLocal<LogRecord> THREAD_LOCAL=new ThreadLocal<>();
//日志service注入
@Autowired
private LogRecordService logRecordService;
//切点是注解ToLog
@Pointcut(value = "@annotation(toLog)")
public void cut(ToLog toLog){
}
//进入切点前封装对象进ThreadLocal
@Before(value = "cut(toLog)")
public void doBefore(JoinPoint joinPoint, ToLog toLog){
LogRecord logRecord=new LogRecord();
StringBuffer param = new StringBuffer();
logRecord.setUsername("测试");//实际应从session取用户
//从注解中取值
logRecord.setTableName(toLog.tableName());
logRecord.setType(toLog.type());
try {
log.info("------aop begin------");
//反射+内省拿到切点上的方法参数
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
Parameter[] parameters = method.getParameters();
Object[] args = joinPoint.getArgs();
if (args != null) {
for (int index = 0; index < args.length; index++) {
Object arg = args[index];
if (!(arg instanceof HttpServletRequest || arg instanceof HttpServletResponse)) {
Parameter parameter = parameters[index];
param.append(JSON.toJSON(arg));
}
}
}
// 将request请求中的请求参数放入日志
logRecord.setParam(param.toString());
}catch (Exception e){
e.printStackTrace();
logRecord.setRemark("AOP ERROR"+e);
log.error("AOP ERROR",e);
}
logRecord.setDate(new Date());
THREAD_LOCAL.set(logRecord);
}
@AfterReturning(pointcut = "cut(toLog)", returning = "returnVal")
public void doAfter(JoinPoint joinPoint, Object returnVal, ToLog toLog){
//取ThreadLocal中的对象
LogRecord logRecord = THREAD_LOCAL.get();
try {
//returnVal为被增强方法的返回值
logRecord.setForeignKeyId((Long) returnVal);
} catch (Exception e) {
e.printStackTrace();
logRecord.setRemark("AOP ERROR"+e);
log.error("AOP ERROR",e);
}
log.info("-------aop end------");
logRecordService.add(logRecord);
}
}
完美