Java Web实战项目:注册登录(一)

javaweb项目实战:注册登录,客户关系管理系统(以xml为数据库)

项目框架分析

●功能:

注册/登录

●页面:

-->login.jsp :登录

-->regist.jsp : 注册

-->index.jsp: 主页(登录成功才能看到)

servlet:

-->LoginServlet

-->RegistServlet

Service:

-->UserService --> 与用户相关的业务类

DAO:

-->UserDao --> 与用户相关的数据库

Domain:

-->User  : username/password/verifyCode(对应数据库,还要对应所有表单)

●数据库设计:

user.xml

<users>

<users username="xxx" password="xxx">

<user username="xxx"  password="xxx">

</users>

●步骤

1.创建项目
2.导包

----CommonUtils.jar(所依赖的commons-beanutils.jar,commons-logging.jar)

----xml使用的dom4j

3.建包

----com.tinstu.user.domain

----------->User

----com.tinstu.user.dao

----------->UserDao

----com.tinstu.user.service

----------->UserService

----com.tinstu.user.web.servlet

----------->LoginServlet

----------->RegistServlet

4.创建jsp
5.创建一个 users.xml

项目框架搭建

略 最后直接放代码

按照项目框架分析中的步骤,新建好所有文件

注册功能流程分析

注册:需要完成

register.jsp

-》完成register的基本功能!

RegistServlet

-》封装表单数据,封装到user对象中.

-》调用service的regist()方法

---->如果这个方法没有问题,输出:注册成功

---->如果这个方法抛出了异常,把错误信息保存到request域,转发到regist.jsp(显示错误信息)

UserService

-》校验用户名是否被注册(通过用户名查询用户)(没有返回值,但注册失败抛出一个自定义的异常,在异常中添加异常信息:用户名已经被注册!)

-》添加用户

UserDao  通过业务分析得到

-》按照用户名查询用户对象:User findByUsername(String username)

-》插入一个用户到数据库中: void add (User user)

工作:

1.在service层添加一个UserException

2.DAO:

-->UserfindByUsername(String username)

-->void add(User user)

3.service

-->void regist() throws UserException

4.servlet

-->封装表单数据到User对象中

-->使用user调用service的regist的方法

-->如果得到UserException,那么把异常信息保存到request域中,转发回regist.jsp

-->输出注册成功!

Dao之按用户名查询用户对象/Dao之添加用户

package com.tinstu.dao;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import com.tinstu.domain.User;
/*
 * 数据类
 */
public class UserDao {
	private String path="D:/eclipse-work/xml/users.xml"; //数据文件
	
	/*
	 * 按用户名查询
	 */
	public  User fingByusername(String username) {
		/*
		 * 1.得到document
		 * 2.xpath查询
		 * 3.校验检查结果是否为null,如果为null,返回null
		 * 4.如果不为null,需要把element封装到user中
		 */
		//1.得到document
		//---创建解析器
		SAXReader reader = new SAXReader();
		try {
			Document doc = reader.read(path);
			//2.通过xpath查询Element
			Element ele = (Element) doc.selectSingleNode("//user[@username='"+username+"']"); // 双斜杠表示没有深度的查询,[] 内放条件,@ 表示属性
			//3.校验ele是否为null
			if(ele == null) 
				return null;
			//4.把ele的数据封装到User对象中
			User user = new User();
			String attrUsername = ele.attributeValue("username"); //获取元素的名为username的属性值
			String attrpassword = ele.attributeValue("password"); // 获取元素的名为password的属性值
			user.setUsername(attrUsername);
			user.setPassword(attrpassword);
			return user;
		} catch (DocumentException e) {
			throw new RuntimeException(e);
		}
	}
	/*
	 * 添加用户
	 */
	public void add(User user) {
		/*
		 * 1.得到document
		 * 2.通过document得到root元素
		 * 3.使用参数user,转发成element对象
		 * 4.把element添加到root元素中
		 * 5.保存document
		 */
		//得到document
		SAXReader reader = new SAXReader();
		try {
			Document doc = reader.read(path);
			//得到根元素
			Element root = doc.getRootElement();
			//通过根元素创建新元素
			Element userEle = root.addElement("user");
			//为userEle设置属性
			userEle.addAttribute("username", user.getUsername());
			userEle.addAttribute("password", user.getPassword());
		  // 保存文档
			OutputFormat format = new OutputFormat("\t",true); // 缩进使用\t ,是否换行,使用是!
			format.setTrimText(true);   // 清楚原有换行
			//创建XmlWriter
			XMLWriter writer;
			try {
				writer = new XMLWriter(new OutputStreamWriter(new FileOutputStream(path),"UTF-8"),format);
				writer.write(doc); //保存dicument对象
				writer.close();
			} catch (Exception e) {
				throw new RuntimeException(e);
			} 
  		} catch (DocumentException e) {
			throw new RuntimeException(e);
		}
	}
}
                                                                                                                                                                                   

 

Dao层测试

测试可使用 单元测试,右击->run as -> Junit Test

1.导入Junit的jar包

2.工程名右键PropertiesJava Build →PathLibrariesAdd Library选中JUnit,然后Next

3.注意xml的格式

service代码实现

userexception.java

package com.tinstu.service;

/**
 * 自定义一个异常类
 * 只是给出父类中的构造器即可,方便用来创建对象
 * @author 35582
 *
 */
public class UserException extends Exception {
	public UserException() {
		super();
		// TODO Auto-generated constructor stub
	}
	public UserException(String message, Throwable cause) {
		super(message, cause);
		// TODO Auto-generated constructor stub
	}
	public UserException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}
	public UserException(Throwable cause) {
		super(cause);
		// TODO Auto-generated constructor stub
	}
   }

 

registservlet.java

package com.tinstu.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.tinstu.domain.User;
import com.tinstu.service.UserException;
import com.tinstu.service.UserService;
import cn.itcast.commons.CommonUtils;
public class RegistServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		
		//依赖UserService
		UserService userService = new UserService () ;
		/*
		 * 1.封装表单数据(封装到User对象中)
		 */
		User form = CommonUtils.toBean(request.getParameterMap(),User.class);
		/*
		 * 调用userService的regist()方法,传递form过去
		 * 3.得到异常:获取异常信息,保存到request域,转发到regist.jsp
		 * 4.没有异常:输出支持成功
		 */
		try {
			userService.regist(form);
			response.getWriter().print("<h1>注册成功!</h1><a href=' "+
			request.getContextPath()+ "/user/login.jsp" + " '>点击这里去登录</a>");	
		}catch(UserException e) {
			request.setAttribute("msg", e.getMessage());
			request.getRequestDispatcher("user/regist.jsp").forward(request, response);
		}
	}
}

10.regist.jsp页面显示错误信息

regist.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<h1>注册</h1>
<p style="color:red;font-weight:900">${ msg }</p>
<!--  ${pageContext.request.contextPath }/RegistServlet -->
<form action="<c:url value='/RegistServlet' />" method="post">
用户名: <input type="text" name="username" /> <br>
密码 : <input type="text" name="password" /> <br>
<input type="submit" value="注册"> 
</form>
</body>
</html>

userService.java

package com.tinstu.service;
/*
 * 业务类
 */
import com.tinstu.dao.UserDao;
import com.tinstu.domain.User;

/**
 * User的业务逻辑
 * @author 35582
 *
 */
public class UserService {
   private UserDao userDao = new UserDao();
   /**
    * 注册功能
    */
   public void regist(User user) throws UserException{
	   /*
	    * 1.使用用户名去查询,如果返回null,完成添加
	    * 2.如果返回的不是null,抛出异常
	    * 
	    */
	   User user2 = userDao.fingByusername(user.getUsername());
	   System.out.println(user.getUsername());
	   if(user2 != null) throw new UserException("用户名"+ user.getUsername() +",已经被注册!" );
	   userDao.add(user);
   }
}

11.给注册添加验证码

给注册添加验证码

1.VerifyCode类

  • Bufferedimage getImage()  ----> 获取随机的验证码图片
  • String getText()  ----->获取图片上的文本
  • static output(BfferedImage,OutputStream) ---->把图片写入到指定的输出流中

2.VerifyCodeServlet

  • 获取随机验证码图片
  • 把验证码图片上的文本保存到session
  • 把图片响应到response的outputStream

3.regist.jsp

  • 添加<img src="指向Servlet" />
  • 添加一个文本框,用来输入验证码
  • “看不清,换一张”是一个超级链接,把上面的<img>的,src重新再次指向Servlet!为了处理浏览器的缓存,需要时间作为参数

4.修改RegistServlet

  • 校验验证码
  • 错误:保存表单数据到request域,保存错误信息到request域,转发回regist.jsp
  • 正确:什么都不做向下指向原来的代码

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
<script type="text/javascript">
   /*
   * 如果一个表单项的name和<img>的id相同,那么可能会出现问题!一般只有IE有
   */
    function _change(){
    	//获取<img>元素
    	var ele = document.getElementById("vCode");
    	ele.src = "<c:url value='/VerifyCodeServlet'/ >?xxx=" + new Date().getTime();
    }

</script>

</head>
<body>
<h1>注册</h1>
<p style="color:red;font-weight:900">${ msg }</p>
<!--  ${pageContext.request.contextPath }/RegistServlet -->
<form action="<c:url value='/RegistServlet' />" method="post">
用户名: <input type="text" name="username" value="${user.name }" />${error.username }<br>
密码 : <input type="text" name="password" value="${user.password} " />${error.password } <br>
验证码<input type="text" name="VerifyCode" value="${user.verifyCode}" size=3">
    <img id="vCode" src="<c:url value='/VerifyCodeServlet' />" border="2">
    <a href="javascript:_change()">换一张</a><br>
<input type="submit" value="注册"> 
</form>
</body>
</html>

进行表单校验(registServlet.java)

		/*
		 * 新添加任务:
		 *   校验验证码
		 *   1.用户填写的验证码已经封装到user中
		 *   2.从session获取真正的验证码
		 *   3.比较两者,如果不同,保存错误信息,保存表单数据,转发regist.jsp
		 *   4.如果相同,什么也不做,向下执行!
		 */

		if(!sessionVerifyCode.equalsIgnoreCase(form.getVerifyCode())) {
			request.setAttribute("msg", "验证码错误!");
			request.setAttribute("user", form);
			request.getRequestDispatcher("/user/regist.jsp").forward(request, response);
			return;
		}

 

12.给注册添加服务器端表单校验

服务器端表单(输入)校验

我们把这段校验,放到获取表单数据之后,验证码校验之前!

1.使用Map类型来装载错误信息!

  • Key:表单项名称,例如:username,password,verifycode
  • value
  • >>非空:用户名不能为空,或"密码不能为空"
  • >>长度:用户名长度必须在3-20之间,密码长度必须在3-20之间

2.在校验失败时,项map添加错误信息! 哪个字段出错,就给哪个字段添加错误信息!

3.判断map是否为空(长度是否为0),如果不空,说明有错误存在,保存map到request域,保存form到request域(回显),转发回regist.jsp

4.在regist.jsp页面中,显示map中的错误信息。${map.username}

registServlet.java

package com.tinstu.web.servlet;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.tinstu.domain.User;
import com.tinstu.service.UserException;
import com.tinstu.service.UserService;

import cn.itcast.commons.CommonUtils;

public class RegistServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		
		//依赖UserService
		UserService userService = new UserService () ;
		/*
		 * 1.封装表单数据(封装到User对象中)
		 */
		User form = CommonUtils.toBean(request.getParameterMap(),User.class);
		
		/*
		 * 添加新任务(表单校验)
		 *  1.用户填写的验证码已经封装到user中
		 *        在校验过程中,如果失败,向map添加错误信息,其中key为表单字段名称
		 *  2.校验之后,查看map长度是否大于0,如果大于0,说明有错误。就是有错误!
		 *    >保存map到request中,保存form到request中,转发到regist.jsp
		 *    
		 *  3.如果map为空,说明没有错误信息,向下没有错误信息,向下执行!
		 */
		//用来装载所有错误信息
		Map<String,String> errors = new HashMap<String,String>();
		//对用户名进行校验
		String username = form.getUsername();  //获取表单的username
		if (username == null || username.trim().isEmpty()) {   // ||后面表示username去掉空格之后为空
			errors.put("username", "用户名不能为空");
		}else if (username.length()<3 || username.length()>15) {
			errors.put("username", "用户名长度必须在3-15之间");					
		}
		//对密码进行校验
		String password = form.getPassword();
		if(password == null || password.trim().isEmpty()) {
			errors.put("password", "密码不能为空");	
		}else if (password.length()<3 || password.length()>15) {
			errors.put("password", "密码长度必须在3-15之间");
		}
		//对验证码进行校验
		String sessionVerifyCode = (String) request.getSession().getAttribute("session_vaode");	
		String verifyCode = form.getVerifyCode();
		if(verifyCode == null || verifyCode.trim().isEmpty()) {
			errors.put("verifyCode", "验证码不能为空");	
		}else if (verifyCode.length()!= 4) {
			errors.put("verifyCode", "验证码长度必须为4");
		}else if (verifyCode.equalsIgnoreCase(sessionVerifyCode)){
			errors.put("verifyCode", "验证码不正确");
		}
		/*
		 * 判断map是否为空,不为空,说明为存在错误
		 */
		if(errors != null && errors.size() > 0 ) {
			/*
			 * 1.保存errors到request域中
			 * 2.保存from到request域,为了回显
			 * 3.转发regist.jsp
			 */
			request.setAttribute("errors", errors);
			request.setAttribute("user", form);
			request.getRequestDispatcher("/regist.jsp").forward(request, response);
			return;
		}
		
		
		/*
		 * 新添加任务:
		 *   校验验证码
		 *   1.用户填写的验证码已经封装到user中
		 *   2.从session获取真正的验证码
		 *   3.比较两者,如果不同,保存错误信息,保存表单数据,转发regist.jsp
		 *   4.如果相同,什么也不做,向下执行!
		 */

//		if(!sessionVerifyCode.equalsIgnoreCase(form.getVerifyCode())) {
//			request.setAttribute("msg", "验证码错误!");
//			request.setAttribute("user", form);
//			request.getRequestDispatcher("/user/regist.jsp").forward(request, response);
//			return;
//		}
		
		/*
		 * 调用userService的regist()方法,传递form过去
		 * 3.得到异常:获取异常信息,保存到request域,转发到regist.jsp
		 * 4.没有异常:输出支持成功
		 */
		try {
			userService.regist(form);
			response.getWriter().print("<h1>注册成功!</h1><a href=' "+
			request.getContextPath()+ "/user/login.jsp" + " '>点击这里去登录</a>");	
		}catch(UserException e) {
			request.setAttribute("msg", e.getMessage());
			request.getRequestDispatcher("/regist.jsp").forward(request, response);
		}
	}
}

regist.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
<script type="text/javascript">
   /*
   * 如果一个表单项的name和<img>的id相同,那么可能会出现问题!一般只有IE有
   */
   function _change(){
   	//获取<img>元素
   	var ele = document.getElementById("verifyCode");
   	ele.src = "<c:url value='/VerifyCodeServlet' />?xxx=" + new Date().getTime();
   }
</script>

</head>
<body>
<h1>注册</h1>
<p style="color:red;font-weight:900">${ msg }</p>
<!--  ${pageContext.request.contextPath }/RegistServlet -->
<form action="<c:url value='/RegistServlet' />" method="post">
用户名: <input type="text" name="username" value="${user.username }" />${errors.username }<br/>
 密 码 : <input type="text" name="password" value="${user.password} " />${errors.password } <br/>
验证码:<input type="text" name="verifyCode" value="${user.verifyCode}" size="3" />
    <img id="verifyCode" src="<c:url value='/VerifyCodeServlet' />" border="2" />
    <a href="javascript:_change()">换一张</a>${errors.verifyCode}<br/>
<input type="submit" value="注册"> 
</form>
</body>
</html>

13.regist.jsp页面回显,注册基本完成

注册信息有误时,点击注册不清空文本框里面的内容!

RegistServlet.java中后面代码修改为

try {
			userService.regist(form);
			response.getWriter().print("<h1>注册成功!</h1><a href=' "+
			request.getContextPath()+ "/user/login.jsp" + " '>点击这里去登录</a>");	
		}catch(UserException e) {
			//获取异常信息保存到request域中
			request.setAttribute("msg", e.getMessage());
			//还要保存表单数据,到request域中
			request.setAttribute("user", form); //用来在表单中回显
			//转发regist.jsp
			request.getRequestDispatcher("/regist.jsp").forward(request, response);
		}

14.登录功能流程分析

登录功能

页面 login.jsp ---> 登录表单

LoginServlet  -->

  • 1.获取表单数据,封装到user中
  • 2.通过service的login( ) ,传递form过去 !
  • 3.如果service的login( ),返回一个User对象!
  • --4.有异常:获取异常信息,保存到request域,保存到form,转发到login.jsp
  • --5.没有异常:保存返回的user对象到session中!! 重定向到welcome.jsp

UserService # login ( )

public User login ( user form){ ...... }

1.使用用户名查询数据库,得到返回的User

  • 返回为null,抛出异常,异常信息为(用户名不存在)
  • 返回不为null,获取查询出来的user的password域form的password的form的password进行比较!如果不同:抛出异常(密码错误!)
  • 如果相同,返回查询结果!

UserDao

1.通过用户名查询用户!(已经存在了,不要再写)

loginServlet.java

package com.tinstu.web.servlet;

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.tinstu.domain.User;
import com.tinstu.service.UserException;
import com.tinstu.service.UserService;

import cn.itcast.commons.CommonUtils;

public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

    public LoginServlet() {
    
    }

	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
	
		//依赖UserService
		UserService userService = new UserService();
		/*
		 * 1.获取表单数据,封装到user中
         * 2.通过service的login( ) ,传递form过去 !
         * 3.如果service的login( ),返回一个User对象!
         * --4.有异常:获取异常信息,保存到request域,保存到form,转发到login.jsp
         * --5.没有异常:保存返回的user对象到session中!! 重定向到welcome.jsp
		 */
		User form = CommonUtils.toBean(request.getParameterMap(),User.class);
		try {
			User user = userService.login(form);
			request.getSession().setAttribute("sessionUser", user);
			response.sendRedirect(request.getContextPath()+"/welcome.jsp");
		} catch (Exception e) {
			request.setAttribute("msg", e.getMessage());
			request.setAttribute("user", form);
			request.getRequestDispatcher("/login.jsp").forward(request, response);
			
		}
	}
}

userServlet.java加入登录功能

  /**
    * 登录功能
    * @param form
    * @return
 * @throws UserException 
    */
public User login(User form) throws UserException {
	/*
	 * 1.使用form中的username进行查询。得到User user
	 */
	User user = userDao.fingByusername(form.getUsername());
	//2.如果返回null,说明用户名不存在,抛出异常,异常信息为“用户名不存在”
	if (user == null) throw new UserException("用户名不存在!");
	//3.比较user的password和form的password,如果不同,抛出异常,异常信息为:密码错误!
	if (!form.getPassword().equals(user.getPassword())) {
		 throw new UserException("密码错误!");
	}
	//返回数据库中查询出来的user,而不是form,因为form中只有用户名和密码,而user是所有用户信息!
	return user;
}

welcome.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>欢迎</title>
</head>
<body>
<h1>welcome!!!</h1>
 <c:choose>
    <c:when test="${empty sessionScope.sessionUser}">请先登录!</c:when>
    <c:otherwise>
       ${sessionScope.sessionUser}
    </c:otherwise>
 
 
 </c:choose>
</body>
</html>

阅读剩余
THE END