家居網購專案實作02
5.功能04-會員登錄
5.1需求分析/圖解
需求如圖:

- 輸入用戶名、密碼后提交
- 判斷該用戶是否存在
- 如果存在,顯示登錄成功頁面
- 否則回傳登錄頁面,要求重新登錄
- 要求改進登錄密碼為md5加密
5.2思路分析
5.3代碼實作
根據上述分析圖,在對應的層添加方法
5.3.1dao層
-
修改MemberDAO介面,宣告queryMemberByUsernameAndPassword()方法
//提供一個通過用戶名和密碼回傳對應的Member的方法 public Member queryMemberByUsernameAndPassword(String username,String password); -
修改MemberDAOImpl實作類,實作queryMemberByUsernameAndPassword()方法
/** * 通過用戶名和密碼回傳對應的Member物件 * * @param username 用戶名 * @param password 密碼 * @return 回傳值為對應的Member物件,如果不存在則回傳null */ @Override public Member queryMemberByUsernameAndPassword(String username, String password) { String sql = "SELECT * FROM `member` WHERE `username`=? AND `password`=MD5(?);"; return querySingle(sql, Member.class, username, password); } -
在utils包中的MemberDAOImplTest類中增加測驗方法
@Test public void queryMemberByUsernameAndPassword() { Member member = memberDAO.queryMemberByUsernameAndPassword ("king", "king"); System.out.println("member=" + member); }
代碼測驗通過
5.3.2service層
-
修改MemberService介面,宣告login方法
//登錄用戶 //相比于直接傳遞用戶名和密碼,傳遞一個Member物件拓展性會比較好一些 public Member login(Member member); -
修改MemberServiceImpl介面實作類,實作login方法
/** * 根據登錄傳入的member資訊,回傳對應的在資料庫中的member物件 * * @param member * @return 回傳的是資料庫中的member物件,若不存在則回傳null */ @Override public Member login(Member member) { return memberDAO.queryMemberByUsernameAndPassword (member.getUsername(), member.getPassword()); } -
在utils包中的MemberServiceImplTest類中增加測驗方法
@Test public void login() { Member member = memberService.login (new Member(null, "admin", "admin", null)); System.out.println("member=" + member); }
代碼測驗通過
5.3.3web層
-
配置loginServlet
<servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>com.li.furns.web.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/loginServlet</url-pattern> </servlet-mapping> -
創建LoginServlet
package com.li.furns.web; import com.li.furns.entity.Member; import com.li.furns.service.MemberService; import com.li.furns.service.impl.MemberServiceImpl; import javax.servlet.*; import javax.servlet.http.*; import java.io.IOException; public class LoginServlet extends HttpServlet { private MemberService memberService = new MemberServiceImpl(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.接收用戶名和密碼 //如果前端輸入的是null,后臺接收的資料為空串"" String username = request.getParameter("username"); String password = request.getParameter("password"); //構建一個member物件 Member member = new Member(null, username, password, null); //2.呼叫MemberServiceImpl的login方法 if (memberService.login(member) == null) {//資料庫中沒有該用戶,回傳登錄頁面 //注意路徑 request.getRequestDispatcher("/views/member/login.html") .forward(request, response); } else { //否則,跳轉到登錄成功頁面 request.getRequestDispatcher("/views/member/login_ok.html") .forward(request, response); } } }
5.4完成測驗
6.功能05-登錄錯誤提示,表單回顯
6.1需求分析/圖解
- 輸入用戶名,密碼后提交
- 如果輸入有誤,則給出提示
- 在登錄表單回顯用戶名
6.2思路分析
在5.2分析圖的基礎上修改如下兩處:
6.3代碼實作
6.3.1web層
-
修改LoginServlet,將錯誤提示和用戶名放入request域中
package com.li.furns.web; import com.li.furns.entity.Member; import com.li.furns.service.MemberService; import com.li.furns.service.impl.MemberServiceImpl; import javax.servlet.*; import javax.servlet.http.*; import java.io.IOException; public class LoginServlet extends HttpServlet { private MemberService memberService = new MemberServiceImpl(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.接收用戶名和密碼 //如果前端輸入的是null,后臺接收的資料為空串"" String username = request.getParameter("username"); String password = request.getParameter("password"); //構建一個member物件 Member member = new Member(null, username, password, null); //2.呼叫MemberServiceImpl的login方法 if (memberService.login(member) == null) {//資料庫中沒有該用戶,回傳登錄頁面 //登錄失敗,將錯誤資訊和登錄會員名放入request域中 request.setAttribute("errInfo", "登錄失敗,用戶名或者密碼錯誤"); request.setAttribute("username", username); //注意路徑 request.getRequestDispatcher("/views/member/login.jsp") .forward(request, response); } else { //否則,跳轉到登錄成功頁面 request.getRequestDispatcher("/views/member/login_ok.html") .forward(request, response); } } } -
將login.html改為login.jsp(檔案右鍵Refactor-->Rename,在彈窗中點擊Do Refactor,會把其他檔案參考login.html的資訊自動改為login.jsp)
部分代碼,詳細代碼請看 https://github.com/liyuelian/furniture_mall.git
<div > <%--提示錯誤資訊--%> <span style="float: right; font-weight: bold; font-size: 20pt; margin-left: 10px;"> ${requestScope.errInfo} </span> <form action="loginServlet" method="post"> <input type="text" name="username" placeholder="Username" value="https://www.cnblogs.com/liyuelian/p/${requestScope.username}"/> <input type="password" name="password" placeholder="Password"/> <div > <div > <input type="checkbox"/> <a href="javascript:void(0)">Remember me</a> <a href="https://www.cnblogs.com/liyuelian/p/#">Forgot Password?</a> </div> <button type="submit"><span>Login</span></button> </div> </form>
6.4完成測驗
7.功能06-web層servlet減肥
7.1需求分析/圖解
- 如圖,一個請求對應一個Servlet,會造成Servlet太多,不利于管理
- 在專案開發中,同一個業務(模塊),一般對應一個Servlet即可,比如LoginServlet和RegisterServlet都處理和會員相關的業務,應當合并
7.2方案一-if-else
前端頁面兩個表單login和register的action都提交到MemberServlet中
- 分別給兩個表單添加hidden元素,分別表示注冊和登錄
- 當資訊提交到MemberServlet后,獲取action引數值
- 再根據不同的值來呼叫對應的方法即可(將原來的業務分別封裝到login方法和Register方法中)
7.3方案一代碼實作
-
修改login.jsp,分別在login和register表單中添加hidden,兩個表單都提交到MemberServlet處理
-
在web.xml中配置MemberServlet
<servlet> <servlet-name>MemberServlet</servlet-name> <servlet-class>com.li.furns.web.MemberServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MemberServlet</servlet-name> <url-pattern>/memberServlet</url-pattern> </servlet-mapping> -
實作MemberServlet
package com.li.furns.web; import com.li.furns.entity.Member; import com.li.furns.service.MemberService; import com.li.furns.service.impl.MemberServiceImpl; import javax.servlet.*; import javax.servlet.http.*; import java.io.IOException; public class MemberServlet extends HttpServlet { private MemberService memberService = new MemberServiceImpl(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取提交表單的hidden元素值,判斷進行login還是register業務 String action = request.getParameter("action"); if ("login".equals(action)) { //進入登錄業務 login(request, response); } else if ("register".equals(action)) { //進入注冊業務 register(request, response); } } public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.接收用戶名和密碼 //如果前端輸入的是null,后臺接收的資料為空串"" String username = request.getParameter("username"); String password = request.getParameter("password"); //構建一個member物件 Member member = new Member(null, username, password, null); //2.呼叫MemberServiceImpl的login方法 if (memberService.login(member) == null) {//資料庫中沒有該用戶,回傳登錄頁面 //登錄失敗,將錯誤資訊和登錄會員名放入request域中 request.setAttribute("errInfo", "登錄失敗,用戶名或者密碼錯誤"); request.setAttribute("username", username); //注意路徑 request.getRequestDispatcher("/views/member/login.jsp") .forward(request, response); } else { //否則,跳轉到登錄成功頁面 request.getRequestDispatcher("/views/member/login_ok.html") .forward(request, response); } } public void register(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //接收用戶注冊資訊--引數名要以前端頁面的變數名為準 String username = request.getParameter("username"); String password = request.getParameter("password"); String email = request.getParameter("email"); //如果回傳false,說明該用戶資訊可以注冊 if (!memberService.isExistsUsername(username)) { //構建一個member物件 Member member = new Member(null, username, password, email); if (memberService.registerMember(member)) { //如果注冊成功,請求轉發到register_ok.html request.getRequestDispatcher("/views/member/register_ok.html") .forward(request, response); } else { //注冊失敗,請求轉發到register_fail.html request.getRequestDispatcher("/views/member/register_fail.html") .forward(request, response); } } else {//否則不能進行注冊 //請求轉發到login.html //后面可以加入提示資訊 request.getRequestDispatcher("/views/member/login.jsp") .forward(request, response); } } }
7.4方案二-反射+模板設計模式+動態系結
雖然方案一也可以實作業務需求,但是隨著業務的增加,if-else陳述句也會隨之增多,代碼可讀性變差,因此這里使用第二種方案實作,思想如下:
每一個業務Servlet類中都會有doPost和doGet方法,現在創建一個BasicServlet抽象類,其他的業務Servlet類都繼承BasicServlet抽象類,
將業務類中的doPost和doGet方法抽象到BasicServlet中,當http請求到業務類時,因為業務類中沒有重寫doPost和doGet,就會到父類BasicServlet中找并呼叫,
同時在父類BasicServlet的doPost()方法中使用動態系結,通過反射去獲取到子類中的某個業務方法,然后呼叫,
7.5方案二代碼實作
-
修改MemberServlet,將doPost方法抽象到父類BasicServlet中:
package com.li.furns.web; import com.li.furns.entity.Member; import com.li.furns.service.MemberService; import com.li.furns.service.impl.MemberServiceImpl; import javax.servlet.*; import javax.servlet.http.*; import java.io.IOException; /** * 該Servlet處理和Member相關的請求 * * @author 李 * @version 1.0 */ public class MemberServlet extends BasicServlet { private MemberService memberService = new MemberServiceImpl(); /** * 處理會員登錄業務 * * @param request * @param response * @throws ServletException * @throws IOException */ public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.接收用戶名和密碼 //如果前端輸入的是null,后臺接收的資料為空串"" String username = request.getParameter("username"); String password = request.getParameter("password"); //構建一個member物件 Member member = new Member(null, username, password, null); //2.呼叫MemberServiceImpl的login方法 if (memberService.login(member) == null) {//資料庫中沒有該用戶,回傳登錄頁面 //登錄失敗,將錯誤資訊和登錄會員名放入request域中 request.setAttribute("errInfo", "登錄失敗,用戶名或者密碼錯誤"); request.setAttribute("username", username); //注意路徑 request.getRequestDispatcher("/views/member/login.jsp") .forward(request, response); } else { //否則,跳轉到登錄成功頁面 request.getRequestDispatcher("/views/member/login_ok.html") .forward(request, response); } } /** * 處理會員注冊業務 * * @param request * @param response * @throws ServletException * @throws IOException */ public void register(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //接收用戶注冊資訊--引數名要以前端頁面的變數名為準 String username = request.getParameter("username"); String password = request.getParameter("password"); String email = request.getParameter("email"); //如果回傳false,說明該用戶資訊可以注冊 if (!memberService.isExistsUsername(username)) { //構建一個member物件 Member member = new Member(null, username, password, email); if (memberService.registerMember(member)) { //如果注冊成功,請求轉發到register_ok.html request.getRequestDispatcher("/views/member/register_ok.html") .forward(request, response); } else { //注冊失敗,請求轉發到register_fail.html request.getRequestDispatcher("/views/member/register_fail.html") .forward(request, response); } } else {//否則不能進行注冊 //請求轉發到login.html //后面可以加入提示資訊 request.getRequestDispatcher("/views/member/login.jsp") .forward(request, response); } } } -
創建BasicServlet,在該抽象類中使用使用模板模式+反射+動態系結
package com.li.furns.web; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.Method; /** * 業務servlet的共同父類 * BasicServlet 是供子類去繼承的,不需要在web.xml中配置 * 使用模板模式+反射+動態系結===>簡化了多個if-else的陳述句 * * @author 李 * @version 1.0 */ public abstract class BasicServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //獲取提交表單的隱藏域元素的值 //如果我們使用模板模式+反射+動態系結,要滿足action的值要和方法名一致 String action = req.getParameter("action"); //使用反射,獲取到當前物件的方法 //1.this就是請求的業務Servlet,即運行型別 //2.declaredMethod 方法物件就是當前請求的業務servlet對應的action名稱的方法 try { /** * public Method getDeclaredMethod(){} * 該方法回傳一個Method物件,它反射此Class物件所表示的類或介面的指定已宣告方法, * 引數:此方法接受兩個引數: * -方法名稱,這是要獲取的方法, * -引數型別 這是指定的方法的引數型別的陣列, * 回傳值:此方法以 Method 物件的形式回傳此類的指定方法, */ Method declaredMethod = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class); //使用方法物件進行反射呼叫 //public Object invoke(Object obj, Object... args){} declaredMethod.invoke(this, req, resp); } catch (Exception e) { e.printStackTrace(); } } }
之后再去開發業務類,只需要繼承BasicServlet即可,推薦使用方案二
7.6完成測驗
注冊業務:

登錄業務:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/540106.html
標籤:Java
上一篇:19 Java記憶體模型與執行緒_JVM層面的鎖優化
下一篇:資料分析之pandas的使用
