初學(xué)Java Web(9)——學(xué)生管理系統(tǒng)(簡(jiǎn)易版)總結(jié)

項(xiàng)目開始時(shí)間:2018年4月8日14:37:47
項(xiàng)目完成時(shí)間:2018年4月9日10:03:30

技術(shù)準(zhǔn)備

這個(gè)項(xiàng)目是自己用于鞏固 J2EE 相關(guān)知識(shí)的練手項(xiàng)目,非常簡(jiǎn)單,但是相關(guān)的功能卻非常實(shí)用,所以在這里分享一下

為了完成這個(gè)項(xiàng)目蒙袍,需要掌握如下技術(shù):

  • Java
    基礎(chǔ)知識(shí)
  • 前端:
    HTML, CSS, JAVASCRIPT, JQUERY
  • J2EE:
    Tomcat, Servlet, JSP, Filter
  • 數(shù)據(jù)庫:
    MySQL

開發(fā)流程

項(xiàng)目雖然很簡(jiǎn)單,很小,但是為了開發(fā)的有條不紊玩郊,還是按照商業(yè)項(xiàng)目的開發(fā)來完成。

① 需求分析

首先要確定要做哪些功能

  • 使用數(shù)據(jù)庫保存數(shù)據(jù)
  • 增刪改查學(xué)生的信息(學(xué)號(hào)枉阵,名稱译红,年齡,性別兴溜,出生日期)

② 表結(jié)構(gòu)設(shè)計(jì)

根據(jù)需求侦厚,那么只需要一個(gè) student 表就能夠完成功能了。

  • 創(chuàng)建數(shù)據(jù)庫:student
    將數(shù)據(jù)庫編碼格式設(shè)置為 UTF-8 拙徽,便于存取中文數(shù)據(jù)
DROP DATABASE IF EXISTS student;
CREATE DATABASE student DEFAULT CHARACTER SET utf8;
  • 創(chuàng)建學(xué)生表:student
    不用學(xué)生學(xué)號(hào)(studentID)作為主鍵的原因是:不方便操作悔橄,例如在更新數(shù)據(jù)的時(shí)候迄沫,同時(shí)也要更改學(xué)號(hào)囱修,那這樣的操作怎么辦呢吠卷?
    所以我們加了一個(gè) id 用來唯一表示當(dāng)前數(shù)據(jù)。
CREATE TABLE student(
  id int(11) NOT NULL AUTO_INCREMENT,
  studentID int(11) NOT NULL UNIQUE,
  name varchar(255) NOT NULL,
  age int(11) NOT NULL,
  sex varchar(255) NOT NULL,
  birthday date DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

③ 原型設(shè)計(jì)

就是設(shè)計(jì)界面,在商業(yè)項(xiàng)目中来破,這是很重要的一步篮灼,我們可以解除界面原型,低成本徘禁、高效率的與客戶達(dá)成需求的一致性诅诱。

這個(gè)項(xiàng)目一共就分為兩個(gè)頁面:

  • 主頁面:


    首頁
  • 學(xué)生編輯頁面:


    編輯頁面

④ 實(shí)體類的設(shè)計(jì)

實(shí)體類僅僅是對(duì)數(shù)據(jù)庫中表的一一映射,同時(shí)可能還需要兼顧對(duì)業(yè)務(wù)能力的支持晌坤。

  • 在 Packge[bean]下創(chuàng)建 Student 類:
package bean;

import java.util.Date;

public class Student {

    private int id;             // 在數(shù)據(jù)庫中的ID
    private int studentID;      // 學(xué)號(hào)逢艘,跟ID區(qū)分開為了方便數(shù)據(jù)庫操作
    private String name;        // 姓名
    private int age;            // 年齡
    private String sex;         // 性別
    private Date birthday;      // 出生日期

    // setter 和 getter (為節(jié)約篇幅沒列出來)
}

⑤ DAO 類的設(shè)計(jì)

DAO,即 Date Access Object骤菠,數(shù)據(jù)庫訪問對(duì)象它改,就是對(duì)數(shù)據(jù)庫相關(guān)操作的封裝,讓其他地方看不到 JDBC 的代碼商乎。

首先我們先創(chuàng)建一個(gè)數(shù)據(jù)庫操作的工具類:

  • 在 Packge[util]下創(chuàng)建 DBUtil 類:
/**
 * 數(shù)據(jù)庫工具類央拖,這個(gè)類的作用是初始化驅(qū)動(dòng),并且提供一個(gè)getConnection用于獲取連接鹉戚。
 */
package util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBUtil {

    static String ip = "127.0.0.1";
    static int port = 3306;
    static String database = "student";
    static String encoding = "UTF-8";
    static String loginName = "root";
    static String password = "root";

    static {

        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        String url = String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s", ip, port, database, encoding);
        return DriverManager.getConnection(url, loginName, password);
    }

    public static void main(String[] args) throws SQLException {
        System.out.println(getConnection());

    }

}
  • 寫工具類的好處:
    便于統(tǒng)一維護(hù)鲜戒,降低維護(hù)成本

然后是 DAO 類,除了進(jìn)行典型的 ORM 支持功能之外抹凳,也需要提供各種業(yè)務(wù)方法遏餐。

  • 在 Packge[dao]下創(chuàng)建 StudentDAO 類:
package dao;

import bean.Student;
import util.DBUtil;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class StudentDAO {

    public int getTotal() {

        int total = 0;

        String sql = "SELECT COUNT(*) FROM student";
        try (Connection c = DBUtil.getConnection(); Statement st = c.createStatement()) {

            ResultSet rs = st.executeQuery(sql);
            while (rs.next()) {
                total = rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return total;
    }

    public void add(Student student) {

        String sql = "INSERT INTO student VALUES(NULL,?,?,?,?,?)";
        try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {

            ps.setInt(1, student.getStudentID());
            ps.setString(2, student.getName());
            ps.setInt(3, student.getAge());
            ps.setString(4, student.getSex());
            ps.setDate(5, new java.sql.Date(student.getBirthday().getTime()));

            ps.execute();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void delete(int id) {

        String sql = "DELETE FROM student WHERE ID = ?";
        try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {

            ps.setInt(1, id);

            ps.execute();

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void update(Student student) {

        String sql = "update student set student_id = ?, name = ?, age = ?, sex = ?, birthday = ? where id = ? ";
        try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {

            ps.setInt(1, student.getStudentID());
            ps.setString(2, student.getName());
            ps.setInt(3, student.getAge());
            ps.setString(4, student.getSex());
            ps.setDate(5, new java.sql.Date(student.getBirthday().getTime()));
            ps.setInt(6, student.getId());

            ps.execute();

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public Student get(int id) {

        Student student = new Student();

        String sql = "SELECT * FROM student WHERE ID = " + id;
        try (Connection c = DBUtil.getConnection(); Statement st = c.createStatement()) {

            ResultSet rs = st.executeQuery(sql);

            if (rs.next()) {

                int student_id = rs.getInt("student_id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                String sex = rs.getString("sex");
                Date birthday = rs.getDate("birthday");
                student.setStudentID(student_id);
                student.setName(name);
                student.setAge(age);
                student.setSex(sex);
                student.setBirthday(birthday);
                student.setId(id);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }

        return student;
    }

    public List<Student> list() {
        return list(0, Short.MAX_VALUE);
    }

    public List<Student> list(int start, int count) {

        List<Student> students = new ArrayList<>();

        String sql = "SELECT * FROM student ORDER BY student_id desc limit ?,?";

        try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {

            ps.setInt(1, start);
            ps.setInt(2, count);

            ResultSet rs = ps.executeQuery();

            while (rs.next()) {
                Student student = new Student();
                int id = rs.getInt("id");
                int studentID = rs.getInt("student_id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                String sex = rs.getString("sex");
                Date birthday = rs.getDate("birthday");
                student.setId(id);
                student.setStudentID(studentID);
                student.setName(name);
                student.setAge(age);
                student.setSex(sex);
                student.setBirthday(birthday);

                students.add(student);
            }

            rs.close();

        } catch (SQLException e) {
            e.printStackTrace();
        }

        return students;
    }

}
  • 該類中,既提供了增刪改查這些基本的 CRUD 操作
    1.增加:public void add(Student student)
    2.刪除:public void delete(int id)
    3.修改:public void update(Student student)
    4.查詢所有:public List<Student> list()
  • 又提供了一些非 CRUD 方法
    1.獲取總數(shù):public int getTotal()
    2.根據(jù) id 獲扔住:public Student get(int id)

⑥ 業(yè)務(wù)類介紹

作為 J2EE Web 應(yīng)用失都,一般都會(huì)按照如圖所示的設(shè)計(jì)流程進(jìn)行:
Servlet -> Service(業(yè)務(wù)類) -> DAO -> database

當(dāng)瀏覽器提交請(qǐng)求到 Tomcat Web 服務(wù)器的時(shí)候,對(duì)應(yīng)的 Servlet 的doGet/doPost 方法會(huì)被調(diào)用幸冻,接著在 Servlet 中調(diào)用 Service類粹庞,然后在 Service 類中調(diào)用DAO類,最后在 DAO 中訪問數(shù)據(jù)庫獲取相應(yīng)的數(shù)據(jù)洽损。


單本項(xiàng)目沒有使用 Service 這一層庞溜,原因是在對(duì) DAO 類進(jìn)行開發(fā)中,已經(jīng)提供了很好的支持業(yè)務(wù)的方法碑定,沒有必要再包括上一層 Service 業(yè)務(wù)類流码。

參考鏈接:這里

⑦ 功能開發(fā)

需要按照模塊之間的依賴關(guān)系,順序開發(fā)延刘。

  • 首先為項(xiàng)目添加必要的 jar 包
    jstl.jar
    mysql-connector-java-5.0.8-bin.jar
    servlet-api.jar
    standard.jar
    這也是 Web 開發(fā)中最基本的 4 個(gè)包

——【1.編寫 Filter】——

由于項(xiàng)目中設(shè)計(jì)表單 POST 方式的提交旅掂,所以我們先來編寫好相關(guān)編碼的過濾器,好支持中文的存取

  • 在 Packge[filter] 下編寫 EncodingFilter 類:
package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/*")
public class EncodingFilter implements Filter {

    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        // 設(shè)置編碼格式為 UTF-8
        request.setCharacterEncoding("UTF-8");

        chain.doFilter(request, response);
    }

    public void init(FilterConfig config) throws ServletException {
    }

}

——【2. 編寫 Servlet 】——

按照傳統(tǒng)的方式访娶,我們項(xiàng)目的業(yè)務(wù)為增刪改查,所以對(duì)應(yīng)四個(gè)路徑觉阅,也就是需要編寫四個(gè) Servlet 才可以

  • AddServlet:
package servlet;

import bean.Student;
import dao.StudentDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@WebServlet("/addStudent")
public class AddServlet extends HttpServlet {

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        Student student = new Student();

        // 直接從表單中獲取數(shù)據(jù)
        int studentID = Integer.parseInt(req.getParameter("studentID"));
        String name = req.getParameter("name");
        int age = Integer.parseInt(req.getParameter("age"));
        String sex = req.getParameter("radio");
        Date birthday = null;

        // String 類型按照 yyyy-MM-dd 的格式轉(zhuǎn)換為 java.util.Date 類
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            birthday = simpleDateFormat.parse(req.getParameter("birthday"));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        student.setStudentID(studentID);
        student.setName(name);
        student.setAge(age);
        student.setSex(sex);
        student.setBirthday(birthday);

        new StudentDAO().add(student);

        resp.sendRedirect("/listStudent");  // 這里可以理解為刷新崖疤,重新請(qǐng)求
    }
}
  • DeleteServlet:
package servlet;

import dao.StudentDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/deleteStudent")
public class DeleteServlet extends HttpServlet {

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        int id = Integer.parseInt(req.getParameter("id"));
        new StudentDAO().delete(id);

        resp.sendRedirect("/listStudent");
    }
}
  • EditServlet:
package servlet;

import bean.Student;
import dao.StudentDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/editStudent")
public class EditServlet extends HttpServlet {

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        int id = Integer.parseInt(req.getParameter("id"));
        Student student = new StudentDAO().get(id);

        req.setAttribute("student", student);

        req.getRequestDispatcher("/editStudent.jsp").forward(req, resp);
    }
}
  • ListServlet:
package servlet;

import bean.Student;
import dao.StudentDAO;
import util.Page;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet("/listStudent")
public class ListServlet extends HttpServlet {

    private StudentDAO studentDAO = new StudentDAO();

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 獲取分頁參數(shù)
        int start = 0;
        int count = 10;

        try {
            start = Integer.parseInt(req.getParameter("page.start"));
            count = Integer.parseInt(req.getParameter("page.count"));
        } catch (Exception e) {
        }

        Page page = new Page(start, count);

        List<Student> students = studentDAO.list(page.getStart(), page.getCount());
        int total = studentDAO.getTotal();
        page.setTotal(total);

        req.setAttribute("students", students);
        req.setAttribute("page", page);

        req.getRequestDispatcher("/listStudent.jsp").forward(req, resp);
    }
}
  • UpdateServlet:
package servlet;

import bean.Student;
import dao.StudentDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@WebServlet("/updateStudent")
public class UpdateServlet extends HttpServlet {

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        Student student = new Student();

        int id = Integer.parseInt(req.getParameter("id"));
        int studentID = Integer.parseInt(req.getParameter("studentID"));
        String name = req.getParameter("name");
        int age = Integer.parseInt(req.getParameter("age"));
        String sex = req.getParameter("radio");

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date birthday = null;
        try {
            birthday = simpleDateFormat.parse(req.getParameter("birthday"));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        student.setId(id);
        student.setStudentID(studentID);
        student.setName(name);
        student.setAge(age);
        student.setSex(sex);
        student.setBirthday(birthday);

        new StudentDAO().update(student);

        resp.sendRedirect("/listStudent");
    }
}

——【3. JSP 的編寫】——

我們把默認(rèn)的 index.jsp 修改成如下代碼:

<%
    request.getRequestDispatcher("/listStudent").forward(request, response);
%>
  • 引入 JQ 和 Bootstrap
    為了簡(jiǎn)化操作秘车,引入了 JQuery 和 Bootstrap
  • 編寫 listStudent.jsp
    其實(shí)主要還是利用 Bootstrap 編寫好整個(gè)頁面,我寫的時(shí)候也是對(duì)照這里寫的
<!DOCTYPE html>
<%@ page contentType="text/html;charset=UTF-8" language="java"
         pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
<head>

    <%-- 引入JQ和Bootstrap --%>
    <script src="js/jquery/2.0.0/jquery.min.js"></script>
    <link href="css/bootstrap/3.3.6/bootstrap.min.css" rel="stylesheet">
    <script src="js/bootstrap/3.3.6/bootstrap.min.js"></script>
    <link href="css/style.css" rel="stylesheet">

    <title>學(xué)生管理頁面 - 首頁</title>

    <script>
        $(function () {
            $("ul.pagination li.disabled a").click(function () {
                return false;
            });
        });
    </script>
</head>

<body>

<div class="listDIV">
    <table class="table table-striped table-bordered table-hover table-condensed">

        <caption>學(xué)生列表 - 共${page.total}人</caption>
        <thead>
        <tr class="success">
            <th>學(xué)號(hào)</th>
            <th>姓名</th>
            <th>年齡</th>
            <th>性別</th>
            <th>出生日期</th>

            <th>編輯</th>
            <th>刪除</th>
        </tr>
        </thead>

        <tbody>
        <c:forEach items="${students}" var="s" varStatus="status">
            <tr>
                <td>${s.studentID}</td>
                <td>${s.name}</td>
                <td>${s.age}</td>
                <td>${s.sex}</td>
                <td>${s.birthday}</td>

                <td><a href="/editStudent?id=${s.id}"><span class="glyphicon glyphicon-edit"></span> </a></td>
                <td><a href="/deleteStudent?id=${s.id}"><span class="glyphicon glyphicon-trash"></span> </a></td>
            </tr>
        </c:forEach>

        </tbody>
    </table>
</div>

<nav class="pageDIV">
    <ul class="pagination">
        <li <c:if test="${!page.hasPreviouse}">class="disabled"</c:if>>
            <a href="?page.start=0">
                <span>?</span>
            </a>
        </li>

        <li <c:if test="${!page.hasPreviouse}">class="disabled"</c:if>>
            <a href="?page.start=${page.start-page.count}">
                <span>?</span>
            </a>
        </li>

        <c:forEach begin="0" end="${page.totalPage-1}" varStatus="status">

            <c:if test="${status.count*page.count-page.start<=30 && status.count*page.count-page.start>=-10}">
                <li <c:if test="${status.index*page.count==page.start}">class="disabled"</c:if>>
                    <a
                            href="?page.start=${status.index*page.count}"
                            <c:if test="${status.index*page.count==page.start}">class="current"</c:if>
                    >${status.count}</a>
                </li>
            </c:if>
        </c:forEach>

        <li <c:if test="${!page.hasNext}">class="disabled"</c:if>>
            <a href="?page.start=${page.start+page.count}">
                <span>?</span>
            </a>
        </li>
        <li <c:if test="${!page.hasNext}">class="disabled"</c:if>>
            <a href="?page.start=${page.last}">
                <span>?</span>
            </a>
        </li>
    </ul>
</nav>

<div class="addDIV">

    <div class="panel panel-success">
        <div class="panel-heading">
            <h3 class="panel-title">增加學(xué)生</h3>
        </div>
        <div class="panel-body">

            <form method="post" action="/addStudent" role="form">
                <table class="addTable">
                    <tr>
                        <td>學(xué)號(hào):</td>
                        <td><input type="text" name="studentID" id="studentID" placeholder="請(qǐng)?jiān)谶@里輸入學(xué)號(hào)"></td>
                    </tr>
                    <tr>
                        <td>姓名:</td>
                        <td><input type="text" name="name" id="name" placeholder="請(qǐng)?jiān)谶@里輸入名字"></td>
                    </tr>
                    <tr>
                        <td>年齡:</td>
                        <td><input type="text" name="age" id="age" placeholder="請(qǐng)?jiān)谶@里輸入年齡"></td>
                    </tr>
                    <tr>
                        <td>性別:</td>
                        <td><input type="radio" class="radio radio-inline" name="radio" value="男"> 男
                            <input type="radio" class="radio radio-inline" name="radio" value="女"> 女
                        </td>
                    </tr>
                    <tr>
                        <td>出生日期:</td>
                        <td><input type="date" name="birthday" id="birthday" placeholder="請(qǐng)?jiān)谶@里輸入出生日期"></td>
                    </tr>
                    <tr class="submitTR">
                        <td colspan="2" align="center">
                            <button type="submit" class="btn btn-success">提 交</button>
                        </td>

                    </tr>

                </table>
            </form>
        </div>
    </div>

</div>

</body>
</html>
  • eidtStudent.jsp
    編輯表單對(duì)照著首頁的增加表單稍微改一改參數(shù)就好了
<!DOCTYPE html>
<%@ page contentType="text/html;charset=UTF-8" language="java"
         pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
<head>

    <%-- 引入JQ和Bootstrap --%>
    <script src="js/jquery/2.0.0/jquery.min.js"></script>
    <link href="css/bootstrap/3.3.6/bootstrap.min.css" rel="stylesheet">
    <script src="js/bootstrap/3.3.6/bootstrap.min.js"></script>
    <link href="css/style.css" rel="stylesheet">

    <title>學(xué)生管理頁面 - 編輯頁面</title>
</head>

<body>

<div class="editDIV">

    <div class="panel panel-success">
        <div class="panel-heading">
            <h3 class="panel-title">編輯學(xué)生</h3>
        </div>
        <div class="panel-body">

            <form method="post" action="/updateStudent" role="form">
                <table class="editTable">
                    <tr>
                        <td>學(xué)號(hào):</td>
                        <td><input type="text" name="studentID" id="studentID" value="${student.studentID}"
                                   placeholder="請(qǐng)?jiān)谶@里輸入學(xué)號(hào)"></td>
                    </tr>
                    <tr>
                        <td>姓名:</td>
                        <td><input type="text" name="name" id="name" value="${student.name}" placeholder="請(qǐng)?jiān)谶@里輸入名字">
                        </td>
                    </tr>
                    <tr>
                        <td>年齡:</td>
                        <td><input type="text" name="age" id="age" value="${student.age}" placeholder="請(qǐng)?jiān)谶@里輸入年齡"></td>
                    </tr>
                    <tr>
                        <td>性別:</td>
                        <td><input type="radio" class="radio radio-inline" name="radio" value="男"> 男
                            <input type="radio" class="radio radio-inline" name="radio" value="女"> 女
                        </td>
                    </tr>
                    <tr>
                        <td>出生日期:</td>
                        <td><input type="date" name="birthday" id="birthday" value="${student.birthday}"
                                   placeholder="請(qǐng)?jiān)谶@里輸入出生日期"></td>
                    </tr>
                    <tr class="submitTR">
                        <td colspan="2" align="center">
                            <input type="hidden" name="id" value="${student.id}">
                            <button type="submit" class="btn btn-success">提 交</button>
                        </td>

                    </tr>

                </table>
            </form>
        </div>
    </div>

</div>

</body>
</html>
  • style.css 文件:
body {
    padding-top: 60px;
}

div.listDIV {
    width: 600px;
    margin: 0 auto;
}

div.editDIV {
    width: 400px;
    margin: 0 auto;
}

nav.pageDIV {
    text-align: center;
}

div.addDIV {
    width: 300px;
    margin: 0 auto;
}

table.addTable {
    width: 100%;
    padding: 5px;
}

table.addTable td {
    padding: 5px;
}

table.editTable {
    width: 100%;
    padding: 5px;
}

table.editTable td {
    padding: 5px;
}

——【4. 項(xiàng)目細(xì)節(jié)】——

  • 項(xiàng)目的整理結(jié)構(gòu):


分頁功能

  • 首頁在 Packge[util] 下創(chuàng)建一個(gè) Page 工具類:
package util;

public class Page {

    int start;      // 開始數(shù)據(jù)
    int count;      // 每一頁的數(shù)量
    int total;      // 總共的數(shù)據(jù)量

    public Page(int start, int count) {
        super();
        this.start = start;
        this.count = count;
    }

    public boolean isHasPreviouse(){
        if(start==0)
            return false;
        return true;

    }
    public boolean isHasNext(){
        if(start==getLast())
            return false;
        return true;
    }

    public int getTotalPage(){
        int totalPage;
        // 假設(shè)總數(shù)是50劫哼,是能夠被5整除的叮趴,那么就有10頁
        if (0 == total % count)
            totalPage = total /count;
            // 假設(shè)總數(shù)是51,不能夠被5整除的权烧,那么就有11頁
        else
            totalPage = total / count + 1;

        if(0==totalPage)
            totalPage = 1;
        return totalPage;

    }

    public int getLast(){
        int last;
        // 假設(shè)總數(shù)是50眯亦,是能夠被5整除的,那么最后一頁的開始就是40
        if (0 == total % count)
            last = total - count;
            // 假設(shè)總數(shù)是51般码,不能夠被5整除的妻率,那么最后一頁的開始就是50
        else
            last = total - total % count;

        last = last<0?0:last;
        return last;
    }

    // 各種 setter 和 getter
}
  • totalPage 是計(jì)算得來的數(shù),用來表示頁碼一共的數(shù)量

在首頁顯示的 StudentList 用 page 的參數(shù)來獲劝遄!:

List<Student> students = studentDAO.list(page.getStart(), page.getCount());

并且在 DAO 類中用 LIMIT 關(guān)鍵字:

String sql = "SELECT * FROM student ORDER BY student_id desc limit ?,?";
  • 第一個(gè)參數(shù)為 start宫静,第二個(gè)參數(shù)為 count
    這樣就能根據(jù)分頁的信息來獲取到響應(yīng)的數(shù)據(jù)

  • 編寫分頁欄:

1.寫好頭和尾

<nav class="pageDIV">
    <ul class="pagination">
    .....
    </ul>
</nav>

2.寫好? ?這兩個(gè)功能按鈕
使用 <c:if>標(biāo)簽來增加邊界判斷,如果沒有前面的頁碼了則設(shè)置為disable狀態(tài)

        <li <c:if test="${!page.hasPreviouse}">class="disabled"</c:if>>
            <a href="?page.start=0">
                <span>?</span>
            </a>
        </li>

        <li <c:if test="${!page.hasPreviouse}">class="disabled"</c:if>>
            <a href="?page.start=${page.start-page.count}">
                <span>?</span>
            </a>
        </li>

再通過 JavaScrip 代碼來完成禁用功能:

<script>
    $(function () {
        $("ul.pagination li.disabled a").click(function () {
            return false;
        });
    });
</script>

3.完成中間頁碼的編寫
0 循環(huán)到 page.totalPage - 1 券时,varStatus 相當(dāng)于是循環(huán)變量

  • status.count 是從1開始遍歷
  • status.index 是從0開始遍歷
  • 要求:顯示當(dāng)前頁碼的前兩個(gè)和后兩個(gè)就可孤里,例如當(dāng)前頁碼為3的時(shí)候,就顯示 1 2 3(當(dāng)前頁) 4 5 的頁碼
  • 理解測(cè)試條件:
    -10 <= 當(dāng)前頁*每一頁顯示的數(shù)目 - 當(dāng)前頁開始的數(shù)據(jù)編號(hào) <= 30
  • 只要理解了這個(gè)判斷條件橘洞,其他的就都好理解了
<c:forEach begin="0" end="${page.totalPage-1}" varStatus="status">

    <c:if test="${status.count*page.count-page.start<=30 && status.count*page.count-page.start>=-10}">
        <li <c:if test="${status.index*page.count==page.start}">class="disabled"</c:if>>
            <a
                    href="?page.start=${status.index*page.count}"
                    <c:if test="${status.index*page.count==page.start}">class="current"</c:if>
            >${status.count}</a>
        </li>
    </c:if>
</c:forEach>

4.在 Servlet 中獲取參數(shù)

// 獲取分頁參數(shù)
int start = 0;
int count = 10;

try {
    start = Integer.parseInt(req.getParameter("page.start"));
    count = Integer.parseInt(req.getParameter("page.count"));
} catch (Exception e) {
}

....

// 共享 page 數(shù)據(jù)
req.setAttribute("page", page);

Date 轉(zhuǎn)換的問題

    /**
     * Date類型轉(zhuǎn)為指定格式的String類型
     * 
     * @param source
     * @param pattern
     * @return
     */
    public static String DateToString(Date source, String pattern) {
        simpleDateFormat = new SimpleDateFormat(pattern);
        return simpleDateFormat.format(source);
    }
    /**
     * 
     * 字符串轉(zhuǎn)換為對(duì)應(yīng)日期
     * 
     * @param source
     * @param pattern
     * @return
     */
    public static Date stringToDate(String source, String pattern) {
        simpleDateFormat = new SimpleDateFormat(pattern);
        Date date = null;
        try {
            date = simpleDateFormat.parse(source);
        } catch (Exception e) {
        }
        return date;
    }

項(xiàng)目總結(jié)

這一個(gè)項(xiàng)目實(shí)在有些太簡(jiǎn)單了捌袜,可能最需要理解的一個(gè)功能就屬于【分頁功能】了吧

不過還是借助這個(gè)項(xiàng)目,進(jìn)一步鞏固了 J2EE 開發(fā)的相關(guān)知識(shí)炸枣,也對(duì)開發(fā)的流程愈發(fā)熟悉虏等,整個(gè)項(xiàng)目編寫時(shí)間不超過 8 個(gè)小時(shí),對(duì)于我自己來說抛虏,不算快博其,但還算比較順暢的

需要改進(jìn)的地方:

  1. 登錄驗(yàn)證
    本項(xiàng)目沒有增加登錄驗(yàn)證,可以增加一個(gè)登錄頁面并結(jié)合 session 來完成驗(yàn)證

  2. 代碼重構(gòu)
    本項(xiàng)目?jī)H僅完成的是一個(gè)學(xué)生表的增刪改查迂猴,卻有以下的五個(gè) Servlet :

如果項(xiàng)目大起來慕淡,那可想而知,Servlet 有多臃腫沸毁,維護(hù)成本有多高

  • 改進(jìn)方法:用一個(gè) StudentServlet 代替
  • 具體做法:使用 Filter + Servlet 完成

① 首先編寫一個(gè)過濾所有地址的 Filter峰髓,并解析地址欄的地址提取出其中的方法傳遞給 StudentServlet (這個(gè)時(shí)候需要統(tǒng)一的地址息尺,如:student_list携兵、student_editstudent_delete搂誉、student_update

request.setAttribute("method", method);

② 在 Servlet 中獲取 method 方法徐紧,并調(diào)用

// 獲取到對(duì)應(yīng)的方法
String method = (String) request.getAttribute("method");
// 對(duì) method 作判斷,調(diào)用對(duì)應(yīng)的方法
  1. 沒有對(duì)輸入的數(shù)據(jù)的正確性進(jìn)行驗(yàn)證
    這顯然會(huì)導(dǎo)致許多問題,可以通過 js 代碼來完成驗(yàn)證

歡迎轉(zhuǎn)載并级,轉(zhuǎn)載請(qǐng)注明出處拂檩!
簡(jiǎn)書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關(guān)注公眾微信號(hào):wmyskxz
分享自己的學(xué)習(xí) & 學(xué)習(xí)資料 & 生活
想要交流的朋友也可以加qq群:3382693

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嘲碧,隨后出現(xiàn)的幾起案子稻励,更是在濱河造成了極大的恐慌,老刑警劉巖愈涩,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件望抽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡履婉,警方通過查閱死者的電腦和手機(jī)煤篙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谐鼎,“玉大人舰蟆,你說我怎么就攤上這事±旯鳎” “怎么了身害?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)草戈。 經(jīng)常有香客問我塌鸯,道長(zhǎng),這世上最難降的妖魔是什么唐片? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任丙猬,我火速辦了婚禮,結(jié)果婚禮上费韭,老公的妹妹穿的比我還像新娘茧球。我一直安慰自己,他們只是感情好星持,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布抢埋。 她就那樣靜靜地躺著,像睡著了一般督暂。 火紅的嫁衣襯著肌膚如雪揪垄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天逻翁,我揣著相機(jī)與錄音饥努,去河邊找鬼。 笑死八回,一個(gè)胖子當(dāng)著我的面吹牛酷愧,可吹牛的內(nèi)容都是我干的驾诈。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼伟墙,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼翘鸭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起戳葵,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎汉匙,沒想到半個(gè)月后拱烁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡噩翠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年戏自,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伤锚。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡擅笔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屯援,到底是詐尸還是另有隱情猛们,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布狞洋,位于F島的核電站弯淘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吉懊。R本人自食惡果不足惜庐橙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望借嗽。 院中可真熱鬧态鳖,春花似錦、人聲如沸恶导。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽甲锡。三九已至兆蕉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缤沦,已是汗流浹背虎韵。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缸废,地道東北人包蓝。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓驶社,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親测萎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子亡电,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,814評(píng)論 0 11
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法硅瞧,內(nèi)部類的語法份乒,繼承相關(guān)的語法,異常的語法腕唧,線程的語...
    子非魚_t_閱讀 31,664評(píng)論 18 399
  • 轉(zhuǎn)自陳明乾的博客或辖,可能有一定更新。 轉(zhuǎn)原文聲明:原創(chuàng)作品枣接,允許轉(zhuǎn)載颂暇,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必以超鏈接形式標(biāo)明文章 原始出處 、...
    C86guli閱讀 4,700評(píng)論 6 72
  • 最近中高考都結(jié)束了但惶,暑假又沒有開始耳鸯,應(yīng)該稍微輕松點(diǎn)了,本以為安排的備課膀曾,看書县爬,充電,鍛煉妓肢,都應(yīng)該可以穩(wěn)步推進(jìn)了捌省,然...
    況老師閱讀 512評(píng)論 0 1
  • 今天晚上代表團(tuán)隊(duì)參加了pk,有點(diǎn)緊張碉钠。莉塔老師很善于鼓勵(lì)隊(duì)員纲缓,我也要多展示自己,才能成長(zhǎng)得更快喊废。 加粉有很多方式祝高,...
    Doris186閱讀 187評(píng)論 0 0