记录:
logPointCut
方法只是用于定义切点,指定了哪些方法会被拦截,而获取方法上的 OperateLog
注解是为了在切面逻辑中判断是否需要记录操作日志。这两者是配合使用的,前者确定拦截的位置,后者确定在拦截的位置上是否执行操作日志记录逻辑。
//登陆操作日志
// 解析用户代理字符串
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
// 构建用户登录日志实体
UserLoginLogEntity logEntity = UserLoginLogEntity.builder()
.userId(employeeDTO.getId()) // 设置用户ID
.userName(employeeDTO.getActualName()) // 设置用户名
.remoteIp(SmartIPUtil.getRemoteIp(request)) // 设置远程IP地址
.remotePort(request.getRemotePort()) // 设置远程端口号
.remoteBrowser(userAgent.getBrowser().getName()) // 设置远程浏览器
.remoteOs(userAgent.getOperatingSystem().getName()) // 设置远程操作系统
.loginStatus(JudgeEnum.YES.getValue()) // 设置登录状态
.build();
// 添加登录日志
logService.addLog(logEntity);
二、加密解密
- 接收前端Base64加密的密码。
- 在后端进行一次Base64解码,得到原始密码。
- 使用你自己的加密方法(例如:
SmartDigestUtil.encryptPassword
)对原始密码进行加密。 - 使用这个加密后的密码和数据库中的密码进行比对。
// 第一步:Base64解码,得到原始密码
String decodedPassword = this.base64Decode(loginForm.getLoginPwd());
// 第二步:使用自己的加密方法进行加密
String encryptedPwd = null;
try {
encryptedPwd = SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, decodedPassword);
} catch (Exception e) {
e.printStackTrace();
}
// 第三步:调用employeeDao的login方法进行登录验证,并将信息存储到employeeDTO中
EmployeeDTO employeeDTO = employeeDao.login(loginForm.getLoginName(), encryptedPwd);
public static String encryptPassword(String salt, String password) {
return SmartDigestUtil.md5Hex(String.format(salt, password));
}
public static final class Password {
public static final String DEFAULT = "123456";
public static final String SALT_FORMAT = "smart_%s_admin";
}
1.测试
class LoginServiceTest {
@Test//Base64解密
void login() {
BASE64Decoder decoder = new BASE64Decoder();
String ji = base64Decode("MTIzNDU2");
System.out.println(ji);
}
private String base64Decode(String str){
return new String(Base64.decodeBase64(str.getBytes()));
}
@Test//Base64加密
void base64(){
String originalText = "123456";
byte[] encodedBytes = Base64.encodeBase64(originalText.getBytes());
String encodedText = new String(encodedBytes);
System.out.println("Encoded: " + encodedText);
}
@Test
void test(){
// 对密码进行md5加密
BASE64Decoder decoder = new BASE64Decoder();
String loginPwd = null;
try {
loginPwd = SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, new String(decoder.decodeBuffer("123456")));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(loginPwd);
}
}
三、AOP
1.概念
-
切面(Aspect):切面是一个模块化的关注点,例如日志记录或事务管理。切面可以定义通知和切入点。
-
通知(Advice):通知是切面的具体行为。通知定义了在特定的连接点执行的代码。主要类型有:
- 前置通知(Before):在连接点之前执行。
- 后置通知(After):在连接点之后执行。
- 返回通知(After Returning):在连接点正常完成之后执行。
- 异常通知(After Throwing):在连接点抛出异常后执行。
- 环绕通知(Around):在连接点之前和之后执行。
-
切入点(Pointcut):切入点定义了通知应该在何处应用。通过使用表达式或模式匹配,可以精确地指定在哪些方法、类或包上应用通知。
-
连接点(Join Point):连接点是程序执行过程中的某个阶段,例如方法的调用或异常的抛出。通知会在这些点上被触发。
-
织入(Weaving):织入是将切面与其他类型(如类和方法)结合在一起创建一个被通知的对象的过程。这可以在编译时、类加载时或运行时完成。
-
目标对象(Target Object):目标对象是被一个或多个切面通知的对象。
-
代理(Proxy):代理是一个被切面通知的对象。在运行时,AOP容器会为目标对象创建一个代理对象。
2.连接点的范围比切入点要大
完全正确。连接点的范围确实比切入点要大。
- 连接点(Join Point):连接点是程序中所有可能的插入点,包括所有的方法调用、构造函数调用、异常抛出等。它代表了程序中所有可以插入附加行为(如日志记录、事务处理等)的地方。
- 切入点(Pointcut):切入点则是从所有这些连接点中选择的一个子集。通过定义切入点,您可以精确地控制在哪些特定连接点上插入附加行为。
用一个简单的比喻来理解,可以把连接点看作是一本书中的所有单词,而切入点则是我选择的某些特定单词或短语。
在AOP的实际应用中,您可能不希望在每个连接点上都插入附加行为,因为这样可能会导致代码混乱和性能下降。通过定义切入点,您可以选择性地在特定连接点上插入附加行为,从而获得更精确的控制。
自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface OperateLog {
/* 类型,LOGIN-登录⽇志、OPERATION操作⽇志 */
String type() default "";
/* 日志内容 */
String value() default "";
/* 业务类型,业务⽅⾃⼰定义 */
String businessType() default "";
/* 登录用户类型 1 员工 2企业 3 会员(同up_sys_user)*/
int loginType() default 1;
}
链接:
https://gitee.com/jiang2360/city-government
链接: