JavaWeb實現(xiàn)用戶登錄注冊功能實例代碼(基于Servlet+JSP+JavaBean模式)
下面通過通過圖文并茂的方式給大家介紹JavaWeb實現(xiàn)用戶登錄注冊功能實例代碼,一起看看吧。
一、Servlet+JSP+JavaBean開發(fā)模式(MVC)介紹
Servlet+JSP+JavaBean模式(MVC)適合開發(fā)復(fù)雜的web應(yīng)用,在這種模式下,servlet負(fù)責(zé)處理用戶請求,jsp負(fù)責(zé)數(shù)據(jù)顯示,javabean負(fù)責(zé)封裝數(shù)據(jù)。 Servlet+JSP+JavaBean模式程序各個模塊之間層次清晰,web開發(fā)推薦采用此種模式。
這里以一個最常用的用戶登錄注冊程序來講解Servlet+JSP+JavaBean開發(fā)模式,通過這個用戶登錄注冊程序綜合案例,把之前的學(xué)過的XML、Xpath、Servlet、jsp的知識點都串聯(lián)起來。
二、創(chuàng)建MVC架構(gòu)的Web項目
在MyEclipse中新創(chuàng)建一個webmvcframework項目,導(dǎo)入項目所需要的開發(fā)包(jar包),創(chuàng)建項目所需要的包,在java開發(fā)中,架構(gòu)的層次是以包的形式體現(xiàn)出來的
項目所需要的開發(fā)包(jar包) | ||
序號 | 開發(fā)包名稱 | 描述 |
1 | dom4j-1.6.1.jar | dom4j用于操作XML文件 |
2 | jaxen-1.1-beta-6.jar | 用于解析XPath表達(dá)式 |
3 | commons-beanutils-1.8.0.jar | 工具類,用于處理bean對象 |
4 | commons-logging.jar | commons-beanutils-1.8.0.jar的依賴jar包 |
5 | jstl.jar | jstl標(biāo)簽庫和EL表達(dá)式依賴包 |
6 | standard.jar | jstl標(biāo)簽庫和EL表達(dá)式依賴包 |
一個良好的JavaWeb項目架構(gòu)應(yīng)該具有以上的11個包,這樣顯得層次分明,各個層之間的職責(zé)也很清晰明了,搭建JavaWeb項目架構(gòu)時,就按照上面的1~11的序號順序創(chuàng)建包:domain→dao→dao.impl→service→service.impl→web.controller→web.UI→web.filter→web.listener→util→junit.test,包的層次創(chuàng)建好了,項目的架構(gòu)也就定下來了,當(dāng)然,在實際的項目開發(fā)中,也不一定是完完全全按照
項目所需要的包 | |||
序號 | 包名 | 描述 | 所屬層次 |
1 | me.gacl.domain | 存放系統(tǒng)的JavaBean類(只包含簡單的屬性以及屬性對應(yīng)的get和set方法,不包含具體的業(yè)務(wù)處理方法),提供給【數(shù)據(jù)訪問層】、【業(yè)務(wù)處理層】、【W(wǎng)eb層】來使用 | domain(域模型)層 |
2 | me.gacl.dao | 存放訪問數(shù)據(jù)庫的操作接口類 | 數(shù)據(jù)訪問層 |
3 | me.gacl.dao.impl | 存放訪問數(shù)據(jù)庫的操作接口的實現(xiàn)類 | |
4 | me.gacl.service | 存放處理系統(tǒng)業(yè)務(wù)接口類 | 業(yè)務(wù)處理層 |
5 | me.gacl.service.impl | 存放處理系統(tǒng)業(yè)務(wù)接口的實現(xiàn)類 | |
6 | me.gacl.web.controller | 存放作為系統(tǒng)控制器的Servlet | Web層(表現(xiàn)層) |
7 | me.gacl.web.UI | 存放為用戶提供用戶界面的servlet(UI指的是user interface) | |
8 | me.gacl.web.filter | 存放系統(tǒng)的用到的過濾器(Filter) | |
9 | me.gacl.web.listener | 存放系統(tǒng)的用到的監(jiān)聽器(Listener) | |
10 | me.gacl.util | 存放系統(tǒng)的通用工具類,提供給【數(shù)據(jù)訪問層】、【業(yè)務(wù)處理層】、【W(wǎng)eb層】來使用 | |
11 | junit.test | 存放系統(tǒng)的測試類 |
上面說的來創(chuàng)建包的層次結(jié)構(gòu),而是根據(jù)項目的實際情況,可能還需要創(chuàng)建其
他的包,這個得根據(jù)項目的需要來定了
在src目錄(類目錄)下面,創(chuàng)建用于保存用戶數(shù)據(jù)的xml文件(DB.xml)
在WEB-INF目錄下創(chuàng)建一個pages目錄,pages目錄存放系統(tǒng)的一些受保護(hù)(不允許用戶直接通過URL地址訪問)的jsp頁面,用戶要想訪問這些受保護(hù)的jsp頁面,那么只能通過me.gacl.web.UI這個包里面的Servlet
創(chuàng)建好的項目如下圖(圖-1)所示:
圖-1
三、分層架構(gòu)的代碼編寫
分層架構(gòu)的代碼也是按照【域模型層(domain)】→【數(shù)據(jù)訪問層(dao、dao.impl)】→【業(yè)務(wù)處理層(service、service.impl)】→【表現(xiàn)層(web.controller、web.UI、web.filter、web.listener)】→【工具類(util)】→【測試類(junit.test)】的順序進(jìn)行編寫的。
3.1、開發(fā)domain層
在me.gacl.domain包下創(chuàng)建一個User類
User類具體代碼如下:
package me.gacl.domain; import java.io.Serializable; import java.util.Date; /** * @author gacl * 用戶實體類 */ public class User implements Serializable { private static final long serialVersionUID = -L; // 用戶ID private String id; // 用戶名 private String userName; // 用戶密碼 private String userPwd; // 用戶郵箱 private String email; // 用戶生日 private Date birthday; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPwd() { return userPwd; } public void setUserPwd(String userPwd) { this.userPwd = userPwd; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
3.2、開發(fā)數(shù)據(jù)訪問層(dao、dao.impl)
在me.gacl.dao包下創(chuàng)建一個IUserDao接口類,對于開發(fā)接口類,我習(xí)慣以字母I作類的前綴,這樣一眼就看出當(dāng)前這個類是一個接口,這也算是一種良好的開發(fā)習(xí)慣吧,通過看類名就可以方便區(qū)分出是接口還是具體的實現(xiàn)類。
IUserDao接口的具體代碼如下:
package me.gacl.dao; import me.gacl.domain.User; public interface IUserDao { /** * 根據(jù)用戶名和密碼來查找用戶 * @param userName * @param userPwd * @return 查到到的用戶 */ User find(String userName, String userPwd); /** * 添加用戶 * @param user */ void add(User user); /**根據(jù)用戶名來查找用戶 * @param userName * @return 查到到的用戶 */ User find(String userName); }
對于接口中的方法定義,這個只能是根據(jù)具體的業(yè)務(wù)來分析需要定義哪些方法了,但是無論是多么復(fù)雜的業(yè)務(wù),都離不開基本的CRUD(增刪改查)操作,Dao層是直接和數(shù)據(jù)庫交互的,所以Dao層的接口一般都會有增刪改查這四種操作的相關(guān)方法。
在me.gacl.dao.impl包下創(chuàng)建一個UserDaoImpl類
UserDaoImpl類是IUserDao接口的具體實現(xiàn)類,對于接口的實現(xiàn)類命名方式,我習(xí)慣以"接口名(去除前綴I)+impl"形式或者"接口名+impl"形式來命名:IUserDao(接口)→UserDaoImpl(實現(xiàn)類)或者IUserDao(接口)→IUserDaoImpl(實現(xiàn)類),這也算是一些個人的編程習(xí)慣吧,平時看到的代碼大多數(shù)都是以這兩種形式中的一種來來命名接口的具體實現(xiàn)類的,反正就是要能夠一眼看出接口對應(yīng)的實現(xiàn)類是哪一個就可以了。
UserDaoImpl類的具體代碼如下:
package me.gacl.dao.impl; import java.text.SimpleDateFormat; import org.domj.Document; import org.domj.Element; import me.gacl.dao.IUserDao; import me.gacl.domain.User; import me.gacl.util.XmlUtils; /** * IUserDao接口的實現(xiàn)類 * @author gacl */ public class UserDaoImpl implements IUserDao { @Override public User find(String userName, String userPwd) { try{ Document document = XmlUtils.getDocument(); //使用XPath表達(dá)式來操作XML節(jié)點 Element e = (Element) document.selectSingleNode("http://user[@userName='"+userName+"' and @userPwd='"+userPwd+"']"); if(e==null){ return null; } User user = new User(); user.setId(e.attributeValue("id")); user.setEmail(e.attributeValue("email")); user.setUserPwd(e.attributeValue("userPwd")); user.setUserName(e.attributeValue("userName")); String birth = e.attributeValue("birthday"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); user.setBirthday(sdf.parse(birth)); return user; }catch (Exception e) { throw new RuntimeException(e); } } @SuppressWarnings("deprecation") @Override public void add(User user) { try{ Document document = XmlUtils.getDocument(); Element root = document.getRootElement(); Element user_node = root.addElement("user"); //創(chuàng)建user結(jié)點,并掛到root user_node.setAttributeValue("id", user.getId()); user_node.setAttributeValue("userName", user.getUserName()); user_node.setAttributeValue("userPwd", user.getUserPwd()); user_node.setAttributeValue("email", user.getEmail()); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); user_node.setAttributeValue("birthday", sdf.format(user.getBirthday())); XmlUtils.writeXml(document); }catch (Exception e) { throw new RuntimeException(e); } } @Override public User find(String userName) { try{ Document document = XmlUtils.getDocument(); Element e = (Element) document.selectSingleNode("http://user[@userName='"+userName+"']"); if(e==null){ return null; } User user = new User(); user.setId(e.attributeValue("id")); user.setEmail(e.attributeValue("email")); user.setUserPwd(e.attributeValue("userPwd")); user.setUserName(e.attributeValue("userName")); String birth = e.attributeValue("birthday"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); user.setBirthday(sdf.parse(birth)); return user; }catch (Exception e) { throw new RuntimeException(e); } } }
3.3、開發(fā)service層(service層對web層提供所有的業(yè)務(wù)服務(wù))
在me.gacl.service包中創(chuàng)建IUserService接口類
IUserService接口的具體代碼如下:
package me.gacl.service; import me.gacl.domain.User; import me.gacl.exception.UserExistException; public interface IUserService { /** * 提供注冊服務(wù) * @param user * @throws UserExistException */ void registerUser(User user) throws UserExistException; /** * 提供登錄服務(wù) * @param userName * @param userPwd * @return */ User loginUser(String userName, String userPwd); }
在me.gacl.service.impl包中創(chuàng)建UserServiceImpl類
UserServiceImpl類為IUserService接口的具體實現(xiàn)類,具體代碼如下:
package me.gacl.service.impl; import me.gacl.dao.IUserDao; import me.gacl.dao.impl.UserDaoImpl; import me.gacl.domain.User; import me.gacl.exception.UserExistException; import me.gacl.service.IUserService; public class UserServiceImpl implements IUserService { private IUserDao userDao = new UserDaoImpl(); @Override public void registerUser(User user) throws UserExistException { if (userDao.find(user.getUserName())!=null) { //checked exception //unchecked exception //這里拋編譯時異常的原因:是我想上一層程序處理這個異常,以給用戶一個友好提示 throw new UserExistException("注冊的用戶名已存在!??!"); } userDao.add(user); } @Override public User loginUser(String userName, String userPwd) { return userDao.find(userName, userPwd); } }
3.4、開發(fā)web層
3.4.1、 開發(fā)注冊功能
1、在me.gacl.web.UI包下寫一個RegisterUIServlet為用戶提供注冊界面
RegisterUIServlet收到用戶請求后,就跳到register.jsp
RegisterUIServlet的代碼如下:
package me.gacl.web.UI; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author gacl * 為用戶提供注冊的用戶界面的Servlet * RegisterUIServlet負(fù)責(zé)為用戶輸出注冊界面 * 當(dāng)用戶訪問RegisterUIServlet時,就跳轉(zhuǎn)到WEB-INF/pages目錄下的register.jsp頁面 */ public class RegisterUIServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
2、在/WEB-INF/pages/目錄下編寫用戶注冊的jsp頁面register.jsp
凡是位于WEB-INF目錄下的jsp頁面是無法直接通過URL地址直接訪問的,
在開發(fā)中如果項目中有一些敏感web資源不想被外界直接訪問,那么可以考慮將這些敏感的web資源放到WEB-INF目錄下,這樣就可以禁止外界直接通過URL來訪問了。
register.jsp頁面的代碼如下:
<%@ page language="java" pageEncoding="UTF-"%> <!DOCTYPE HTML> <html> <head> <title>用戶注冊</title> </head> <body style="text-align: center;"> <form action="${pageContext.request.contextPath}/servlet/RegisterServlet" method="post"> <table width="%" border=""> <tr> <td>用戶名</td> <td> <input type="text" name="userName"> </td> </tr> <tr> <td>密碼</td> <td> <input type="password" name="userPwd"> </td> </tr> <tr> <td>確認(rèn)密碼</td> <td> <input type="password" name="confirmPwd"> </td> </tr> <tr> <td>郵箱</td> <td> <input type="text" name="email"> </td> </tr> <tr> <td>生日</td> <td> <input type="text" name="birthday"> </td> </tr> <tr> <td> <input type="reset" value="清空"> </td> <td> <input type="submit" value="注冊"> </td> </tr> </table> </form> </body> </html>
register.jsp中的<form action="${pageContext.request.contextPath}/servlet/RegisterServlet" method="post">指明表單提交后,交給RegisterServlet進(jìn)行處理
3、在me.gacl.web.controller包下編寫用于處理用戶注冊的RegisterServlet
RegisterServlet擔(dān)任著以下幾個職責(zé):
1、接收客戶端提交到服務(wù)端的表單數(shù)據(jù)。
2、校驗表單數(shù)據(jù)的合法性,如果校驗失敗跳回到register.jsp,并回顯錯誤信息。
3、如果校驗通過,調(diào)用service層向數(shù)據(jù)庫中注冊用戶。
為了方便RegisterServlet接收表單數(shù)據(jù)和校驗表單數(shù)據(jù),在此我設(shè)計一個用于校驗注冊表單數(shù)據(jù)RegisterFormbean,再寫WebUtils工具類,封裝客戶端提交的表單數(shù)據(jù)到formbean中。
在me.gacl.web.formbean包下創(chuàng)建一個用于校驗注冊表單數(shù)據(jù)RegisterFormbean
RegisterFormbean代碼如下:
package me.gacl.web.formbean; import java.util.HashMap; import java.util.Map; import org.apache.commons.beanutils.locale.converters.DateLocaleConverter; /** * 封裝的用戶注冊表單bean,用來接收register.jsp中的表單輸入項的值 * RegisterFormBean中的屬性與register.jsp中的表單輸入項的name一一對應(yīng) * RegisterFormBean的職責(zé)除了負(fù)責(zé)接收register.jsp中的表單輸入項的值之外還擔(dān)任著校驗表單輸入項的值的合法性 * @author gacl * */ public class RegisterFormBean { //RegisterFormBean中的屬性與register.jsp中的表單輸入項的name一一對應(yīng) //<input type="text" name="userName"/> private String userName; //<input type="password" name="userPwd"/> private String userPwd; //<input type="password" name="confirmPwd"/> private String confirmPwd; //<input type="text" name="email"/> private String email; //<input type="text" name="birthday"/> private String birthday; /** * 存儲校驗不通過時給用戶的錯誤提示信息 */ private Map<String, String> errors = new HashMap<String, String>(); public Map<String, String> getErrors() { return errors; } public void setErrors(Map<String, String> errors) { this.errors = errors; } /* * validate方法負(fù)責(zé)校驗表單輸入項 * 表單輸入項校驗規(guī)則: * private String userName; 用戶名不能為空,并且要是-的字母 abcdABcd * private String userPwd; 密碼不能為空,并且要是-的數(shù)字 * private String confirmPwd; 兩次密碼要一致 * private String email; 可以為空,不為空要是一個合法的郵箱 * private String birthday; 可以為空,不為空時,要是一個合法的日期 */ public boolean validate() { boolean isOk = true; if (this.userName == null || this.userName.trim().equals("")) { isOk = false; errors.put("userName", "用戶名不能為空?。?); } else { if (!this.userName.matches("[a-zA-Z]{,}")) { isOk = false; errors.put("userName", "用戶名必須是-位的字母??!"); } } if (this.userPwd == null || this.userPwd.trim().equals("")) { isOk = false; errors.put("userPwd", "密碼不能為空!!"); } else { if (!this.userPwd.matches("\\d{,}")) { isOk = false; errors.put("userPwd", "密碼必須是-位的數(shù)字?。?); } } // private String password; 兩次密碼要一致 if (this.confirmPwd != null) { if (!this.confirmPwd.equals(this.userPwd)) { isOk = false; errors.put("confirmPwd", "兩次密碼不一致??!"); } } // private String email; 可以為空,不為空要是一個合法的郵箱 if (this.email != null && !this.email.trim().equals("")) { if (!this.email.matches("\\w+@\\w+(\\.\\w+)+")) { isOk = false; errors.put("email", "郵箱不是一個合法郵箱!!"); } } // private String birthday; 可以為空,不為空時,要是一個合法的日期 if (this.birthday != null && !this.birthday.trim().equals("")) { try { DateLocaleConverter conver = new DateLocaleConverter(); conver.convert(this.birthday); } catch (Exception e) { isOk = false; errors.put("birthday", "生日必須要是一個日期??!"); } } return isOk; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPwd() { return userPwd; } public void setUserPwd(String userPwd) { this.userPwd = userPwd; } public String getConfirmPwd() { return confirmPwd; } public void setConfirmPwd(String confirmPwd) { this.confirmPwd = confirmPwd; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday = birthday; } }
在me.gacl.util包下創(chuàng)建一個WebUtils工具類,該工具類的功能就是封裝客戶端提交的表單數(shù)據(jù)到formbean中
package me.gacl.util; import java.util.Enumeration; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import org.apache.commons.beanutils.BeanUtils; /** * @author gacl * 把request對象中的請求參數(shù)封裝到bean中 */ public class WebUtils { /** * 將request對象轉(zhuǎn)換成T對象 * @param request * @param clazz * @return */ public static <T> T requestBean(HttpServletRequest request,Class<T> clazz){ try{ T bean = clazz.newInstance(); Enumeration<String> e = request.getParameterNames(); while(e.hasMoreElements()){ String name = (String) e.nextElement(); String value = request.getParameter(name); BeanUtils.setProperty(bean, name, value); } return bean; }catch (Exception e) { throw new RuntimeException(e); } } /** * 生成UUID * @return */ public static String makeId(){ return UUID.randomUUID().toString(); } }
最后看一下負(fù)責(zé)處理用戶注冊的RegisterServlet完整代碼:
package me.gacl.web.controller; import java.io.IOException; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.locale.converters.DateLocaleConverter; import me.gacl.domain.User; import me.gacl.exception.UserExistException; import me.gacl.service.IUserService; import me.gacl.service.impl.UserServiceImpl; import me.gacl.util.WebUtils; import me.gacl.web.formbean.RegisterFormBean; /** * 處理用戶注冊的Servlet * @author gacl * */ public class RegisterServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //將客戶端提交的表單數(shù)據(jù)封裝到RegisterFormBean對象中 RegisterFormBean formbean = WebUtils.requestBean(request,RegisterFormBean.class); //校驗用戶注冊填寫的表單數(shù)據(jù) if (formbean.validate() == false) {//如果校驗失敗 //將封裝了用戶填寫的表單數(shù)據(jù)的formbean對象發(fā)送回register.jsp頁面的form表單中進(jìn)行顯示 request.setAttribute("formbean", formbean); //校驗失敗就說明是用戶填寫的表單數(shù)據(jù)有問題,那么就跳轉(zhuǎn)回register.jsp request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response); return; } User user = new User(); try { // 注冊字符串到日期的轉(zhuǎn)換器 ConvertUtils.register(new DateLocaleConverter(), Date.class); BeanUtils.copyProperties(user, formbean);//把表單的數(shù)據(jù)填充到j(luò)avabean中 user.setId(WebUtils.makeId());//設(shè)置用戶的Id屬性 IUserService service = new UserServiceImpl(); //調(diào)用service層提供的注冊用戶服務(wù)實現(xiàn)用戶注冊 service.registerUser(user); String message = String.format( "注冊成功??!秒后為您自動跳到登錄頁面!!<meta http-equiv='refresh' content=';url=%s'/>", request.getContextPath()+"/servlet/LoginUIServlet"); request.setAttribute("message",message); request.getRequestDispatcher("/message.jsp").forward(request,response); } catch (UserExistException e) { formbean.getErrors().put("userName", "注冊用戶已存在??!"); request.setAttribute("formbean", formbean); request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response); } catch (Exception e) { e.printStackTrace(); // 在后臺記錄異常 request.setAttribute("message", "對不起,注冊失?。?!"); request.getRequestDispatcher("/message.jsp").forward(request,response); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
用戶注冊時如果填寫的表單數(shù)據(jù)校驗不通過,那么服務(wù)器端就將一個存儲了錯誤提示消息和表單數(shù)據(jù)的formbean對象存儲到request對象中,然后發(fā)送回register.jsp頁面,因此我們需要在register.jsp頁面中取出request對象中formbean對象,然后將用戶填寫的表單數(shù)據(jù)重新回顯到對應(yīng)的表單項上面,將出錯時的提示消息也顯示到form表單上面,讓用戶知道是哪些數(shù)據(jù)填寫不合法!
修改register.jsp頁面,代碼如下:
<%@ page language="java" pageEncoding="UTF-"%> <!DOCTYPE HTML> <html> <head> <title>用戶注冊</title> </head> <body style="text-align: center;"> <form action="${pageContext.request.contextPath}/servlet/RegisterServlet" method="post"> <table width="%" border=""> <tr> <td>用戶名</td> <td> <%--使用EL表達(dá)式${}提取存儲在request對象中的formbean對象中封裝的表單數(shù)據(jù)(formbean.userName)以及錯誤提示消息(formbean.errors.userName)--%> <input type="text" name="userName" value="${formbean.userName}">${formbean.errors.userName} </td> </tr> <tr> <td>密碼</td> <td> <input type="password" name="userPwd" value="${formbean.userPwd}">${formbean.errors.userPwd} </td> </tr> <tr> <td>確認(rèn)密碼</td> <td> <input type="password" name="confirmPwd" value="${formbean.confirmPwd}">${formbean.errors.confirmPwd} </td> </tr> <tr> <td>郵箱</td> <td> <input type="text" name="email" value="${formbean.email}">${formbean.errors.email} </td> </tr> <tr> <td>生日</td> <td> <input type="text" name="birthday" value="${formbean.birthday}">${formbean.errors.birthday} </td> </tr> <tr> <td> <input type="reset" value="清空"> </td> <td> <input type="submit" value="注冊"> </td> </tr> </table> </form> </body> </html>
到此,用戶注冊功能就算是開發(fā)完成了!
下面測試一下開發(fā)好的用戶注冊功能:
輸入URL地址:http://localhost:8080/webmvcframework/servlet/RegisterUIServlet訪問register.jsp頁面,運行效果如下:
如果輸入的表單項不符合校驗規(guī)則,那么是無法進(jìn)行注冊的,運行效果如下:
3.4.2、 開發(fā)登錄功能
1、在me.gacl.web.UI包下寫一個LoginUIServlet為用戶提供登錄界面
LoginUIServlet收到用戶請求后,就跳到login.jsp
LoginUIServlet的代碼如下:
package me.gacl.web.UI; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author gacl * LoginUIServlet負(fù)責(zé)為用戶輸出登陸界面 * 當(dāng)用戶訪問LoginUIServlet時,就跳轉(zhuǎn)到WEB-INF/pages目錄下的login.jsp頁面 */ public class LoginUIServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
2、在/WEB-INF/pages/目錄下編寫用戶登錄的jsp頁面login.jsp
login.jsp頁面的代碼如下:
<%@ page language="java" pageEncoding="UTF-"%> <!DOCTYPE HTML> <html> <head> <title>用戶登陸</title> </head> <body> <form action="${pageContext.request.contextPath }/servlet/LoginServlet" method="post"> 用戶名:<input type="text" name="username"><br/> 密碼:<input type="password" name="password"><br/> <input type="submit" value="登陸"> </form> </body> </html>
login.jsp中的<form action="${pageContext.request.contextPath}/servlet/LoginServlet" method="post">指明表單提交后,交給LoginServlet進(jìn)行處理。
3、在me.gacl.web.controller包下編寫用于處理用戶登錄的LoginServlet
LoginServlet的代碼如下:
package me.gacl.web.controller; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import me.gacl.domain.User; import me.gacl.service.IUserService; import me.gacl.service.impl.UserServiceImpl; /** * 處理用戶登錄的servlet * @author gacl * */ public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取用戶填寫的登錄用戶名 String username = request.getParameter("username"); //獲取用戶填寫的登錄密碼 String password = request.getParameter("password"); IUserService service = new UserServiceImpl(); //用戶登錄 User user = service.loginUser(username, password); if(user==null){ String message = String.format( "對不起,用戶名或密碼有誤?。≌堉匦碌卿?!秒后為您自動跳到登錄頁面??!<meta http-equiv='refresh' content=';url=%s'", request.getContextPath()+"/servlet/LoginUIServlet"); request.setAttribute("message",message); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } //登錄成功后,就將用戶存儲到session中 request.getSession().setAttribute("user", user); String message = String.format( "恭喜:%s,登陸成功!本頁將在秒后跳到首頁!!<meta http-equiv='refresh' content=';url=%s'", user.getUserName(), request.getContextPath()+"/index.jsp"); request.setAttribute("message",message); request.getRequestDispatcher("/message.jsp").forward(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
到此,用戶登錄的功能就算是開發(fā)完成了。
下面測試一下開發(fā)好的用戶登錄功能,輸入URL地址:http://localhost:8080/webmvcframework/servlet/LoginUIServlet訪問login.jsp頁面,輸入正確的用戶名和密碼進(jìn)行登錄,運行效果如下:
如果輸入的用戶名和密碼錯誤,那么就無法登錄成功,運行效果如下:
3.4.3、 開發(fā)注銷功能
在me.gacl.web.controller包下編寫用于處理用戶注銷的LogoutServlet
LogoutServlet的代碼如下:
package me.gacl.web.controller; import java.io.IOException; import java.text.MessageFormat; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LogoutServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //移除存儲在session中的user對象,實現(xiàn)注銷功能 request.getSession().removeAttribute("user"); //由于字符串中包含有單引號,在這種情況下使用MessageFormat.format方法拼接字符串時就會有問題 //MessageFormat.format方法只是把字符串中的單引號去掉,不會將內(nèi)容填充到指定的占位符中 String tempStr = MessageFormat.format( "注銷成功??!秒后為您自動跳到登錄頁面!!<meta http-equiv='refresh' content=';url={}'/>", request.getContextPath()+"/servlet/LoginUIServlet"); System.out.println(tempStr);//輸出結(jié)果:注銷成功!!秒后為您自動跳到登錄頁面??!<meta http-equiv=refresh content=;url={}/> System.out.println("---------------------------------------------------------"); /** * 要想解決"如果要拼接的字符串包含有單引號,那么MessageFormat.format方法就只是把字符串中的單引號去掉,不會將內(nèi)容填充到指定的占位符中"這個問題, * 那么可以需要使用單引號引起來的字符串中使用個單引號引起來,例如:"<meta http-equiv=''refresh'' content='';url={}''/>" * 這樣MessageFormat.format("<meta http-equiv=''refresh'' content='';url={}''/>","index.jsp")就可以正常返回 * <meta http-equiv=''refresh'' content='';url=index.jsp'/> */ String tempStr = MessageFormat.format( "注銷成功!!秒后為您自動跳到登錄頁面??!<meta http-equiv=''refresh'' content='';url={}''/>", request.getContextPath()+"/servlet/LoginUIServlet"); /** * 輸出結(jié)果: * 注銷成功!!秒后為您自動跳到登錄頁面!! * <meta http-equiv='refresh' content=';url=/webmvcframework/servlet/LoginUIServlet'/> */ System.out.println(tempStr); String message = String.format( "注銷成功??!秒后為您自動跳到登錄頁面??!<meta http-equiv='refresh' content=';url=%s'/>", request.getContextPath()+"/servlet/LoginUIServlet"); request.setAttribute("message",message); request.getRequestDispatcher("/message.jsp").forward(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
用戶登錄成功后,會將登錄的用戶信息存儲在session中,所以我們要將存儲在session中的user刪除掉,這樣就可以實現(xiàn)用戶注銷了。
用戶登錄成功后就會跳轉(zhuǎn)到index.jsp頁面,在index.jsp頁面中放一個【退出登陸】按鈕,當(dāng)點擊【退出登陸】按鈕時,就訪問LogoutServlet,將用戶注銷。
index.jsp的代碼如下:
<%@ page language="java" pageEncoding="UTF-"%> <%--為了避免在jsp頁面中出現(xiàn)java代碼,這里引入jstl標(biāo)簽庫,利用jstl標(biāo)簽庫提供的標(biāo)簽來做一些邏輯判斷處理 --%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE HTML> <html> <head> <title>首頁</title> <script type="text/javascript"> function doLogout(){ //訪問LogoutServlet注銷當(dāng)前登錄的用戶 window.location.href="${pageContext.request.contextPath}/servlet/LogoutServlet"; } </script> </head> <body> <h>孤傲蒼狼的網(wǎng)站</h> <hr/> <c:if test="${user==null}"> <a href="${pageContext.request.contextPath}/servlet/RegisterUIServlet" target="_blank">注冊</a> <a href="${pageContext.request.contextPath}/servlet/LoginUIServlet">登陸</a> </c:if> <c:if test="${user!=null}"> 歡迎您:${user.userName} <input type="button" value="退出登陸" onclick="doLogout()"> </c:if> <hr/> </body> </html>
測試開發(fā)好的注銷功能,效果如下:
到此,所有的功能都開發(fā)完成了,測試也通過了。
四、開發(fā)總結(jié)
通過這個小例子,可以了解到mvc分層架構(gòu)的項目搭建,在平時的項目開發(fā)中,也都是按照如下的順序來進(jìn)行開發(fā)的:
1、搭建開發(fā)環(huán)境
1.1 創(chuàng)建web項目
1.2 導(dǎo)入項目所需的開發(fā)包
1.3 創(chuàng)建程序的包名,在java中是以包來體現(xiàn)項目的分層架構(gòu)的
2、開發(fā)domain
把一張要操作的表當(dāng)成一個VO類(VO類只定義屬性以及屬性對應(yīng)的get和set方法,沒有涉及到具體業(yè)務(wù)的操作方法),VO表示的是值對象,通俗地說,就是把表中的每一條記錄當(dāng)成一個對象,表中的每一個字段就作為這個對象的屬性。每往表中插入一條記錄,就相當(dāng)于是把一個VO類的實例對象插入到數(shù)據(jù)表中,對數(shù)據(jù)表進(jìn)行操作時,都是直接把一個VO類的對象寫入到表中,一個VO類對象就是一條記錄。每一個VO對象可以表示一張表中的一行記錄,VO類的名稱要和表的名稱一致或者對應(yīng)。
3、開發(fā)dao
3.1 DAO操作接口:每一個DAO操作接口規(guī)定了,一張表在一個項目中的具體操作方法,此接口的名稱最好按照如下格式編寫:“I表名稱Dao”。
├DAO接口里面的所有方法按照以下的命名編寫:
├更新數(shù)據(jù)庫:doXxx()
├查詢數(shù)據(jù)庫:findXxx()或getXxx()
3.2 DAO操作接口的實現(xiàn)類:實現(xiàn)類中完成具體的增刪改查操作
├此實現(xiàn)類完成的只是數(shù)據(jù)庫中最核心的操作,并沒有專門處理數(shù)據(jù)庫的打開和關(guān)閉,因為這些操作與具體的業(yè)務(wù)操作無關(guān)。
4、開發(fā)service(service 對web層提供所有的業(yè)務(wù)服務(wù))
5、開發(fā)web層
以上內(nèi)容是小編給大家介紹的JavaWeb實現(xiàn)用戶登錄注冊功能實例代碼(基于Servlet+JSP+JavaBean模式),希望對大家有所幫助!
相關(guān)文章
spring boot整合redis實現(xiàn)shiro的分布式session共享的方法
本篇文章主要介紹了spring boot整合redis實現(xiàn)shiro的分布式session共享的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01Spark學(xué)習(xí)筆記之Spark中的RDD的具體使用
這篇文章主要介紹了Spark學(xué)習(xí)筆記之Spark中的RDD的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06深入了解Java核心類庫--BigDecimal和System類
這篇文章主要為大家詳細(xì)介紹了javaBigDecimal和System類定義與使用的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能給你帶來幫助2021-07-07