用户登录注册系统(基于JSP和Servlet)

准备工作

开发环境准备

  • 开发工具:eclipse 4.3
  • 技术语言:Java SE 1.7
  • 依赖控制:Maven 3.0.4
  • 服务器:Tomcat 7.0.68
  • 操作系统:Windows 10
  • 版本管理:项目源码地址

搭建一个web项目

参考文档:快速搭建web项目

项目需求

实现一个标准的用户登录注册功能,详细需求见easyPassport需求说明。

开发实现

设计架构思想

用户登录注册系统(基于JSP和Servlet)_第1张图片
设计架构图.jpg

如上图所示,由Servlet提供后台服务,由JSP完成前端的数据展示,JavaBean作为数据存储和传输的介质,并最终持久化至数据库。

模版层设计实现

创建用户信息表:

用户信息表用来保存和记录用户的信息

create table users{
id int,
userid varchar(50),
username varchar(50),
email varchar(50),
phone varchar(11),
password varchar(50),
status varchar(2),
create_datet varchar(20),
mod_datet varchar(20),
func_arr varchar(20) default '00000000000000000000'
}

对应的数据字典:

字段 数据类型 字段说明 是否可以为空 备注
id int 数据库主键ID 数据自动生成
userid varchar(50) 业务主键ID 根据业务规则生成的主键ID
username varchar(50) 用户名称 用户注册时输入的用户名
email varchar(50) 用户邮箱 用户注册时输入的邮箱
phone varchar(11) 手机号 手机号的相关功能本期暂不涉及
password varchar(50) 密码 密码保存用户密码
status varchar(2) 用户状态:0-正常;1停用
create_datet varchar(20) 用户创建时间
mod_datet varchar(20) 用户修改时间
func_arr varchar(20) 特殊状态位 用来区分特殊也属性的用户

JavaBean、JDBC和DAO

JavaBean是数据传输的介质,JDBC是Java应用连接数据库的标准实现,DAO(Data Access Objects)则提供了对原子表的增删查改等功能。三者共同组成了一个Java应用的模版层(也叫持久层)。

JavaBean的实现

public class User implements Serializable{

    private static final long serialVersionUID = 1L;

    private long id;
    private String userId;
    private String userName;
    private String email;
    private String phone;
    private String password;
    private String status;
    private String createDatet;
    private String modDatet;
    private String funcArr;

       // get、set方法省略
       ....
}

使用JDBC技术访问数据库

JDBC是Java EE标准规范的一部分,是Java应用操作数据库时最重要的方法(甚至可以说是唯一的方法,ODBC/OCI等一堆东西除非极端情况,已经基本没人使用了),基于JDBC技术衍生出很多框架,在这里就不做演示了。

一个web项目使用JDBC连接数据库的标准步骤如下:

  • 引入必要的jar包


    com.h2database
    h2
    1.4.191

  • 编写JDBC程序
//引入必要的包
import java.sql.*;

public class JDBCDemo {

    // JDBC 驱动名及数据库 URL(以H2为例)
    static final String JDBC_DRIVER = "org.h2.Driver";  
    static final String DB_URL = "jdbc:h2:tcp://localhost/~/test";

    // 数据库的用户名与密码,需要根据自己的设置
    static final String USER = "sa";
    static final String PASS = "sa";

    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        try{
            // 注册 JDBC 驱动
            Class.forName(JDBC_DRIVER);
        
            // 打开链接
            System.out.println("连接数据库...");
            conn = DriverManager.getConnection(DB_URL,USER,PASS);
        
            // 执行查询
            System.out.println(" 实例化Statement对...");
            stmt = conn.createStatement();
            String sql;
            sql = "SELECT * FROM USERS";
            ResultSet rs = stmt.executeQuery(sql);
        
            // 展开结果集数据库
            while(rs.next()){
                // 通过字段检索
                int id  = rs.getInt("id");
                String name = rs.getString("username");
    
                // 输出数据
                System.out.print("ID: " + id);
                System.out.print(", 用户名称: " + name);
                System.out.print("\n");
            }
            // 完成后关闭
            rs.close();
            stmt.close();
            conn.close();
        }catch(SQLException se){
            // 处理 JDBC 错误
            se.printStackTrace();
        }catch(Exception e){
            // 处理 Class.forName 错误
            e.printStackTrace();
        }finally{
            // 关闭资源
            try{
                if(stmt!=null) stmt.close();
            }catch(SQLException se2){
            }// 什么都不做
            try{
                if(conn!=null) conn.close();
            }catch(SQLException se){
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }
}

使用DAO提供基础功能

DAO通常有两部分组成,一个是通用的接口,提供标准的服务;一个是对应接口的实现类,方便扩展和更新。

接口类的设计如下:

import java.util.List;
import java.util.Map;

import javabean.User;

public interface UserDao {

    // 用户信息查询
    public User findById(long id);
    public User findOne(User user);
    public User findOne(Map paramMap);
    public List findList(User user);
    public List findList(Map paramMap);
    public Map findMap(User user);
    public Map findMap(Map paramMap);
    
    // 用户信息新增
    public int save(User user);
    public int save(Map paramMap);
    
    // 用户信息修改
    public int update(User user);
    public int update(Map paramMap);
}

DAO接口的实现类如下:


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javabean.User;

public class UserDaoImpl implements UserDao {
    
    private static final String JDBC_DRIVER = "org.h2.Driver";  
    private static final String DB_URL = "jdbc:h2:tcp://localhost/~/test";
    private static final String USER = "sa";
    private static final String PASS = "sa";
    
    private Connection conn = null;
    private static String findUserById = " select id, userid, username, email, phone, password, status, create_datet, mod_datet, func_arr from users where id = ? ";
    private static String findUsers = " select id, userid, username, email, phone, password, status, create_datet, mod_datet, func_arr from users ";

    // 创建获取数据库链接的方法
    private Connection getConnection() {
        if (null != conn) {
            return conn;
        } else {
            try {
                Class.forName(JDBC_DRIVER);
                conn = DriverManager.getConnection(DB_URL, USER, PASS);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return conn;
        }
    }
    
    @Override
    public User findById(long id) {
        if(null == conn)
            conn = this.getConnection();
        User user = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(findUserById);
            ps.setLong(1, id);
            rs = ps.executeQuery();
            while(rs.next()){
                user = new User(
                        rs.getLong(1),      // id
                        rs.getString(2),    // userid
                        rs.getString(3),    // userName
                        rs.getString(4),    // email
                        rs.getString(5),    // phone
                        rs.getString(6),    // password
                        rs.getString(7),    // status
                        rs.getString(8),    // createDatet
                        rs.getString(9),    // modDatet
                        rs.getString(10));  // funcArr
            }
            rs.close();
            ps.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 确保资源关闭
            try {
                if (rs != null) rs.close();
            } catch (SQLException e) {
            }           
            try {
                if (ps != null) ps.close();
            } catch (SQLException e) {
            }
        }
        return user;
    }
......

}

控制层设计实现

控制层的功能主要由Servlet实现,通过分析需求文档可以得出,要实现本系统,至少需要Servlet提供以下服务:

  • 用户信息验证
  • 用户信息查询
  • 用户信息新增
  • 用户信息修改
  • 密码重置

使用eclipse新建Servlet类

以实现“用户信息验证”服务为例,控制层实现应首先新建Servlet类。按以下步骤操作“File” -> “New” -> “Servlet”得到如下弹出框。


用户登录注册系统(基于JSP和Servlet)_第2张图片
新建一个Servlet.png

选择包结构,输入自定义的Servlet名称,点击“Next”,输入对这个Servlet类的描述,如果有需要,可以添加初始化参数。


用户登录注册系统(基于JSP和Servlet)_第3张图片
添加描述信息、初始化参数

点击“Next”,根据自己需要扩展Servlet类,最后点击“Finish”完成类的新建。


用户登录注册系统(基于JSP和Servlet)_第4张图片
添加其他接口、选择需要重写的方法

此时eclipse会自动将上述配置的内容转换为web.xml里的配置,接下来我们需要做的,就是在新增的Servlet类中,实现对应的服务。

  
  
    
    UserCheckServlet
    UserCheckServlet
    servlet.UserCheckServlet
  
  
    UserCheckServlet
    /UserCheckServlet
  

实现业务功能

下述代码简单描述了“用户信息验证”的业务流程,即获取参数 -> 获取后台数据 -> 对比用户信息与后台保存是否一致 -> 跳转到指定页面。

/**
 * 用户信息验证
 */
public class UserCheckServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // 默认调用doPost方法,免得同一段代码写多次
        this.doPost(request, response);
    }

    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // 获取用户输入的信息
        String userName = (String)request.getParameter("userName");
        String passWord = (String)request.getParameter("passWord");
        // 将用户名称作为参数传递给后台DAO 
        UserDao userDao = new UserDaoImpl();
        Map paramMap = new HashMap<>();
        paramMap.put("userName", userName);
        // DAO完成用户用户信息检索
        User user = userDao.findOne(paramMap);
        // 根据查询的结果判断用户是否真实存在,并跳转到指定的页面
        if(user.getPassword().equals(passWord)){
            response.sendRedirect("登录成功跳转到首页");
        } else {
            response.sendRedirect("登陆不成功则停留在登录页面");
        }
    }
}

JSP实现前端页面展示

eclipse新建一个JSP文件时会有很多问题,比如默认不支持中文,要解决这类问题就要设置一下eclipse的默认配置。

按照以下步骤“Windows -> “Preferences” -> “Web” -> “JSP File” -> “Editor” -> “Templates”,找到对应的页面。


用户登录注册系统(基于JSP和Servlet)_第5张图片
新建JSP文件

点击“Editor”编辑JSP文件模版,这样再次新建文件时就不会有问题了。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>


  
       
    标题       
  
  
     
  
  
 
 
 ${cursor}
 

总结

至此,我们已经基本实现了用户登录注册系统涉及的功能(项目源码地址)。但一个完善的,工业级别的系统远非仅仅“实现功能”这么简单,以本项目为例,应至少满足以下几点要求才能最终上线。

  1. 系统的性能要足够好
  2. 系统的安全性要有保障

性能是衡量一个软件产品的终极指标,世界上任何一款软件产品都会在满足所以业务功能基础上,尽力提升性能,提高程序的运转效率。JSP和Servlet技术是Java Web技术的基础,它有着上手简单,文档资源丰富等优点,可以让稍有Java基础的同学在搜索引擎的帮助下,快速实现功能。但也正是因为它“太基础”,很多性能相关的内容都需要程序员自己设计实现,而这些内容,恰恰是网上“稀有资源”。

web应用通常会暴露在公网环境中,安全性也不容忽视。安全问题是相对的,不存在“绝对安全”一说,但一个需要正式上线运行的产品一定要有对应的安全规格和标准。这么做既是对产品负责,更是对用户负责。

所以,这个“登录注册系统”下一阶段的目标,就是提升性能表现,提高安全等级。

你可能感兴趣的:(用户登录注册系统(基于JSP和Servlet))