一、Spring事务管理
1.@Transactional//Spring 事务管理



2.事务进阶
1.事务属性-回滚(rollbackFor)

2.传播属性(propagation)



1.DeptLog日志对象
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeptLog {
private Integer id;
private LocalDateTime createTime;
private String description;
}
2.DeptService层
/**
* 根据ID删除部门
* @param id
*/
@Transactional(rollbackFor = Exception.class)//Spring 事务管理
@Override
public void delete(Integer id) throws Exception {
try {
deptMapper.delete(id);
empMapper.deleteByDeptId ( id );//根据部门Id删除该部门的员工
int i= 1/0;
// if (true){
// throw new Exception ("出错啦");
// }
} finally {
DeptLog deptLog =new DeptLog ();
deptLog.setCreateTime ( LocalDateTime.now () );
deptLog.setDescription ( "执行了解散部门的操作,此次解散的是"+id+"号部门" );
deptLogService.insert ( deptLog );
}
3.DeptLogService层
import com.itheima.mapper.DeptLogMapper;
import com.itheima.pojo.DeptLog;
import com.itheima.service.DeptLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DeptLogServiceImpl implements DeptLogService {
@Autowired
private DeptLogMapper deptLogMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void insert(DeptLog deptLog) {
deptLogMapper.insert(deptLog);
}
}
4.DeptLogMapper层
import com.itheima.pojo.DeptLog;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DeptLogMapper {
@Insert("insert into dept_log(create_time,description) values(#{createTime},#{description})")
void insert(DeptLog log);
}
5.数据库层
create table dept_log(
id int auto_increment comment '主键ID' primary key,
create_time datetime null comment '操作时间',
description varchar(300) null comment '操作描述'
)comment '部门操作日志表';
二、AOP-面向切面编程
1.AOP基础



import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@Aspect//AOP类
public class TimeAspect {
@Around ( "execution(* com.itheima.service.*.*(..))" )//切入点表达式
public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
//1.记录开始时间
long begin = System.currentTimeMillis ();
//2.调用原始方法运行
Object result = joinPoint.proceed ();
//3.记录结束时间,计算方法执行耗时
long end = System.currentTimeMillis ();
log.info (joinPoint.getSignature ()+ "方法执行耗时:{}ms",end-begin );
return result;
}
}

2.AOP核心概念
1.概念

2.AOP的执行流程

3.AOP进阶
1.通知类型



import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
public class MyAspect1 {
//抽取切入点表达式
@Pointcut("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
public void p(){}
@Before ("p()" )
public void before(){
log.info ( "before..." );
}
@Around ( "p()" )
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
log.info ( "around before..." );
//调用目标对象的原始方法执行
Object result = joinPoint.proceed ();
log.info ( "around..." );
return result;
}
@After ("p()" )
public void after(){
log.info ( "after..." );
}
@AfterReturning("p()")
public void afterReturning(){
log.info ( "afterReturning..." );
}
@AfterThrowing("p()")
public void afterThrowing(){
log.info ( "afterThrowing" );
}
}
2.通知的执行顺序

3.切入点表达式

1.execution(.....)



2.@annotation

4.连接点

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.util.Arrays;
//切面类
@Slf4j
@Aspect
@Component
public class MyAspect8 {
@Pointcut("execution(* com.itheima.service.DeptService.*(..))")
private void pt(){}
@Before("pt()")
public void before(JoinPoint joinPoint){
log.info("MyAspect8 ... before ...");
}
@Around("pt()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("MyAspect8 around before ...");
//1. 获取 目标对象的类名 .
String className = joinPoint.getTarget().getClass().getName();
log.info("目标对象的类名:{}", className);
//2. 获取 目标方法的方法名 .
String methodName = joinPoint.getSignature().getName();
log.info("目标方法的方法名: {}",methodName);
//3. 获取 目标方法运行时传入的参数 .
Object[] args = joinPoint.getArgs();
log.info("目标方法运行时传入的参数: {}", Arrays.toString(args));
//4. 放行 目标方法执行 .
Object result = joinPoint.proceed();
//5. 获取 目标方法运行的返回值 .
log.info("目标方法运行的返回值: {}",result);
log.info("MyAspect8 around after ...");
return result;
}
}
三、AOP综合案例


1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.设置自定义注解
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.METHOD )
public @interface Log {
}
3.日志类对象
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OperateLog {
private Integer id; //ID
private Integer operateUser; //操作人ID
private LocalDateTime operateTime; //操作时间
private String className; //操作类名
private String methodName; //操作方法名
private String methodParams; //操作方法参数
private String returnValue; //操作方法返回值
private Long costTime; //操作耗时
}
4.AOP类
import com.alibaba.fastjson.JSONObject;
import com.itheima.mapper.OperateLogMapper;
import com.itheima.pojo.OperateLog;
import com.itheima.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
@Component
@Aspect//切面类
@Slf4j
public class LogAspect {
@Autowired
private HttpServletRequest request;
@Autowired
private OperateLogMapper operateLogMapper;
@Around ( "@annotation(com.itheima.anno.Log)" )
public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
//操作人ID 当前登录员工的ID (从令牌中获取信息)
//获取请求头当中的令牌,解析令牌
String jwt = request.getHeader ( "token" );
Claims claims = JwtUtils.parseJWT ( jwt );
Integer operateUser= (Integer) claims.get ( "id" );
//操作时间
LocalDateTime operateTime = LocalDateTime.now ();
//操作类名
String className = joinPoint.getTarget ().getClass ().getName ();
//操作方法名
String methodName = joinPoint.getSignature ().getName ();
//操作方法参数
Object[] args = joinPoint.getArgs ();
String methodParams = Arrays.toString ( args );
long begin = System.currentTimeMillis ();
//调用原始方法目标执行
Object result = joinPoint.proceed ();
long end = System.currentTimeMillis ();
//方法返回值
String returnValue = JSONObject.toJSONString ( result );
//操作耗时
Long costTime=end-begin;
//记录操作日志
OperateLog operateLog = new OperateLog (null,operateUser,operateTime,className,methodName,methodParams,returnValue,costTime);
operateLogMapper.insert ( operateLog );
log.info ( "AOP记录操作日志:{}",operateLog );
return result;
}
}
5.数据库表
-- 操作日志表
create table operate_log(
id int unsigned primary key auto_increment comment 'ID',
operate_user int unsigned comment '操作人ID',
operate_time datetime comment '操作时间',
class_name varchar(100) comment '操作的类名',
method_name varchar(100) comment '操作的方法名',
method_params varchar(1000) comment '方法参数',
return_value varchar(2000) comment '返回值',
cost_time bigint comment '方法执行耗时, 单位:ms'
) comment '操作日志表';