用戶登錄注冊系統(tǒng)(基于JSP和Servlet)

準備工作

開發(fā)環(huán)境準備

  • 開發(fā)工具:eclipse 4.3
  • 技術(shù)語言:Java SE 1.7
  • 依賴控制:Maven 3.0.4
  • 服務(wù)器:Tomcat 7.0.68
  • 操作系統(tǒng):Windows 10
  • 版本管理:項目源碼地址

搭建一個web項目

參考文檔:快速搭建web項目

項目需求

實現(xiàn)一個標準的用戶登錄注冊功能,詳細需求見easyPassport需求說明。

開發(fā)實現(xiàn)

設(shè)計架構(gòu)思想

設(shè)計架構(gòu)圖.jpg

如上圖所示,由Servlet提供后臺服務(wù),由JSP完成前端的數(shù)據(jù)展示,JavaBean作為數(shù)據(jù)存儲和傳輸?shù)慕橘|(zhì),并最終持久化至數(shù)據(jù)庫。

模版層設(shè)計實現(xiàn)

創(chuàng)建用戶信息表:

用戶信息表用來保存和記錄用戶的信息

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'
}

對應(yīng)的數(shù)據(jù)字典:

字段 數(shù)據(jù)類型 字段說明 是否可以為空 備注
id int 數(shù)據(jù)庫主鍵ID 數(shù)據(jù)自動生成
userid varchar(50) 業(yè)務(wù)主鍵ID 根據(jù)業(yè)務(wù)規(guī)則生成的主鍵ID
username varchar(50) 用戶名稱 用戶注冊時輸入的用戶名
email varchar(50) 用戶郵箱 用戶注冊時輸入的郵箱
phone varchar(11) 手機號 手機號的相關(guān)功能本期暫不涉及
password varchar(50) 密碼 密碼保存用戶密碼
status varchar(2) 用戶狀態(tài):0-正常;1停用
create_datet varchar(20) 用戶創(chuàng)建時間
mod_datet varchar(20) 用戶修改時間
func_arr varchar(20) 特殊狀態(tài)位 用來區(qū)分特殊也屬性的用戶

JavaBean、JDBC和DAO

JavaBean是數(shù)據(jù)傳輸?shù)慕橘|(zhì),JDBC是Java應(yīng)用連接數(shù)據(jù)庫的標準實現(xiàn),DAO(Data Access Objects)則提供了對原子表的增刪查改等功能。三者共同組成了一個Java應(yīng)用的模版層(也叫持久層)。

JavaBean的實現(xiàn)

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技術(shù)訪問數(shù)據(jù)庫

JDBC是Java EE標準規(guī)范的一部分,是Java應(yīng)用操作數(shù)據(jù)庫時最重要的方法(甚至可以說是唯一的方法,ODBC/OCI等一堆東西除非極端情況,已經(jīng)基本沒人使用了),基于JDBC技術(shù)衍生出很多框架,在這里就不做演示了。

一個web項目使用JDBC連接數(shù)據(jù)庫的標準步驟如下:

  • 引入必要的jar包
<!-- 省略pom.xml文件中的其他內(nèi)容 -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.191</version>
</dependency>
  • 編寫JDBC程序
//引入必要的包
import java.sql.*;

public class JDBCDemo {

    // JDBC 驅(qū)動名及數(shù)據(jù)庫 URL(以H2為例)
    static final String JDBC_DRIVER = "org.h2.Driver";  
    static final String DB_URL = "jdbc:h2:tcp://localhost/~/test";

    // 數(shù)據(jù)庫的用戶名與密碼,需要根據(jù)自己的設(shè)置
    static final String USER = "sa";
    static final String PASS = "sa";

    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        try{
            // 注冊 JDBC 驅(qū)動
            Class.forName(JDBC_DRIVER);
        
            // 打開鏈接
            System.out.println("連接數(shù)據(jù)庫...");
            conn = DriverManager.getConnection(DB_URL,USER,PASS);
        
            // 執(zhí)行查詢
            System.out.println(" 實例化Statement對...");
            stmt = conn.createStatement();
            String sql;
            sql = "SELECT * FROM USERS";
            ResultSet rs = stmt.executeQuery(sql);
        
            // 展開結(jié)果集數(shù)據(jù)庫
            while(rs.next()){
                // 通過字段檢索
                int id  = rs.getInt("id");
                String name = rs.getString("username");
    
                // 輸出數(shù)據(jù)
                System.out.print("ID: " + id);
                System.out.print(", 用戶名稱: " + name);
                System.out.print("\n");
            }
            // 完成后關(guān)閉
            rs.close();
            stmt.close();
            conn.close();
        }catch(SQLException se){
            // 處理 JDBC 錯誤
            se.printStackTrace();
        }catch(Exception e){
            // 處理 Class.forName 錯誤
            e.printStackTrace();
        }finally{
            // 關(guān)閉資源
            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提供基礎(chǔ)功能

DAO通常有兩部分組成,一個是通用的接口,提供標準的服務(wù);一個是對應(yīng)接口的實現(xiàn)類,方便擴展和更新。

接口類的設(shè)計如下:

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接口的實現(xiàn)類如下:


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 ";

    // 創(chuàng)建獲取數(shù)據(jù)庫鏈接的方法
    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 {
            // 確保資源關(guān)閉
            try {
                if (rs != null) rs.close();
            } catch (SQLException e) {
            }           
            try {
                if (ps != null) ps.close();
            } catch (SQLException e) {
            }
        }
        return user;
    }
......

}

控制層設(shè)計實現(xiàn)

控制層的功能主要由Servlet實現(xiàn),通過分析需求文檔可以得出,要實現(xiàn)本系統(tǒng),至少需要Servlet提供以下服務(wù):

  • 用戶信息驗證
  • 用戶信息查詢
  • 用戶信息新增
  • 用戶信息修改
  • 密碼重置

使用eclipse新建Servlet類

以實現(xiàn)“用戶信息驗證”服務(wù)為例,控制層實現(xiàn)應(yīng)首先新建Servlet類。按以下步驟操作“File” -> “New” -> “Servlet”得到如下彈出框。


新建一個Servlet.png

選擇包結(jié)構(gòu),輸入自定義的Servlet名稱,點擊“Next”,輸入對這個Servlet類的描述,如果有需要,可以添加初始化參數(shù)。


添加描述信息、初始化參數(shù)

點擊“Next”,根據(jù)自己需要擴展Servlet類,最后點擊“Finish”完成類的新建。


添加其他接口、選擇需要重寫的方法

此時eclipse會自動將上述配置的內(nèi)容轉(zhuǎn)換為web.xml里的配置,接下來我們需要做的,就是在新增的Servlet類中,實現(xiàn)對應(yīng)的服務(wù)。

  <!-- web.xml里新增的內(nèi)容 -->
  <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>

實現(xiàn)業(yè)務(wù)功能

下述代碼簡單描述了“用戶信息驗證”的業(yè)務(wù)流程,即獲取參數(shù) -> 獲取后臺數(shù)據(jù) -> 對比用戶信息與后臺保存是否一致 -> 跳轉(zhuǎn)到指定頁面。

/**
 * 用戶信息驗證
 */
public class UserCheckServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // 默認調(diào)用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");
        // 將用戶名稱作為參數(shù)傳遞給后臺DAO 
        UserDao userDao = new UserDaoImpl();
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("userName", userName);
        // DAO完成用戶用戶信息檢索
        User user = userDao.findOne(paramMap);
        // 根據(jù)查詢的結(jié)果判斷用戶是否真實存在,并跳轉(zhuǎn)到指定的頁面
        if(user.getPassword().equals(passWord)){
            response.sendRedirect("登錄成功跳轉(zhuǎn)到首頁");
        } else {
            response.sendRedirect("登陸不成功則停留在登錄頁面");
        }
    }
}

JSP實現(xiàn)前端頁面展示

eclipse新建一個JSP文件時會有很多問題,比如默認不支持中文,要解決這類問題就要設(shè)置一下eclipse的默認配置。

按照以下步驟“Windows -> “Preferences” -> “Web” -> “JSP File” -> “Editor” -> “Templates”,找到對應(yīng)的頁面。


新建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>

總結(jié)

至此,我們已經(jīng)基本實現(xiàn)了用戶登錄注冊系統(tǒng)涉及的功能(項目源碼地址)。但一個完善的,工業(yè)級別的系統(tǒng)遠非僅僅“實現(xiàn)功能”這么簡單,以本項目為例,應(yīng)至少滿足以下幾點要求才能最終上線。

  1. 系統(tǒng)的性能要足夠好
  2. 系統(tǒng)的安全性要有保障

性能是衡量一個軟件產(chǎn)品的終極指標,世界上任何一款軟件產(chǎn)品都會在滿足所以業(yè)務(wù)功能基礎(chǔ)上,盡力提升性能,提高程序的運轉(zhuǎn)效率。JSP和Servlet技術(shù)是Java Web技術(shù)的基礎(chǔ),它有著上手簡單,文檔資源豐富等優(yōu)點,可以讓稍有Java基礎(chǔ)的同學(xué)在搜索引擎的幫助下,快速實現(xiàn)功能。但也正是因為它“太基礎(chǔ)”,很多性能相關(guān)的內(nèi)容都需要程序員自己設(shè)計實現(xiàn),而這些內(nèi)容,恰恰是網(wǎng)上“稀有資源”。

web應(yīng)用通常會暴露在公網(wǎng)環(huán)境中,安全性也不容忽視。安全問題是相對的,不存在“絕對安全”一說,但一個需要正式上線運行的產(chǎn)品一定要有對應(yīng)的安全規(guī)格和標準。這么做既是對產(chǎn)品負責,更是對用戶負責。

所以,這個“登錄注冊系統(tǒng)”下一階段的目標,就是提升性能表現(xiàn),提高安全等級。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,840評論 18 399
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 4,033評論 0 11
  • 復(fù)習(xí)復(fù)習(xí)?。。「闫饋恚?!Servlet和JSP是Java EE規(guī)范最基本成員,他們是Java Web開發(fā)的重點知識...
    JackFrost_fuzhu閱讀 2,994評論 1 70
  • 前一陣子公司電影節(jié)辦影展,有一場讓我印象深刻。當時放的是一個新晉導(dǎo)演的處女座,講九十年代深圳移民的故事。鏡頭跟隨一...
    司昀閱讀 693評論 0 2
  • 小李掐指一算不少小秘書都放暑假了,暑假宅在家最適合煲劇了... 于是,貼心的給小秘書們送上美劇——《妙警賊探》 基...
    0773e17b1899閱讀 1,633評論 0 1

友情鏈接更多精彩內(nèi)容