java springboot郵箱找回密碼功能的實(shí)現(xiàn)講解
一、主要內(nèi)容
基于springboot實(shí)現(xiàn)密碼找回功能。
二、郵箱找回密碼的思想
1.輸入注冊(cè)郵箱,點(diǎn)擊獲取驗(yàn)證碼。會(huì)將驗(yàn)證碼發(fā)送到郵箱。
2.用戶(hù)進(jìn)入郵箱,查看驗(yàn)證碼。
3.用戶(hù)輸入驗(yàn)證碼,輸入新密碼,點(diǎn)擊修改密碼,完成修改。
三、前臺(tái)頁(yè)面


四、注意事項(xiàng)
如果是163或者qq郵箱需要打開(kāi)授權(quán),以163為例:



如果是阿里的企業(yè)郵箱,則不用打開(kāi)

五、部分實(shí)現(xiàn)代碼
pom.xml 添加依賴(lài)
<dependency> ?? ?<groupId>org.springframework.boot</groupId> ?? ?<artifactId>spring-boot-starter-mail</artifactId> </dependency>
application.properties 配置文件
#這里使用的是阿里企業(yè)郵箱 spring.mail.host=smtp.qiye.aliyun.com spring.mail.username=****@XXXX.com spring.mail.password=123456
5.1 頁(yè)面代碼
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="expires" content="0">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta charset="UTF-8" />
<title>重置密碼</title>
</head>
<body>
<div class="login-bg"></div>
<div class="login-box-reset-pss">
<div class="logbox-left-pss fl">
<div class="logbox-logos-pss">
<img class="sch-logo" src="/images/login_logo.png" alt="" onerror="javascript:this.src='/images/login_logo.png'" />
</div>
</div>
<div class="logbox-right fr">
<div class="title">重置密碼</div>
<div class="inputbar">
<input type="text" class="form-control-reset-pss" id="loginNameReset" placeholder="郵箱">
</div>
<div class="inputbar">
<input type="text" class="form-control-reset-pss" id="verificationCode" placeholder="驗(yàn)證碼">
<span class="js-reset-captcha btn-captcha" id="btn-captcha">獲取驗(yàn)證碼</span>
</div>
<div class="inputbar">
<input type="password" class="form-control-reset-pss" id="newLoginPwd" placeholder="新密碼">
</div>
<div class="inputbar">
<input type="password" class="form-control-reset-pss" id="confirmloginPwd" placeholder="確認(rèn)新密碼">
</div>
<div class="logbtn"><button type="button" class="fl btn" id="loginIdReset" style="width:100%;height:100%;">保存</button></div>
<div class="logbox-error" style="display:;">您輸入的用戶(hù)名或密碼有誤,請(qǐng)重新輸入!</div>
</div>
</div>
</body>5.2 發(fā)送驗(yàn)證碼到注冊(cè)郵箱的代碼
前臺(tái)代碼:
/**
* 獲取驗(yàn)證碼
*/
$el_btnVc.on('click', function(){
var data = {
loginNameReset: $.trim($el_loginReset.val())
}
if(MC.isEmpty(data.loginNameReset)){
return msg_fn('請(qǐng)輸入您的用戶(hù)名!');
}
if (data.loginNameReset.indexOf('.com') > 0 || data.loginNameReset.indexOf('.cn') > 0){
if (!reg_mail.test(data.loginNameReset)){
return msg_fn('請(qǐng)您輸入正確的郵箱!');
}
data.resetType = '1';
} else {
if (data.loginNameReset.length != 11){
return msg_fn('請(qǐng)您輸入正確的手機(jī)號(hào)!');
}
data.resetType = '0';
}
// verificationMailOrPhone(data);
reset_getCode(data);
});
/**
* 獲取重置密碼的驗(yàn)證碼
* @param data
*/
var reset_getCode = function(data){
$.ajax({
url: window.mcConfig.DATA_HOST,
type: 'post',
dataType: 'json',
// async: false,
data: {
eventType: "web.teacher.user.resetPassword.code",
entity: MC.json.encode(data)
},
success: function(rsp) {
if (parseInt(rsp.err) == 0) {
// window.location.href = data.callback + rsp.code;
MC.msg('info', '驗(yàn)證碼已經(jīng)發(fā)送成功!');
} else {
msg_fn(rsp.errMsg || '您輸入的用戶(hù)名或密碼有誤,請(qǐng)重新輸入!');
}
},
error: function(response) {
if (!response.error) {
MC.msg('alert', "系統(tǒng)后臺(tái)異常,請(qǐng)與管理員聯(lián)系!", 'warn');
}
}
});
};后臺(tái)代碼:
controller層
/**
* 獲取重置密碼的驗(yàn)證碼
* @param entity
* @param request
* @param response
* @return
*/
@RequestMapping(value = "/getCode", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, Object> getCode(String entity, HttpServletRequest request, HttpServletResponse response) throws MessagingException {
return userService.getCode(JsonUtil.jsonToMap(entity)).toMap(setting);
}service層:
@Autowired
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String mailUserName;
/**
* 獲取重置密碼需要的驗(yàn)證碼
* @param map
* @return
*/
public ProcResult getCode(Map<String, Object> map) throws MessagingException {
String loginNameReset = StringUtil.toString(map.get("loginNameReset")).trim();
if (StringUtil.isEmpty(loginNameReset)){
return ProcResult.error(ErrorCode.USER_LOGIN_NAME_EMPTY);
}
List<Teacher> list = getTeacherByMailOrPhoneNumber(loginNameReset,map.get("resetType").toString());
if (list == null || list.size() == 0) {
return ProcResult.error(ErrorCode.LOGIN_USER_NOT_EXISTS_ERROR);
}
if (list.size() > 1) {
return ProcResult.error(ErrorCode.USER_NOT_ONE_ERROR);
}
Teacher teacher = list.get(0);
String verifyCode = String.valueOf(new Random().nextInt(899999) + 100000);//生成短信驗(yàn)證碼
Timestamp outDate = new Timestamp(System.currentTimeMillis() + 5 * 60 * 1000);// 5分鐘后過(guò)期
//將驗(yàn)證碼 和 過(guò)期時(shí)間更新到數(shù)據(jù)庫(kù)
teacher.setCodeExpiredTime(outDate);
teacher.setValidataCode(verifyCode);
teacherDao.update(teacher);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<html><head><title></title></head><body>");
stringBuilder.append("您好<br/>");
stringBuilder.append("您的驗(yàn)證碼是:").append(verifyCode).append("<br/>");
stringBuilder.append("您可以復(fù)制此驗(yàn)證碼并返回至XXX,以驗(yàn)證您的郵箱。<br/>");
stringBuilder.append("此驗(yàn)證碼只能使用一次,在5分鐘內(nèi)有效。驗(yàn)證成功則自動(dòng)失效。<br/>");
stringBuilder.append("如果您沒(méi)有進(jìn)行上述操作,請(qǐng)忽略此郵件。");
MimeMessage mimeMessage = mailSender.createMimeMessage();
//發(fā)送驗(yàn)證碼到手機(jī)或者是郵箱
if ("1".equals(map.get("resetType"))){ //郵箱
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage,true);
mimeMessageHelper.setFrom(mailUserName);//這里只是設(shè)置username 并沒(méi)有設(shè)置host和password,因?yàn)閔ost和password在springboot啟動(dòng)創(chuàng)建JavaMailSender實(shí)例的時(shí)候已經(jīng)讀取了
mimeMessageHelper.setTo(loginNameReset);
mimeMessage.setSubject("郵箱驗(yàn)證-XXX");
mimeMessageHelper.setText(stringBuilder.toString(),true);
mailSender.send(mimeMessage);
}else if ("0".equals(map.get("resetType"))){ //手機(jī)
}
return ProcResult.success();
}郵箱截圖:

5.3 修改密碼
前臺(tái)代碼:
/**
* lpw
* 重置密碼登錄操作
*/
$el_btnRt.on('click', function(){
var reg_mail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/;//郵箱格式是否正確
var data = {
loginNameReset: $.trim($el_loginReset.val()),
newPassword : $.trim($el_npwd.val()),
confirmNewPassword : $.trim($el_cnpwd.val()),
verificationCode : $.trim($el_vc.val())
}
if(MC.isEmpty(data.loginNameReset)){
return msg_fn('請(qǐng)輸入您的用戶(hù)名!');
}
if(MC.isEmpty(data.verificationCode)){
return msg_fn('請(qǐng)輸入驗(yàn)證碼!');
}
if (data.loginNameReset.indexOf('.com') > 0 || data.loginNameReset.indexOf('.cn') > 0){
if (!reg_mail.test(data.loginNameReset)){
return msg_fn('請(qǐng)您輸入正確的郵箱!');
}
data.resetType = '1';
} else {
if (data.loginNameReset.length != 11){
return msg_fn('請(qǐng)您輸入正確的手機(jī)號(hào)!');
}
data.resetType = '0';
}
if(MC.isEmpty(data.newPassword)){
return msg_fn('請(qǐng)輸入您的新密碼!');
}
if(MC.isEmpty(data.confirmNewPassword)){
return msg_fn('請(qǐng)確認(rèn)您的新密碼!');
}
if(data.confirmNewPassword != data.newPassword){
return msg_fn('兩次輸入的密碼不一致!');
}
MC.require('md5', function(exports){
data.newPassword = hex_md5(data.newPassword);
data.confirmNewPassword = hex_md5(data.confirmNewPassword);
reset_PassWord(data);
});
});
/**
* 修改密碼
* @param data
*/
var reset_PassWord = function(data){
$.ajax({
url: window.mcConfig.DATA_HOST,
type: 'post',
dataType: 'json',
// async: false,
data: {
eventType: "web.teacher.user.resetPassword.resetPassword",
entity: MC.json.encode(data)
},
success: function(rsp) {
if (parseInt(rsp.err) == 0) {
MC.msg('info', '密碼修改成功,請(qǐng)重新登錄!');
} else {
msg_fn(rsp.errMsg || '您輸入的用戶(hù)名或驗(yàn)證碼有誤,請(qǐng)重新輸入!');
}
},
error: function(response) {
if (!response.error) {
MC.msg('alert', "系統(tǒng)后臺(tái)異常,請(qǐng)與管理員聯(lián)系!", 'warn');
}
}
});
};controller層:
/**
* 修改密碼
* @param entity
* @param request
* @param response
* @return
*/
@RequestMapping(value = "/resetPassword", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, Object> resetPassword(String entity, HttpServletRequest request, HttpServletResponse response) {
return userService.resetPassword(JsonUtil.jsonToMap(entity)).toMap(setting);
}service層:
/**
* 重新設(shè)置密碼
* @param map
* @return
*/
public ProcResult resetPassword(Map<String, Object> map) {
String loginNameReset = StringUtil.toString(map.get("loginNameReset")).trim();
if (StringUtil.isEmpty(loginNameReset)){
return ProcResult.error(ErrorCode.USER_LOGIN_NAME_EMPTY);
}
String newPassword = StringUtil.toString(map.get("newPassword")).trim();
if (StringUtils.isEmpty(newPassword)) {
return ProcResult.error(ErrorCode.USER_PASSWORD_EMPTY);
}
String verificationCode = StringUtil.toString(map.get("verificationCode")).trim();
if (StringUtils.isEmpty(verificationCode)) {
return ProcResult.error(ErrorCode.VERIFICATION_CODE_EMPTY);
}
List<Teacher> list = getTeacherByMailOrPhoneNumber(loginNameReset,map.get("resetType").toString());
if (list == null || list.size() == 0) {
return ProcResult.error(ErrorCode.LOGIN_USER_NOT_EXISTS_ERROR);
}
if (list.size() > 1) {
return ProcResult.error(ErrorCode.USER_NOT_ONE_ERROR);
}
Teacher teacher = list.get(0);
if (teacher.getValidataCode() == null || "".equals(teacher.getValidataCode())){
return ProcResult.error(ErrorCode.VERIFICATION_CODE_EMPTY);
}
//判斷驗(yàn)證碼是否還有效
Date codeExpiredTime = teacher.getCodeExpiredTime();
Date date = new Date();
if (date.getTime() > codeExpiredTime.getTime() || "0".equals(teacher.getValidataCode())){
return ProcResult.error(ErrorCode.VERIFICATION_CODE_INVALID);
}
//判斷驗(yàn)證碼是否正確
if (!verificationCode.equals(teacher.getValidataCode())){
return ProcResult.error(ErrorCode.VERIFICATION_CODE_ERROR);
}
//通過(guò)用戶(hù)no查詢(xún)user信息
QueryConds queryConds = new QueryConds();
queryConds.cond("userNo", teacher.getUserNo(), QueryOp.EQUAL);
queryConds.cond("del", ECommon.NO_DEL);
List<User> listUser = userDao.findUserByConds(queryConds);
if (listUser == null || listUser.size() == 0) {
return ProcResult.error(ErrorCode.LOGIN_USER_NOT_EXISTS_ERROR);
}
if (listUser.size() > 1) {
return ProcResult.error(ErrorCode.USER_NOT_ONE_ERROR);
}
User user = listUser.get(0);
//修改密碼
user.setPassword(newPassword);
user.setUpdateTime(date);
userDao.update(user);
//失效當(dāng)前驗(yàn)證碼
teacher.setValidataCode("0");
teacher.setUpdateTime(date);
teacherDao.update(teacher);
return ProcResult.success();
}OK,至此,郵箱修改密碼功能就完成了。
總結(jié)
在不使用spring-boot-starter-mail發(fā)送郵件的時(shí)候,需要在代碼中設(shè)置host和password

spring-boot-starter-mail只需要在配置文件中配置,在啟動(dòng)springboot的會(huì)去配置文件讀取host和password屬性。不需要再代碼中顯性設(shè)置。如果不配置springboot啟動(dòng)會(huì)報(bào)錯(cuò):
#這里使用的是阿里企業(yè)郵箱 spring.mail.host=smtp.qiye.aliyun.com spring.mail.username=****@XXXX.com spring.mail.password=123456

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Spring Boot使用redis實(shí)現(xiàn)數(shù)據(jù)緩存
本篇文章主要介紹了詳解Spring Boot使用redis實(shí)現(xiàn)數(shù)據(jù)緩存,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04
關(guān)于注解FeignClient的使用規(guī)范
這篇文章主要介紹了關(guān)于注解FeignClient的使用規(guī)范,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
ConditionalOnProperty注解的作用和使用方式
在SpringBoot項(xiàng)目開(kāi)發(fā)中,@ConditionalOnProperty注解允許根據(jù)配置文件中的屬性值來(lái)控制配置類(lèi)是否生效,該注解通過(guò)屬性name和havingValue來(lái)判斷配置是否注入,如果application.properties中的對(duì)應(yīng)屬性值為空或不匹配havingValue設(shè)定值2024-09-09
JDBC簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
什么是JDBC?這篇文章就為大家詳細(xì)介紹了Java語(yǔ)言中用來(lái)規(guī)范客戶(hù)端程序如何來(lái)訪問(wèn)數(shù)據(jù)庫(kù)的應(yīng)用程序接口,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
Spring MVC學(xué)習(xí)教程之RequestMappingHandlerAdapter詳解
這篇文章主要給大家介紹了關(guān)于Spring MVC學(xué)習(xí)教程之RequestMappingHandlerAdapter的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
Spring中配置ContextLoaderListener方式
這篇文章主要介紹了Spring中配置ContextLoaderListener方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-04-04
java多線(xiàn)程加鎖以及Condition類(lèi)的使用實(shí)例解析
這篇文章主要介紹了java多線(xiàn)程加鎖以及Condition類(lèi)的使用實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11

