iT邦幫忙

0

【左京淳的JAVA WEB學習筆記】第十二章 用戶管理

如果用戶在登入畫面成功登入,則在session創建用戶對象及其購物車對象。
若失敗則返回登入頁面,提示重新登入。

新建LoginSvl

@WebServlet("/LoginSvl")
public class LoginSvl extends HttpServlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.getRequestDispatcher("/WEB-INF/main/login.jsp").forward(request, response);
  }
}

從首頁的登入按鈕觸發以下連結,呼叫LoginSvl的doGet()方法,轉發到login.jsp

localhost:8080/BookShop/LoginSvl

如果用戶在login.jsp輸入帳號密碼並送出,則會觸發doPost()方法。
編輯doPost()方法

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String uname = request.getParameter("uname");
    String pwd = request.getParameter("pwd");
    if(uname != null && pwd != null && !uname.equals("") && !pwd.equals("")) {
      UserBiz biz = new UserBiz();
      try {
        TUser user = biz.login(uname,pwd);
        if(user != null) {
          //登入成功
          request.getSession().setAttribute("user", user);
          Map<String,Integer> shopCar = new HashMap<String,Integer>();
          request.getSession().setAttribute("shopCar", shopCar);
          request.getRequestDispatcher("/MainSvl").forward(request, response);
        }else {
          //登入失敗
          request.setAttribute("msg", "用戶名或密碼錯誤");
          request.getRequestDispatcher("/WEB-INF/main/login.jsp").forward(request, response);
        }
      }catch(InputNullException e) {
        request.setAttribute("msg", e.getMessage());
        request.getRequestDispatcher("/WEB-INF/main/login.jsp").forward(request, response);
      }catch(Exception e) {
        Log.logger.error(e.getMessage(), e);
        request.setAttribute("msg", e.getMessage());
        request.getRequestDispatcher("/WEB-INF/main/login.jsp").forward(request, response);
      }
    }else {
      request.setAttribute("msg", "用戶名或密碼不能為空");
      request.getRequestDispatcher("/WEB-INF/main/login.jsp").forward(request, response);
    }
  }

新增UserBiz

  public TUser login(String uname, String pwd) throws Exception{
    TUser user = null;
    if(uname == null || pwd == null || uname.equals("") || pwd.equals("")) {
      throw new InputNullException("用戶名或密碼不能為空");
    }
    IUserDao dao = new UserDaoMysql();
    try {
      user = dao.login(uname,pwd);
    }finally{
      dao.closeConnection();
    }
    return user;
  }
}

新增UserDaoMysql

public class UserDaoMysql extends BaseDao {
  public TUser login(String uname,String pwd) throws Exception{
    TUser user = null;
    String sql = "select * from tuser where name = ? and pwd = ?";
    this.openConnection();
    PreparedStatement ps = this.connection.prepareStatement(sql);
    ps.setString(1, uname);
    ps.setString(2, pwd);
    ResultSet rs = ps.executeQuery();
    if(rs != null) {
      while(rs.next()) {
        user = new TUser();
        user.setUname(uname);
        user.setPwd(pwd);
        user.setAccount(rs.getDouble("account"));
        user.setRole(Integer.parseInt(rs.getString("role")));
        break;
      }
    }
    rs.close();
    ps.close();
    return user;
  }
}

用戶登出

當用戶點擊登出鈕,清空session並重定向至首頁。

新增LogoutSvl
需為已登入用戶才能登出,因此連結網址前綴需為/user/*,讓過濾器進行檢查。

@WebServlet("/user/LogoutSvl")
public class LogoutSvl extends HttpServlet {
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      request.getSession().invalidate();
      //request.getRequestDispatcher("/WEB-INF/main/main.jsp").forward(request, response);
      String path = request.getContextPath();
      String basePath = request.getScheme() + "://" + request.getServerName()  
      + ":" + request.getServerPort() + path + "/";
      response.sendRedirect(basePath + "MainSvl");
    }
}

記憶重點

  • 使用request.getSession().invalidate();讓session失效。
  • 使用response.sendRedirect(url);進行重定向。不使用轉發是為了讓url列更新。進行重定向需先準備好絕對路徑。

用戶註冊

在用戶註冊頁面,需校驗用戶名是否重複
使用AJAX搭配UnameCheckSvl進行校驗

新增regist.jsp頁面
使用input標籤的onkeyup方法觸發校驗函式。

<table>
  <tr>
    <td width="107" height="36">用戶名:</td>
    <td width="524">
      <input type="text" id="uname" name="uname" maxlength="16" onkeyup="unameValid()">
      <span id="unameAlert" style="color:red;font-size:8px"></span>
    </td>
  </tr>
  <tr>
    <td>密碼</td>
    <td><input type="password" name="pwd"></td>
  </tr>
  <tr>
    <td>密碼確認</td>
    <td><input type="password" name="pwd2"></td>
  </tr>
  <tr>
    <td><input type="submit" value="送出"></td>
    <td><a href="<%=basePath%>MainSvl>">返回</a></td>
  </tr>
</table>

編寫校驗函式

<script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.4.4.min.js"></script>
<script  type="text/javascript">
  function unameValid(){
    var uname = $('#uname').val();
    if(uname != ""){
      var destUrl = "<%=basePath%>UnameCheckSvl?uname=" + uname;
      $.ajax({
        type:"GET",
        url:destUrl,
        dataType:"text",
        timeout:3000,
        success:function(msg){
          if(msg == 0){
            $('#unameAlert').html('用戶名可用');
          }else if(msg == 1){
            $('#unameAlert').html('用戶名重複');
          }else if(msg == 2){
            $('#unameAlert').html('系統異常');
          }else{}
        },
        error:function(){
          alert("連線逾時");
        }
      });
    }
  }
</script>

記憶重點

  • 使用$('#uname').val();取得要校驗的資料
  • 事先準備好目標Servlet的url,並把要校驗的資料也加進去。
  • 使用jquery的 $.ajax({});招喚AJAX。

新增UnameCheckSvl

@WebServlet("/UnameCheckSvl")
public class UnameCheckSvl extends HttpServlet {    
  public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
      String uname = request.getParameter("uname");
      UserBiz biz = new UserBiz();
      PrintWriter out = response.getWriter();
      try {
        boolean bRet = biz.isHaveUserName(uname);
        if(bRet) {
          out.print("1"); //用戶名重複
        }else {
          out.print("2"); //用戶名可用
        }
      }catch(Exception e) {
        out.print("-1");
      }
      out.flush();
      out.close();
    }
}

校驗後使用response.getWriter();寫出結果。

在UserBiz內新增isHaveUserName(String uname)

  public boolean isHaveUserName(String uname) throws Exception{
    if(uname == null || uname.trim().equals("")) {
      throw new Exception("用戶名不能為空");
    }
    IUserDao dao = new UserDaoMysql();
    try {
      return dao.isHaveUserName(uname);
    }finally{
      dao.closeConnection();
    }
  }

在UserDaoMysql內新增isHaveUserName(String uname)

  public boolean isHaveUserName(String uname) throws Exception{
    boolean bFind = false;
    String sql = "select uname from tuser where uname = ?";
    this.openConnection();
    PreparedStatement ps = this.connection.prepareStatement(sql);
    ps.setString(1, uname);
    ResultSet rs = ps.executeQuery();
    while(rs.next()) {
      bFind = true;
      break;
    }
    rs.close();
    ps.close();
    return bFind;
  }

記憶重點

  • ResultSet在這邊沒有進行null判定。查了一下發現即便返回0件資料,也可以用while(rs.next())來確認,不會報空指針錯誤。
  • 進行null判定是當有處理要放在迴圈外時使用,例如new ArrayList<>()之類的。

註冊

校驗完成後即可進入註冊程序
修改regist.jsp

  <form action="<%=basePath%>RegistSvl" id="myform" onsubmit="return checkUserInfo()" method="post">
    <table border="0" cellpadding="0" cellspacing="0" align="center">
      <tr><td height="100"></td></tr>
      <tr>
        <td width="107" height="36">用戶名:</td>
        <td width="524"><input type="text" id="uname" name="uname"
          maxlength="16" onkeyup="unameValid()"> <span
          id="unameAlert" style="color: red; font-size: 8px"></span></td>
      </tr>
      <tr>
        <td width="107" height="36">密碼:</td>
        <td width="524"><input type="password" id="pwd" name="pwd"></td>
      </tr>
      <tr>
        <td width="107" height="36">確認密碼:</td>
        <td width="524"><input type="password" id="pwd2" name="pwd2"></td>
      </tr>
      <tr>
        <td colspan="2">
          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
          <input type="submit" value="送出">&nbsp;
          <a href="<%=basePath%>MainSvl>">返回</a>
        </td>
      </tr>
      <tr>
        <td colspan="2">
          <span style="color:red;font-size:8px">${msg }</span>
        </td>
      </tr>
    </table>
  </form>

記憶重點

  • 使用標籤來建立HTML表單
  • 表單可指定目標url
  • 表單可使用onsubmit()在送出前進行資料檢查
  • 使用來設定表單格式
    雖然不使用和也可以送出資料,不過正式的格式還是應該套用這些標籤。

新增js腳本checkUserInfo()

  function checkUserInfo(){
    var uname = $(#'uname').val();
    var pwd = $(#'pwd').val();
    var pwd2 = $(#'pwd2').val();
    if(uname == ""){
      alert("用戶名不能為空!");
      return false;
    }
    if(pwd == ""){
      alert("密碼不能為空!");
      return false;
    }
    if(pwd2 != pwd){
      alert("密碼不一致!");
      return false;
    }
  }

新建RegistSvl

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.getRequestDispatcher("/WEB-INF/main/regist.jsp").forward(request, response);
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String uname = request.getParameter("uname");
    String pwd = request.getParameter("pwd");
    UserBiz biz = new UserBiz();
    TUser user = new TUser();
    user.setUname(uname);
    user.setPwd(pwd);
    user.setRole(IRole.CUSER);
    try {
      biz.addUser(user);
      request.setAttribute("msg", "註冊成功,請重新登入");
      request.getRequestDispatcher("/WEB-INF/main/login.jsp").forward(request, response);
    }catch(java.sql.SQLIntegrityConstraintViolationException e){
      request.setAttribute("msg", "用戶名衝突,請重新輸入");
      request.getRequestDispatcher("/WEB-INF/main/regist.jsp").forward(request, response);
    }catch(Exception e) {
      request.setAttribute("msg", "系統忙碌中,請稍後再試");
      request.getRequestDispatcher("/WEB-INF/error.jsp").forward(request, response);
    }
  }

記憶重點,Servlet負責:

  • 取得表單參數
  • 叫服務層出來幹活
  • 依據處理結果將用戶導向不同網頁

修改UserBiz,新增addUser()

  public void addUser(TUser user) throws Exception{
    IUser dao = new UserDaoMysql();
    try {
      dao.addUser(user);
    }finally {
      dao.closeConnection();
    }
  }

記憶重點,Biz負責:

  • 叫DAO層出來幹活
  • 活做完關connection
  • 出問題使用throws Exception回報給Servlet

修改UserDaoMysql,新增addUser()

  public void addUser(TUser user) throws Exception{
    String sql = "insert into tuser values(?,?,?,?)";
    this.openConnection();
    PreparedStatement ps = this.connection.prepareStatement(sql);
    ps.setString(1, user.getUname());
    ps.setString(2, user.getPwd());
    ps.setDouble(3, user.getAccount());
    ps.setInt(4, IRole.CUSER);
    ps.executeUpdate();
    ps.close();
  }

記憶重點,Dao負責:

  • 準備好sql文
  • openConnection()
  • prepareStatement(sql)
  • 依照資料型態使用setString、setInt等方法將資料寫入prepareStatement物件
  • executeUpdate(),記得查詢(executeQuery)與編輯資料(executeUpdate)是不同指令。
  • close()

尚未有邦友留言

立即登入留言