【JSP+Servlet】实现登录和注册

  • JSP+SerVlet,对Servlet和Dao层进行优化,抽取出共同代码

  • 只实现了简单的登录和注册,用户名查重、记住用户名和密码、验证码、表单校验并没有实现

  • GitHub源码地址


文章目录

  • 前端界面
  • 代码结构
  • 1. 建立登录注册相关模型(Bean层)
    • 建立用户表user
    • 建立对应的User类
  • 2. 建立Utils层获取数据库连接
  • 3. 建立Dao层操作数据库数据
    • 建立BaseDao, 专门被其他Dao继承,BaseDao定义一些基础方法(泛型)
    • UserDao: 继承BaseDao操作User表
  • 4. 建立service层
    • UserService 完成用户的登录注册功能
  • 5. 建立servlet层:处理用户请求


前端界面

【JSP+Servlet】实现登录和注册_第1张图片 【JSP+Servlet】实现登录和注册_第2张图片

代码结构

【JSP+Servlet】实现登录和注册_第3张图片 【JSP+Servlet】实现登录和注册_第4张图片

1. 建立登录注册相关模型(Bean层)

  • 建立用户表user

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  • 建立对应的User类

/**
 * 对应数据库中的user表
 */
public class User {
     

    private Integer id;
    private String username;
    private String password;

    public User(Integer id, String username, String password) {
     
        this.id = id;
        this.username = username;
        this.password = password;

    }
    // 无参构造函数必须得有
    public User() {
     
        super();
    }

    public Integer getId() {
     
        return id;
    }

    public void setId(Integer id) {
     
        this.id = id;
    }

    public String getUsername() {
     
        return username;
    }

    public void setUsername(String username) {
     
        this.username = username;
    }

    public String getPassword() {
     
        return password;
    }

    public void setPassword(String password) {
     
        this.password = password;
    }



    @Override
    public String toString() {
     
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}


2. 建立Utils层获取数据库连接

使用 JDBC + c3p0 获取数据库连接

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。

导包并右键 add as library
【JSP+Servlet】实现登录和注册_第5张图片
JDBCUtils

/**
 * 获取数据库连接的工具类
 *
 * @author smallbeef
 *
 */
public class JDBCUtils {
     
	// 此处要与c3p0的配置文件中的name一致
    private static ComboPooledDataSource dataSource = new ComboPooledDataSource(
            "c3p0Config");

    private JDBCUtils() {
     
    }

    /**
     * 获取数据库连接
     *
     * @return 如果获取连接成功,返回数据的连接对象。
* 如果获取数据库连接失败,则返回null */
public static Connection getConnection() { Connection connection = null; try { // 从c3p0中获取数据库连接 connection = dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return connection; } /** * 释放数据库连接 */ public static void closeConnection(Connection conn) { if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } public static void main(String[] args) { getConnection(); } }

c3p0-config.xml

<c3p0-config>
	
	<named-config name="c3p0Config">
			<property name="driverClass">com.mysql.jdbc.Driverproperty>
			<property name="jdbcUrl">jdbc:mysql://localhost:3306/userandbookproperty>
			<property name="user">rootproperty>
			<property name="password">rootproperty>
			
			<property name="maxPoolSize">10property>
			
			<property name="minPoolSize">5property>
			
			<property name="initialPoolSize">3property>
			
			<property name="idleConnectionTestPeriod">3600property>
			
			<property name="acquireIncrement">5property>
			
			<property name="maxIdleTime">50property>
	named-config>	

c3p0-config>

应当把c3p0-config.xml 放在 src 下,不然 new ComboPooledDataSource(“configName"); 可能会找不到 c3p0-config.xml 文件

数据库连接测试

public class JDBCUtilTest {
     

	@Test
	public void testGetConnection() {
     
		Connection conn = JDBCUtils.getConnection();
		System.out.println(conn);
		JDBCUtils.closeConnection(conn);
	}
	
}

在这里插入图片描述
连接成功!


3. 建立Dao层操作数据库数据

  • 建立BaseDao, 专门被其他Dao继承,BaseDao定义一些基础方法(泛型)

    导包:DButils
    使用 DBUtils的QueryRunner.update / query 方法实现增删改查

    DbUtils是一种 JDBC Utility Component (翻译过来大概就是:JDBC实用部件),故名思意,和数据库操作有关。官网上的简介也称之为 JDBC helper library ,由此可知,DbUtils是一个工具类库,用来进行数据库通信的
    【JavaWeb】DbUtils入门之QueryRunner

    BaseDao

public class BaseDao<T> {
     
    // 需要获取实际的type
    private Class<T> type;

    private QueryRunner queryRunner = new QueryRunner();

    public BaseDao(){
     
        // 获取父类的类型,父类是带参数的
        ParameterizedType superclass = (ParameterizedType) this.getClass().getGenericSuperclass();
        System.out.println(superclass.getClass());
        // 获取泛型中的具体的类型的class
        type = (Class<T>) superclass.getActualTypeArguments()[0];
    }

    /**
     * 获取一个对象
     * @param sql  sql语句
     * @param params 可变参数
     * @return
     */
    public T getBean(String sql, Object...params){
     
        Connection connection = JDBCUtils.getConnection();
        T query = null;
        try {
     
            // 查询一个数据,BeanHandler封装一个对象
            query = queryRunner.query(connection,sql,new BeanHandler<>(type),params);
        } catch (SQLException e) {
     
            e.printStackTrace();
        } finally {
     
            JDBCUtils.closeConnection(connection);
        }
        return query;
    }

    /**
     * 获取对象的集合
     * @return
     */
    public List<T> getBeanList(String sql, Object...params){
     
        Connection connection = JDBCUtils.getConnection();
        List<T> query = null;
        try {
     
            // 查询一组数据,BeanListHandler封装一组对象
            query = queryRunner.query(connection,sql,new BeanListHandler<>(type),params);
        } catch (SQLException e) {
     
            e.printStackTrace();
        } finally {
     
            JDBCUtils.closeConnection(connection);
        }

        return query;
    }

    
    /**
     * 执行增删改
     */
    public int update(String sql, Object ...params){
     
        int count = 0;
        Connection connection = JDBCUtils.getConnection();
        try {
     
            count = queryRunner.update(connection, sql, params);
        } catch (SQLException e) {
     
            e.printStackTrace();
        } finally {
     
            JDBCUtils.closeConnection(connection);
        }
        return count;
    }


}

  • UserDao: 继承BaseDao操作User表

    面向接口编程 : 定义UserDao接口UserDaoImpl 实现
/**
 * UserDAO具体的实现类
 *
 * @author smallbeef
 *
 */
public class UserDaoImp extends BaseDao<User> implements UserDao {
     

    /**
     * 按照用户名和密码查询信息
     * @param user
     * @return
     */
    @Override
    public User getUserByUserNameAndPassWord(User user) {
     
        String sql = "select id,username,password from user where username = ? and password = ?";
        User bean = this.getBean(sql, user.getUsername(), user.getPassword());
        return bean;
    }

    /**
     * 注册 保存用户
     * @param user
     * @return
     */
    @Override
    public boolean registUser(User user) {
     
        String sql = "insert into user(`id`,`username`,`password`) values(null, ?, ?)";
        int update = this.update(sql, user.getUsername(), user.getPassword());
        if(update>0){
     
            return true;
        }else
            return false;
    }
}

4. 建立service层

  • UserService 完成用户的登录注册功能

public class UserServiceImp implements UserService {
     
    private UserDao ud = new UserDaoImp();

    @Override
    public User login(User user) {
     
        return ud.getUserByUserNameAndPassWord(user);
    }

    @Override
    public boolean regist(User user) {
     
        return ud.registUser(user);
    }
}

5. 建立servlet层:处理用户请求

一般是建立 LoginServletRegistServlet , 注册和登录界面表单分别调用不同的servlet。

此处我们希望一个UserServlet就能够处理注册和登录请求,让用户的注册和登录请求都经过同一个Userservlet,而不是分别经过loginservlet和registservlet。

实现方法:给form表单带上method参数请求UserServlet,UserServlet通过这个参数判断是注册请求还是登录请求

<form action="/UserServlet?method=login" method="post">

<form action="/UserServlet?method=regist" method="post">

在这里插入图片描述
UserServelt

@WebServlet(name = "UserServlet", urlPatterns = "/UserServlet")
public class UserServlet extends HttpServlet {
     
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     
        String method = request.getParameter("method");
        System.out.println(method);
        if("regist".equals(method)){
     
            //注册
            regist(request,response);
        }
        if("login".equals(method)){
     
            //登录
            login(request,response);
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     
        doPost(request,response);
    }

    private UserService us = new UserServiceImp();

    protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        boolean b = us.regist(new User(null, username, password));
        if(b){
     
            //注册成功,返回成功页面,重定向
            request.getRequestDispatcher("/pages/regist_success.html").forward(request,response);

        }else{
     
            //注册失败,返回失败页面,转发
            response.sendRedirect(request.getContextPath()+"/pages/error.jsp");
        }
    }

    protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        User user = us.login(new User(null, username, password));
        if(user == null){
     
            //登录失败,返回登录页面,转发(换界面)
            request.getRequestDispatcher("/pages/error.jsp").forward(request,response);
        }else{
     
            //登录成功,返回成功界面 重定向(直接刷新界面)
            response.sendRedirect(request.getContextPath() + "/pages/login_success.html");
        }
    }
}

为了不陷入层层的if判断,我们利用反射来优化此代码

反射:你指定一个方法名,我找到这个方法并直接调用)

public class UserServlet extends HttpServlet {
        
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     
        // 获取要调用的方法
        String method = request.getParameter("method");
        System.out.println(method);
        // getDeclaredMethod(方法名,参数列表(传的是各个参数的类))

        // 通过反射找到该方法并调用
        try {
     
            Method declaredMethod = this.getClass().getDeclaredMethod(method, HttpServletRequest.class, HttpServletResponse.class);
            // 把方法权限设大
            declaredMethod.setAccessible(true);
            // invoke(对象,参数) 执行该方法
            declaredMethod.invoke(this,request,response);
        } catch (NoSuchMethodException e) {
     
            e.printStackTrace();
        } catch (IllegalAccessException e) {
     
            e.printStackTrace();
        } catch (InvocationTargetException e) {
     
            e.printStackTrace();
        }
//        if("regist".equals(method)){
     
//            //注册
//            regist(request,response);
//        }
//        if("login".equals(method)){
     
//            //登录
//            login(request,response);
//        }
    }

所有的servlet都是通过反射来调用相应的方法,所以我们可以抽取出一个BaseServlet

抽取之后Userservlet只需要编写相关逻辑代码就可以了,以后定义的任何方法只需要在form表单上带上方法名即可

【JSP+Servlet】实现登录和注册_第6张图片

BaseServlet

public class BaseServlet extends HttpServlet {
     
//    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
     
        doPost(request, response);
    }

//    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
     
        // 解决post乱码问题,设置请求的参数字符集为UTf-8
        request.setCharacterEncoding("UTF-8");
        // 获取要调用的方法
        String method = request.getParameter("method");
        System.out.println(method);

        // 通过反射找到该方法并调用
        // getDeclaredMethod(方法名,参数列表(传的是各个参数的类))
        try {
     
            Method declaredMethod = this.getClass().getDeclaredMethod(method, HttpServletRequest.class, HttpServletResponse.class);
            // 把方法权限设大
            declaredMethod.setAccessible(true);
            // invoke(对象,参数) 执行该方法
            declaredMethod.invoke(this,request,response);
        } catch (NoSuchMethodException e) {
     
            e.printStackTrace();
        } catch (IllegalAccessException e) {
     
            e.printStackTrace();
        } catch (InvocationTargetException e) {
     
            e.printStackTrace();
        }

    }
}

UserServlet

@WebServlet(name = "UserServlet" ,urlPatterns = "/UserServlet")
public class UserServlet extends BaseServlet {
     


    private UserService us = new UserServiceImp();

    protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        boolean b = us.regist(new User(null, username, password));
        if(b){
     
            //注册成功,返回成功页面,重定向
            request.getRequestDispatcher("/pages/regist_success.html").forward(request,response);

        }else{
     
            //注册失败,返回注册页面,转发
            response.sendRedirect(request.getContextPath()+"/pages/error.html");
        }
    }

    protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        User user = us.login(new User(null, username, password));
        if(user == null){
     
            //登录失败,返回登录页面,转发(换界面)
            request.getRequestDispatcher("/pages/error.html").forward(request,response);
        }else{
     
            //登录成功,返回成功界面 重定向(直接刷新界面)
            response.sendRedirect(request.getContextPath() + "/pages/login_success.html");
        }
    }
}

一连串的request.getParameter取参过程其实也可以抽取出来,此处就不做了


注意修改域名为默认:
【JSP+Servlet】实现登录和注册_第7张图片

你可能感兴趣的:(Java学习路线,#,Jsp+Servlet,java,jsp,servlet)