书城项目阶段二:用户注册和登陆的实现

书城项目阶段二:用户注册和登陆的实现

需求 1:用户注册

1)访问注册页面
2)填写注册信息,提交给服务器
3)服务器应该保存用户
4)当用户已经存在----提示用户注册 失败,用户名已存在
5)当用户不存在-----注册成功

需求 2:用户登陆

1)访问登陆页面
2)填写用户名密码后提交
3)服务器判断用户是否存在
4)如果登陆失败 —>>>> 返回用户名或者密码错误信息
5)如果登录成功 —>>>>

JavaEE项目的三层框架

在这里插入图片描述

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

web层com.atguigu.web/servlet/controller
service层com.atguigu.service.implService 接口包、实现类
dao层com.atguigu.dao.impDao 接口包、实现类
实体Bean层com.atguigu.pojo/entity/domain/beanJavaBean接口实现类
测试包com.atguigu.test/junit
工具类com.atguigu.test/junit

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

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;

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

​ 3.2 在src源码目录下编写jdbc.properties属性配置文件,放在resources目录下

username=root
password=123456
url=jdbc:mysql://localhost:3306/book?characterEncoding=UTF-8
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10 (最大连接数量)

​ 3.3 编写JdbcUtils工具类

方法:获取数据库连接池中的连接和关闭连接,使用数据库连接池可以提高性能

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

  //获取数据库连接池中的连接
  //return 如果返回空,说明获取连接失败,有值就是连接成功
  public static Connection getConnection(){
    Connection conn = null;
    try {
      conn = dataSource.getConnection();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return conn;
  }
  //关闭连接,放回数据库连接池
  public static void close(Connection conn){
    if(conn != null){
      try {
        conn.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
  }
}

​ 3.4 JdbcUtils测试

package com.atguigu.test;

import com.atguigu.utils.JdbcUtils;
import org.junit.jupiter.api.Test;
import java.sql.Connection;

public class JdbcUtilsTest {
  @Test
  public void testJdbcUtils(){
    for (int i = 0; i < 30; i++) {
      Connection connection = JdbcUtils.getConnection();
      System.out.println(connection);
      JdbcUtils.close(connection);
    }
  }
}

4、编写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 {
  private QueryRunner queryRunner = new QueryRunner();
  //update方法用来执行Insert、update、delete语句
  //如果返回-1,说明执行失败,返回其他表示影响的行数
  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对应的参数值
   * @return
   * @param <T> 返回类型的泛型
   */
  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 (SQLException e) {
      e.printStackTrace();
    }finally {
      JdbcUtils.close(conn);
    }
    return null;
  }
  //查询返回多个JavaBean的SQL语句
  public <T> List<T> queryForList(Class<T> type,String sql,Object ... args){
    Connection conn = JdbcUtils.getConnection();
    try {
      return queryRunner.query(conn,sql,new BeanListHandler<T>(type),args);
    } catch (SQLException e) {
      e.printStackTrace();
    }finally {
      JdbcUtils.close(conn);
    }
    return null;
  }
  //执行返回一行一列的SQL语句
  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接口

package com.atguigu.dao;

import com.atguigu.pojo.User;

public interface UserDao {

  //根据用户名查询用户信息
  //如果返回null,说明没有这个用户
  public User queryUserByUsername(String name);

  //根据用户名和密码查询用户信息
  //如果返回null,说明用户名或密码错误
  public User queryUserByUsernameAndPassword(String username, String password);

  //保护用户信息
  public int saveUser(User user);
}

UserDaoImpl实现类

package com.atguigu.dao.impl;

import com.atguigu.dao.UserDao;
import com.atguigu.pojo.User;

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测试

package com.atguigu.test;

import com.atguigu.dao.UserDao;
import com.atguigu.dao.impl.UserDaoImpl;
import com.atguigu.pojo.User;
import org.junit.jupiter.api.Test;

import static org.junit.Assert.*;


public class UserDaoTest {
  UserDao userDao = new UserDaoImpl();
  @Test
  public void queryUserByUsername() {

    if(userDao.queryUserByUsername("admin") == null){
      System.out.println("用户名可用!");
    }else{
      System.out.println("用户名已存在!");
    }
  }

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

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

web阶段使用Base(路径写到工程名http://localhost:8080/工程名)+相对。Base标签一般写到Title下面

框架之后,使用绝对路径

6、编写UserService和测试

UserService接口

package com.atguigu.service;

import com.atguigu.pojo.User;

public interface UserService {

  public void registUser(User user);

  public User login(User user);

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

UserServiceImplements实现类

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;

public class UserServiceImpl implements UserService {
  //用Dao对象操作数据库
  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) {
      return false;
    }
      return true;
  }
}

UserServiceTest测试

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 static org.junit.Assert.*;

public class UserServiceTest {
  UserService userService = new UserServiceImpl();
  @Test
  public void registUser() {
    userService.registUser(new User(null,"lala","lala666","lala@163.com"));
  }

  @Test
  public void login() {
    System.out.println(userService.login(new User(null,"admin","admin",null)));
  }

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

7、编写web层

实现用户注册功能

当用户在注册页面输入完成后,就会点击提交按钮,把参数都发送给服务器,去注册保存。

7.1 RegistServlet程序:

  1. 获取请求参数

  2. 检验验证码是否正确

    1. 正确

      检查用户名是否存在

      ​ 存在 返回注册页面

      ​ 不存在 调用Service保存到数据库并返回注册成 功页面

    2. 不正确

      返回注册页面

package com.atguigu.web;

import com.atguigu.pojo.User;
import com.atguigu.service.UserService;
import com.atguigu.service.impl.UserServiceImpl;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class RegistServlet extends HttpServlet {
  private UserService userService = new UserServiceImpl();
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  //1、获取请求参数
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    String email = request.getParameter("email");
    String code = request.getParameter("code");
    //2、检查验证码是否正确 == 写死 要求验证码为:abcde
    if("abcde".equalsIgnoreCase(code)){
      //检查用户名是否可用
      if(userService.existUsername(username)){
        //存在不可用,跳回注册页面
        System.out.println("用户名["+username+"]已存在!");
         			 request.getRequestDispatcher("/pages/user/regist.html").forward(request,response);
      }else{
        //可用,调用Service保存数据库中
        userService.registUser(new User(null,username,password,email));
        request.getRequestDispatcher("/pages/user/regist_success.html").forward(request,response);
      }
    }else{
      //不正确,跳回注册页面,请求转发
      System.ou.println("验证码["+code+"]错误!");
      request.getRequestDispatcher("/pages/user/regist.html").forward(request,response);
    }
  }
}

7.2修改regist.html和regist_success.html页面

  1. 添加Base标签(永远固定相对路径的跳转结果)

    <base href="http://localhost:8080/bookstore/">
    
  2. 修改base标签对页面中所有相对路径的影响

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

7.3 编写LoginServlet程序

  1. 获取请求参数
  2. 调用Service方法处理业务,userService.login( )登录
  3. 根据login( )方法返回的结果判断是否登录成功,若用户名和密码匹配都正确,跳转到登录成功页面,否则,跳转到登录页面
package com.atguigu.web; 

import com.atguigu.pojo.User;
import com.atguigu.service.UserService;
import com.atguigu.service.impl.UserServiceImpl;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class LoginServlet extends HttpServlet {
  UserService userService = new UserServiceImpl();
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    User loginUser = userService.login(new User(null, username, password, null));
    if(loginUser == null){
      request.getRequestDispatcher("/pages/user/login.html").forward(request,response);
    }else{
      request.getRequestDispatcher("/pages/user/login_success.html").forward(request,response);
    }
  }
}

st(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    User loginUser = userService.login(new User(null, username, password, null));
    if(loginUser == null){
      request.getRequestDispatcher("/pages/user/login.html").forward(request,response);
    }else{
      request.getRequestDispatcher("/pages/user/login_success.html").forward(request,response);
    }
  }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值