Ch13-1 : Change Email

[Email]

修改電子信箱這個功能,首先我們要先回顧我們原本的表單設計,member_main這個table,我們把email,這個欄位當作UNIQUE KEY使用,我們要讓這個欄位是唯一的資料,所以使用者修改電子信箱時,必須符合當時申請帳號的規範,該電子信箱不可重覆,只能存在一筆資料,在我們的資料庫,保證這個電子信箱,只會對應到一個人的帳號。

我們需要設計一個新的表單,去儲存使用者要修改的電子信箱,並且分成兩個階段,第一個階段是,輸入新電子信箱後,進行一些基本檢核,確認無誤之後,會寄送修改電子信箱信件到新信箱。第二階段是,我們需要從新的信箱,去點選修改密碼連結後,回到我們網站,我們網站需要輸入信件內的驗證碼,確保這份信件的正確性,若都填寫正確,將會更新相關表單,最後寄送修改電子信箱成功信到使用的新信箱。


[設計階段]

設計修改電子信箱,分成兩個兩階段,而每一個階段,都有兩個主要步驟需要處理,以及檢驗資料是否正確,以下是我設計出來的流程。

第一個階段

兩個主要步驟,拆分成使用者點選信箱功能時,首先要先出現原本電子信箱,已寄送修改新的電子信箱,還有使用者要自己填寫要修改的信箱,這部分會是1-1所要達成的項目。之後1-2所要達成的目標是,使用者填寫新的電子信箱時,需要檢核相關資訊是否正確,,確保使用者可以用新的電子信箱,進行後續驗證動作。還有一點要特別注意,這兩個動作都需要在登入狀態下,才能完成。

Stage 1-1

點選修改信箱功能,顯示相關資訊
若有尚未修改信箱且尚未逾期,也會顯示在畫面上

Step 1 : 驗證是否是登入狀態中(AuthCheck)
Step 2 : 抓取使用者memberNo
Step 3 : 抓取使用者註冊信箱,尚未認證信箱

Ok     : 顯示修改信箱頁面

---
Stage 1-2

開始進行修改電子信箱資料驗整

Step 1 : 驗證是否是登入狀態中(AuthCheck)
Step 2 : 是否有填新信箱
Step 3 : 信箱是否有填寫
Step 4 : 信箱檢查是否使用中

OK 1 : 產生更換信箱相關資料
Ok 2 : 寫入更換信箱表單
Ok 3 : 寄送更換信箱認證碼信件

第二個階段

一樣有兩個主要的步驟。第一個階段,最後完成時,會寄送修改電子信箱連結,當使用者點選信件修改信箱連結時,會檢核連結是否正確。連結檢驗證正確之後,使用者需要填入信件的驗證碼,確保我們寄到的電子信箱是正確無誤的,之後才會進行更新會員電子信箱動作。

Stage 2-1

重設電子信箱信件寄送回來後,顯示相關資訊

Step 1 : 檢查電子信箱信件連結是否有資料
Step 2 : 檢查Token,是否可以查詢到會員資料
Step 3 : 檢查Token,是否使用過了
Step 4 : 檢查Token,是否逾期了

OK : 檢查通過,可以進行重設電子信箱動作,並把Token儲存在表單裡

---

Stage 2-2

開始進行修改電子信箱資料驗證

Step 1 : 檢查電子信箱信件連結是否有資料
Step 2 : 檢查Token,是否可以查詢到會員資料
Step 3 : 檢查Token,是否使用過了
Step 4 : 檢查Token,是否逾期了
Step 5 : 驗證碼是否正確

Ok 1 : 寫入會員修改資料紀錄
Ok 2 : 會員的電子信箱進行更新
Ok 3 : 會員修改電子信箱表單,更新成使用過
Ok 4 : 寄信到新的電子信箱,已更新

[相關表單]

member_changeEmail,會員修改信箱表單,當使用者使用修改信箱的功能時,將會紀錄到這個表單。

-- 會員修改信箱
-- member_changeEmail
-- member_no  會員編號 (索引鍵)
-- oldEmail   舊信箱
-- newEmail   新信箱
-- token      驗證字串
-- checkCode  驗證碼
-- isUse      是否使用過
-- createDate 創立日期
-- expiryTime 逾期時間
CREATE TABLE `member_changeEmail` (
 `memberNo`        VARCHAR(15)  NOT NULL NULL COLLATE 'utf8_unicode_ci',
 `oldEmail`   VARCHAR(150) NOT NULL NULL COLLATE 'utf8_unicode_ci',
 `newEmail`   VARCHAR(150) NOT NULL NULL COLLATE 'utf8_unicode_ci',
 `token`      VARCHAR(150) NOT NULL NULL COLLATE 'utf8_unicode_ci',
 `checkCode`  VARCHAR(6)   NOT NULL NULL COLLATE 'utf8_unicode_ci',
 `isUse`      BOOL        NOT NULL NULL COLLATE 'utf8_unicode_ci',
 `createDate` VARCHAR(50)  NOT NULL NULL COLLATE 'utf8_unicode_ci',
 `expiryDate` VARCHAR(50)  NOT NULL NULL COLLATE 'utf8_unicode_ci',
 CONSTRAINT pk_memberNo PRIMARY KEY (memberNo),
 INDEX (token)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
;

[相關程式路徑]

app
 └ controllers
   └ WebController.java               <-- 新增ChangeEmail相關功能  
 └ pojo
   └ web 
     └ email 
       └ MemberChangeEmail.java       <-- 新增更換信箱pojo
         MemberSendChangeEmail.java   <-- 新增寄信相關pojo
 └ views
   └ web
     └ headerNav.scala.html           <-- 調整新增連結
     └ loginSignup
       └ authNewEmail.scala.html      <-- 第二階段,修改信箱,點選信件回來時的驗證頁面
         changeEmail.scala.html       <-- 第一階段,修改信箱主頁面
         changeEmailOk.scala.html     <-- 第二階段,修改信箱成功頁面
         sendChangeEmailOk.scala.html <-- 第一階段,申請修改信箱,寄信成功頁面
 └ utils
   └ signup 
     └ Utils_Signup.java      <--- 新增ChangeEmail相關功能  
       Utils_Email.java       <--- 新增寄信相關功能      
└ services
   └ Impl
     └ WebServiceImpl.java    <--- 實作WebService的新功能
   └ WebService.java          <--- 新增ChangeEmail相關功能  
└ conf
  └ routes                    <--- 新增相關服務路徑
  └ services
    └ WebService.xml          <--- 新增相關SQL

[相關程式]

app.pojo.web.email.MemberChangeEmail.java

使用者一進入修改信箱頁面的時候,需要顯示的相關內容,我們設計成pojo來使用

package pojo.web.email;

public class MemberChangeEmail {

  /** 原始信箱  */
  private String originalEmail;

  /** 尚未認證信箱 */
  private String unAuthEmail;

  /** 新信箱 */
  private String newEmail;

  public String getOriginalEmail() {
    return originalEmail;
  }

  public void setOriginalEmail(String originalEmail) {
    this.originalEmail = originalEmail;
  }

  public String getUnAuthEmail() {
    return unAuthEmail;
  }

  public void setUnAuthEmail(String unAuthEmail) {
    this.unAuthEmail = unAuthEmail;
  }

  public String getNewEmail() {
    return newEmail;
  }

  public void setNewEmail(String newEmail) {
    this.newEmail = newEmail;
  }


}

app.pojo.web.email.MemberSendChangeEmail.java

使用者填寫修改信箱成功時,我們要記錄相關的欄位資訊,儲存到資料表member_changeEmail,轉換成pojo來方便我的使用。

package pojo.web.email;

public class MemberSendChangeEmail {

  /** 會員編號*/
  private String memberNo;

  /** 原本信箱*/
  private String oldEmail;

  /** 新信箱*/
  private String newEmail;

  /** 信件token*/
  private String token;

  /** 驗證碼*/
  private String checkCode;

  /** 是否使用過*/
  private boolean isUse;

  /** 創立日期*/
  private String createDate;

  /** 逾期日期*/
  private String expiryDate;

  /** 資料庫時間*/
  private String dbTime;

  public String getMemberNo() {
    return memberNo;
  }

  public void setMemberNo(String memberNo) {
    this.memberNo = memberNo;
  }

  public String getOldEmail() {
    return oldEmail;
  }

  public void setOldEmail(String oldEmail) {
    this.oldEmail = oldEmail;
  }

  public String getNewEmail() {
    return newEmail;
  }

  public void setNewEmail(String newEmail) {
    this.newEmail = newEmail;
  }

  public String getToken() {
    return token;
  }

  public void setToken(String token) {
    this.token = token;
  }

  public String getCheckCode() {
    return checkCode;
  }

  public void setCheckCode(String checkCode) {
    this.checkCode = checkCode;
  }

  public boolean isUse() {
    return isUse;
  }

  public void setUse(boolean isUse) {
    this.isUse = isUse;
  }

  public String getCreateDate() {
    return createDate;
  }

  public void setCreateDate(String createDate) {
    this.createDate = createDate;
  }

  public String getExpiryDate() {
    return expiryDate;
  }

  public void setExpiryDate(String expiryDate) {
    this.expiryDate = expiryDate;
  }

  public String getDbTime() {
    return dbTime;
  }

  public void setDbTime(String dbTime) {
    this.dbTime = dbTime;
  }

}

app.services.WebService.java

新增修改電子信箱相關服務

import pojo.web.email.MemberChangeEmail;
import pojo.web.email.MemberSendChangeEmail;

...

  /** 更換信箱,撈取使用者信箱,尚未修改信箱 */
  public MemberChangeEmail getMemberEmails(@Param("memberNo")String memberNo);

  /** 寫入更換信箱相關資訊 */
  public int genMemberSendChangeEmail(@Param("data")MemberSendChangeEmail data);

  /** 撈取更換信箱表單相關資訊 */
  public MemberSendChangeEmail getMemberSendChangeEmailByToken(@Param("token")String token);

  /** 更新使用者的電子信箱 */
  public int updateMemberEmail(@Param("memberNo") String memberNo, @Param("newEmail") String newEmail);

...

app.services.Impl.WebServiceImpl.java

新增修改信箱相關實作

import pojo.web.email.MemberChangeEmail;
import pojo.web.email.MemberSendChangeEmail;

...


  @Override
  public MemberChangeEmail getMemberEmails(@Param("memberNo") String memberNo) {
    return this.webService.getMemberEmails(memberNo);
  }

  @Override
  public int genMemberSendChangeEmail(MemberSendChangeEmail data) {
    return this.webService.genMemberSendChangeEmail(data);
  }

  @Override
  public MemberSendChangeEmail getMemberSendChangeEmailByToken(@Param("token")String token){
    return this.webService.getMemberSendChangeEmailByToken(token);
  }

  @Override
  public int updateMemberEmail(@Param("memberNo")String memberNo , @Param("newEmail")String newEmail){
    return this.webService.updateMemberEmail(memberNo , newEmail);
  }

...

conf.services.WebService.xml

新增相關SQL指令。

...



     <!-- 更換信箱,撈取使用者信箱,尚未修改信箱,若有尚未修改信箱,且未逾期未使用,一樣顯示給使用者知道-->
    <select id="getMemberEmails" parameterType="String" resultType="pojo.web.email.MemberChangeEmail">
        SELECT
            (SELECT email FROM member_main WHERE memberNo = #{memberNo} ) AS originalEmail ,
            (SELECT newEmail FROM member_changeEmail 
              WHERE memberNo = #{memberNo} AND expiryDate > (DATE_FORMAT(NOW() , '%Y%m%d%H%i%s')) AND isUse = 0) AS unAuthEmail
        FROM DUAL
    </select>


    <!-- 會員更換電子信箱表單 -->
    <insert id="genMemberSendChangeEmail" parameterType="pojo.web.email.MemberSendChangeEmail">
        insert into
        member_changeEmail(memberNo , oldEmail , newEmail , token , checkCode , isUse , createDate , expiryDate)
        values
        ( 
            #{data.memberNo} , 
            #{data.oldEmail} ,
            #{data.newEmail} ,
            #{data.token} ,
            #{data.checkCode} ,
            #{data.isUse} ,
            #{data.createDate} ,
            #{data.expiryDate} 
        ) ON DUPLICATE KEY UPDATE 
        memberNo     = #{data.memberNo},
        oldEmail     = #{data.oldEmail},
        newEmail     = #{data.newEmail},
        token         = #{data.token},
        checkCode     = #{data.checkCode},
        isUse         = #{data.isUse},
        createDate  = #{data.createDate},
        expiryDate  = #{data.expiryDate}
    </insert>    


     <!-- 使用會員編號與密碼確認該會員存在 -->
    <select id="getMemberSendChangeEmailByToken" parameterType="String" resultType="pojo.web.email.MemberSendChangeEmail">
        SELECT * , DATE_FORMAT(NOW(),'%Y%m%d%H%i%s') as dbTime FROM member_changeEmail WHERE token = #{token}
    </select>


    <!--  更新會員電子信箱 -->
    <update id="updateMemberEmail">
        UPDATE member_main SET email = #{newEmail} WHERE memberNo = #{memberNo}
    </update>    
...

app.views.web.loginSignup.changeEmail.scala.html

第一階段,修改信箱主頁面,用來給使用者填入要修改的信箱。

@(data:pojo.web.email.MemberChangeEmail)

<!DOCTYPE html>
<html >
  <head>
    <meta charset="UTF-8">
    <title>修改信箱</title>

    @views.html.web.headerLibs()

    @views.html.web.loginSignup.loginSignupLibs()


  </head>

  <body>
    <div id="page-wrapper">
        <div id="select_nav_user">@views.html.web.headerNav()</div>
    </div>
    <div class="form">

      <ul class="tab-group">
        <li class="tab active"><a>修改信箱</a></li>
      </ul>
      <div class="tab-content">
        <div id="Form" > 
          <form action="@controllers.routes.WebController.changeEmail.url" method="post" id="changeEmailForm">
            <div class="field-wrap">
                <label class="lable-field-wrap">原本信箱</label>
                <input type="text" required autocomplete="off" name="originalEmail" value="@if(data!=null && data.getOriginalEmail()!=null){@data.getOriginalEmail()}" readonly/>
            </div>
            @if(data!=null && data.getUnAuthEmail()!=null){
                <div class="field-wrap">
                    <label class="lable-field-wrap">尚未認證新信箱</label>
                    <input type="text" required autocomplete="off" name="unAuthEmail" value="@data.getUnAuthEmail()" readonly/>
                </div>
            }
            <div class="field-wrap">
                <label class="lable-field-wrap">新信箱</label>
                <input type="email" required autocomplete="off" name="newEmail"/>
            </div>
            @if(flash.containsKey("error")) {
                <span style="color:red;">@flash.get("error")</span>
            }
            <a>
                <input type="submit" value="SUBMIT" class="button button-block">
            </a>
            </form>
        </div>
        </div><!-- tab-content -->   
    </div> <!-- /form -->
    <div id="titleBar"></div>
    <script src='@routes.Assets.versioned("javascripts/loginSignup.js")'></script>
    <script>
        $( document ).ready(function() {
            document.getElementById("editPasswordForm").reset();
        });
    </script>
  </body>
</html>

app.views.web.loginSignup.sendChangeEmailOk.scala.html

第一階段,修改信箱資訊填寫正確後,寄信給使用者後,成功畫面提示。

<!DOCTYPE html>
<html >
  <head>
    <meta charset="UTF-8">
    <title>寄送修改電子信箱</title>

    @views.html.web.headerLibs()

    @views.html.web.loginSignup.loginSignupLibs()


  </head>

  <body>
    <div id="page-wrapper">
        <div id="select_nav_user">@views.html.web.headerNav()</div>
    </div>
    <div class="form">

      <ul class="tab-group">
        <li class="tab active"><a href="#">寄送修改電子信箱</a></li>
      </ul>

      <div class="tab-content"> 
        <div id="signup">   
            <span>修改註冊信箱信件已寄出,請到新信箱進行收取信件,進行後續認證動作,謝謝。</span>
        </div> 
      </div><!-- tab-content -->   
    </div> <!-- /form -->
    <div id="titleBar"></div>
  </body>
</html>

app.views.web.loginSignup.authNewEmail.scala.html

第二階段,修改信箱,點選信件回來時的驗證頁面,使用這需要在這個頁面上,填寫信件內的驗證碼檢核。

@(token:String)
<!DOCTYPE html>
<html >
  <head>
    <meta charset="UTF-8">
    <title>更換電子信箱</title>

    @views.html.web.headerLibs()

    @views.html.web.loginSignup.loginSignupLibs()


  </head>

  <body>
    <div id="page-wrapper">
        <div id="select_nav_user">@views.html.web.headerNav()</div>
    </div>
    <div class="form">

      <ul class="tab-group">
        <li class="tab active"><a>更換電子信箱</a></li>
      </ul>
      <div class="tab-content">
        <div id="Form" > 
          <form action="@controllers.routes.WebController.doAuthNewEmail.url" method="post" id="doAuthNewEmailForm">
            <div class="field-wrap">
                <label class="lable-field-wrap">驗證碼</label>
                <input type="text" required autocomplete="off" name="checkCode"/>
                @if(flash.containsKey("error")) {
                    <span style="color:red;">@flash.get("error")</span>
                }
            </div>
            <h5>PS:請輸入信件內的驗證碼,完成認證動作。</h5>
            <input type="hidden" value="@token" name="token"/>
            <a>
                <input type="submit" value="SUBMIT" class="button button-block">
            </a>
            </form>
        </div>
        </div><!-- tab-content -->   
    </div> <!-- /form -->
    <div id="titleBar"></div>
    <script src='@routes.Assets.versioned("javascripts/loginSignup.js")'></script>
    <script>
        $( document ).ready(function() {
            document.getElementById("setPasswordForm").reset();
        });
    </script>
  </body>
</html>

app.views.web.loginSignup.changeEmailOk.scala.html

第二階段,修改信箱成功頁面。相關驗證正確後,會轉頁到信箱修改成功的頁面。

<!DOCTYPE html>
<html >
  <head>
    <meta charset="UTF-8">
    <title>修改電子信箱成功</title>

    @views.html.web.headerLibs()

    @views.html.web.loginSignup.loginSignupLibs()


  </head>

  <body>
    <div id="page-wrapper">
        <div id="select_nav_user">@views.html.web.headerNav()</div>
    </div>
    <div class="form">

      <ul class="tab-group">
        <li class="tab active"><a href="#">修改電子信箱成功</a></li>
      </ul>

      <div class="tab-content"> 
        <div id="signup">   
            <span>修改註冊信箱信件成功,請到回到首頁,重新登入,謝謝。</span>
        </div> 
      </div><!-- tab-content -->   
    </div> <!-- /form -->
    <div id="titleBar"></div>
  </body>
</html>

app.views.web.headerNav.scala.html

上面Menu新增修改信箱功能連結。

@import utils.session.Utils_Session; var utilsSession = new Utils_Session();

<!-- Nav -->
<nav id="nav">
    <ul>
        <li id="nav_index"><a href="@controllers.routes.WebController.index.url">首頁</a></li>
        <li id="nav_user">
            <a>我的世界</a>
            <ul>
                <li><a href="@controllers.routes.WebController.login.url">登入</a></li>
                @if(utilsSession.isClinetHaveCookie(request)){
                    <li><a href="@controllers.routes.WebController.editPassword.url">修改密碼</a></li>
                    <li><a href="@controllers.routes.WebController.editEmail.url">修改信箱</a></li>
                }
                <li><a href="@controllers.routes.WebController.logout.url">登出</a></li>
            </ul>
        </li>
        <li id="nav_signup">
            <a href="@controllers.routes.WebController.signup.url">註冊</a>
            <ul>
                <li><a href="@controllers.routes.WebController.resendAuthEmail.url">重發認證信</a></li>
                <li><a href="@controllers.routes.WebController.forgotPassword.url">忘記密碼</a></li>
            </ul>
        </li>
    </ul>
</nav>

...

app.controllers.WebController.java

相關的服務寫好之後,我們要開始寫實際的修改電子信箱流程,主要分成兩個階段。

第一個階段:填寫要修改的電子信箱,進行相關驗證後,寄送信件。

第二個階段:使用者點選修改信箱連結後,進行相關驗證後,進行修改信箱動作以及寄信。

...
import pojo.web.email.MemberChangeEmail;
import pojo.web.email.MemberSendChangeEmail;
...

  /**
   * <pre>
   *  Stage 1-1
   *  
   *  取得修改信箱頁面 
   *  若有尚未修改信箱且尚未逾期,會顯示在畫面上
   *  
   *  Step 1 : 驗證是否是登入狀態中(AuthCheck)
   *  Step 2 : 抓取使用者memberNo
   *  Step 3 : 抓取使用者註冊信箱,尚未認證信箱
   *  Ok     : 回傳結果到頁面
   * </pre>
   */
  @AuthCheck
  public Result editEmail(){

    // Step 2
    String memberNo = new Utils_Session().getUserNo();
    Logger.info("memberNo = " + memberNo);
    if( memberNo == null || "".equals(memberNo) ){
      flash().put("error", "系統忙碌中,請稍後再嘗試修改電子信箱,謝謝。0x2");
      return ok(changeEmail.render(null));
    }

    // Step 3
    MemberChangeEmail data = null;
    try{
      data = this.webService.getMemberEmails(memberNo);
    } catch (Exception e){
      e.printStackTrace();
      return ok(changeEmail.render(null));
    } finally {
      if(data==null || data.getOriginalEmail()==null  || "".equals(data.getOriginalEmail())){
        flash().put("error", "讀取會員資料忙碌中,請稍後再嘗試,謝謝。0x3");
        return ok(changeEmail.render(null));
      }
    }

    Logger.info("data = " + Json.toJson(data));

    return ok(changeEmail.render(data));
  } 


  /**
   * <pre>
   * Stage 1-2
   * 
   * Step 1 : 驗證是否是登入狀態中(AuthCheck)
   * Step 2 : 驗證表單資料
   * Step 3 : 信箱檢查是否註冊過或重覆
   * Step 4 : 信箱檢查是否使用中
   * OK 1 : 產生更換信箱相關資料
   * Ok 2 : 寫入更換信箱表單
   * Ok 3 : 寄送更換信箱認證碼信件
   *</pre> 
   */
  @AuthCheck
  public Result changeEmail(){ 

    // Step 2
    MemberChangeEmail data = null;
    try{
      data = formFactory.form(MemberChangeEmail.class).bindFromRequest().get();
    } catch(Exception e){
      e.printStackTrace();
    } finally {
      if(data==null){
        flash().put("error", "系統忙碌中,請稍後再嘗試修改電子信箱,謝謝。0x4");
        return ok(changeEmail.render(null));
      }
    }

    // Step 3
    if(data.getNewEmail()==null || "".equals(data.getNewEmail())){
      flash().put("error", "請填入要修改的信箱,謝謝。0x5");
      return ok(changeEmail.render(data));
    }

    // Step 4
    boolean isExists = false;
    Member member =null;
    try{
      isExists = this.webService.checkMemberByEmail(data.getNewEmail());
      member = this.webService.findMemberByMemberNo(new Utils_Session().getUserNo());
    } catch (Exception e){
      e.printStackTrace();
      flash().put("error", "系統忙碌中,請稍後再嘗試修改電子信箱,謝謝。0x6");
      return ok(changeEmail.render(data));
    } 
    if(isExists || data.getNewEmail().equals(member.getEmail())){
      flash().put("error", "該電子信箱使用中,請更換其他電子信箱,謝謝。0x7");
      return ok(changeEmail.render(data));
    }

    MemberSendChangeEmail sendData = null;
    int isWriteOk = 0;
    boolean isSendOk = false;
    try {
      // OK 1
      String memberNo = new Utils_Session().getUserNo();
      String oldEmail = data.getOriginalEmail();
      String newEmail = data.getNewEmail();
      sendData = new Utils_Signup().genMemberSendChangeEmail(memberNo, oldEmail, newEmail);
      if(sendData==null){
        flash().put("error", "產生修改信箱資料發生錯誤,請聯絡管理者,謝謝。0x8");
        return ok(changeEmail.render(data));
      }

      // OK 2
      isWriteOk = this.webService.genMemberSendChangeEmail(sendData);
      if(isWriteOk==0){
        flash().put("error", "產生寄信資料發生錯誤,請聯絡管理者,謝謝。0x9");
        return ok(changeEmail.render(data));
      }

      // OK 3
      Utils_Email utilsEmail = new Utils_Email(); 
      String userName = this.webService.findMemberByMemberNo(memberNo).getUsername();
      Email mail = utilsEmail.genMemberSendChangeEmailData(userName,sendData);
      isSendOk = utilsEmail.sendMail(mail);
      if(!isSendOk){
        flash().put("error", "寄送更換信箱信件發生錯誤,請重新使用修改信箱功能,謝謝。0x10");
        return ok(changeEmail.render(data));
      }

    } catch(Exception e) {
      e.printStackTrace();
      flash().put("error", "系統忙碌中,請稍後再嘗試修改電子信箱,謝謝。0x11");
      return ok(changeEmail.render(data));
    } finally {
      Logger.info("isWriteOk = " + isWriteOk + " , isSendOk = " + isSendOk + " , sendData = " + (sendData!=null ? Json.toJson(sendData) : "轉換傳送信件格式錯誤"));
    }

    return ok(sendChangeEmailOk.render());
  }


  /**
   * <pre>
   * Stage 2-1
   * 
   * 重設電子信箱信件寄送回來後
   * 
   * Step 1 : 檢查電子信箱信件連結是否有資料
   * Step 2 : 檢查Token,是否可以查詢到會員資料
   * Step 3 : 檢查Token,是否使用過了
   * Step 4 : 檢查Token,是否逾期了
   * OK : 檢查通過,可以進行重設電子信箱動作,並把Token儲存在表單裡
   * </pre>
   */
  public Result authNewEmail(){
    // 清除暫存錯誤訊息
    flash().clear();

    // Step 1
    String token = "";
    try{
      token = request().getQueryString("token");
    } catch (Exception e){
      e.printStackTrace();
      flash().put("error", "重設電子信箱連結有誤,請確認是否有點選正確,謝謝。0x1");
      return ok(authNewEmail.render(""));
    }

    // Step 2
    MemberSendChangeEmail data = null;
    try{
      data = webService.getMemberSendChangeEmailByToken(token);
    } catch(Exception e){
      e.printStackTrace();
      flash().put("error", "系統忙碌中,請稍候再嘗試,謝謝。");
      return ok(authNewEmail.render(""));
    } finally {
      if(data == null){
        flash().put("error", "重設電子信箱連結有誤,請確認是否有點選正確,謝謝。0x2");
        return ok(authNewEmail.render(""));
      }
    }

    // Step 3
    if(data.isUse()){
      flash().put("error", "重設電子信箱連結已失效,請重新使用修改信箱功能,謝謝。0x3");
      play.Logger.warn("memberToken  = " + Json.toJson(data));
      return ok(authNewEmail.render(""));
    }

    // Step 4
    long    dbTime      = Long.parseLong(data.getDbTime());     // 資料庫時間
    long    expiryDate  = Long.parseLong(data.getExpiryDate()); // 逾期時間
    play.Logger.info("dbTime = " + dbTime + ", expiryDate  = " + expiryDate);
    if(dbTime > expiryDate){
      flash().put("error", "重設電子信箱連結已經超過24小時,請重新使用修改信箱功能,謝謝。0x4");
      return ok(authNewEmail.render(""));
    } 

    // Ok
    return ok(authNewEmail.render(token));
  }


  /**
   * <pre>
   * Stage 2-2
   * 
   * 開始進行重設信子信箱
   * 
   * Step 1 : 檢查電子信箱信件連結是否有資料
   * Step 2 : 檢查Token,是否可以查詢到會員資料
   * Step 3 : 檢查Token,是否使用過了
   * Step 4 : 檢查Token,是否逾期了
   * Step 5 : 驗證碼是否正確
   * 
   * Ok 1 : 寫入會員修改資料紀錄
   * Ok 2 : 會員的電子信箱進行更新
   * Ok 3 : 會員修改電子信箱表單,更新成使用過
   * Ok 4 : 寄信到新的電子信箱,已更新
   * 
   * </pre>
   */
  public Result doAuthNewEmail(){
    // 清除暫存錯誤訊息
    flash().clear();

    // Step 1
    String token = "";
    try{
      token = formFactory.form().bindFromRequest().get().getData().get("token").toString();
    } catch (Exception e){
      e.printStackTrace();
      flash().put("error", "重設電子信箱連結有誤,請確認是否有點選正確,謝謝。0x1");
      return ok(authNewEmail.render(""));
    }

    // Step 2
    MemberSendChangeEmail data = null;
    try{
      data = webService.getMemberSendChangeEmailByToken(token);
    } catch(Exception e){
      e.printStackTrace();
      flash().put("error", "系統忙碌中,請稍候再嘗試,謝謝。");
      return ok(authNewEmail.render(""));
    } finally {
      if(data == null){
        flash().put("error", "重設電子信箱連結有誤,請確認是否有點選正確,謝謝。0x2");
        return ok(authNewEmail.render(""));
      }
    }

    // Step 3
    if(data.isUse()){
      flash().put("error", "重設電子信箱連結已失效,請重新使用修改信箱功能,謝謝。0x3");
      play.Logger.warn("memberToken  = " + Json.toJson(data));
      return ok(authNewEmail.render(""));
    }

    // Step 4
    long    dbTime      = Long.parseLong(data.getDbTime());     // 資料庫時間
    long    expiryDate  = Long.parseLong(data.getExpiryDate()); // 逾期時間
    play.Logger.info("dbTime = " + dbTime + ", expiryDate  = " + expiryDate);
    if(dbTime > expiryDate){
      flash().put("error", "重設電子信箱連結已經超過24小時,請重新使用修改信箱功能,謝謝。0x4");
      return ok(authNewEmail.render(""));
    } 

    // Step 5
    String checkCode = "";
    try{
      checkCode = formFactory.form().bindFromRequest().get().getData().get("checkCode").toString();
    } catch (Exception e){
      e.printStackTrace();
      flash().put("error", "系統忙碌中,請稍候再嘗試,謝謝。");
      return ok(authNewEmail.render(""));
    }
    if(!data.getCheckCode().equals(checkCode)){
      flash().put("error", "驗證碼輸入錯誤,請重新輸入,謝謝。0x5");
      return ok(authNewEmail.render(token));
    }

    int isLogMemberOk = 0;
    int isUpdateEmailOk = 0;
    int isUpdateUseOk = 0;
    boolean isSendOk = false;

    try{
      // Ok 1
      Member beforeUpdatemember = this.webService.findMemberByMemberNo(data.getMemberNo());
      isLogMemberOk = this.webService.genMemberChangeLog(beforeUpdatemember);

      // Ok 2
      String memberNo = data.getMemberNo();
      String newEmail = data.getNewEmail();
      isUpdateEmailOk = this.webService.updateMemberEmail(memberNo,newEmail);
      if(isUpdateEmailOk==0){
        flash().put("error", "更新會員資料發生錯誤,請聯絡管理者,謝謝。0x6");
        return ok(authNewEmail.render(token));
      }

      // Ok 3
      data.setUse(true);
      isUpdateUseOk = this.webService.genMemberSendChangeEmail(data);
      if(isUpdateUseOk==0){
        flash().put("error", "更新會員資料發生錯誤,請聯絡管理者,謝謝。0x7");
        return ok(authNewEmail.render(token));
      }

      // Ok 4
      Utils_Email utilsEmail = new Utils_Email(); 
      Member afterUpdateMember = this.webService.findMemberByMemberNo(memberNo);
      Email mail = utilsEmail.genMemberChangeEmailOk(afterUpdateMember);
      isSendOk = utilsEmail.sendMail(mail);

    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      play.Logger.info("isLogMemberOk = " + isLogMemberOk + " , isUpdateEmailOk = " + isUpdateEmailOk  + 
                       " , isUpdateUseOk = " + isUpdateUseOk + " , isSendOk = " + isSendOk);
    }

    // Clear cookie
    new Utils_Session().clearClientCookie(response());

    return ok(changeEmailOk.render());
  }

conf.routes

相關的程式都已經就位,我們最後要把相關的網站服務路徑,寫到routes上,確保我們的服務可以被呼叫到。

# http://127.0.0.1:9000/web/editEmail
GET    /web/editEmail                        controllers.WebController.editEmail()

# http://127.0.0.1:9000/web/changeEmail
POST    /web/changeEmail                    controllers.WebController.changeEmail()

# http://127.0.0.1:9000/web/authNewEmail
GET    /web/authNewEmail                    controllers.WebController.authNewEmail()

# http://127.0.0.1:9000/web/doAuthNewEmail
POST    /web/authNewEmail                    controllers.WebController.doAuthNewEmail()

[Stage 1-1 ~ 1-2 Test Case]

CASE 1 : 抓取使用者memberNo錯誤

CASE 2 : 抓取使用者註冊信箱,尚未認證信箱

CASE 3 :驗證表單資料失敗

CASE 4 : 信箱是否有填寫

CASE 5 : 信箱檢查是否使用中

CASE 6 : 產生修改信箱資料發生錯誤

CASE 7 : 產生寄信資料發生錯誤

CASE 8 : 寄送更換信箱信件發生錯誤

OK : 以上檢核成功,會成功寄出修改電子信箱信件,且轉到成功寄信頁面。這樣我們第一個階段,就算是完成了,接下來就是使用者,從信件點選修改電子信箱連結,進行後續驗證動作


[Test Case 2-1~2-2]

CASE 1 : 檢查電子信箱信件連結是否有資料

CASE 2 : 檢查Token,是否可以查詢到會員資料

CASE 3 : 檢查Token,是否使用過了

CASE 4 : 檢查Token,是否逾期了

CASE 5 : 驗證碼是否正確

CASE 6 : 更新會員信箱資料發生錯誤

CASE 7 : 更新會員修改電子信箱表單發生錯誤

OK :第二階段,以上都檢核完畢,會進行四個動作,1.寫入會員修改資料紀錄、2.更新會員的電子信箱、3.會員修改電子信箱表單,更新成使用過、4.寄信到新的電子信箱。提示使用者這些動作都完成之後,他的信箱就會成功更換成新的電子信箱。


[Final]

以上就是使用者進行更換電子信箱的相關流程與實作,下一個小節,我們將會讓使用者,填寫更完善詳細的會員資料。

results matching ""

    No results matching ""