文章目录
- 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;// 验证码图片Bufferprivate 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;// 图像bufferbuffImg = 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";@Resourceprivate UserInfoService userInfoService;@Resourceprivate 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层
@Overridepublic 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);}
@Overridepublic 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);}