目录
javaEE项目的三层架构:
分层的目的是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护和升级。
.
项目阶段二:用户注册和登陆的实现。
需求
1
:用户注册
需求如下:
1
)访问注册页面
2
)填写注册信息,提交给服务器
3
)服务器应该保存用户
4
)当用户已经存在
----
提示用户注册 失败,用户名已存在
5
)当用户不存在
-----
注册成功
需求
2
:用户登陆
需求如下:
1
)访问登陆页面
2
)填写用户名密码后提交
3
)服务器判断用户是否存在
4
)如果登陆失败
---
返回用户名或者密码错误信息
5
)如果登录成功
---
返回登陆成功 信息
思路分析:
1.先根据用户信息创建数据库book
2.
编写数据库表对应的
JavaBean
对象,这一步是为了后面增删改查以对象的方式提供结果,包含了ORM思想。
3.创建连接数据库的工具类JdbcUtils。工具类JdbcUtils中包括创建数据库连接池与数据库建立连接,断开连接这三个方法,用到了druid数据库连接池。
Dao持久层:
4.创建操作数据库的工具类BaseDao,只有这个类是直接操作数据库的。里面主要包括三个方法,获取一条数据,获取多条数据,获取一个数据,这些方法都是通过DBUtils这个类实现的。里面用到了反射和泛型。
5.创建UserDao接口,和其实现类,这两个类是根据用户需求创建的,包括两个需求注册和登录,注册需要根据用户名查询这个用户是否注册过,因为用户名是唯一的,调用上面操作数据库的类BaseDao中的查询一条数据的方法,如果没有在数据库中找到,返回null,可以注册,调用上面操作数据库的类BaseDao中的插入数据的方法,向数据库中保存数据,如果找到了说明已经注册过。登录需要根据用户名和密码查询这个用户是否在数据库存在,如果存在就登陆成功,如果不存在就登陆失败。因此一共有三个方法,一个是根据用户名查询用户是否注册过,一个是保存用户信息到数据库,一个是根据用户名和密码查询数据库中是否有用户信息,没有的话就是输入错误。这三个方法都是与数据库之间的操作,只返回数据库中的信息,具体的逻辑实现要通过Service业务层实现。
Service业务层:
6.创建UserService接口和实现类,主要是调用UserDao去实现业务逻辑和保存数据到数据库,包括上面说的三个业务逻辑。
Web层:
创建两个类,RegistServlet类和LoginServlet类,用于接收web页面用户传来的信息,然后调用UserService中的方法去实现具体的功能。主要用到了Tomcat
Web
服务器。
搭建书城项目开发环境:
一、先创建书城需要的数据库和表
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) VALUE('admain','admain','admain@qq.com');
SELECT * FROM t_user;
二、编写数据库表对应的 JavaBean 对象
javabean对象的理解:https://www.zhihu.com/question/19773379
大体意思就是为了不破坏代码的向后兼容性,就写一个类把一些公共属性等封装起来,用set或get方法得到,即使修改其中的代码,用户还是通过set或get方法得到其中的值。
特点:
1、所有属性为private
2、提供默认构造方法
3、提供getter和setter
4、实现serializable接口
package pojo;
public class User {
private int id;
private String username;
private String password;
private String email;
//有参构造器
public User(int id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}
//无参构造器
public User() {
}
//get,set方法
public int getId() {
return id;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getEmail() {
return email;
}
public void setId(int id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setEmail(String email) {
this.email = email;
}
//重写toString方法
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
'}';
}
}
三、编写工具类 JdbcUtils
需要一些jar包,包括mysql数据库驱动,数据库连接池。
3.1 配置文件
username=root
password=730136
url=jdbc:mysql://localhost:3306/book
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
3.2 编写 JdbcUtils 工具类
使用数据库连接池获取连接:
注意:1.创建数据库连接池时,用静态代码块创建,因为我们不想每次获取连接的时候都创建一个新的数据库连接池。因为druid连接池没有直接创建连接池的类,所以需要通过一个工厂类来创建连接池。
2.声明一个空的连接,用于关闭连接时判断是否有连接创建成功。
package utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtils {
//先创建一个数据库连接池,用静态代码块创建,因为我们不想每次获取连接的时候都创建一个新的数据库连接池
private static DataSource source;
static {
Properties properties = new Properties();
//读取属性配置文件
InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
//从流中加载文件
properties.load(is);
//创建数据库连接池
source = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//共有两个方法
//方法一:获取数据库连接池中的连接
/**
* @return 返回值就是获取成功,返回null就是获取失败
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = source.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();
}
}
}
}
四、编写 BaseDao
basedao类是一个操作数据库的具体实现类
package dao.daoimpl;
import org.apache.commons.dbutils.DbUtils;
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 utils.JdbcUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* 主要用于操作数据库
*/
public abstract class BaseDao {
//使用DBUtils操作数据库
private QueryRunner queryRunner = new QueryRunner();
/**
* 用来执行: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 的 sql 语句
* @param sql 执行的 sql 语句
* @param t 返回的对象类型,new BeanHandler<>(t)里面需要一个Class类的参数,比如Customer.class
* @param args
* @param <T> 返回的类型的泛型
* @return
*/
public <T> T queryForOne(String sql, Class<T> t, Object ...args) {
Connection conn = JdbcUtils.getConnection();
BeanHandler<T> handler = new BeanHandler<>(t);
try {
Object query = queryRunner.query(conn, sql, handler, args);
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(conn);
}
return null;
}
/**
* 查询返回多个 javaBean 的 sql 语句
* @param sql
* @param t
* @param args
* @return
*/
public <T>List<T> queryForList(String sql, Class<T> t, Object ...args) {
Connection conn = JdbcUtils.getConnection();
BeanListHandler<T> handler = new BeanListHandler<T>(t);
try {
return queryRunner.query(conn, sql, handler, args);
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(conn);
}
return null;
}
/**
* 执行返回一行一列的 sql 语句
* @param sql
* @param args
* @return
*/
public Object queryForSingleValue(String sql, Object ...args) {
Connection conn = JdbcUtils.getConnection();
ScalarHandler handler = new ScalarHandler();
try {
return queryRunner.query(conn, sql, handler, args);
} catch (SQLException e) {
e.printStackTrace();
}finally {
DbUtils.closeQuietly(conn);
}
return null;
}
}
五、编写 UserDao 和测试
userdao是一个需求接口
package dao;
import pojo.User;
public interface UserDao {
//注册需要的方法
/**
* 根据用户输入的姓名查询是否用户在数据库中的信息
* @param username
* @return 如果返回null,说明没有这个用户,反之则有
*/
public User queryUserByUsername(String username);
/**
* 保存用户信息
* @param user
* @return
*/
public int saveUser(User user);
//登录需要的方法
/**
* 根据用户名和密码查询用户信息
* @param username
* @param password
* @return 返回null说明用户名或密码错误
*/
public User queryUserByUsernameAndPassWord(String username, String password);
}
userdaoimpl是对userdao的实现类
package dao;
import dao.daoimpl.BaseDao;
import 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(sql, User.class, username);
}
@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());
}
@Override
public User queryUserByUsernameAndPassWord(String username, String password) {
String sql = "select id, username, password, email from t_user where username = ? and password = ?";
return queryForOne(sql, User.class, username, password);
}
}
userdaotest是测试类
package test;
import dao.UserDao;
import dao.UserDaoImpl;
import org.junit.Test;
import pojo.User;
public class UserDaoTest {
UserDao userDao = new UserDaoImpl();
@Test
public void queryUserByUsername() {
if (userDao.queryUserByUsername("admin1234") == null) {
System.out.println("用户名可用!");
} else {
System.out.println("用户名已存在!");
}
}
@Test
public void saveUser() {
System.out.println( userDao.saveUser(new User("wzg168", "123456", "wzg168@qq.com")) );
}
@Test
public void queryUserByUsernameAndPassWord() {
if(userDao.queryUserByUsernameAndPassWord("admin", "admin") == null){
System.out.println("用户名或密码错误,登陆失败");
}else {
System.out.println("查询成功");
}
}
}
六、编写 UserService 和测试
userService接口,里面写了需要实现的各种业务:
package service;
import pojo.User;
public interface UserService {
//一共有三个业务,登录,注册,查询用户名是否可用
/**
* 注册用户
* @param user
*/
public void registUser(User user);
/**
* 登录
* @param user
* @return
*/
public User login(User user);
/**
* 检查用户名是否可用
* @param username
* @return 返回true表示用户名已存在,false表示用户名可用
*/
public boolean existsUsername(String username);
}
UserServiceImpl 实现类,用来实现userService接口中的业务,里面创建一个userDaoImpl对象用来处理对数据库的操作,因为userServiceImpl无法直接对数据库进行操作。
package service.serviceimpl;
import dao.UserDao;
import dao.UserDaoImpl;
import pojo.User;
import 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;
}
}
UserService 测试:
package test;
import org.junit.Test;
import pojo.User;
import service.UserService;
import service.serviceimpl.UserServiceImpl;
public class UserServiceTest {
UserService userService = new UserServiceImpl();
@Test
public void registeUser() {
userService.registUser(new User("b168", "666666", "bbj168@qq.com"));
}
@Test
public void login() {
System.out.println(userService.login(new User("wzg168", "123456", "wzg168@qq.com")));
}
@Test
public void existsUsername() {
if (userService.existsUsername("wzg16888")) {
System.out.println("用户名已存在!");
} else {
System.out.println("用户名可用!");
}
}
}
七、编写 web 层
7.1、实现用户注册的功能
图解用户注册的流程:
修改
regist.html
和
regist_success.html 页面中的路径,可以加入Base标签,构成相对路径。同时也要修改表单的提交的路径,修改为registeServer,这样表单中的数据就会提交到http://localhost:8080/book/registeServer这个资源路径下,然后在web.xml配置文件中找到RegistServer这个类中。
注意:web部分一定要放到web这个目录下,因为Tomcat访问工程的路径就是在其webapps文件夹下,在idea中要放到web目录下。
package web;
import pojo.User;
import service.UserService;
import service.serviceimpl.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();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
String code = request.getParameter("code");
// 2、检查 验证码是否正确 === 写死,要求验证码为:abcde
if ("abcde".equalsIgnoreCase(code)) {
// 3、检查用户名是否可用
if (userService.existsUsername(username)) {
System.out.println("用户名[" + username + "]已存在!");
// 跳回注册页面
//请求转发必须要以斜杠打头,/ 斜杠表示地址为:http://ip:port/工程名/ , 映射到 IDEA 代码的 web 目录
request.getRequestDispatcher("/pages/user/regist.html").forward(request, response);
} else { // 可用
// 调用 Sservice 保存到数据库
userService.registUser(new User(username, password, email));
// 跳到注册成功页面regist_success.html
request.getRequestDispatcher("/pages/user/regist_success.html").forward(request, response);
}
} else {
System.out.println("验证码[" + code + "]错误");
request.getRequestDispatcher("/pages/user/regist.html").forward(request, response);
}
}
}
7.2 用户登录功能的实现
loginServlet类
package web;
import pojo.User;
import service.UserService;
import service.serviceimpl.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();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
//2.调用userService
User user = userService.login(new User(username, password, null));
if (user == null) { //用户名或密码错误,返回登录界面
request.getRequestDispatcher("/pages/user/login.html").forward(request,response);
}else {
request.getRequestDispatcher("/pages/user/login_success.html").forward(request,response);
}
}
}
其他同7.2