1. AOP登录验证
AOP(aspect oriented programming 面向切面编程),什么是切面?打个比方,有两个堆在一起的积木,他们之间相接的面积就是切面,在Spring中,这里的切面可以理解为不同方法、不同类、甚至模块之间的公有部分,AOP即是处理不同方法、类、属性之间的交界问题,考虑将这些公共的问题分离出来,以保证业务逻辑正确。下面这张图就十分形象(Java中的面向切面编程(AOP)_切面java-CSDN博客)
在本项目中,注册、忘记密码、登录都需要用到参数校验(避免输入参数出现格式不对的低级错误),这三个方法都存在公有部分,比如邮箱格式、验证码格式的校验,因此可以考虑采用AOP减少代码复用,涉及的主要代码为GlobalInterceptor、VerifyParam、GlobalOperationAspect(负责拦截GlobalInterceptor方法注解,为什么不拦截VerifyParam?),这一部分有讲解aop实现参数校验_哔哩哔哩_bilibili
AOP代码的实现逻辑图是:
代码实现总结及备注:
如何根据注解来进行校验呢?注解其实就是加了标记,当切面代码通过反射获取所有的类之后,通过搜索,查找含有目标注解的方法,对这些方法进行操作(下图10-16行代码所示,为搜索含有GlobalInterceptor的类方法)。那么前面为什么不拦截VerifyParam呢?因为VerifyParam是一个参数的校验,不是方法,而pointcut注解是拦截方法的,对于 VerifyParam注解的操作是放在validateParams 方法中的。对于注解和反射的运行,可以参考 不懂注解?那就自己写一个,安排的明明白白_哔哩哔哩_bilibili
GlobalInterceptor部分代码
// 获取目标对象
Object target = point.getTarget();
// 获取方法参数
Object[] arguments = point.getArgs();
// 获取方法名
String methodName = point.getSignature().getName();
// 获取方法的参数类型
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
// 获取方法实例
Method method = target.getClass().getMethod(methodName, parameterTypes);
// 获取方法上的 @GlobalInterceptor 注解
GlobalInterceptor interceptor = method.getAnnotation(GlobalInterceptor.class);
//检查是否发现保含GlobalInterceptor注解的方法
if (null == interceptor) {
return;
}
- 注册操作
注册的代码逻辑如下:
总结及备注:
checkcode是图形校验码,emailcode是邮箱验证码,存到数据库的是emailcode,注册这一部分没有特别难以理解的,要特别注意邮箱验证码是有时效的,前端没有写,时间是15分钟,邮箱验证码是通过与数据库内存储的做的对比,这也是前面为什么会存储到数据库中,这个做法可以记录一下,不放在redis中,而是放到MySQL数据库中
EmailCodeServiceImpl部分代码
public void checkCode(String email, String code) {
EmailCode emailCode = emailCodeMapper.selectByEmailAndCode(email, code);
if (null == emailCode) {
throw new BusinessException("邮箱验证码不正确");
}
if (emailCode.getStatus() == 1 || System.currentTimeMillis() - emailCode.getCreateTime().getTime() > Constants.LENGTH_15 * 1000 * 60) {
throw new BusinessException("邮箱验证码已失效");
}
emailCodeMapper.disableEmailCode(email);
}
}
- 登录
登录的实现逻辑如下:
代码实现总结及备注:
(1)
EmailCodeServiceImpl部分代码
@RequestMapping("/login")
@GlobalInterceptor(checkLogin = false, checkParams = true)
public ResponseVO login(HttpSession session, HttpServletRequest request,
@VerifyParam(required = true) String email,
@VerifyParam(required = true) String password,
@VerifyParam(required = true) String checkCode) {
try {
if (!checkCode.equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY))) {
throw new BusinessException("图片验证码不正确");
}
SessionWebUserDto sessionWebUserDto = userInfoService.login(email, password);
session.setAttribute(Constants.SESSION_KEY, sessionWebUserDto);
return getSuccessResponseVO(sessionWebUserDto);
} finally {
session.removeAttribute(Constants.CHECK_CODE_KEY);
}
}
其中session.setAttribute(Constants.SESSION_KEY, sessionWebUserDto);
这行代码将sessionWebUserDto对象存储到当前会话中,使用Constants.SESSION_KEY作为键,想从当前会话中找到可以用getAttribute(KEY);