用户注册和登录的实现:
需求1:用户注册
需求如下:
- 访问注册页面
- 填写注册信息,提交给服务器
- 服务器保存用户
- 当用户已经存在——提示用户注册失败,用户名已存在
- 当用户名不存在——注册成功
需求2:用户登录
需求如下:
- 访问登陆页面
- 填写用户名密码后提交
- 服务器判断用户是否存在
- 如果登陆失败 ——返回用户名或者密码错误信息
- 如果登录成功 ——返回登陆成功 信息
项目的三层架构
分层的目的是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护和升级。
1、先创建书城需要的数据库和表。
drop database if exists book;
create database book;
use book;
create table t_user(
`id` int primary key auto_increment,
`username` varchar(20) not null unique,
`password` varchar(32) not null,
`email` varchar(200)
);
insert into t_user(`username`,`password`,`email`) values('admin','admin','admin@atguigu.com');
select * from t_user;
2 、编写数据库表对应的 JavaBean 对象。 对象。
package com.atguigu.pojo;
public class User {
private Integer id;
private String username;
private String password;
private String 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 + '\'' +
'}';
}
public User() {
}
public User(Integer id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}
}
3、编写工具类 JdbcUtils
3.1 、导入需要的 jar 包(数据库和连接池需要):
3.2 、在 src 源码目录下编写 jdbc.properties 属性配置文件:
username=root
password=123456 //自己设的密码
url=jdbc:mysql://localhost:3306/book //数据库路径
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
3.3 、编写 JdbcUtils 工具类:
package com.atguigu.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.util.JdbcUtils;
import javax.sql.rowset.JdbcRowSet;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtile {
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);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取数据库连接池中的连接
public static Connection getConnection(){
Connection conn=null;
try {
conn=dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
// 关闭连接,返回数据库连接池
public static void close(Connection conn){
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
4、编写 BaseDao
4.1 、导入 DBUtils 的 的 jar 包
4.2 、编写 BaseDao:
package com.atguigu.dao.impl;
import com.atguigu.utils.JdbcUtile;
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 {
// 使用 DbUtils 操作数据库
private QueryRunner queryRunner=new QueryRunner();
/**
* update() 方法用来执行: Insert\Update\Delete 语句
*
* @return 如果返回 -1, 说明执行失败 <br/> 返回其他表示影响的行数
*/
public int update(String sql,Object...args){
Connection connection= JdbcUtile.getConnection();
try {
return queryRunner.update(connection,sql,args);
} catch (SQLException e) {
e.printStackTrace();
}finally{
JdbcUtile.close(connection);
}
return -1;
}
/**
* 查询返回一个 javaBean 的 sql 语句
*
* @param type 返回的对象类型
* @param sql 执行的 sql 语句
* @param args sql 对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
public<T> T queryForOne(Class<T> type,String sql,Object...args){
Connection con=JdbcUtile.getConnection();
try {
return queryRunner.query(con,sql,new BeanHandler<T>(type),args);
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtile.close(con);
}
return null;
}
/**
* 查询返回多个 javaBean 的 sql 语句
*
* @param type 返回的对象类型
* @param sql 执行的 sql 语句
* @param args sql 对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
public <T> List<T> queryForList(Class<T> type, String sql, Object...args){
Connection con=JdbcUtile.getConnection();
try {
return queryRunner.query(con,sql,new BeanListHandler<T>(type),args);
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtile.close(con);
}
return null;
}
/**
* 执行返回一行一列的 sql 语句
* @param sql 执行的 sql 语句
* @param args sql 对应的参数值
* @return
*/
public Object queryForSingleValue(String sql,Object...args){
Connection conn=JdbcUtile.getConnection();
try {
return queryRunner.query(conn,sql,new ScalarHandler(),args);
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtile.close(conn);
}
return null;
}
}
5 、编写 UserDao 和测试
UserDao 接口:
package com.atguigu.dao;
import com.atguigu.pojo.User;
public interface UserDao {
// 根据用户名查询用户信息
public User queryUserByUsername(String username);
// 根据用户名和密码查询用户信息
public User queryUserByUsernameAndPassword(String username,String password);
// 保存用户信息
public int saveUser(User user);
}
UserDaoImpl 实现类:
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`) values(?,?,?)";
return update(sql,user.getUsername(),user.getPassword(),user.getEmail());
}
}
6 、编写 UserService 和测试
UserService 接口:
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 existsUsername(String username);
}
UserServiceImpl 实现类:
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 existsUsername(String username) {
if(userDao.queryUserByUsername(username)==null){
return false;
}
return true;
}
}
7 、编写 web 层
7.1 、实现用户注册的功能
7.1.1 、图解用户注册的流程:
7.1.2 、修改 regist.html 和 regist_success.html 页面
1、添加 base 标签
<!-- 写 base 标签,永远固定相对路径跳转的结果 -->
<base href="http://localhost:8080/book">
2、修改 base 标签对页面中所有相对路径的影响(浏览器 F12,哪个报红,改哪个)
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<script type="text/javascript" src="static/script/jquery-1.7.2.js"></script>
3、修改注册表单的提交地址和请求方式
7.1.3 、编写 RegistServlet 程序
public class RegistServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@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 、检查 验证码是否正确 === 写死 , 要求验证码为 :abcde
if ("abcde".equalsIgnoreCase(code)) {
// 3 、检查 用户名是否可用
if (userService.existsUsername(username)) {
System.out.println(" 用户名[" + username + "] 已存在!");
// 跳回注册页面
req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp);
} else {
// 可用
// 调用 Sservice 保存到数据库
userService.registUser(new User(null, username, password, email));
// 跳到注册成功页面 regist_success.html
req.getRequestDispatcher("/pages/user/regist_success.html").forward(req, resp);
}
} else {
System.out.println(" 验证码[" + code + "] 错误");
req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp);
}
}
}
7.2、用户登录功能的实现
7.2.1、图解用户登录
7.2.2 、修改 login.html 页面和 login_success.html 页面
7.2.3 、LoginServlet 程序
public class LoginServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
// 1 、获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
// 调用 userService.login() 登录处理业务
User loginUser = userService.login(new User(null, username, password, null));
// 如果等于 null, 说明登录 失败 !
if (loginUser == null) {
// 跳回登录页面
req.getRequestDispatcher("/pages/user/login.html").forward(req, resp);
} else {
// 登录 成功
// 跳到成功页面 login_success.html
req.getRequestDispatcher("/pages/user/login_success.html").forward(req, resp);
}
}
}