需求如圖:
根據上述分析圖,在對應的層新增方法
修改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);
}
程式碼測試通過
修改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);
}
程式碼測試通過
設定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.2分析圖的基礎上修改如下兩處:
修改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 class="login-register-form">
<%--提示錯誤資訊--%>
<span class="errorMsg"
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="${requestScope.username}"/>
<input type="password" name="password" placeholder="Password"/>
<div class="button-box">
<div class="login-toggle-btn">
<input type="checkbox"/>
<a class="flote-none" href="javascript:void(0)">Remember me</a>
<a href="#">Forgot Password?</a>
</div>
<button type="submit"><span>Login</span></button>
</div>
</form>
前端頁面兩個表單login和register的action都提交到MemberServlet中
修改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);
}
}
}
雖然方案一也可以實現業務需求,但是隨著業務的增加,if-else語句也會隨之增多,程式碼可讀性變差,因此這裡使用第二種方案實現,思想如下:
每一個業務Servlet類中都會有doPost和doGet方法,現在建立一個BasicServlet抽象類,其他的業務Servlet類都繼承BasicServlet抽象類。
將業務類中的doPost和doGet方法抽象到BasicServlet中,當http請求到業務類時,因為業務類中沒有重寫doPost和doGet,就會到父類別BasicServlet中找並呼叫。
同時在父類別BasicServlet的doPost()方法中使用動態繫結,通過反射去獲取到子類中的某個業務方法,然後呼叫。
修改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即可,推薦使用方案二
註冊業務:
登入業務: