Java项目记录

谷粒书城项目

用户注册和登录(Servlet)

脉络梳理

分层的目的是为了解耦。 解耦就是为了降低代码的耦合度。 方便项目后期的维护和升级
在这里插入图片描述
用户注册与登录主要是锻炼Servlet技术的使用,Servlet是JavaEE 规范之一,规范就是接口。它可以接收客户端发送过来的请求, 并响应数据给客户端。接下来将对上图中的各大板块进行详细叙述。

1. 搭建环境

搭建环境这部分,我采用的是idea 2021版本的,在新建wen工程开发这部分,和以前的idea版本的创建有所区别,这部分我将用另一个博客来介绍。

2. 数据库

创建书城需要的数据库和表,采用MySQL数据库。

DROP DATABASE IF EXISTS book;
CREATE DATABASE book;
USE book;
DROP TABLE IF EXISTS t_user;
CREATE TABLE t_user(
    `id` INT PRIMARY KEY AUTO_INCREMENT,
    `username` VARCHAR(20) NOT NULL UNIQUE,
    `password` VARCHAR(32),
    `email` VARCHAR(200)
);

INSERT INTO t_user(`username`,`password`,`email`) VALUES('admin','admin','admin@qq.com');
SELECT * FROM t_user
3. Dao持久层

在此部分需要和数据库进行交互,在此之前编写JdbcUtils工具类方便操作。

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);
            System.out.println(dataSource.getConnection());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    public static void main(String[] args) {

    }
    /**
     * 获取数据库连接池中的连接
     * @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();
            }
        }
    }
}

测试代码:

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);
        }
    }
}
根据JdbcUtils实现增删改查操作,编写BaseDao
public abstract class BaseDao {
    //使用Dbutils操作数据库
    private QueryRunner queryRunner = new QueryRunner();

    /**
     * update():方法用来执行:Insert/Update/Delete语句
     * @param sql  sql语句
     * @param args update的参数
     * @return 如果返回-1,则表示执行失败<br/>返回其他则表示影响的行数
     */
    public int update(String sql, Object... args){
        Connection connection = JdbcUtils.getConnection();
        try {
            return queryRunner.update(connection,sql,args);
        } catch (SQLException throwables) {
            throwables.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 throwables) {
            throwables.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 throwables) {
            throwables.printStackTrace();
        } finally {
            JdbcUtils.close(con);
        }
        return null;
    }

    /**
     * 查询返回一行一列的sql语句(查询返回单一值的sql语句,类似于count(*)的值)
     * @param sql
     * @param args
     * @return
     */
    public Object queryForSingleValue(String sql, Object... args){
        Connection con = JdbcUtils.getConnection();
        try {
            return queryRunner.query(con,sql,new ScalarHandler(),args);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            JdbcUtils.close(con);
        }
        return null;
    }
}

定义一个UserDao接口规范,并基于BaseDao父类,可以很容易的创建一个关于用户的实现类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类进行测试

public class UserDaoTest {

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

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

    @Test
    public void saveUser() {
        System.out.println(userDao.saveUser(new User(2,"sgu123","123487","sgu@qq.com")));
    }
}
4. Service层

主要是完成一些逻辑业务,本次分项目中,逻辑业务包括注册、登录。首先定义一个UserService接口规范。

public interface UserService {
    /**
     * 注册用户
     * @param user
     */
    public void registUser(User user);

    /**
     * 登录
     * @param user
     * @return
     */
    public User login(User user);

    /**
     * 检查用户名是否可用
     * @param username
     * @return 如果返回true则表示用户名已存在,用户名不可用,反之则表示用户表可用
     */
    public boolean existUsername(String username);
}

创建一个Service实现类

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 existUsername(String username) {

        if (userDao.queryUserByUsername(username) == null) {
            // 等于null,说明没查到,没查到表示可用
            return false;
        }

        return true;

    }
}

对Service层进行测试

public class UserServiceTest {

    UserService userService = new UserServiceImpl();
    @Test
    public void registerUser() {
        userService.registUser(new User(null,"perfect","perfect123","xk@qq.com"));
    }

    @Test
    public void login() {
        System.out.println(userService.login(new User(null, "perfect1", "perfect123", "xk@qq.com")));
    }

    @Test
    public void existUsername() {
        if(userService.existUsername("perfect2")==true){
            System.out.println("用户已存在");
        }else{
            System.out.println("用户名可用");
        }
    }
}
5. Web层

Web层采用Servlet编程,主要负责接收来自客户端的请求,并发送服务器端的响应给客户端,本次分项目涉及两个Servlet程序,分别负责注册和登录两个功能。大体流程如下:
在这里插入图片描述

5.1 注册
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.existUsername(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);
        }
    }
}

5.2 登录
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");
        //2.调用Userservice中的login服务
        User login = userService.login(new User(null, username, password, null));
        if(login==null){
            //匹配失败,跳回登录界面
            req.getRequestDispatcher("/pages/user/login.html").forward(req,resp);
        }else{
            //匹配成功,跳转到登录成功界面
            req.getRequestDispatcher("/pages/user/login_success.html").forward(req,resp);
        }
    }
}
客户端

此部分功能在我的上一篇博客中已经完成,在之前完成的基础上,主要变化有两处:(1)添加了相对路径的概念,设置一个针对此html代码的固定相对路径,之后所有的代码都是基于这个路径上的。(2)设置form action,当点击提交按钮后,form 表单提交到不同的servlet程序中,提交方式有get和post,本次项目采用post方法进行提交。

<base href="http://localhost:8080/book/">  (1)
<form action="registServlet" method="post"> (2)

Bug调试

在本次项目中,主要是遇到了两个特别愚蠢的错误,(1)首先是在web.xml配置中,servlet-mapping配置的地方忘记加“/”,导致我工程直接访问不到页面,即卡死在了html显示那一步.(2)在regist.xml中,相对路径配置的有问题,导致每次点击提交后,客户端的请求无法传递给Tomcat服务器。
(本博客仅仅是个人简单记录,如有错误,还请帮忙指出,感激不尽)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值