实现用户的注册和登录,用户填写注册信息,发送给服务器后,服务器保存用户信息到数据库,下一次用户登录,将登录信息发送给服务器后,服务器到数据库检查用户信息是否正确,正确则浏览器跳转到正确登录的页面,错误则浏览器跳转到错误登录的页面


JavaEE三层架构介绍

9-书城项目(第二阶段)_html

搭建书城项目环境,一个web项目的结构如下

9-书城项目(第二阶段)_java_02

新建动态web工程book

9-书城项目(第二阶段)_html_03

将第一阶段的html页面等复制到web目录下,新建相应的包

9-书城项目(第二阶段)_html_04

1,创建书城需要的数据库和t_user用户表

9-书城项目(第二阶段)_ide_05

2,创建数据库表对应的JavaBean对象——User类

package com.atguigu.pojo;

public class User {

private Integer id;
private String username;
private String password;
private String email;

public User() {
}

public User(Integer id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
'}';
}
}

3,编写JdbcUtils工具类及测试

将数据库连接的驱动添加到WEB-INF下的lib目录

9-书城项目(第二阶段)_ide_06

创建类库

9-书城项目(第二阶段)_用户名_07

9-书城项目(第二阶段)_用户名_08

先不添加到模块,给该类库改名,apply

9-书城项目(第二阶段)_用户名_09

给book工程添加book_lib类库

9-书城项目(第二阶段)_ide_10

9-书城项目(第二阶段)_用户名_11

9-书城项目(第二阶段)_sql_12

点击apply

9-书城项目(第二阶段)_sql_13

9-书城项目(第二阶段)_java_14

用于连接数据库的配置文件

9-书城项目(第二阶段)_java_15

JDBCUtils工具类用于获取和关闭数据库连接

package com.atguigu.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class JdbcUtils {

private static DruidDataSource dataSource;

static {
try {
Properties properties = new Properties();
// 读取jdbc.properties属性配置文件
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(inputStream);
// 创建数据库连接池
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);

// 写一个空的main()并执行,能获取到连接
// System.out.println(dataSource.getConnection()); // com.mysql.jdbc.JDBC4Connection@29444d75
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 获取数据库连接池中的连接
* @return
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = dataSource.getConnection();
}catch (Exception e) {
e.printStackTrace();
}
return conn;
}

/**
* 关闭连接
* @param conn
*/
public static void close(Connection conn) {
if (conn != null) {
try {
conn.close();
}catch (SQLException e) {
e.printStackTrace();
}
}
}
}

测试

package com.atguigu.test;

import com.atguigu.utils.JdbcUtils;
import org.junit.Test;

import java.sql.Connection;

public class JdbcUtilsTest {

@Test
public void testJdbcUtils() {
for (int i = 0 ; i < 100 ; i++) {
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
JdbcUtils.close(connection); // 设置了连接池的最大连接数是10,所以用完要及时释放
}
}
}


4,编写BaseDao

将dbutils包复制到lib下

9-书城项目(第二阶段)_用户名_16

添加到book_lib类库中

9-书城项目(第二阶段)_用户名_17

package com.atguigu.dao.impl;

import com.atguigu.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public abstract class BaseDao {

private QueryRunner queryRunner = new QueryRunner();

/**
* update()用来执行insert、update、delete操作
* @return 返回-1表示执行失败,返回其他值表示操作影响的行数
*/
public int update(String sql, Object ... args) {
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.update(conn, sql, args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
}
return -1;
}

/**
* 将查询得到的结果返回为一个JavaBean对象
* @param type 返回对象的类型
* @param sql 执行的sql语句
* @param args 传入sql语句的参数
* @param <T> 返回类型的泛型
* @return
*/
public <T> T queryForOne(Class<T> type, String sql, Object ... args) {
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.query(conn, sql, new BeanHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
}
return null;
}

/**
* 查询结果有多个时,返回多个JavaBean对象
* @param type
* @param sql
* @param args
* @param <T>
* @return
*/
public <T> List<T> queryForList(Class<T> type, String sql, Object ... args) {
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.query(conn, sql, new BeanListHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
}
return null;
}

/**
* 返回某一行某一列的数据
* @param sql
* @param args
* @return
*/
public Object queryForSingleValue(String sql, Object ... args) {
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.query(conn, sql, new ScalarHandler(), args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
}
return null;
}
}

5,编写UserDaoImpl和测试

package com.atguigu.dao;

import com.atguigu.pojo.User;

public interface UserDao {

/**
* 根据用户名查询用户信息,用在注册时
* @param username 用户名
* @return 返回null表示该用户不存在
*/
public User queryUserByUsername(String username);

/**
* 根据用户名和密码查询用户信息,用在登录时
* @param username
* @param password
* @return 返回null表示用户名或密码错误
*/
public User queryUserByUsernameAndPassword(String username, String password);

/**
* 保存用户信息
* @param user
* @return 返回-1代表操作失败,其他值表示操作影响的行数
*/
public int saveUser(User user);
}
package com.atguigu.dao.impl;

import com.atguigu.dao.UserDao;
import com.atguigu.pojo.User;

public class UserDaoImpl extends BaseDao implements UserDao {

@Override
public User queryUserByUsername(String username) {
String sql = "select `id`, `username`, `password`, `email` from t_user where username = ?";
return queryForOne(User.class, sql, username);
}

@Override
public User queryUserByUsernameAndPassword(String username, String password) {
String sql = "select `id`, `username`, `password`, `email` from t_user where username = ? and password = ?";
return queryForOne(User.class, sql, username, password);
}

@Override
public int saveUser(User user) {
String sql = "insert into t_user(`username`, `password`, `email`) value(?,?,?)";
return update(sql, user.getUsername(), user.getPassword(), user.getEmail());
}
}

在接口中按Ctrl+shift+t

9-书城项目(第二阶段)_html_18

生成测试方法

9-书城项目(第二阶段)_用户名_19

9-书城项目(第二阶段)_java_20

package com.atguigu.test;

import com.atguigu.dao.impl.UserDaoImpl;
import com.atguigu.pojo.User;
import org.junit.Test;

import static org.junit.Assert.*;

public class UserDaoTest {

UserDaoImpl userDao = new UserDaoImpl();

@Test
public void queryUserByUsername() {
if (userDao.queryUserByUsername("admin") == null) {
System.out.println("用户名可用");
} else {
System.out.println("用户名已存在");
}
}

@Test
public void queryUserByUsernameAndPassword() {
if (userDao.queryUserByUsernameAndPassword("admin", "admin") == null) {
System.out.println("用户名或密码错误,登录失败");
} else {
System.out.println("登录成功");
}
}

@Test
public void saveUser() {
System.out.println(userDao.saveUser(new User(null, "wzg", "123456", "wzg168@qq.com")));
}
}

6,编写UserServiceImpl和测试

package com.atguigu.service;

import com.atguigu.pojo.User;

public interface UserService {

/**
* 注册用户
* @param user
*/
public void registUser(User user);

/**
* 登录
* @param user
* @return 返回null代表登录失败
*/
public User login(User user);

/**
* 检查用户名是否可用
* @param username
* @return 返回true表示用户名已存在,false表示用户名可用
*/
public boolean existUsername(String username);
}
package com.atguigu.service.impl;

import com.atguigu.dao.UserDao;
import com.atguigu.dao.impl.UserDaoImpl;
import com.atguigu.pojo.User;
import com.atguigu.service.UserService;

public class UserServiceImpl implements UserService {

private UserDao userDao = new UserDaoImpl();

@Override
public void registUser(User user) {
userDao.saveUser(user);
}

@Override
public User login(User user) {
return userDao.queryUserByUsernameAndPassword(user.getUsername(), user.getPassword());
}

@Override
public boolean existUsername(String username) {
if (userDao.queryUserByUsername(username) == null) {
return false;
}
return true;
}
}
package com.atguigu.test;

import com.atguigu.pojo.User;
import com.atguigu.service.UserService;
import com.atguigu.service.impl.UserServiceImpl;
import org.junit.Test;

public class UserServiceTest {

UserService userService = new UserServiceImpl();

@Test
public void registUser() {
userService.registUser(new User(null, "bbj168", "666666", "bbj168@qq.com"));
userService.registUser(new User(null, "abc168", "666666", "abc168@qq.com"));
}

@Test
public void login() {
System.out.println(userService.login(new User(null, "wzg", "123456", null)));
}

@Test
public void existUsername() {
if (userService.existUsername("wzg168")){
System.out.println("用户名已存在");
} else {
System.out.println("用户名可用");
}
}
}

实现用户注册的功能

9-书城项目(第二阶段)_ide_21

在注册页面regist.html中配置提交给服务器的地址,web阶段使用base+相对路径,框架之后使用绝对路径。但使用base标签存在一个问题,比如下面link标签中的地址,使用相对路径是从当前目录开始的,而base标签会将它变为从http://localhost:8080/book/开始,这个页面中其他使用相对路径的地方也是一样,所以在浏览器中显示时就找不到这些资源的地址

9-书城项目(第二阶段)_ide_22

9-书城项目(第二阶段)_java_23

修改注册页面中使用到相对路径的地方,方法就是看浏览器中报红的文件。因为base标签的地址对应到web目录,所以只需将页面中相对路径里的上层目录删掉

9-书城项目(第二阶段)_java_24

比如

9-书城项目(第二阶段)_html_25

给工程添加tomcat服务器

9-书城项目(第二阶段)_java_26

9-书城项目(第二阶段)_用户名_27

运行并访问注册页面

9-书城项目(第二阶段)_java_28

给显示注册成功的页面regist_success.html也使用base标签,修改相应的地址值

9-书城项目(第二阶段)_html_29

web.xml

9-书城项目(第二阶段)_sql_30

在regist.html中配置提交给服务器的地址,使用post方法。结合base标签,服务器地址就是http://localhost:8080/book/registServlet,即上面web.xml中配置的Servlet程序访问地址

9-书城项目(第二阶段)_html_31

给验证码的标签加上name属性

9-书城项目(第二阶段)_sql_32

RegistServlet.java

package com.atguigu.web;

import com.atguigu.pojo.User;
import com.atguigu.service.UserService;
import com.atguigu.service.impl.UserServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class RegistServlet extends HttpServlet {

private UserService userService = new UserServiceImpl();

// 注册含有密码信息,要用post请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1,获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
// 2,校验验证码是否正确,这里先使用固定验证码
if ("abcde".equalsIgnoreCase(code)) {
// web层不能直接调用Dao层,要通过Service层
if (userService.existUsername(username)) {
System.out.println("用户名[" + username + "]已存在");
// 请求转发,用户名已存在,跳转到注册页面
req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp);
} else {
// 将注册的用户信息保存到数据库
userService.registUser(new User(null, username, password, email));
// 用户名可使用,跳转至注册成功页面
req.getRequestDispatcher("/pages/user/regist_success.html").forward(req, resp);
}
} else {
System.out.println("验证码[" + code + "]错误");
// 请求转发,跳回注册页面
req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp);
}
}
}

用户登录功能实现

9-书城项目(第二阶段)_ide_33

给登录页面和显示登录成功页面添加base标签并修改使用到相对路径的地方

9-书城项目(第二阶段)_ide_34

web.xml

9-书城项目(第二阶段)_html_35

在login.html配置提交给服务器的地址

9-书城项目(第二阶段)_sql_36

LoginServlet.java

package com.atguigu.web;

import com.atguigu.pojo.User;
import com.atguigu.service.UserService;
import com.atguigu.service.impl.UserServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LoginServlet extends HttpServlet {

private UserService userService = new UserServiceImpl();

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");

User loginUser = userService.login(new User(null, username, password, null));
if (loginUser == null) {
req.getRequestDispatcher("/pages/user/login.html").forward(req, resp);
} else {
req.getRequestDispatcher("/pages/user/login_success.html").forward(req, resp);
}
}
}