JavaWeb注册登陆功能分析

Dao层

只用实现数据库的查询增删,将判断用户是不是存在这个环节交给service

首先要创建个User类,每个User有username password vorifycode

Dao层实现数据库的增删查询,所有有两个方法 findByUsername(){}和add(){}

对于查询功能

findByUsername返回的是一个user类,相当于把根据名字查询到的用户信息返还给service层,所以传进来的参数应该是String类型

数据库操作首先要创建一个文件解析器SAXReader,对我们的数据库(xml文件)进行read解析

根据数据库的表单形式:

<users>
	<user username="李四" password="lisi"/>
	<user username="张三" password="zhangsan"/>
	<user username="王五" password="wangwu"/>
</users>

我们要获取user元素下有没有username等于需要查询的username的元素,"//user[@username='" + username + "']"

如果得到的元素为空,返还

如果得到的元素不为空,那我们就把这个元素的属性值赋给一个新的User返还

对于增删功能

add无需返还值,但是既然要添加用户,那我们的参数就应该是User

增加很简单,同样需要一个SAXReader解析器,然后通过getrootelement获得根节点,创建一个user元素

元素的属性值分别是user类user.getUsername和user.getPassword方法获得。然后将元素addattribute添加到根节点下

元素增加完后,这只是在内存上进行了修改,我们还需要把文件输出到数据库中保存

为了保证输出时的格式,用一个格式化器,先将空格都消除,然后用\t进行缩进并换行

首先创建一个XMLWriter,参数为一个输出流和格式。把前面修改过的document写出,最后再关闭输出流。

这个Dao层的两个功能就算完成了

package cn.itcast.user.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 cn.itcast.user.domain.User;

/**
 * 数据类
 * @author cxf
 *
 */
public class UserDao {
	private String path = "F:/users.xml";//依赖数据文件
	
	/**
	 * 按用户名查询
	 * @param username
	 * @return
	 */
	public User findByUsername(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,如果为null,返回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);
		}
	}
	
	/**
	 * 添加用户
	 * @param user
	 */
	public void add(User user) {
		/*
		 * 1. 得到Document
		 * 2. 通过Document得到root元素!<users>
		 * 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);//保存document对象
				writer.close();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		} catch (DocumentException e) {
			throw new RuntimeException(e);
		}
	}
}

既然我们已经实现了数据库的查询增删,那我们就可以提供一些服务——注册和登陆

首先我们先做注册

创建一个regist函数,如果我们要注册,总要知道这个用户注册过来的信息吧,所以传进来的参数应该为一个User

注册我们首先要判断数据库中有没有这个用户,如果没有那我们就调用数据库add方法添加这个用户

如果这个用户已经存在那我们就需要返回一个错误信息,说这个用户已经被注册了。

接着我们要有个UserDao类来调用数据库查询增删的功能

调用findByUsername如果返回值为空,说明这个用户已经存在,那就要抛出一个异常,并说这个用户已经存在

返回值如果不是空,说明注册成功。

接着做登陆

创建一个login函数,同样我们传进来的应该是个User表单(用户和密码即可,但为了简单我们这里统一用User进行封装这个表单),如果登陆成功要进入欢迎界面那我们还需要用户信息,所以返回值也应该是个User,这个User就应该是用户的整个信息

同样利用findByUsername查询数据库是否有这个username,如果返回值为空,说明没有这个人,那么就输出异常:用户不存在

如果返回值不为空,接着对比表单中的密码和数据空中username所对应的密码是否一致,不一致就输出异常:用户名密码错误

用户名密码都正确我们才返还User,即用户的所用信息

package cn.itcast.user.service;

import cn.itcast.user.dao.UserDao;
import cn.itcast.user.domain.User;

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

	/**
	 * 登录功能
	 * @param form
	 * @return
	 * @throws UserException 
	 */
	public User login(User form) throws UserException {
		/*
		 * 1. 使用form中的username进行查询,得到User user
		 */
		User user = userDao.findByUsername(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;
	}
}

注册和登陆功能都实现了,接着就是处理用户数据了,注册和登陆之前我们先要进行表单检验

例如:注册时名字和密码长度限制,登陆时需要验证码。

由于可能存在三种错误,我们将三种错误封装成一个map,键对应的三个可能出错的地方,值对应着异常。

对于用户名和密码1、不能为空,不能只是空格2、长度要在3-15之间

对于验证码1、不能为空2、要正确

现在对错误信息进行处理,如果map集合不为空,则向注册页面转发返还错误信息

如果map集合为空,说明表单校验没有出现问题,接下来进行注册,调用service的注册功能,并对注册页面输出注册成功信息

这里用输出写一条html语句,“注册成功”+跳转登陆页面,不是以原样输出的,需要编译的要加“”

package cn.itcast.user.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 cn.itcast.commons.CommonUtils;
import cn.itcast.user.domain.User;
import cn.itcast.user.service.UserException;
import cn.itcast.user.service.UserService;

public class RegistServlet extends HttpServlet {

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		
		// 依赖UserServlet
		UserService userService = new UserService();
		
		/*
		 * 1. 封装表单数据(封装到User对象中)
		 */
		User form = CommonUtils.toBean(request.getParameterMap(), User.class);
		
		
		/*
		 * 添加新任务(表单校验)
		 * 1. 创建一个Map,用来装载所有的表单错误信息
		 *   在校验过程中,如果失败,向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()) {
			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_vcode");
		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. 保存form到request域,为了回显
			 * 3. 转发到regist.jsp
			 */
			request.setAttribute("errors", errors);
			request.setAttribute("user", form);
			request.getRequestDispatcher("/user/regist.jsp").forward(request, response);
			return;
		}
		
		
		
		/*
		 * 2. 调用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域
			request.setAttribute("msg", e.getMessage());
			// 还要保存表单数据,到request域
			request.setAttribute("user", form);//用来在表单中回显!
			// 转发到regist.jsp
			request.getRequestDispatcher("/user/regist.jsp").forward(request, response);
		}
	}

}

对于自定义异常,只需要继承exception并给出父类构造器即可。

package cn.itcast.user.service;

/**
 * 自定义一个异常类
 *   只是给出父类中的构造器即可!方便用来创建对象!
 * @author cxf
 *
 */
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
    }
    
}


对于登陆时数据处理Servlet,有这么几件事要干:

1、利用toBean将登陆的账号密码保存到表单中

2、调用service的登录功能,如果成功登陆,就将user信息保存到session域,不成功就抛出异常信息

3、成功再转发到welcome页面

package cn.itcast.user.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 cn.itcast.commons.CommonUtils;
import cn.itcast.user.domain.User;
import cn.itcast.user.service.UserException;
import cn.itcast.user.service.UserService;

/**
 * UserServlet层
 * @author cxf
 *
 */
public class LoginServlet extends HttpServlet {
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");//请求编码(POST)
		response.setContentType("text/html;charset=utf-8");//响应编码
		
		// 依赖UserService
		UserService userService = new UserService();
		
		/*
		 * 1. 封装表单数据到User form中
		 * 2. 调用service的login()方法,得到返回的User user对象。
		 *   > 如果抛出异常:获取异常信息,保存到request域,再保存form,转发到login.jsp
		 *   > 如果没有异常:保存返回值到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() + "/user/welcome.jsp");
		} catch(UserException e) {
			request.setAttribute("msg", e.getMessage());
			request.setAttribute("user", form);
			request.getRequestDispatcher("/user/login.jsp").forward(request, response);
		}
		
	}
}

接下来在还要做一个生成验证码的servlet

调用VorifyCode类中的生成图片的方法并保存在bufferedImage中,我们还需要保存每一个验证码的文字到session域中,最后输出图片到客户端

package cn.itcast.user.web.servlet;

import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.itcast.vcode.utils.VerifyCode;

public class VerifyCodeServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 1. 创建验证码类
		 */
		VerifyCode vc = new VerifyCode();
		/*
		 * 2. 得到验证码图片
		 */
		BufferedImage image = vc.getImage();
		/*
		 * 3. 把图片上的文本保存到session中
		 */
		request.getSession().setAttribute("session_vcode", vc.getText());
		/*
		 * 4. 把图片响应给客户端
		 */
		VerifyCode.output(image, response.getOutputStream());
	}
}

好的一个简单的用户注册登陆功能就基本实现了


错误分析:

1、验证码地方一直出不来图片,搜寻不到VerifyCodeServlet。最后发现是web.xml没有添加servlet路径

<servlet>
	<servlet-name>VerifyCodeServlet</servlet-name>
	<servlet-class>user.web.servlet.VerifyCodeServlet</servlet-class>
</servlet>
	<servlet-mapping>
		<servlet-name>VerifyCodeServlet</servlet-name>
		<url-pattern>/VerifyCodeServlet</url-pattern>
	</servlet-mapping>

2、空指针异常

java.lang.NullPointerException
	user.web.servlet.RegistServlet.doPost(RegistServlet.java:30)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

发现是username去空格以后,我对空名字长度进行了length()方法的调用

猜你喜欢

转载自blog.csdn.net/TangXiaoPang/article/details/86709512