书城第二阶段——用户注册和登陆

书城第二阶段——用户注册和登陆

1、JavaEE 项目的三层架构

image

分层的目的是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护和升级。

image

搭建书城项目开发环境:

image

2、先创建书城需要的数据库和表

建表语句

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;

3、编写数据库表对应的 JavaBean 对象。

public class User { 
    private Integer id; 
    private String username; 
    private String password;
    private String email;

4、编写工具类 JdbcUtils

4.1、导入需要的 jar 包(数据库和连接池需要):

druid-1.1.9.jar

mysql-connector-java-5.1.7-bin.jar

以下是测试需要:

hamcrest-core-1.3.jar

junit-4.12.jar

4.2、 src 源码目录下编写 jdbc.properties 属性配置文件:

username=root 
password=123456 
url=jdbc:mysql://localhost:3306/book 
driverClassName=com.mysql.cj.jdbc.Driver 
initialSize=5 
maxActive=10

4.3、编写 JdbcUtils 工具类:

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();
        }
    }
    

    /*** 获取数据库连接池中的连接
     * @return 如果返回 null,说明获取连接失败<br/>
     * 有值就是获取连接成功 */
    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();
            }
        }
    }
}

4.4、JdbcUtils 测试

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);
        }
    }
}

5、编写 BaseDao

5.1、导入 DBUtils jar

commons-dbutils-1.3.jar

5.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 (Exception 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 conn = JdbcUtils.getConnection();
        try {
            return queryRunner.query(conn,sql,new BeanHandler<T>(type),args);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.close(conn);
        }
        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 conne = JdbcUtils.getConnection();
        try {
            return queryRunner.query(conne,sql,new ScalarHandler(),args);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.close(conne);
        }
        return null;
    }
}

6、编写 UserDao 和测试

UserDao 接口:

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 表示操作失败,其他是 sql 语句影响的行数
     */
    public int saveUser(User user);
}

UserDaoImpl 实现类:

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());
    }
}

UserDao 测试:

class UserDaoTest {

    UserDao userDao = new UserDaoImpl();
    @Test
    void queryUserByUsername() {
        if (userDao.queryUserByUsername("admin1234")==null){
            System.out.println("用户名可用!");
        }else{
            System.out.println("用户名已存在!");
        }
    }

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

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

7、编写 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, "wsc123", "123456", null)));
    }

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

}

8、编写 web

8.1、实现用户注册的功能

8.1.1、图解用户注册的流程:

image

8.1.2、修改 regist.html regist_success.html 页面

1、添加 base 标签

image

2、修改 base 标签对页面中所有相对路径的影响(浏览器 F12,哪个报红,改哪个)

以下是几个修改的示例:

image

3、修改注册表单的提交地址和请求方式

image

8.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);
        }
    }
}

8.2、用户登录功能的实现

8.2.1、图解用户登录

image

8.2.2、修改 login.html 页面和 login_success.html 页面

1、添加 base 标签

image

2、修改 base 标签对页面中所有相对路径的影响(浏览器 F12,哪个报红,改哪个)

image

3、修改 login.html 表单的提交地址和请求方式

image

8.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);
        }
    }
}
posted @ 2021-11-29 11:46  飞翔奥尔良烤翅  阅读(287)  评论(0)    收藏  举报