目录
1. 新建JavaWeb项目、导入jar包
dom4j.jar =>操作XML文件
jaxen-xxx.jar =>解析XPath表达式
commons-beanutils-xxx.jar => 工具类,用于处理bean对象
commons-logging.jar => commons-beanutils-xxx.jar的依赖包
taglibs-standard-jstlel-1.2.5 => jstl标签库和EL表达式依赖包
commons-collections.jar
2. 新建jsp
WEB-INF 下
index.jsp
message.jsp
WEB-INF 下建立pages目录 +
login.jsp
register.jsp
index.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<%--为了避免在jsp页面中出现java代码,这里引入jstl标签库,利用jstl标签库提供的标签来做一些逻辑判断处理 --%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML>
<html>
<head>
<title>首页</title>
<script type="text/javascript">
function doLogout(){
// 访问LogoutServlet注销当前登录的用户
window.location.href="${pageContext.request.contextPath}/LogoutServlet";
}
</script>
</head>
<body>
<h1>网站</h1>
<hr/>
<c:if test="${user==null}">
<a href="${pageContext.request.contextPath}/RegisterUIServlet" target="_blank">注册</a>
<a href="${pageContext.request.contextPath}/LoginUIServlet">登陆</a>
</c:if>
<c:if test="${user!=null}">
欢迎您:${user.userName}
<input type="button" value="退出登陆" onclick="doLogout()">
</c:if>
<hr/>
</body>
</html>
message.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>全局消息显示页面</title>
</head>
<body>
${message}
</body>
</html>
login.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>用户登陆</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/LoginServlet" method="post">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="登陆">
</form>
</body>
</html>
register.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>用户注册</title>
</head>
<body style="text-align: center;">
<form action="${pageContext.request.contextPath}/RegisterServlet" method="post">
<table width="60%" border="1">
<tr>
<td>用户名</td>
<td>
<%--使用EL表达式${}提取存储在request对象中的formbean对象中封装的表单数据(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>确认密码</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>
3. 创建java类
开发顺序
domain→ 模型层
dao→ 数据库接口层
dao.impl→ 数据库实现层
service→ 服务(逻辑处理)接口层
service.impl→ 服务实现层
web.UI→ 跳转jsp层(放在WEB-INF下外界通过url访问不到)
web.controller→ 处理jsp逻辑层
web.filter→ 过滤层
web.listener→ 监听层
util→ 工具层
junit.test
exception 异常层
web.formbean 表单验证层
- 模型层
建包com.sst.cx.domain
新建User.java
package com.sst.cx.domain;
import java.util.Date;
public class User {
private static final long serialVersionUID = -4313782718477229465L;
// 用户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;
}
}
- 数据库接口层
建包com.sst.cx.dao
新建IUserDao.java
package com.sst.cx.dao;
import com.sst.cx.domain.User;
public interface IUserDao {
/**
* 根据用户名和密码来查找用户
* @param userName
* @param userPwd
* @return 查到到的用户
*/
User find(String userName, String userPwd);
/**
* 添加用户
* @param user
*/
void add(User user);
/**根据用户名来查找用户
* @param userName
* @return 查到到的用户
*/
User find(String userName);
}
- 数据库实现层
建包com.sst.cx.dao.impl
新建UserDaoImpl.java
package com.sst.cx.dao.impl;
import java.text.SimpleDateFormat;
import org.dom4j.Document;
import org.dom4j.Element;
import com.sst.cx.dao.IUserDao;
import com.sst.cx.domain.User;
import com.sst.cx.util.XmlUtils;
public class UserDaoImpl implements IUserDao {
@Override
public User find(String userName, String userPwd) {
try{
Document document = XmlUtils.getDocument();
// 使用XPath表达式来操作XML节点
Element e = (Element) document.selectSingleNode("//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"); // 创建user结点,并挂到root
user_node.addAttribute("id", user.getId());
user_node.addAttribute("userName", user.getUserName());
user_node.addAttribute("userPwd", user.getUserPwd());
user_node.addAttribute("email", user.getEmail());
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
user_node.addAttribute("birthday", sdf.format(user.getBirthday()));
XmlUtils.write2Xml(document);
}catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public User find(String userName) {
try{
Document document = XmlUtils.getDocument();
Element e = (Element) document.selectSingleNode("//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);
}
}
}
- 服务(逻辑处理)接口层
建包com.sst.cx.service
新建IUserService.java
package com.sst.cx.service;
import com.sst.cx.domain.User;
import com.sst.cx.exception.UserExistException;
public interface IUserService {
/**
* 提供注册服务
* @param user
* @throws UserExistException
*/
void registerUser(User user) throws UserExistException;
/**
* 提供登录服务
* @param userName
* @param userPwd
* @return
*/
User loginUser(String userName, String userPwd);
}
- 服务实现层
建包com.sst.cx.service.impl
新建UserServiceImpl.java
package com.sst.cx.service.impl;
import com.sst.cx.dao.IUserDao;
import com.sst.cx.dao.impl.UserDaoImpl;
import com.sst.cx.domain.User;
import com.sst.cx.exception.UserExistException;
import com.sst.cx.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);
}
}
- web.UI
建包com.sst.cx.web.UI
新建LoginUIServlet.java
package com.sst.cx.web.UI;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/LoginUIServlet")
public class LoginUIServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
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);
}
}
新建RegisterUIServlet.java
package com.sst.cx.web.UI;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/RegisterUIServlet")
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);
}
}
- 处理jsp逻辑层
建包com.sst.cx.web.controller
新建LoginServlet.java
package com.sst.cx.web.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sst.cx.domain.User;
import com.sst.cx.service.IUserService;
import com.sst.cx.service.impl.UserServiceImpl;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
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(
"对不起,用户名或密码有误!!请重新登录!2秒后为您自动跳到登录页面!!<meta http-equiv='refresh' content='2;url=%s'",
request.getContextPath()+"/LoginUIServlet");
request.setAttribute("message",message);
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
// 登录成功后,就将用户存储到session中
request.getSession().setAttribute("user", user);
String message = String.format(
"恭喜:%s,登陆成功!本页将在3秒后跳到首页!!<meta http-equiv='refresh' content='3;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);
}
}
新建LogoutServlet.java
package com.sst.cx.web.controller;
import java.io.IOException;
import java.text.MessageFormat;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 移除存储在session中的user对象,实现注销功能
request.getSession().removeAttribute("user");
// 由于字符串中包含有单引号,在这种情况下使用MessageFormat.format方法拼接字符串时就会有问题
// MessageFormat.format方法只是把字符串中的单引号去掉,不会将内容填充到指定的占位符中
String tempStr1 = MessageFormat.format(
"注销成功!!3秒后为您自动跳到登录页面!!<meta http-equiv='refresh' content='3;url={0}'/>",
request.getContextPath()+"/LoginUIServlet");
System.out.println(tempStr1);//输出结果:注销成功!!3秒后为您自动跳到登录页面!!<meta http-equiv=refresh content=3;url={0}/>
System.out.println("---------------------------------------------------------");
/**
* 要想解决"如果要拼接的字符串包含有单引号,那么MessageFormat.format方法就只是把字符串中的单引号去掉,不会将内容填充到指定的占位符中"这个问题,
* 那么可以需要使用单引号引起来的字符串中使用2个单引号引起来,例如:"<meta http-equiv=''refresh'' content=''3;url={0}''/>"
* 这样MessageFormat.format("<meta http-equiv=''refresh'' content=''3;url={0}''/>","index.jsp")就可以正常返回
* <meta http-equiv=''refresh'' content=''3;url=index.jsp'/>
*/
String tempStr2 = MessageFormat.format(
"注销成功!!3秒后为您自动跳到登录页面!!<meta http-equiv=''refresh'' content=''3;url={0}''/>",
request.getContextPath()+"/LoginUIServlet");
/**
* 输出结果:
* 注销成功!!3秒后为您自动跳到登录页面!!
* <meta http-equiv='refresh' content='3;url=/webmvcframework/servlet/LoginUIServlet'/>
*/
System.out.println(tempStr2);
String message = String.format(
"注销成功!!3秒后为您自动跳到登录页面!!<meta http-equiv='refresh' content='3;url=%s'/>",
request.getContextPath()+"/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);
}
}
新建RegisterServlet.java
package com.sst.cx.web.controller;
import java.io.IOException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
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 com.sst.cx.domain.User;
import com.sst.cx.exception.UserExistException;
import com.sst.cx.service.IUserService;
import com.sst.cx.service.impl.UserServiceImpl;
import com.sst.cx.util.WebUtils;
import com.sst.cx.web.formbean.RegisterFormBean;
@WebServlet("/RegisterServlet")
public class RegisterServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
1、接收客户端提交到服务端的表单数据。
2、校验表单数据的合法性,如果校验失败跳回到register.jsp,并回显错误信息。
3、如果校验通过,调用service层向数据库中注册用户。
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 将客户端提交的表单数据封装到RegisterFormBean对象中
RegisterFormBean formbean = WebUtils.request2Bean(request,RegisterFormBean.class);
// 校验用户注册填写的表单数据
if (formbean.validate() == false) {// 如果校验失败
// 将封装了用户填写的表单数据的formbean对象发送回register.jsp页面的form表单中进行显示
request.setAttribute("formbean", formbean);
// 校验失败就说明是用户填写的表单数据有问题,那么就跳转回register.jsp
request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response);
return;
}
User user = new User();
try {
// 注册字符串到日期的转换器
ConvertUtils.register(new DateLocaleConverter(), Date.class);
BeanUtils.copyProperties(user, formbean);// 把表单的数据填充到javabean中
user.setId(WebUtils.makeId());// 设置用户的Id属性
IUserService service = new UserServiceImpl();
// 调用service层提供的注册用户服务实现用户注册
service.registerUser(user);
String message = String.format(
"注册成功!!3秒后为您自动跳到登录页面!!<meta http-equiv='refresh' content='3;url=%s'/>",
request.getContextPath()+"/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);
}
}
- jsp验证层
建包com.sst.cx.web.formbean
新建RegisterFormBean.java
package com.sst.cx.web.formbean;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
public class RegisterFormBean {
// RegisterFormBean中的属性与register.jsp中的表单输入项的name一一对应
//<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方法负责校验表单输入项
* 表单输入项校验规则:
* private String userName; 用户名不能为空,并且要是3-8的字母 abcdABcd
* private String userPwd; 密码不能为空,并且要是3-8的数字
* 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]{3,8}")) {
isOk = false;
errors.put("userName", "用户名必须是3-8位的字母!!");
}
}
if (this.userPwd == null || this.userPwd.trim().equals("")) {
isOk = false;
errors.put("userPwd", "密码不能为空!!");
} else {
if (!this.userPwd.matches("\\d{3,8}")) {
isOk = false;
errors.put("userPwd", "密码必须是3-8位的数字!!");
}
}
// private String password2; 两次密码要一致
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;
}
}
- 工具层
建包com.sst.cx.util
新建WebUtils.java
package com.sst.cx.util;
import java.util.Enumeration;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.beanutils.BeanUtils;
// 封装客户端提交的表单数据到formbean中
public class WebUtils {
/**
* 将request对象转换成T对象
* @param request
* @param clazz
* @return
*/
public static <T> T request2Bean(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();
}
}
新建XmlUtils.java
package com.sst.cx.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
public class XmlUtils {
private static String filename = "DB.xml";
public static Document getDocument() throws DocumentException{
URL url = XmlUtils.class.getClassLoader().getResource(filename);
String realpath = url.getPath();
File file = null;
try {
file = new File(URLDecoder.decode(realpath,"UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
SAXReader reader = new SAXReader();
return reader.read(file);
}
public static void write2Xml(Document document) throws IOException{
URL url = XmlUtils.class.getClassLoader().getResource(filename);
String realpath = url.getPath();
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(new FileOutputStream(URLDecoder.decode(realpath,"UTF-8")), format );
writer.write( document );
writer.close();
}
}
- 异常层
建包com.sst.cx.exception
新建UserExistException.java
package com.sst.cx.exception;
public class UserExistException extends Exception{
public UserExistException() {
super();
}
public UserExistException(String message, Throwable cause) {
super(message, cause);
}
public UserExistException(String message) {
super(message);
}
public UserExistException(Throwable cause) {
super(cause);
}
}
src下新建DB.XML
<?xml version="1.0" encoding="UTF-8"?>
<users>
</users>
其他
出错了,查一下出错的原因,可能需要导入其他jar包.重启Tomcat
org.dom4j.DocumentException找不到xml
URLDecoder.decode(realpath,"UTF-8")