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

准备工作

开发环境准备

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

搭建一个web项目

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

项目需求

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

开发实现

设计架构思想

设计架构图.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包
<!-- 省略pom.xml文件中的其他内容 -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.191</version>
</dependency>
  • 编写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<String, Object> paramMap);
    public List<User> findList(User user);
    public List<User> findList(Map<String, Object> paramMap);
    public Map<String, Object> findMap(User user);
    public Map<String, Object> findMap(Map<String, Object> paramMap);
    
    // 用户信息新增
    public int save(User user);
    public int save(Map<String, Object> paramMap);
    
    // 用户信息修改
    public int update(User user);
    public int update(Map<String, Object> 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”得到如下弹出框。


新建一个Servlet.png

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


添加描述信息、初始化参数

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


添加其他接口、选择需要重写的方法

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

  <!-- web.xml里新增的内容 -->
  <servlet>
    <description></description>
    <display-name>UserCheckServlet</display-name>
    <servlet-name>UserCheckServlet</servlet-name>
    <servlet-class>servlet.UserCheckServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>UserCheckServlet</servlet-name>
    <url-pattern>/UserCheckServlet</url-pattern>
  </servlet-mapping>

实现业务功能

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

/**
 * 用户信息验证
 */
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<String, Object> 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文件

点击“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+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">   
    <title>标题</title>       
  <meta http-equiv="pragma" content="no-cache">
  <meta http-equiv="cache-control" content="no-cache">
  <meta http-equiv="expires" content="0">   
  <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  <meta http-equiv="description" content="This is my page">
 </head>
 <body>
 ${cursor}
 </body>
</html>

总结

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

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

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

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

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

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 35,288评论 18赞 399
  • 一. Java基础部分.................................................
    wy_sure阅读 4,115评论 0赞 11
  • 复习复习!!!搞起来!!Servlet和JSP是Java EE规范最基本成员,他们是Java Web开发的重点知识...
    JackFrost_fuzhu阅读 3,019评论 1赞 70
  • 前一阵子公司电影节办影展,有一场让我印象深刻。当时放的是一个新晋导演的处女座,讲九十年代深圳移民的故事。镜头跟随一...
    司昀阅读 710评论 0赞 2
  • 小李掐指一算不少小秘书都放暑假了,暑假宅在家最适合煲剧了... 于是,贴心的给小秘书们送上美剧——《妙警贼探》 基...
    0773e17b1899阅读 1,709评论 0赞 1

友情链接更多精彩内容