文章目录
- 4.2登录注册模块设计
- 4.2.1获取验证码
- (1)思路
- (2)接口
- (3)controller层
- (4)CreateImageCodeUtils工具类
- (5)测试结果
- 4.2.2发送邮箱验证码
- (1)接口
- (2)controller层
- (3)service层
- 4.2.3基于AOP实现参数校验
- (1)添加切面依赖
- (2)自定义注解—标识哪些类需要被增强
- (3)定义切面、切点、切点表达式、通知
- 4.2.4登录
- (1)登录接口
- (2)controller层
- (3)service层
- 4.2.5注册
- (1)接口
- (2)controller层
- (3)service层
- 4.2.6重置密码
- (1)接口
- (2)controller层
- (3)service层
4.2登录注册模块设计
4.2.1获取验证码
(1)思路
- 思路:在登录页面和注册页面均为涉及到一个图片验证码的输入,防止用户拿到该接口去重复刷,避免系统崩溃
(2)接口
-
获取验证码接口:Get请求
http://localhost:7090/api/checkCode?type=0
-
提交参数
- type为0:获取登录注册页面的验证码
- type为1:获取将要验证邮箱的验证码
- 区别在于后端在返回session时,设置的key值不同,type为1即将要验证邮箱,当用户输入该验证码后,后端去session中取check_code_key_email为key的值与用户输入的验证码比较,而不是取注册页面的验证码与其比较
(3)controller层
@RequestMapping(value = "/checkCode")
public void checkCode(HttpServletResponse response, HttpSession session, Integer type) throws IOException {
CreateImageCodeUtils vCode = new CreateImageCodeUtils(130, 38, 5, 10);
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
String code = vCode.getCode();
if (type == null || type == 0) {
//该验证码为登录注册页面的验证码
session.setAttribute(Constants.CHECK_CODE_KEY, code);
} else {
//该验证码为验证邮箱的验证码
session.setAttribute(Constants.CHECK_CODE_KEY_EMAIL, code);
}
vCode.write(response.getOutputStream());
}
(4)CreateImageCodeUtils工具类
- com.easy.entity.utils.CreateImageCodeUtils类(通用)
public class CreateImageCodeUtils {
// 图片的宽度。
private int width = 160;
// 图片的高度。
private int height = 40;
// 验证码字符个数
private int codeCount = 4;
// 验证码干扰线数
private int lineCount = 20;
// 验证码
private String code = null;
// 验证码图片Buffer
private BufferedImage buffImg = null;
Random random = new Random();
public CreateImageCodeUtils() {
creatImage();
}
public CreateImageCodeUtils(int width, int height) {
this.width = width;
this.height = height;
creatImage();
}
public CreateImageCodeUtils(int width, int height, int codeCount) {
this.width = width;
this.height = height;
this.codeCount = codeCount;
creatImage();
}
public CreateImageCodeUtils(int width, int height, int codeCount, int lineCount) {
this.width = width;
this.height = height;
this.codeCount = codeCount;
this.lineCount = lineCount;
creatImage();
}
// 生成图片
private void creatImage() {
int fontWidth = width / codeCount;// 字体的宽度
int fontHeight = height - 5;// 字体的高度
int codeY = height - 8;
// 图像buffer
buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = buffImg.getGraphics();
//Graphics2D g = buffImg.createGraphics();
// 设置背景色
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
// 设置字体
//Font font1 = getFont(fontHeight);
Font font = new Font("Fixedsys", Font.BOLD, fontHeight);
g.setFont(font);
// 设置干扰线
for (int i = 0; i < lineCount; i++) {
int xs = random.nextInt(width);
int ys = random.nextInt(height);
int xe = xs + random.nextInt(width);
int ye = ys + random.nextInt(height);
g.setColor(getRandColor(1, 255));
g.drawLine(xs, ys, xe, ye);
}
// 添加噪点
float yawpRate = 0.01f;// 噪声率
int area = (int) (yawpRate * width * height);
for (int i = 0; i < area; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
buffImg.setRGB(x, y, random.nextInt(255));
}
String str1 = randomStr(codeCount);// 得到随机字符
this.code = str1;
for (int i = 0; i < codeCount; i++) {
String strRand = str1.substring(i, i + 1);
g.setColor(getRandColor(1, 255));
// g.drawString(a,x,y);
// a为要画出来的东西,x和y表示要画的东西最左侧字符的基线位于此图形上下文坐标系的 (x, y) 位置处
g.drawString(strRand, i * fontWidth + 3, codeY);
}
}
// 得到随机字符
private String randomStr(int n) {
String str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
String str2 = "";
int len = str1.length() - 1;
double r;
for (int i = 0; i < n; i++) {
r = (Math.random()) * len;
str2 = str2 + str1.charAt((int) r);
}
return str2;
}
// 得到随机颜色
private Color getRandColor(int fc, int bc) {// 给定范围获得随机颜色
if (fc > 255) fc = 255;
if (bc > 255) bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
/**
* 产生随机字体
*/
private Font getFont(int size) {
Random random = new Random();
Font font[] = new Font[5];
font[0] = new Font("Ravie", Font.PLAIN, size);
font[1] = new Font("Antique Olive Compact", Font.PLAIN, size);
font[2] = new Font("Fixedsys", Font.PLAIN, size);
font[3] = new Font("Wide Latin", Font.PLAIN, size);
font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, size);
return font[random.nextInt(5)];
}
// 扭曲方法
private void shear(Graphics g, int w1, int h1, Color color) {
shearX(g, w1, h1, color);
shearY(g, w1, h1, color);
}
private void shearX(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(2);
boolean borderGap = true;
int frames = 1;
int phase = random.nextInt(2);
for (int i = 0; i < h1; i++) {
double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
g.copyArea(0, i, w1, 1, (int) d, 0);
if (borderGap) {
g.setColor(color);
g.drawLine((int) d, i, 0, i);
g.drawLine((int) d + w1, i, w1, i);
}
}
}
private void shearY(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(40) + 10; // 50;
boolean borderGap = true;
int frames = 20;
int phase = 7;
for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
g.copyArea(i, 0, 1, h1, 0, (int) d);
if (borderGap) {
g.setColor(color);
g.drawLine(i, (int) d, i, 0);
g.drawLine(i, (int) d + h1, i, h1);
}
}
}
public void write(OutputStream sos) throws IOException {
ImageIO.write(buffImg, "png", sos);
sos.close();
}
public BufferedImage getBuffImg() {
return buffImg;
}
public String getCode() {
return code.toLowerCase();
}
}
(5)测试结果
4.2.2发送邮箱验证码
(1)接口
-
发送邮箱验证码接口:Post
http://localhost:7090/api/sendEmailCode
-
编码格式:
multipart/form-data
-
请求参数:
(2)controller层
- 获取session域中名为check_code_key_email的值,比较与用户输入的checkCode值是否相同,不同则输入图片验证码不正确
- 相同则调用 EmailCodeService的sendEmailCode()方法
@RequestMapping("/sendEmailCode")
@GlobalInterceptor(checkLogin = false, checkParams = true)
public ResponseVO sendEmailCode(HttpSession session,
@VerifyParam(required = true, regex = VerifyRegexEnum.EMAIL, max = 150) String email,
@VerifyParam(required = true) String checkCode,
@VerifyParam(required = true) Integer type) {
try {
if (!checkCode.equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY_EMAIL))) {
throw new BusinessException("图片验证码不正确");
}
emailCodeService.sendEmailCode(email, type);
return getSuccessResponseVO(null);
} finally {
session.removeAttribute(Constants.CHECK_CODE_KEY_EMAIL);
}
}
(3)service层
- EmailCodeServiceImpl的sendEmailCode方法
- 首先若是注册用户,则校验邮箱是否存在
- 通过工具类随机生成五位数;再执行发送邮箱的真正逻辑
@Override
@Transactional(rollbackFor = Exception.class)
public void sendEmailCode(String toEmail, Integer type) {
//如果是注册,校验邮箱是否已存在
if (type == Constants.ZERO) {
UserInfo userInfo = userInfoMapper.selectByEmail(toEmail);
if (null != userInfo) {
throw new BusinessException("邮箱已经存在");
}
}
String code = StringTools.getRandomNumber(Constants.LENGTH_5);
sendEmailCode(toEmail, code);
emailCodeMapper.disableEmailCode(toEmail);
EmailCode emailCode = new EmailCode();
emailCode.setCode(code);
emailCode.setEmail(toEmail);
emailCode.setStatus(Constants.ZERO);
emailCode.setCreateTime(new Date());
emailCodeMapper.insert(emailCode);
}
-
发送邮箱的真正逻辑
-
导入依赖:
<!--邮件发送--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> <version>${springboot.version}</version> </dependency>
-
配置邮件发送者信息、密码:
# 配置邮件服务器的地址 smtp.qq.com spring.mail.host=smtp.qq.com # 配置邮件服务器的端口(465或587) spring.mail.port=587 # 配置用户的账号 spring.mail.username=改成自己的 # 配置用户的密码 spring.mail.password=改成自己的(推荐使用qq邮箱的授权登录密码)
-
使用自动注入的MimeMessageHelper对象、MimeMessage对象来发送邮件
-
通过AppConfig类加载yml配置好的邮件发送者信息
-
重要:Redis存放邮件中固定的格式,RedisComponent.getSysSettingsDto()、以及SysSettingDto类:
public SysSettingsDto getSysSettingsDto() { SysSettingsDto sysSettingsDto = (SysSettingsDto) redisUtils.get(Constants.REDIS_KEY_SYS_SETTING) if (sysSettingsDto == null) { sysSettingsDto = new SysSettingsDto(); redisUtils.set(Constants.REDIS_KEY_SYS_SETTING, sysSettingsDto); } return sysSettingsDto; }
@JsonIgnoreProperties(ignoreUnknown = true) public class SysSettingsDto implements Serializable { /** * 注册发送邮件标题 */ private String registerEmailTitle = "【微网盘】—系统注册邮件"; /** * 注册发送邮件内容 */ private String registerEmailContent = "您好,非常感谢您注册微网盘账号!您的验证码为 %s ,为了保证您账号的安全性,该验证码有效期为15分钟!"; /** * 用户初始化空间大小 5M */ private Integer userInitUseSpace = 5; }
发送邮件核心代码
private void sendEmailCode(String toEmail, String code) { try { MimeMessage message = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); //邮件发件人 helper.setFrom(appConfig.getSendUserName()); //邮件收件人 1或多个 helper.setTo(toEmail); //获取邮件内容格式 SysSettingsDto sysSettingsDto = redisComponent.getSysSettingsDto(); //邮件主题 helper.setSubject(sysSettingsDto.getRegisterEmailTitle()); //邮件内容 helper.setText(String.format(sysSettingsDto.getRegisterEmailContent(), code)); //邮件发送时间 helper.setSentDate(new Date()); //发送邮件 javaMailSender.send(message); } catch (Exception e) { logger.error("邮件发送失败", e); throw new BusinessException("邮件发送失败"); } }
-
-
4.2.3基于AOP实现参数校验
(1)添加切面依赖
<!--切面-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectjweaver.version}</version>
</dependency>
(2)自定义注解—标识哪些类需要被增强
- com.easypan.annotation.GlobalInterceptor
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface GlobalInterceptor {
/**
* 校验登录
*/
boolean checkLogin() default true;
/**
* 校验参数
*/
boolean checkParams() default false;
/**
* 校验管理员
*/
boolean checkAdmin() default false;
}
(3)定义切面、切点、切点表达式、通知
- com.easypan.aspect.GlobalOperationAspect
@Component("operationAspect")
@Aspect
public class GlobalOperationAspect {
private static Logger logger = LoggerFactory.getLogger(GlobalOperationAspect.class);
private static final String TYPE_STRING = "java.lang.String";
private static final String TYPE_INTEGER = "java.lang.Integer";
private static final String TYPE_LONG = "java.lang.Long";
@Resource
private UserInfoService userInfoService;
@Resource
private AppConfig appConfig;
/**
* @Description: 1、requestInterceptor()方法为切点
* 2、@annotation(com.easypan.annotation.GlobalInterceptor) 为切点表达式
* 3、只有在执行带有 @GlobalInterceptor注解的方法时,才会触发 requestInterceptor()方法中的逻辑
*/
@Pointcut("@annotation(com.easypan.annotation.GlobalInterceptor)")
private void requestInterceptor() {
}
//通知
@Before("requestInterceptor()")
public void interceptorDo(JoinPoint point) throws BusinessException {
try {
Object target = point.getTarget(); //返回被代理的目标对象,即拦截器拦截的目标方法所属的对象实例
Object[] arguments = point.getArgs(); //方法返回被拦截方法的参数数组
String methodName = point.getSignature().getName(); //获取被拦截方法的 Method 对象的名称
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes(); //返回方法的参数类型数组
Method method = target.getClass().getMethod(methodName, parameterTypes); //通过method名称和参数数组获取 方法对象
GlobalInterceptor interceptor = method.getAnnotation(GlobalInterceptor.class); //获取该方法上的GlobalInterceptor注解
if (null == interceptor) {
return;
}
/**
* 检查是否需要 校验登录
* 当GlobalInterceptor注解的checkLogin的属性为True 或 checkAdmin属性为true,即需要检验登录
*/
if (interceptor.checkLogin() || interceptor.checkAdmin()) {
checkLogin(interceptor.checkAdmin());
}
/**
* 检查是否需要 校验请求路径参数
* 当GlobalInterceptor注解的checkParams的属性为True,即需要检验请求路径参数
*/
if (interceptor.checkParams()) {
validateParams(method, arguments);
}
} catch (BusinessException e) {
logger.error("全局拦截器异常", e);
throw e;
} catch (Exception e) {
logger.error("全局拦截器异常", e);
throw new BusinessException(ResponseCodeEnum.CODE_500);
} catch (Throwable e) {
logger.error("全局拦截器异常", e);
throw new BusinessException(ResponseCodeEnum.CODE_500);
}
}
}
- 校验登录: checkLogin(Boolean checkAdmin)
//校验登录
private void checkLogin(Boolean checkAdmin) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpSession session = request.getSession();
SessionWebUserDto sessionUser = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);
//果当前处于开发模式下,并且没有用户登录信息,则尝试自动登录第一个查询到的用户信息
if (sessionUser == null && appConfig.getDev() != null && appConfig.getDev()) {
List<UserInfo> userInfoList = userInfoService.findListByParam(new UserInfoQuery());
if (!userInfoList.isEmpty()) {
UserInfo userInfo = userInfoList.get(0);
sessionUser = new SessionWebUserDto();
sessionUser.setUserId(userInfo.getUserId());
sessionUser.setNickName(userInfo.getNickName());
sessionUser.setAdmin(true);
session.setAttribute(Constants.SESSION_KEY, sessionUser);
}
}
//查到的sessionUser仍为空
if (null == sessionUser) {
throw new BusinessException(ResponseCodeEnum.CODE_901); //登录超时
}
if (checkAdmin && !sessionUser.getAdmin()) {
throw new BusinessException(ResponseCodeEnum.CODE_404);//普通用户访问管理员页面,请求地址不存在
}
}
-
校验请求参数validateParams
-
注意:补充@VerifyParam注解:com.easypan.annotation.VerifyParam
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PARAMETER, ElementType.FIELD}) public @interface VerifyParam { /** * 校验正则 * * @return */ VerifyRegexEnum regex() default VerifyRegexEnum.NO; /** * 最小长度 * * @return */ int min() default -1; /** * 最大长度 * * @return */ int max() default -1; boolean required() default false; }
/**
* @Description: 校验方法的参数
* @Parm: Method m:增强方法对象;Object[] arguments:增强方法的参数数组
*/
private void validateParams(Method m, Object[] arguments) throws BusinessException {
Parameter[] parameters = m.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Object value = arguments[i];
VerifyParam verifyParam = parameter.getAnnotation(VerifyParam.class); //获取每个参前面的@VerifyParam注解
if (verifyParam == null) {
//没有加@VerifyParam注解
continue;
}
//基本数据类型
if (TYPE_STRING.equals(parameter.getParameterizedType().getTypeName()) || TYPE_LONG.equals(parameter.getParameterizedType().getTypeName()) || TYPE_INTEGER.equals(parameter.getParameterizedType().getTypeName())) {
checkValue(value, verifyParam);
} else {
//如果传递的是对象
checkObjValue(parameter, value);
}
}
}
- 校验基本数据类型
/**
* 校验参数
*/
private void checkValue(Object value, VerifyParam verifyParam) throws BusinessException {
Boolean isEmpty = value == null || StringUtils.isEmpty(value.toString());
Integer length = value == null ? 0 : value.toString().length();
/**
* 校验空
*/
if (isEmpty && verifyParam.required()) {
throw new BusinessException(ResponseCodeEnum.CODE_600);
}
/**
* 校验长度
*/
if (!isEmpty && (verifyParam.max() != -1 && verifyParam.max() < length || verifyParam.min() != -1 && verifyParam.min() > length)) {
throw new BusinessException(ResponseCodeEnum.CODE_600);
}
/**
* 校验正则
*/
if (!isEmpty && !StringUtils.isEmpty(verifyParam.regex().getRegex()) && !VerifyUtils.verify(verifyParam.regex(), String.valueOf(value))) {
throw new BusinessException(ResponseCodeEnum.CODE_600);
}
}
- 校验对象
private void checkObjValue(Parameter parameter, Object value) {
try {
String typeName = parameter.getParameterizedType().getTypeName();
Class classz = Class.forName(typeName);
Field[] fields = classz.getDeclaredFields();
for (Field field : fields) {
VerifyParam fieldVerifyParam = field.getAnnotation(VerifyParam.class);
if (fieldVerifyParam == null) {
continue;
}
field.setAccessible(true);
Object resultValue = field.get(value);
checkValue(resultValue, fieldVerifyParam);
}
} catch (BusinessException e) {
logger.error("校验参数失败", e);
throw e;
} catch (Exception e) {
logger.error("校验参数失败", e);
throw new BusinessException(ResponseCodeEnum.CODE_600);
}
}
4.2.4登录
(1)登录接口
-
登录接口:Post请求
http://localhost:7090/api/login
-
编码格式:
multipart/form-data
-
提交参数:
(2)controller层
/**
* @Description: 登录
*/
@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);
}
}
(3)service层
@Override
public SessionWebUserDto login(String email, String password) {
UserInfo userInfo = this.userInfoMapper.selectByEmail(email);
if (null == userInfo || !userInfo.getPassword().equals(password)) {
throw new BusinessException("账号或者密码错误");
}
if (UserStatusEnum.DISABLE.getStatus().equals(userInfo.getStatus())) {
throw new BusinessException("账号已禁用");
}
UserInfo updateInfo = new UserInfo();
updateInfo.setLastLoginTime(new Date());
this.userInfoMapper.updateByUserId(updateInfo, userInfo.getUserId());
SessionWebUserDto sessionWebUserDto = new SessionWebUserDto();
sessionWebUserDto.setNickName(userInfo.getNickName());
sessionWebUserDto.setUserId(userInfo.getUserId());
if (ArrayUtils.contains(appConfig.getAdminEmails().split(","), email)) {
sessionWebUserDto.setAdmin(true);
} else {
sessionWebUserDto.setAdmin(false);
}
//用户空间
UserSpaceDto userSpaceDto = new UserSpaceDto();
userSpaceDto.setUseSpace(fileInfoService.getUserUseSpace(userInfo.getUserId()));
userSpaceDto.setTotalSpace(userInfo.getTotalSpace());
redisComponent.saveUserSpaceUse(userInfo.getUserId(), userSpaceDto);
return sessionWebUserDto;
}
4.2.5注册
(1)接口
-
注册接口:Post
http://localhost:7090/api/register
-
编码格式:
multipart/form-data
-
请求参数:
(2)controller层
@RequestMapping("/register")
@GlobalInterceptor(checkLogin = false, checkParams = true)
public ResponseVO register(HttpSession session,
@VerifyParam(required = true, regex = VerifyRegexEnum.EMAIL, max = 150) String email,
@VerifyParam(required = true, max = 20) String nickName,
@VerifyParam(required = true, regex = VerifyRegexEnum.PASSWORD, min = 8, max = 18) String password,
@VerifyParam(required = true) String checkCode,
@VerifyParam(required = true) String emailCode) {
try {
if (!checkCode.equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY))) {
throw new BusinessException("图片验证码不正确");
}
userInfoService.register(email, nickName, password, emailCode);
return getSuccessResponseVO(null);
} finally {
session.removeAttribute(Constants.CHECK_CODE_KEY);
}
}
(3)service层
- 检验邮箱是否已经存在
- 检验昵称是否已经存在
- 校验邮箱验证码 :
@Override
@Transactional(rollbackFor = Exception.class)
public void register(String email, String nickName, String password, String emailCode) {
UserInfo userInfo = this.userInfoMapper.selectByEmail(email);
if (null != userInfo) {
throw new BusinessException("邮箱账号已经存在");
}
UserInfo nickNameUser = this.userInfoMapper.selectByNickName(nickName);
if (null != nickNameUser) {
throw new BusinessException("昵称已经存在");
}
//校验邮箱验证码
emailCodeService.checkCode(email, emailCode);
String userId = StringUtils.getRandomNumber(Constants.LENGTH_10);
userInfo = new UserInfo();
userInfo.setUserId(userId);
userInfo.setNickName(nickName);
userInfo.setEmail(email);
userInfo.setPassword(StringUtils.encodeByMD5(password));
userInfo.setJoinTime(new Date());
userInfo.setStatus(UserStatusEnum.ENABLE.getStatus());
SysSettingsDto sysSettingsDto = redisComponent.getSysSettingsDto();
userInfo.setTotalSpace(sysSettingsDto.getUserInitUseSpace() * Constants.MB);
userInfo.setUseSpace(0L);
this.userInfoMapper.insert(userInfo);
}
@Override
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);
}
4.2.6重置密码
(1)接口
-
重置密码接口:
http://localhost:7090/api/resetPwd
-
编码格式:
multipart/form-data
-
请求参数:
(2)controller层
@RequestMapping("/resetPwd")
@GlobalInterceptor(checkLogin = false, checkParams = true)
public ResponseVO resetPwd(HttpSession session,
@VerifyParam(required = true, regex = VerifyRegexEnum.EMAIL, max = 150) String email,
@VerifyParam(required = true, regex = VerifyRegexEnum.PASSWORD, min = 8, max = 18) String password,
@VerifyParam(required = true) String checkCode,
@VerifyParam(required = true) String emailCode) {
try {
if (!checkCode.equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY))) {
throw new BusinessException("图片验证码不正确");
}
userInfoService.resetPwd(email, password, emailCode);
return getSuccessResponseVO(null);
} finally {
session.removeAttribute(Constants.CHECK_CODE_KEY);
}
}
(3)service层
@Override
@Transactional(rollbackFor = Exception.class)
public void resetPwd(String email, String password, String emailCode) {
UserInfo userInfo = this.userInfoMapper.selectByEmail(email);
if (null == userInfo) {
throw new BusinessException("邮箱账号不存在");
}
//校验邮箱验证码
emailCodeService.checkCode(email, emailCode);
UserInfo updateInfo = new UserInfo();
updateInfo.setPassword(StringUtils.encodeByMD5(password));
this.userInfoMapper.updateByEmail(updateInfo, email);
}