用户类设计及用户DAO
用户类
我们在entity包下创建一个名为User.java的类。User是一个只含有三个属性的JavaBean对象。其中的uid是用户id,用于标识一个用户,使用在url上会更加方便。
entity.User.java
package entity;
public class User {
private String uid;
private String name;
private String password;
public User(){
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
用户DAO
对操作逻辑进行必要的分析,我们可以知道UserDAO需要有如下方法:
- 注册:
- 判断用户是否已经存在
- 插入用户数据
- 登陆
- 判断输入的用户名和用户密码确定用户是否存在
具体实现与之前设计BookDAO的过程相同。这里如下几点需要说明:
1、注册用户成功时,也就是插入user数据成功时,需要返回一个uid。我们需要将uid也写入到session中,因为我们是通过uid来组成连接访问用户主页(这里不做个人主页的实现),以及将购买的图书写入数据库(利用uid和isbn确定是谁购买的图书)等重要作用。相同的,在登陆的时候也需要返回uid。
2、在数据库设计中,我将用户名name设置为唯一,也就是不允许含有两个相同名字的用户。所在当插入相同名字的记录时,会抛出异常,这样我们也可以直接使用这个异常来判断注册的用户名是否已经存在了。
//注册用户方法
// 方法一
if(!isExistByName(name)){
addUser(user);
}
// 方法二
String uid = addUser(user);
if(uid == "exist"){
System.out.println("用户已存在");
}else if(uid == null){
System.out.println("服务器出错");
}
dao.UserDAO.java
package dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException;
import entity.User;
import util.DBHelper;
public class UserDAO {
// 注册
// 判断用户是否已经存在
public boolean isExistByName(String username){
Connection conn = null;
PreparedStatement preStmt = null;
ResultSet userSet = null;
try{
//【1. 连接数据库】
conn = DBHelper.getConnection();
//【 2. 执行SQL语句,接收执行结果集ResultSet 】
String sql = "select * from user where user=?";
preStmt = conn.prepareStatement(sql);
preStmt.setString(1, username);
userSet = preStmt.executeQuery();
//【 3. 处理执行结果集ResultSet】
if(userSet.next()){
return true;
}
return false;
}catch(Exception ex){
ex.printStackTrace();
return true;
}finally{
//【 4. 必要的关闭ResultSet、Statement 】
if(userSet != null){
try {
userSet.close();
userSet = null;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(preStmt != null){
try {
preStmt.close();
preStmt = null;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
// 插入用户数据,同时判断用户是否存在
public String addUser(User user){
Connection conn = null;
PreparedStatement preStmt = null;
ResultSet affectedSet = null;
String uid = null;
try{
conn = DBHelper.getConnection();
String sql = "insert into user(name, password) values(?, ?)";
// [!]注意这里的insert获取id的写法
preStmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
preStmt.setString(1, user.getName());
preStmt.setString(2, user.getPassword());
preStmt.executeUpdate();
affectedSet = preStmt.getGeneratedKeys();
if(affectedSet.next()){
uid = affectedSet.getString(1);
}
return uid;
}catch(MySQLIntegrityConstraintViolationException ex){
if(ex.getErrorCode() == 1062){
// System.out.println("用户已存在");
return "exist";
}
ex.printStackTrace();
return null;
}catch(Exception ex){
ex.printStackTrace();
return null;
}finally{
if(affectedSet != null){
try {
affectedSet.close();
affectedSet = null;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(preStmt != null){
try {
preStmt.close();
preStmt = null;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
// 登陆
// 判断用户名和用户密码是否匹配
public String userLogin(User user){
Connection conn = null;
PreparedStatement preStmt = null;
ResultSet userSet = null;
try{
conn = DBHelper.getConnection();
String sql = "select uid from user where name=? and password=?";
preStmt = conn.prepareStatement(sql);
preStmt.setString(1, user.getName());
preStmt.setString(2, user.getPassword());
userSet = preStmt.executeQuery();
if(userSet.next()){
return userSet.getString("uid");
}
return "false";
}catch(Exception ex){
ex.printStackTrace();
return "false";
}finally{
//【 4. 必要的关闭ResultSet、Statement 】
if(userSet != null){
try {
userSet.close();
userSet = null;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(preStmt != null){
try {
preStmt.close();
preStmt = null;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String args[]){
UserDAO userdao = new UserDAO();
User user = new User();
user.setName("xiandddg");
user.setPassword("112222");
// userdao.addUser(user);
System.out.println(userdao.userLogin(user));
System.out.println("完成");
}
}
个人感觉我对这个DAO类的设计不够合理,在insert方法和userLogin方法中会用三种数据返回,分别是(uid,用户已存在,服务器错误)和(uid,用户不存在或者密码错误,服务器错误)。这里直接用String的返回再判断总感觉不怎么合理,或者应该用异常类处理。如果有更好的实现方法,欢迎和我交流。
注册
serlvet业务处理
在开始之前我们需要在”java Resources”目录下创建一个名为”servlet”的包,用于存放servlet类。注册的过程很简单,只需如下四步。
1. 获取前端提交过来的数据
2. 判断数据合法性(是否为空或者长度不合法)
3. 判断用户是否在数据库中已存在,存在则继续,否则返回
4. 加密密码,写入数据库,放回uid
5. 将用户信息写入session,跳转到index页面
在获取提交过来的数据之前我们需要使用request.request.setCharacterEncoding("utf-8");
防止提交过来的非字符数据出现乱码。
为了保护用户信息,我们需要对密码进行加密,这里使用的是SHA加密方法。在util包中创建如下类,并做如下实现,这样我们就可以直接调用SHA的encrypt
静态方法密码进行加密了。
util.SHA.java
package util;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SHA {
// 该值不可修改
public static final String KEY_SHA = "SHA";
public static String encrypt(String password){
BigInteger sha = null;
byte[] byteDate = password.getBytes();
MessageDigest md;
try {
md = MessageDigest.getInstance(KEY_SHA);
// 更新摘要
md.update(byteDate);
// //完成哈希计算
sha = new BigInteger(md.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
return sha.toString(32);
}
}
写入数据之后要记得将用户信息写入session中,用于检验用户是否已经登录,用于区分登录与未登录进行的不同操作。由于servlet没有内置对象,所以我们不能用session.segAttribute("user",user);
的方式进行写入,需要用下面的代码写入。
request.getSession().setAttribute("user", user);
request.getSession().setMaxInactiveInterval(14400);
serlvet作为中间控制器,用于处理业务逻辑,所以处理完成之后我们可以进行服务器内部转发或者重定向。注意这里的重定向时需要先获得项目的根目录,否则无法进行正常的跳转。response.sendRedirect(request.getContextPath() + "/index.jsp");
。转发或者重定向之后记得return
,否则会继续执行下面的操作。
注册错误提示。既然用户有输入,必然需要做出相应的提示,这里是利用request
进行设置,并用request.getRequestDispatcher("/signin.jsp").forward(request, response);
进行服务器内部跳转,使得在一次请求内将相关信息从servlet传递到JSP中。注意,在内部跳转中,我们只需要使用/signin.jsp
,而无需进行路径的拼接。
servlet.Signin.java
package 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 dao.UserDAO;
import entity.User;
import util.SHA;
/**
* Servlet implementation class Signin
*/
//该servlet在web.xml中进行了配置
//@WebServlet("/signin")
public class Signin extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public Signin() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 用户通过url的方式访问该servlet,重定向到登陆页面
request.getRequestDispatcher("/signin.jsp").forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if(request.getSession().getAttribute("user") != null){
// 用户已经登录,此时不能再注册
response.sendRedirect(request.getContextPath() + "/index.jsp");
return;
}
// 防止表单中非字符输入乱码
request.setCharacterEncoding("utf-8");
String username = (String) request.getParameter("name");
String password = (String) request.getParameter("password");
String repassword = (String) request.getParameter("repassword");
// 用户名和密码验证
if(username == null || username.length() == 0){
request.setAttribute("error", "用户名不能为空");
request.getRequestDispatcher("/signin.jsp").forward(request, response);
return;
}
if( username.length() > 10){
request.setAttribute("error", "用户名长度不能大于10");
request.getRequestDispatcher("/signin.jsp").forward(request, response);
return;
}
if(password == null || password.length() == 0){
request.setAttribute("error", "密码不能为空");
request.getRequestDispatcher("/signin.jsp").forward(request, response);
return;
}
if(password.length() < 6 || password.length() > 16){
request.setAttribute("error", "密码长度应该在6到16之间");
request.getRequestDispatcher("/signin.jsp").forward(request, response);
return;
}
if(repassword == null || repassword.length() == 0){
request.setAttribute("error", "重复密码不能为空");
request.getRequestDispatcher("/signin.jsp").forward(request, response);
return;
}
if(!password.equals(repassword)){
request.setAttribute("error", "两次输入密码不同");
request.getRequestDispatcher("/signin.jsp").forward(request, response);
return;
}
User user = new User();
user.setName(username);
// 通过SHA加密之后再写入数据库
user.setPassword(SHA.encrypt(password));
UserDAO userdao = new UserDAO();
String uid = userdao.addUser(user);
if(uid.equals("exist")){
request.setAttribute("error", "用户名已存在");
request.getRequestDispatcher("/signin.jsp").forward(request, response);
return;
}
// 将用户信息写入到session中,并设置有效时间为4小时(14400s)
user.setPassword("");
request.getSession().setAttribute("user", user);
request.getSession().setMaxInactiveInterval(14400);
// 重定向到首页
response.sendRedirect(request.getContextPath()+"/index.jsp");
}
}
在web.xml中的web-app下写入如下内容即可完成对servlet.signin.java的基本配置。注意这里的两处name需要相同。
<!-- 配置Servlet的名字 -->
<servlet>
<servlet-name>signin</servlet-name>
<servlet-class>servlet.Signin</servlet-class>
</servlet>
<!-- 配置Servlet的url -->
<servlet-mapping>
<servlet-name>signin</servlet-name>
<url-pattern>/signin</url-pattern>
</servlet-mapping>
JSP前端展示
由于我们已经需要登录注册了,所以这里对header.jsp进行简单的修改如下。将<li class="li-col"><a href="#">CUSTOMER</a></li>
修改如下代码。同时还要导入User类:<%@ page import="entity.User" %>
这里可以利用JSP的内置对象session
获取我们之前出入的user,并用于登陆状态的判断,从而做出不同的展示。
<li class="dropdown li-col">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
CUSTOMER
<b class="caret"></b>
</a>
<%
if(session.getAttribute("user") == null){
%>
<ul class="dropdown-menu">
<li><a href="signin.jsp">注册</a></li>
<li><a href="login.jsp">登录</a></li>
</ul>
<%
}else{
%>
<ul class="dropdown-menu">
<li><a href="#"><%= ((User)session.getAttribute("user")).getName() %></a></li>
<li><a href="./orderlist.jsp">我的订单</a></li>
<li class="divider"></li>
<li><a href="logout">登出</a></li>
</ul>
<%
}
%>
</li>
代码主体。在主体部分,我们做一个普通的表单提交,这里提交到"signin"
即可,"signin"
是我们对servlet.Signin.java
的配置。此外,这里需要防止已登录用户进入该页面,以及显示出相应的错误提示信息。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>
<div class="main main-white">
<div class="container-fluid">
<div class="row">
<div class="col-md-4 col-md-offset-4 col-sm-4 col-sm-offset-4">
<div class="signin-div">
<%
if(session.getAttribute("user") != null){
// 用户已经登录,此时不能再注册
response.sendRedirect(request.getContextPath() + "/index.jsp");
}
if(request.getAttribute("error") != null){
%>
<div class="alert-div">
<a href="javascript:void(0)" class="close">
×
</a>
<strong>警告!</strong><span class="tips-text"><%= request.getAttribute("error") %></span>
</div>
<%
}
%>
<form class="signin-form" role="form" action="signin" method="post">
<div class="form-group">
<label for="username">USERNAME</label>
<input type="text" class="form-control" name="name" placeholder="enter name" />
</div>
<div class="form-group">
<label for="password">PASSWORD</label>
<input type="password" class="form-control" name="password" placeholder="enter password" />
</div>
<div class="form-group">
<label for="repassword">REPEAT PASSWORD</label>
<input type="password" class="form-control" name="repassword" placeholder="repeat password" />
</div>
<button type="submit" class="btn btn-default">SIGNIN</button>
</form>
</div>
</div>
</div>
</div>
</div>
<%@ include file="footer.jsp" %>
登陆
serlvet业务处理
登陆的实现和注册的实现差别不会太大。
1. 获取前端提交过来的数据
2. 判断数据合法性(是否为空或者长度不合法)
3. 判断用户是否在数据库中已存在,存在则继续,否则返回
4. 将用户信息写入session,跳转到index页面
servlet.Login.java
package 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 dao.UserDAO;
import entity.User;
import util.SHA;
/**
* Servlet implementation class Login
*/
@WebServlet(name="loginservlet",urlPatterns={"/login","/loginto"})
public class Login extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public Login() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 用户通过url的方式访问该servlet,重定向到登陆页面
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if(request.getSession().getAttribute("user") != null){
// 用户已经登录,此时不能再注册
response.sendRedirect(request.getContextPath() + "/index.jsp");
return;
}
// 设置编码,放置表单中非字符输入乱码
request.setCharacterEncoding("utf-8");
String username = request.getParameter("name");
String password = request.getParameter("password");
String uid = "";
if(username == null || username.length() == 0){
request.setAttribute("error", "用户名不能为空");
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
}
if(password == null || username.length() == 0){
request.setAttribute("error", "密码不能为空");
request.getRequestDispatcher("/login.jsp").forward(request,response);
return;
}
password = SHA.encrypt(password);
User user = new User();
user.setName(username);
user.setPassword(password);
UserDAO userdao = new UserDAO();
uid = userdao.userLogin(user);
if(uid == "false"){
request.setAttribute("error", "用户名或者密码错误");
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
}
user.setUid(uid);
// 登陆成功,将用户信息设置到session中,并设置有效时间为4小时(4 * 60 * 60 = 14400s)
// 注意这里是servlet,所以不能直接用jsp的内置对象session
user.setPassword("");
request.getSession().setAttribute("user", user);
request.getSession().setMaxInactiveInterval(14400);
System.out.println(request.getSession().getAttribute("user"));
// 处理后重定向到主页
response.sendRedirect(request.getContextPath() + "/index.jsp");
}
}
JSP前端展示
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>
<div class="main main-white">
<div class="container-fluid">
<div class="row">
<div class="col-md-4 col-md-offset-4 col-sm-4 col-sm-offset-4">
<div class="signin-div">
<%
if(session.getAttribute("user") != null){
// 用户已经登录,此时不能再注册
response.sendRedirect(request.getContextPath() + "/index.jsp");
}
if(request.getAttribute("error") != null){
%>
<div class="alert-div">
<a href="javascript:void(0)" class="close">
×
</a>
<strong>警告!</strong><span class="tips-text"><%= request.getAttribute("error") %></span>
</div>
<%
}
%>
<form class="signin-form" role="form" action="login" method="post">
<span class="tosignin">Don't have a account? <a href="./signin.jsp">sign in</a></span>
<hr />
<div class="form-group">
<label for="username">USERNAME</label>
<input type="text" class="form-control" name="name" placeholder="enter name" />
</div>
<div class="form-group">
<label for="password">PASSWORD</label>
<input type="password" class="form-control" name="password" placeholder="enter password" />
</div>
<button type="submit" class="btn btn-default">LOGIN</button>
</form>
</div>
</div>
</div>
</div>
</div>
<%@ include file="footer.jsp" %>
登出
该类的合性代码只有两行,只要在doGet
方法中实现这两行代码即可。
// 将session中的user设置为null
request.getSession().setAttribute("user", null);
// 重定向到index.jsp
response.sendRedirect(request.getContextPath() + "/index.jsp");
servlet.Logout.java
package 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;
/**
* Servlet implementation class Logout
*/
@WebServlet("/logout")
public class Logout extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public Logout() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getSession().setAttribute("user", null);
response.sendRedirect(request.getContextPath() + "/index.jsp");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}