前情回顧
之前跟着 github 上一個簡易商城項目練手的時候,發現原po老師在用戶注冊界面只設置了登錄、注冊選項,沒有修改密碼的按鈕,這對於我們的常識來說這個界面是做的還不夠的,在跟着實現完一遍商城項目后,自己添加了密碼修改這一選項。記錄具體思路和實現。
最開始的登錄界面:
想要實現成這樣的:
然后點擊 忘記密碼? 跳轉到修改密碼界面:
具體實現
由於這個操作是針對用戶的,所以直接在 UserSevice 接口里面添加一個 changePassword 方法:
1 void changePassword(String telephone, String password) throws BusinessException;
在其實現類里面,實現 changPassword 方法:
1. 根據電話獲取用戶,判斷該電話號碼是否注冊過,如果沒有注冊過,則拋出異常提示用戶,該電話尚未注冊。如果注冊過,則執行后面代碼。
2. 用戶的基本信息(id、姓名、電話、性別)和密碼信息(密碼、用戶id)存放在數據庫里不同的表里面,分別為 user_info 和 user_password。在利用Mybatis為對應表生成映射文件.xml、dao、dataobject的時候,就分別有兩種,基本信息映射和密碼信息映射,根據電話信息修改密碼,首先要根據電話獲取用戶id,然后在密碼信息映射文件中添加 sql 方法:
1 <update id="updateByUserIdSelective" parameterType="com.miaoshaproject.dataobject.UserPasswordDO"> 2 update user_password 3 <set> 4 <if test="encrptPassword != null"> 5 encrpt_password = #{encrptPassword,jdbcType=VARCHAR}, 6 </if> 7 <if test="userId != null"> 8 user_id = #{userId,jdbcType=INTEGER}, 9 </if> 10 </set> 11 where user_id = #{userId,jdbcType=INTEGER} 12 </update>
在其對應 dao 接口添加方法:
1 int updateByUserIdSelective(UserPasswordDO record);
這樣我們就可以在 UserServiceImpl 里根據用戶電話,更新用戶密碼了。
UserServiceImpl
1 @Override 2 @Transactional 3 public void changPassword(String telephone, String password) throws BusinessException { 4 // 根據電話獲取用戶,判斷該電話號碼是否注冊過,如果沒有注冊過,則拋出異常 5 UserDO userDO = userDOMapper.selectByTelephone(telephone); 6 if (userDO == null) { 7 throw new BusinessException(EnumBusinessError.USER_NOT_EXIST, "用戶還未注冊,請注冊"); 8 } 9 10 try { 11 // 根據 telephone 獲取 用戶id。 12 UserPasswordDO userPasswordDO = new UserPasswordDO(); 13 userPasswordDO.setEncrptPassword(password); 14 userPasswordDO.setUserId(userDOMapper.selectByTelephone(telephone).getId()); 15 // 需要在 UserPasswordDOMapper 里面添加根據用戶 id 更新密碼的方法嗎? 16 userPasswordDOMapper.updateByUserIdSelective(userPasswordDO); 17 } catch (Exception ex) { 18 System.out.println(ex); 19 } 20 }
控制層
1 // 用戶修改密碼接口 2 @RequestMapping(value = "/changePassword", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED}) 3 @ResponseBody 4 public CommonReturnType changePassword(@RequestParam(name = "telephone") String telephone, 5 @RequestParam(name = "otpCode") String otpCode, 6 @RequestParam(name = "password") String password 7 ) throws BusinessException { 8 9 // 驗證手機號和獲取到的 otpCode 相匹配 10 System.out.println("new otpCode:" + this.httpServletRequest.getSession().getAttribute(telephone)); 11 String inSessionOtpCode = (String) this.httpServletRequest.getSession().getAttribute(telephone); 12 if (!StringUtils.equals(otpCode, inSessionOtpCode)) { 13 throw new BusinessException(EnumBusinessError.PARAMETER_VALIDATION_ERROR, "短信驗證碼不匹配"); 14 } 15 16 // 如果匹配,則調用 service 服務進行修改密碼 17 userService.changPassword(telephone, this.EncodeByBase64(password)); 18 19 return CommonReturnType.create(null); 20 }
前端的展示頁面
由於在進行修改密碼的時候,用戶輸入手機號,獲取一個驗證信息 otpCode,這個過程和用戶最開始注冊的時候是一致的,新用戶注冊的時候輸入手機號后台也會傳一個 otpCode 給用戶,用來驗證身份。所以獲取 otpCode 這個接口代碼可以復用,但是問題來了,新用戶在注冊的時候,在獲取otpCode頁面,如果獲取成功,則直接跳轉用戶注冊界面,需要填寫所有的基本信息和密碼信息。成功后跳轉到登錄界面。但是對於修改密碼這一操作來說,獲取 otpCode 之后,應該跳轉到修改密碼頁面,只需要填寫用戶電話、otpCode、新密碼。然后再跳轉到登錄界面。該如何區分某個時刻的獲取 otpCode 界面是跳到新用戶注冊界面呢,還是修改密碼界面呢?
解決辦法是用戶在登錄界面點擊 忘記密碼? 之后, 直接跳轉到 修改密碼界面,該界面包含 獲取otpCode和提交修改兩個選項,分別對應后端的獲取 otpCode 接口和修改密碼接口,這樣后端的代碼就不會復用了。
登錄頁面代碼
1 <html> 2 <head> 3 <meta charset="UTF-8"> 4 <link href="static/assets/global/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"/> 5 <link href="static/assets/global/css/components.css" rel="stylesheet" type="text/css"/> 6 <link href="static/assets/admin/pages/css/login.css" rel="stylesheet" type="text/css"/> 7 <script src="static/assets/global/plugins/jquery-1.11.0.min.js" type="text/javascript"></script> 8 <title>Title</title> 9 </head> 10 <body class="login"> 11 <div class="content"> 12 <h3 class="form-title">用戶登錄</h3> 13 <div class="form-group"> 14 <label class="control-label">手機號</label> 15 <div> 16 <input class="form-control" type="text" placeholder="手機號" name="telephone" id="telephone"/> 17 </div> 18 </div> 19 <div class="form-group"> 20 <label class="control-label">密碼</label> 21 <div> 22 <input class="form-control" type="password" placeholder="密碼" name="password" id="password"/> 23 </div> 24 </div> 25 <div class="form-actions"> 26 <button class="btn blue" id="login" type="submit"> 27 登錄 28 </button> 29 <button class="btn green" id="register" type="submit"> 30 注冊 31 </button> 32 <button class="btn red" id="changePassword" type="submit"> 33 忘記密碼? 34 </button> 35 </div> 36 </div> 37 38 </body> 39 40 <script> 41 jQuery(document).ready(function () { 42 43 //綁定注冊按鈕的click事件用於跳轉到注冊頁面 44 $("#register").on("click",function () { 45 window.location.href = "getOtp.html"; 46 }); 47 48 //綁定登錄按鈕的click事件用於登錄 49 $("#login").on("click",function () { 50 51 var telephone=$("#telephone").val(); 52 var password=$("#password").val(); 53 if (telephone == null || telephone == "") { 54 alert("手機號不能為空"); 55 return false; 56 } 57 if (password==null || password=="") { 58 alert("密碼不能為空"); 59 return false; 60 } 61 62 //映射到后端@RequestMapping(value = "/login", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED}) 63 $.ajax({ 64 type:"POST", 65 contentType:"application/x-www-form-urlencoded", 66 url:"http://localhost:8090/user/login", 67 data:{ 68 "telephone":telephone, 69 "password":password 70 }, 71 xhrFields:{withCredentials:true}, 72 73 success:function (data) { 74 if (data.status == "success") { 75 alert("登錄成功"); 76 window.location.href = "listitem.html"; 77 }else { 78 alert("登錄失敗,原因為" + data.data.errMsg); 79 } 80 }, 81 error:function (data) { 82 alert("登錄失敗,原因為"+data.responseText); 83 } 84 }); 85 return false; 86 }); 87 88 //綁定 修改密碼按鈕 的click事件用於跳轉到獲取 changepassword 頁面 89 $("#changePassword").on("click",function () { 90 window.location.href = "changepassword.html"; 91 }); 92 93 }); 94 </script> 95 </html>
修改密碼界面
1 <html> 2 <head> 3 <meta charset="UTF-8"> 4 <link href="static/assets/global/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"/> 5 <link href="static/assets/global/css/components.css" rel="stylesheet" type="text/css"/> 6 <link href="static/assets/admin/pages/css/login.css" rel="stylesheet" type="text/css"/> 7 <script src="static/assets/global/plugins/jquery-1.11.0.min.js" type="text/javascript"></script> 8 <title>Title</title> 9 </head> 10 11 <body class="login"> 12 <div class="content"> 13 <h3 class="form-title">修改密碼</h3> 14 <div class="form-group"> 15 <label class="control-label">手機號</label> 16 <div> 17 <input class="form-control" type="text" placeholder="手機號" name="telephone" id="telephone"/> 18 </div> 19 </div> 20 <div class="form-group"> 21 <label class="control-label">點擊獲取驗證碼</label> 22 <div> 23 <input class="form-control" type="text" placeholder="驗證碼" name="otpCode" id="otpCode"/> 24 </div> 25 </div> 26 27 <div class="form-actions"> 28 <button class="btn blue" id="getOtp" type="submit"> 29 獲取otp短信 30 </button> 31 </div> 32 33 34 <div class="form-group"> 35 <label class="control-label">新密碼</label> 36 <div> 37 <input class="form-control" type="password" placeholder="密碼" name="password" id="password"/> 38 </div> 39 </div> 40 41 <div class="form-actions"> 42 <button class="btn blue" id="changePassword" type="submit"> 43 提交更改 44 </button> 45 </div> 46 </div> 47 48 </body> 49 50 <script> 51 jQuery(document).ready(function () { 52 53 //綁定otp的click事件用於向后端發送獲取手機驗證碼的請求 54 $("#getOtp").on("click",function () { 55 56 var telephone=$("#telephone").val(); 57 if (telephone==null || telephone=="") { 58 alert("手機號不能為空"); 59 return false; 60 } 61 62 //映射到后端@RequestMapping(value = "/getOtp", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED}) 63 $.ajax({ 64 type:"POST", 65 contentType:"application/x-www-form-urlencoded", 66 url:"http://localhost:8090/user/getOtp", 67 data:{ 68 "telephone":$("#telephone").val(), 69 }, 70 xhrFields:{withCredentials:true}, 71 success:function (data) { 72 if (data.status == "success") { 73 alert("otp已經發送到了您的手機,請注意查收"); 74 // window.location.href="register.html"; 75 }else { 76 alert("otp發送失敗,原因為" + data.data.errMsg); 77 } 78 }, 79 error:function (data) { 80 alert("otp發送失敗,原因為"+data.responseText); 81 } 82 }); 83 return false; 84 }); 85 86 //綁定 changePassword 按鈕的click事件 87 $("#changePassword").on("click",function () { 88 89 var telephone=$("#telephone").val(); 90 var otpCode=$("#otpCode").val(); 91 var password=$("#password").val(); 92 93 if (telephone==null || telephone=="") { 94 alert("手機號不能為空"); 95 return false; 96 } 97 if (otpCode==null || otpCode=="") { 98 alert("驗證碼不能為空"); 99 return false; 100 } 101 if (password==null || password=="") { 102 alert("密碼不能為空"); 103 return false; 104 } 105 106 //映射到后端@RequestMapping(value = "/changePassword", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED}) 107 $.ajax({ 108 type:"POST", 109 contentType:"application/x-www-form-urlencoded", 110 url:"http://localhost:8090/user/changePassword", 111 data:{ 112 "telephone":telephone, 113 "otpCode":otpCode, 114 "password":password, 115 }, 116 xhrFields:{withCredentials:true}, 117 success:function (data) { 118 if (data.status=="success") { 119 alert("修改成功"); 120 window.location.href = "login.html"; 121 }else { 122 alert("修改失敗,原因為" + data.data.errMsg); 123 } 124 }, 125 error:function (data) { 126 alert("修改失敗,原因為"+data.responseText); 127 } 128 }); 129 return false; 130 }); 131 }); 132 </script> 133 </html>
總結
emmmmm感覺還可以找到更好的解決方式,后面遇到了再來考慮下。