您现在的位置是:首页 > 正文

项目阶段一:用户注册和登陆

2024-04-01 02:25:19阅读 5

项目阶段一:用户注册和登陆的实现。

需求 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>");
        }
    }
}

网站文章

  • 浅析ARMv8体系结构:异常处理机制

    浅析ARMv8体系结构:异常处理机制

    异常处理指的是处理器在运行过程中发生了外部事件,导致处理器需要中断当前执行流程转而去处理异常事件的一种机制。在Intel处理器的术语中,中断与异常被分开来描述,但在ARMv8体系结构中,异常和中断统一被称为异常处理。

    2024-04-01 02:24:34
  • Python-pyinstaller:No such file or directory 解决方案

    Python-pyinstaller:No such file or directory 解决方案

    Python-pyinstaller:No such file or directory 解决方案

    2024-04-01 02:24:27
  • 原型模式-学习设计模式

    做个笔记引用https://blog.csdn.net/lovelion/article/details/7424623/** *接口类 */interface OfficialDocument ex...

    2024-04-01 02:24:18
  • python之生成器、迭代器

    python之生成器、迭代器

    python之生成器、迭代器一、生成器创建生成器的方法二、迭代器一、生成器使用列表推导的前提是将所有数据都存入内存,若是数据特别大,则内存消耗会很大,使用生成器可以在循环遍历列表的时候动态生成下一个元...

    2024-04-01 02:23:36
  • php版canvas,HTML5 Canvas

    php版canvas,HTML5 Canvas

    canvas 元素用于在网页上绘制图形。什么是 Canvas?HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像。 (推荐学习:html教程)画布是一个矩形区域,您可以控制...

    2024-04-01 02:23:28
  • 在Linux下交叉编译生成windows程序

    在Ubuntu环境下,利用mingw32,交叉编译windows程序,以便在windows下运行。

    2024-04-01 02:23:21
  • 【深度学习】ubuntu系统指定gcc版本并调整优先级

    【深度学习】ubuntu系统指定gcc版本并调整优先级

    sudo apt install build-essential gcc --version (查看gcc版本)可以看到我的gcc版本是4.8.5 安装最新版gcc9 sudo apt install...

    2024-04-01 02:23:14
  • java中什么是互斥,什么是Java中的互斥和信号量? 主要区别是什么?

    信号量可以被计数,而互斥量只能算到1。假设你有一个接受客户端连接的线程正在运行。 这个线程可以同时处理10个客户端。 然后每个新的客户端设置信号量,直到它达到10.当信号量有10个标志,那么你的线程将...

    2024-04-01 02:22:25
  • 华为p50鸿蒙os1020,鸿蒙OS+液态镜头+麒麟1020华为P50,华为P30即将悲惨让路价崩

    华为p50鸿蒙os1020,鸿蒙OS+液态镜头+麒麟1020华为P50,华为P30即将悲惨让路价崩

    原标题:鸿蒙OS+液态镜头+麒麟1020华为P50,华为P30即将悲惨让路价崩鸿蒙OS+液态镜头+麒麟1020华为P50,华为P30即将悲惨让路价崩据最新消息,华为P50系列有可能采用“液态镜头”,这...

    2024-04-01 02:22:17
  • 麒麟子Cocos Creator实用技巧一:如何正确地显示微信头像

    麒麟子Cocos Creator实用技巧一:如何正确地显示微信头像

    不管是游戏App,还是H5,又或者是微信小游戏。但凡接入了微信登录的应用,都可能需要显示微信头像。在Cocos Creator中,我们常见的显示方法像下面这样var headimg = 'http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83erD6MOUwRKV9NyBAqnoFDTnltzAe2zWOkKxyDOFibVBb1ZV5CaATJw...

    2024-04-01 02:21:28