项目阶段一:用户注册和登陆的实现。
需求 1:用户注册 需求如下:
1)访问注册页面
2)填写注册信息,提交给服务器
3)服务器应该保存用户
4)当用户已经存在----提示用户注册 失败,用户名已存在
5)当用户不存在-----注册成功
需求 2:用户登陆 需求如下:
1)访问登陆页面 、
2)填写用户名密码后提交
3)服务器判断用户是否存在
4)如果登陆失败 —>>>> 返回用户名或者密码错误信息
5)如果登录成功 —>>>> 返回登陆成功 信息
JavaEE 项目的三层架构
分层的目的是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护和升级。
-
web 层 com.atguigu.web/servlet/controller service 层 com.atguigu.service Service接口包 com.atguigu.service.impl Service接口实现类 dao 持久层 com.atguigu.dao Dao 接口包 com.atguigu.dao.impl Dao 接口实现类 实体 bean 对象 com.atguigu.pojo/entity/domain/bean JavaBean 类 测试包 com.atguigu.test/junit 工具类 com.atguigu.utils
搭建书城项目开发环境:
1、先创建书城需要的数据库和表
drop database if exists bookstore;
create database bookstore;
user bookstore;
create table t_user(
`id` int primary key auto_increment,
`username` varchar(32) not null unique,
`password` varchar(32) not null,
`email` varchar(200) not null
);
insert into t_user(`username`,`password`,email) values('admin','admin','admin@163.com');
2、编写数据库表对应的 JavaBean 对象
public class User {
private Integer id;
private String username;
private String password;
private String email;
3、编写工具类 JdbcUtils
3.1、导入需要的 jar 包(数据库和连接池需要):
- druid-1.1.9.jar
- mysql-connector-java-5.1.7-bin.jar
以下是测试需要:
- hamcrest-core-1.3.jar
- junit-4.12.jar
3.2、在 src 源码目录下编写 jdbc.properties 属性配置文件
username=root
password=1127
url=jdbc:mysql://localhost:3306/bookstore?useUnicode=true&characterEncoding=utf-8
#url=jdbc:mysql://localhost:3306/bookstore
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
3.3、编写 JdbcUtils 工具类
public class JdbcUtils {
private static DruidDataSource dataSource;
/**
* 静态代码块,类加载的时候执行
* 把注册驱动程序的代码放在静态代码块中,避免多次获取连接对象时重复调用
*/
static{
try {
Properties pros = new Properties();
// 读取 jdbc.properties属性配置文件
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
// 从流中加载数据
pros.load(inputStream);
// 创建 数据库连接 池
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接池中的连接
* @return如果返回null,说明获取连接失败<br/>值就是获取连接成功
*/
public static Connection getConnection(){
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭连接,放回数据库连接池
* @param conn
*/
public static void close(Connection conn){
DbUtils.closeQuietly(conn);
}
}
3.4、JdbcUtils 测试
public class JdbcUtilsTest {
@Test
public void testJdbcUtil() {
for (int i = 0; i < 100; i++) {
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
JdbcUtils.close(connection);
}
}
}
4、编写 BaseDao
4.1、导入 DBUtils 的 jar 包
commons-dbutils-1.3.jar
4.2、编写 BaseDao:
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 = JdbcUtils.getConnection();
try {
return queryRunner.update(connection, sql, args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.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 = JdbcUtils.getConnection();
try {
return queryRunner.query(con, sql, new BeanHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.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 = JdbcUtils.getConnection();
try {
return queryRunner.query(con, sql, new BeanListHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(con);
}
return null;
}
/**
* 执行返回一行一列的sql语句
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @return
*/
public Object queryForSingleValue(String sql, Object... args){
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.query(conn, sql, new ScalarHandler(), args);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
}
return null;
}
}
5、编写 UserDao 和测试
UserDao 接口:
public interface UserDao {
/**
* 根据用户名查询用户信息
* @param username 用户名
* @return 返回null:说明没这个用户名,否则该用户名存在
*/
public abstract User queryUserByUsername(String username);
/**
* 根据 用户名和密码查询用户信息
* @param username
* @param password
* @return 如果返回null,说明用户名或密码错误,反之则成功
*/
public abstract User queryUserByUsernameAndPwd(String username,String password);
//接口中public abstract 可省略不写
/**
* 保存用户信息
* @param user 要保存的用户名的信息
* @return 返回-1表保存失败,其他是sql语句影响的行数
*/
int saveUser(User user);
}
UserDaoImpl 实现类:
public class UserDaoImpl extends BaseDao implements UserDao {
@Override
public User queryUserByUsername(String username) {
String sql = "select * from t_user where username = ?";
return queryForOne(User.class,sql,username);
}
@Override
public User queryUserByUsernameAndPwd(String username, String password) {
String sql = "select * 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());
}
}
UserDao 测试:
public class UserDaoImplTest {
UserDao user = new UserDaoImpl();
@Test
public void queryUserByUsername() {
if(user.queryUserByUsername("admin1") != null){
System.out.println("用户名已存在");
}else{
System.out.println("用户名可用");
}
}
@Test
public void queryUserByUsernameAndPwd() {
if(user.queryUserByUsernameAndPwd("admin","admin123") != null){
System.out.println("登录成功");
}else{
System.out.println("用户名或密码错误,登录失败");
}
}
@Test
public void saveUser() {
int count = user.saveUser(new User(null, "zhangsan", "123", "zhangsan@163.com"));
if(count != -1){
System.out.println("注册成功");
}else{
System.out.println("注册失败");
}
}
}
6、编写 UserService 和测试
UserService 接口:
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 实现类:
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) {
// 等于null,说明没查到,没查到表示可用
return false;
}
return true;
}
}
UserService 测试:
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, "wzg168", "123456", null)) );
}
@Test
public void existsUsername() {
if (userService.existsUsername("wzg16888")) {
System.out.println("用户名已存在!");
} else {
System.out.println("用户名可用!");
}
}
}
7、编写 web 层
7.1、实现用户注册的功能
7.1.1、图解用户注册的流程:
1、添加 base 标签
<!--写base标签,永远固定相对路径跳转的结果-->
<base href="http://localhost:8080/MyBookStore/"/>
2、修改 base 标签对页面中所有相对路径的影响(浏览器 F12,哪个报红,改哪个)
3、修改注册表单的提交地址和请求方式
7.1.2、编写 RegistServlet 程序
public class RegistServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
/**
* 包含密码用post请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@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");
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
// 2、检查 验证码是否正确 === 写死,要求验证码为:6n6np
if("6n6np".equalsIgnoreCase(code)){
// 3、检查 用户名是否可用
if(userService.existsUsername(username)){
writer.println("<script language='javascript'>alert('该用户名已存在!')</script>");
// 跳回注册页面
writer.println("<script language='javascript'>window.location.href='/MyBookStore/pages/user/myregist.html'</script>");
// req.getRequestDispatcher("/pages/user/myregist.html").forward(req, resp);不能用这种方式转回注册页面,会出现乱码
}
}else{
// 可用
// 调用service保存到数据库
userService.registUser(new User(null,username,password,email));
// 跳到注册成功页面 regist_success.html
writer.println("<script language='javascript'>window.location.href='/MyBookStore/pages/user/regist_success.html'</script>");
}
}else{
//请求转发必须要以斜杠打头,/ 斜杠表示地址为:http://ip:port/工程名/
writer.println("<script language='javascript'>window.location.href='/MyBookStore/pages/user/myregist.html'</script>");
}
}
}
web配置:
<!-- RegistServlet的配置-->
<servlet>
<servlet-name>RegistServlet</servlet-name>
<servlet-class>loey.web.RegistServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegistServlet</servlet-name>
<url-pattern>/registServlet</url-pattern>
</servlet-mapping>
7.2、IDEA 中 Debug 调试的使用
7.2.1、Debug 调试代码,首先需要两个元素:断点 +Debug 启动服务器
1、断点,只需要在代码需要停的行的左边上单击,就可以添加和取消
2、Debug 启动 Tomcat 运行代码:
7.2.2、测试工具栏:
7.2.3、变量窗口
变量窗口:它可以查看当前方法范围内所有有效的变量。
7.2.4、方法调用栈窗口
1、方法调用栈可以查看当前线程有哪些方法调用信息
2、下面的调用上一行的方法
其他常用调试相关按钮
7.3、用户登录功能的实现
7.3.1、图解用户登录
1、添加 base 标签
<!--写 base 标 签 , 永 远 固 定 相 对 路 径 跳 转 的 结 果-->
<base href="http://localhost:8080/MyBookStore/"/>
2、修改 base 标签对页面中所有相对路径的影响(浏览器 F12,哪个报红,改哪个
3、修改 login.html 表单的提交地址和请求方式
7.3.2、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");
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
// 调用 userService.login()登录处理业务
if(userService.login(new User(null,username,password,null)) != null){
//登录成功
//转到登录成功页面
writer.println("<script language='javascript'>window.location.href='/MyBookStore/pages/user/login_success.html'</script>");
}else{
// 登录 成功
//跳到成功页面login_success.html
writer.println("<script language='javascript'>alert('用户名或密码错误!')</script>");
writer.println("<script language='javascript'>window.location.href='/MyBookStore/pages/user/login.html'</script>");
}
}
}