然后我们运行代码:
开发工具:IDEA2020.3、Mysql8.0、Tomcat8.0
在开发之前,我们首先明确JavaEE的三层架构:
①Web层/视图展现层:
获取请求参数,封装称为Bean对象
调用Service层,处理对象
相应数据给客户端,请求转发重定向
②:Service业务层:
处理业务逻辑
调用持久层保存到数据库
③:Dao持久层:
Dao持久层只负责和数据库进行交互
CRUD操作:增删改查 Create Read Update Delete
这三层实际上相当于我们以后将要学习的Spring、SpringMVC、MyBaties
Dao持久层(JDBC、MyBaties):只负责跟数据库交互。
Service业务层(Spring)包括:①处理业务;②调用DAO持久层将数据保存到数据库。
Web层(SpringMVC)包括:a.使用Servlet程序接收客户端的请求参数,封装成为Bean对象;b.调用Service层处理业务;c.响应数据给客户端,请求转发,请求重定向。
了解了这些之后我们进行进一步的操作。
目录
4.编写JdbcUtils工具类(管理数据库连接池,从其中获取连接)
1.创建工程
我们选择Java Enterprise,创建项目名称为book,将静态页面复制粘贴到webapp中,静态页面我们使用的是尚硅谷中的,资料可以在尚硅谷课程javaweb中下载。链接:百度网盘 请输入提取码 提取码:3rz5。
然后创建包web、utils、test、service.impl(业务层的实现类的包)、pojo、dao.impl(持久层的实现类的包),这个在原来的包已经删除的情况下创建的。 (由于test在下方Idea已经自动创建好了,我们后面就不用这里的test了) 。
2.创建书城项目所需的数据库的表
我们所用到的工具是mysql数据库:
DROP DATABASE IF EXISTS book;#如果存在数据库book先进行删除
CREATE DATABASE book;# 创建数据库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)
);#创建t_user表
INSERT INTO t_user(`username`,`password`,`email`) VALUES('admin',
'admin','admin@zr.com');#向表中添加对应的值
SELECT * FROM t_user;#查看表t_user
此时book数据库和t_user表已经创建好了。
3.编写数据库表对应的JavaBean对象
- 在pojo中创建User类,在User类中写下一些必要的属性
private Integer id;
private String username;
private String password;
private String email;
对这些属性生成get、set方法,有参无参构造,toString方法
4.编写JdbcUtils工具类(管理数据库连接池,从其中获取连接)
- 这里需要用到数据库连接池(druid-1.1.9.jar)和数据库驱动(mysql-connector-java-5.1.7-bin.jar),把它放在WEB-INF下创建的lib中
- 将其名称修改为book_lib,并且在点击应用
- 在resources中创建jdbc.properties
username=root
password=abc123
url=jdbc:mysql://localhost:13306/book
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
#其中要输入自己的mysql用户名和密码,
以及自己的数据库是什么版本的,这里我采用的
是8.0版本的,因此我们的端口号为13306,5.0为3306
- JdbcUtiles类的代码为:
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);
} catch (Exception e) {
e.printStackTrace();
}
}
/*获取数据库连接池中的连接
* 如果返回值为null,说明获取连接池失败,有值就是获取连接成功
* */
public static Connection getConnection(){
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
/*关闭连接,放回数据库连接池*/
public static void close(Connection conn){
if(conn!=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
- 创建JdbcUtilsTest测试JdbcUtils是否创建成功
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);
}
}
@Test
public void testJdbcUtils2(){
for (int i = 0;i<100;i++){
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
//注意此时没有关闭只能打印出10个,因为在jdbc.properties中我们已经设置了最大连接个数,及时释放的话才可以成功
}
}
}
在获取连接成功的情况下说明已经成功了。
5.编写BaseDao
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 {
//使用DbUtiles操作数据库
private QueryRunner queryRunner = new QueryRunner();
/*
* update方法来执行Insert\update\Delete语句
*
* @retuen 如果返回-1,则说明执行失败,返回其他表示影响的行数
* */
public int update(String sql, Object... args) {
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.update(connection, sql, args);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return -1;
}
/**
* 查询返回一个javaBean的sql语句
*
* @param type:返回对象类型
* @param sql:执行的sql语句
* @param args:sql对应的参数值
* @param <T>:返回的类型的泛型
* @return
*/
public <T> Object 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 throwables) {
throwables.printStackTrace();
}
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 throwables) {
throwables.printStackTrace();
}
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();
}
return null;
}
}
6.编写UserDao和测试
package com.atguigu.dao;
import com.atguigu.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);
}
package com.atguigu.dao.impl;
import com.atguigu.dao.UserDao;
import com.atguigu.pojo.User;
/**
* @Program:fadaizhouzhou
* @description:impl
* @author: jiangzeren
* @create: 2022-10-15 17
**/
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 (User) queryForOne(User.class,sql,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 (User) queryForOne(User.class,sql,username,password);
}
}
package com.atguigu.test;
import com.atguigu.dao.UserDao;
import com.atguigu.dao.impl.UserDaoImpl;
import com.atguigu.pojo.User;
import org.junit.Test;
import static org.junit.Assert.*;
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(null,"admin2","123456","wwwwji@qq.com")));
}
@Test
public void queryUserByUsernameAndPassword() {
if (userDao.queryUserByUsernameAndPassword("admin","admin111") == null){
System.out.println("用户名或密码错误,登录失败!");
}else {
System.out.println("查询成功!");
}
}
}
7.编写UserServicce和测试
- 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;
/**
* @Program:fadaizhouzhou
* @description:impl
* @author: jiangzeren
* @create: 2022-10-15 20
**/
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoImpl();//这里感觉关键
//这里的体现了多态!userDao的左边是接口 右边实现类 所以调用userDao的方法时看似是调用了接口中的方法(编译状态下) 但实际调用的是调用实现类中的方法(运行状态)
@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测试:
package com.atguigu.test;
import com.atguigu.pojo.User;
import com.atguigu.service.UserService;
import com.atguigu.service.impl.UserServiceImpl;
import org.junit.Test;
import sun.security.util.Password;
import static org.junit.Assert.*;
public class UserServiceTest {
UserService userService = new UserServiceImpl();
@Test
public void registUser() {
userService.registUser(new User(null,"qqq7488", "666666","7488@qq.com"));
userService.registUser(new User(null,"woshi", "wwjiji","7wi928@qq.com"));
}
@Test
public void login() {
System.out.println( userService.login(new User(null,"qqq7488", "666666",null)));
}
@Test
public void existsUsername() {
if (userService.existsUsername("woshi")){
System.out.println("用户名已存在");
}else {
System.out.println("用户名可用");
}
}
}
- 执行:
- SQL结果:
由于点了重复添加相同信息,因此添加失败,但我们看到id自增并未按顺序增加,这里以后应该能解决。
8.编写Web层
需求1:用户注册
访问汪册贝面
填写注册信息,提交给服务器
服务器应该保存用户
当用户已经存在一提示用户注册失败,用户名已存在
当用户不存在---注册成功
需求2:用户登录
首先在类RegistServlet中继承HttpServlet
然后再WEB-INF下配置web.xml文件
<servlet>
<servlet-name>RegistServlet</servlet-name>
<servlet-class>com.atguigu.web.RegistServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegistServlet</servlet-name>
<url-pattern>/RegistServlet</url-pattern>
</servlet-mapping>
- 在regist.html页面中将地址写为/registServlet
- base+相对路径
需要咋title下面加上<base href="http://localhost:8080/book/">
但是这会带来很多问题,我们尝试打开regist.html发现样式和图片等打不开,原因是在加了base之后,会在前面默认加上"http://localhost:8080/book/,如果再使用../,那么book的上一层已经没有东西了,无法访问,解决方法是把../全部删掉。
<!--写base标签,永远固定相对路径的跳转结果-->
这里的结果时需要在部署服务器Tomcat的基础上运行的
服务器的部署为:
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;
/**
* @Program:fadaizhouzhou
* @description:impl
* @author: jiangzeren
* @create: 2022-10-15 20
**/
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoImpl();//这里感觉关键
//这里的体现了多态!userDao的左边是接口 右边实现类 所以调用userDao的方法时看似是调用了接口中的方法(编译状态下) 但实际调用的是调用实现类中的方法(运行状态)
@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;
}
}
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;
/**
* @Program:fadaizhouzhou
* @description:web
* @author: jiangzeren
* @create: 2022-10-16 09
**/
public class RegistServlet extends HttpServlet {
/**
* 由于Web层不能直接操作Dao,我们只能操作Service层
*/
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{
// 可用:
System.out.println("用户名可用!");
// 调用Sservice保存到数据库。
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);
}
}
}
我们接下来进行测试:
出现了405错误,这说明是请求methods问题中出错,我们这里是由于多写了一个空格导致的。
删掉空格我们再次尝试过程中也可能会出现页面跳转失败问题(404 NOT found),同样的道理我们可能是因为路径出错,应该把“../”去除。
这时明显跳转成功,接下来查看Mysql数据库中看看是否数据成功保存。
登录操作: