夫陶公清风千古,余又何人,敢称庶几
本文是对面向切面编程的简单应用。下文中用到的是后置通知实现日志的记录,当该方法执行以后,记录相关的日志信息。AspectJ中常用的注解:
@AspectJ:定义一个切面
@Before:前置通知
@AfterReturning:后置通知
@Around:环绕通知
@AfterThrowing:异常通知
@After:最终通知
提示:以下是本篇文章正文内容,下面案例可供参考
系统日志是记录系统中硬件、软件和系统问题的信息,同时还可以监视系统中发生的事件。用户可以通过它来检查错误发生的原因,或者寻找受到攻击时攻击者留下的痕迹。系统日志包括系统日志、应用程序日志和安全日志。
>
>org.projectlombok >
>lombok >
>1.18.16 >
>provided >
>
>
>mysql >
>mysql-connector-java >
>5.1.48 >
>
>
>org.springframework >
>spring-aop >
>5.2.12.RELEASE >
>
>
>org.springframework >
>spring-aspects >
>5.2.12.RELEASE >
>
>
>com.alibaba >
>druid >
>1.2.4 >
>
>
>com.baomidou >
>mybatis-plus-boot-starter >
>3.4.1 >
>
server:
port: 8088
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/aop-test?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
代码如下(示例):
/**
* 用户实体
* @author XinLiu
*/
@Data
@ToString
@TableName(value = "sysUser")
public class SysUser {
/**
* 主键
*/
@TableId
private String id;
/**
* 用户名
*/
@TableField("name")
private String name;
/**
* 密码
*/
@TableField("password")
private String password;
/**
* 创建时间
*/
@TableField("createDate")
private Date createDate;
}
对应的数据表:
/**
* 日志实体
* @author XinLiu
*/
@Data
@ToString
@TableName("log")
public class SysLog {
/**
* 主键
*/
@TableId
private String id;
/**
* 访问的类名
*/
@TableField("className")
private String className;
/**
* 执行的操作
*/
@TableField("methodName")
private String methodName;
/**
* 创建日志时间
*/
@TableField("createDate")
private Date createDate;
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
* 执行操作的名称
* @return 操作名
*/
String value() ;
}
这里其实是面向切面编程的典型应用,此处日志的实现用到了后置通知,也就是当访问的方法正确返回时执行此后置通知。首先我们需要编写一个切入点,也就是声明要执行那个方法或者那些方法,前面我们自定义了一个注解:@Log
,此注解有一个属性value
,它的作用是用于保存执行指定操作的名称;接下来我们需要编写一个后置通知,也就是增强的方法,方法需要一个参数JoinPoint joinPoint
,通过它可以获得@Log
注解,通过反射可以获得注解上的值,这个值就是操作名称,我们需要保存到日志表中;编写好通知后,我们就可以保存我们需要保存的日志信息了,比如:访问者用户名、请求参数、请求的URI、请求者IP地址、执行的操作
等等。
/**通知类
* @author XinLiu
*/
@SuppressWarnings("all")
@Component
@Aspect
public class LogAdvice {
@Autowired
private LogMapper logMapper;
/**
* 配置切入点
*/
@Pointcut("@annotation(com.qingfeng.aoptest.common.anno.Log)")
private void serviceAspect() {
}
/**
* 后置通知,用于记录日志
*
* @param joinPoint
* @return
* @throws Throwable
*/
@AfterReturning("serviceAspect()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
Log log = method.getAnnotation(Log.class);
SysLog sysLog = new SysLog();
sysLog.setId((UUID.randomUUID().toString()).replaceAll("-", ""));
sysLog.setClassName(joinPoint.getTarget().getClass().getName());
sysLog.setMethodName(log.value());
sysLog.setCreateDate(new Date());
logMapper.insert(sysLog);
}
}
简单解释一下,这里继承了一个BaseMapper
类,通过继承该类 ,我们就可以使用mybatis plus里的方法,里面实现常用的操作,比如CRUD。
public interface LogMapper extends BaseMapper<SysLog> {
}
/**
* 系统用户数据层
* @author XinLiu
*/
public interface UserMapper extends BaseMapper<SysUser> {
}
这是一个配置类,@Configuration
注解的作用是,将此类交给ioc容器处理;@MapperScan("com.qingfeng.aoptest.mapper")
的作用是扫描该包路径下的所有mapper接口,简化每次都要在mapper类上添加注解:@Mapper
,如果配置了此类,就可以不用写@Mapper
注解了。
@Configuration
@MapperScan("com.qingfeng.aoptest.mapper")
public class MybatisPlusConfig {
}
/**
* @author XinLiu
*/
public interface UserService extends IService<SysUser> {
/**
* 用户注册
* @param sysUser 用户实体
* @return
*/
public boolean reg(SysUser sysUser);
/**
* 查询所有的用户
* @return
*/
public List<SysUser> queryAllUser();
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,SysUser> implements UserService {
@Autowired
private UserMapper userMapper;
/**
* 用户注册
*
* @param sysUser 用户实体
* @return
*/
@Override
@Log("用户注册")
public boolean reg(SysUser sysUser) {
return userMapper.insert(sysUser)>0;
}
@Override
@Log("查询所有的用户")
public List<SysUser> queryAllUser() {
return userMapper.selectList(new QueryWrapper<SysUser>());
}
}
@SpringBootTest
@RunWith(SpringRunner.class)
class AopTestApplicationTests {
@Autowired
private UserService userService;
@Test
void contextLoads() {
}
}
@Test
public void testReg(){
System.out.println(userService);
SysUser sysUser = new SysUser();
sysUser.setCreateDate(new Date());
sysUser.setId((UUID.randomUUID().toString()).replaceAll("-",""));
sysUser.setName("admin");
sysUser.setPassword("123456");
userService.reg(sysUser);
}
运行结果:
@Test
public void testFindAll(){
List<SysUser> sysUsers = userService.queryAllUser();
sysUsers.forEach(sysUser -> System.out.println(sysUser));
}
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了如何通过注解的方式实现日志,以及AspectJ的使用, 对一个小白入门是有一些帮助的,此文也有很多东西未实现,因为没有写前端,所有日志中没有保存访问的用户。