本篇開始使用 jstl 這個 jsp 的標簽庫,在同一個 Servlet 中實現處理 CRUD 請求,以及使用 jdbc 數據庫基本操作。然后你會發現 Servlet 和 jdbc 還是有很多不方便之處,然后在篇章五將開始正式使用框架。
使用 jstl 是為了前后端分離,試想如果 jsp 中嵌入一堆的 java 代碼片段,那樣的話前端就很難開發除非它懂 java 技術,或者得由后端開發這個。
這次我們就做一個書籍列表的功能,記錄購買過的書籍的名稱、價格和頁數信息,可以添加、刪除、修改單本書籍信息(同時刪除多本書籍這個需要 js 的幫助,這里暫時不用,留在之后回顧)。
1. 簡單的邏輯梳理
要實現增刪改查需要設計一下流程,這里只給出一個簡單的設計:
首頁 有展示書籍列表的入口,
書籍列表頁提供一個表格展示數據庫中存入的書籍,每個書籍(每行記錄后)都附帶編輯和刪除操作,
編輯需要跳轉到編輯頁面實現,過程中需要查詢一次數據庫得到數據,而不是從列表頁直接獲取傳遞,編輯書籍頁面提交給真正的編輯方法來執行入庫
刪除操作不需要專門頁面來處理,直接數據庫操作,返回結果展示到一個消息頁面,該頁面通用,
表格下方有添加數據的鏈接,添加需要跳轉到添加頁面實現,添加書籍頁面數據提交給真正的添加動作方法來執行入庫,
如刪除操作所述,基本頁面的操作結果由通用消息頁面展示,該頁面根據傳遞過來的字符串和URL決定跳轉到地址。
2. jstl el 表達式
使用 el 表達式必須關掉 忽略 el 表達式的設定,如下
<%@ page isELIgnored ="false" %>,如果不關閉,則頁面上會出現很多${"sth"},不會被解析成 jstl 標簽。
常用的 jstl 庫及其用法示例
- 核心庫 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
-
格式化文本庫 <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
-
函數庫 <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
核心庫,提供了類似語言的基礎服務,比如流程控制,輸出語句,賦值語句等。
格式化文本,顧名思義,可以格式化時間、浮點數等。
函數庫,提供了很多函數,比如字符串的操作如子串,長度等功能,還有map、list這種集合類判空等方法,自行研究。
這里貼幾段示例
第一個:用到的有核心庫里的流程控制語句,還有循環語句,函數庫的長度方法以及處理 map 的方法。
<c:choose>
<c:when test="${empty fileMap or fn:length(fileMap) == 0}">
<p>您還沒有上傳文件,請點擊這里上傳:<a href=/file/add>上傳文件</a></p>
</c:when>
<c:otherwise>
<c:forEach items="${fileMap}" var="entry">
<p>文件名: ${entry.key} <a href="/file/download?fileName=${entry.value}" >下載</a></p>
</c:forEach>
</c:otherwise>
</c:choose>
第二個:用到的有格式化浮點數的語句
<c:forEach items="${bookList}" var="book">
<tr>
<th>ids</th>
<th><input type="checkbox" value="${book.id}" /></th>
<td>${book.name}</td>
<td><fmt:formatNumber value="${book.price}" pattern="0.00"/></td>
<td>${book.pageCount}</td>
<td><a href="/book?method=update&id=${book.id}">編輯</a> <a href="/book?method=delete&id=${book.id}">刪除</a></td>
</tr>
</c:forEach>
差點忘記說了,上邊有取數的操作,比如最開始的${bookList}、${fileMap},它是怎樣從 Servlet 傳遞到 jsp 中的呢?
答案是 servlet 中用 request.setAttribute("bookList", bookList);這種方式。
3. 數據庫操作 jdbc
創建數據庫連接的基本動作步驟
- 加載 jdbc 驅動類 DriverManager
- 創建連接(連接URL的格式)
- 創建 statement, 防止 Sql 注入的 PreparedStatement
- 執行語句 查詢 executeQuery(); 更改、刪除 executeUpdate()
- 處理返回結果 ResultSet
- 關閉連接
public class JDBCTest { public static void main(String[] args) { String driver = "com.mysql.jdbc.Driver"; String dbName = "spring"; String passwrod = "root"; String userName = "root"; String url = "jdbc:mysql://localhost:3308/" + dbName; String sql = "select * from users"; try { Class.forName(driver); Connection conn = DriverManager.getConnection(url, userName, passwrod); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); while (rs.next()) { System.out.println("id : " + rs.getInt(1) + " name : " + rs.getString(2) + " password : " + rs.getString(3)); } // 關閉記錄集 if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } // 關閉聲明 if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } // 關閉鏈接對象 if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } } }
4. 具體實現
因為一個 Servlet 只有一個 service 方法,所以它能處理的請求URL也只有一類,為了實現 CRUD 操作,采用 /book?method=list這種方式以method參數區分。這里的實現不是為了展示技術的,所以沒有用RESTFul 的方式,也不要嫌 low,正是因為 servlet 的不好用之處,才逼着我們去用更好用的框架比如 Spring MVC,對吧。
BookServlet.java
@WebServlet(name = "bookServlet", urlPatterns = {"/book"})
public class BookServlet extends HttpServlet {
@Override
public void init() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{
request.setCharacterEncoding("UTF-8");
String method = request.getParameter("method");
Connection conn;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/webpractice", "root", "Circle233???");
switch (method) {
case "list":
list(request, response, conn);
break;
case "add":
add(request, response);
break;
case "create":
create(request, response, conn);
break;
case "delete":
delete(request, response, conn);
break;
case "update":
update(request, response, conn);
break;
case "updateOp":
updateOp(request, response, conn);
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void add(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.getRequestDispatcher("/WEB-INF/page/book_add.jsp").forward(request, response);
}
private void create(HttpServletRequest request, HttpServletResponse response, Connection conn) throws IOException, ServletException {
String message;
PreparedStatement ps = null;
String insertSql = "insert into books(name, price, page_count) values(?,?,?)";
try {
String name = request.getParameter("name");
String pricePara = request.getParameter("price");
double price = Double.valueOf(pricePara);
String pageCountPara = request.getParameter("pageCount");
int pageCount = Integer.parseInt(pageCountPara);
ps = conn.prepareStatement(insertSql);
ps.setString(1, name);
ps.setDouble(2, price);
ps.setInt(3, pageCount);
ps.executeUpdate();
message = "添加書籍成功!";
request.setAttribute("message",message);
request.setAttribute("suggestURL", "/book?method=list");
request.setAttribute("declaration", "查看書籍列表");
request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
message = "添加書籍出錯!";
request.setAttribute("message",message);
request.setAttribute("suggestURL", "/book?method=add");
request.setAttribute("declaration", "重新添加書籍");
request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response);
} finally {
returnResource(null, ps, conn);
}
}
private void delete(HttpServletRequest request, HttpServletResponse response, Connection conn) throws IOException, ServletException {
String message;
PreparedStatement ps = null;
String deleteSql = "delete from books where id = (?)";
try {
String id = request.getParameter("id");
ps = conn.prepareStatement(deleteSql);
ps.setString(1, id);
ps.executeUpdate();
message = "刪除書籍成功!";
request.setAttribute("message",message);
request.setAttribute("suggestURL", "/book?method=list");
request.setAttribute("declaration", "查看書籍列表");
request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
message = "刪除書籍出錯!";
request.setAttribute("message",message);
request.setAttribute("suggestURL", "/book?method=list");
request.setAttribute("declaration", "回到書籍列表");
request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response);
} finally {
returnResource(null, ps, conn);
}
}
private void update(HttpServletRequest request, HttpServletResponse response, Connection conn) throws IOException, ServletException {
PreparedStatement ps = null;
ResultSet rs = null;
String message;
try {
String queryOneSql = "select * from books where id = ?";
ps = conn.prepareStatement(queryOneSql);
ps.setString(1, request.getParameter("id"));
rs = ps.executeQuery();
if (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
double price = rs.getDouble("price");
int pageCount = rs.getInt("page_count");
Book book = new Book(name, price, pageCount);
book.setId(id);
request.setAttribute("book", book);
request.getRequestDispatcher("/WEB-INF/page/book_update.jsp").forward(request, response);
} else {
message = "沒有查到對應書籍,請刷新列表頁面!";
request.setAttribute("message",message);
request.setAttribute("suggestURL", "/book?method=list");
request.setAttribute("declaration", "回到書籍列表");
request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
message = "編輯書籍出錯!";
request.setAttribute("message",message);
request.setAttribute("suggestURL", "/book?method=list");
request.setAttribute("declaration", "回到書籍列表");
request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response);
} finally {
returnResource(rs, ps, conn);
}
}
private void updateOp(HttpServletRequest request, HttpServletResponse response, Connection conn) throws IOException, ServletException {
PreparedStatement ps = null;
ResultSet rs = null;
String message;
try {
String updateSql = "update books set name = ?, price = ?, page_count = ? where id = ?";
ps = conn.prepareStatement(updateSql);
ps.setString(1, request.getParameter("name"));
ps.setDouble(2, Double.valueOf(request.getParameter("price")));
ps.setInt(3, Integer.parseInt(request.getParameter("pageCount")));
ps.setInt(4, Integer.parseInt(request.getParameter("id")));
int result = ps.executeUpdate();
System.out.println("result: " + result);
if (result == 1) {
message = "修改書籍成功!";
request.setAttribute("message", message);
request.setAttribute("suggestURL", "/book?method=list");
request.setAttribute("declaration", "查看書籍列表");
request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response);
} else {
message = "修改書籍失敗!";
request.setAttribute("message", message);
request.setAttribute("suggestURL", "/book?method=list");
request.setAttribute("declaration", "回到書籍列表");
request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
message = "修改書籍失敗!";
request.setAttribute("message", message);
request.setAttribute("suggestURL", "/book?method=list");
request.setAttribute("declaration", "回到書籍列表");
request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response);
} finally {
returnResource(rs, ps, conn);
}
}
private void list(HttpServletRequest request, HttpServletResponse response, Connection conn) throws IOException, ServletException{
PreparedStatement ps = null;
ResultSet rs = null;
try {
List<Book> list = new ArrayList<>();
ps = conn.prepareStatement("select * from books");
rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
double price = rs.getDouble("price");
int pageCount = rs.getInt("page_count");
Book book = new Book(name, price, pageCount);
book.setId(id);
list.add(book);
}
request.setAttribute("bookList", list);
request.getRequestDispatcher("/WEB-INF/page/book_list.jsp").forward(request, response);
} catch (SQLException e) {
e.printStackTrace();
} finally {
returnResource(rs, ps, conn);
}
}
private void returnResource(ResultSet rs, PreparedStatement ps, Connection conn) {
try {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
book_add.jsp
<%-- Created by IntelliJ IDEA. User: yixin Date: 2018/7/12 Time: 14:49 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %> <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>添加新書籍</title> </head> <body> <form action="/book?method=create" method="post" > 書名:<input name="name" type="text"><br /> 價格:<input name="price" type="text"><br /> 頁數:<input name="pageCount" type="number"> <br /> <input type="submit" value="提交"> <input type="reset" value="重置"> </form> <a href="/index.html">回到首頁</a> </body> </html>
book_list.jsp
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ page isELIgnored ="false" %> <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>書籍展示頁</title> </head> <body> <div> <h2><span>購買過的書籍列表</span></h2> <c:choose> <c:when test="${empty bookList}"> <tr>沒有內容</tr> </c:when> <c:otherwise> <table border="1"> <tr> <th><input type="checkbox" id="chbAll"></th> <th>編號</th> <th>書名</th> <th>價格</th> <th>頁數</th> <th>操作</th> </tr> <tbody> <c:forEach items="${bookList}" var="book"> <tr> <th>ids</th> <th><input type="checkbox" value="${book.id}" /></th> <td>${book.name}</td> <td><fmt:formatNumber value="${book.price}" pattern="0.00"/></td> <td>${book.pageCount}</td> <td><a href="/book?method=update&id=${book.id}">編輯</a> <a href="/book?method=delete&id=${book.id}">刪除</a></td> </tr> </c:forEach> </tbody> </table> </c:otherwise> </c:choose> <div> <p> <a href="/book?method=add">添加書籍</a> <a href="/index.html">返回首頁</a> </p> </div> </div> </body> </html>
book_update.jsp
<%-- Created by IntelliJ IDEA. User: yinjd Date: 2018/7/15 Time: 17:33 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page isELIgnored ="false" %> <!DOCTYPE HTML> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>修改書籍</title> </head> <body> <form action="/book?method=updateOp" method="post" > 書名:<input name="name" type="text" value="${book.name}"><br /> 價格:<input name="price" type="text" value="${book.price}"><br /> 頁數:<input name="pageCount" type="number" value="${book.pageCount}"> <br /> <input type="hidden" name="id" value="${book.id}"><br /> <input type="submit" value="提交"> </form> </body> </html>
message.jsp
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%> <%@ page isELIgnored ="false" %> <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>消息頁</title> </head> <body> <p>${message}</p> <p>點擊這里><a href="${suggestURL}">${declaration}</a></p> </body> </html>
index.html
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>歡迎頁</title> </head> <body> <a href="/file/list">上傳文件列表</a><br /> <a href="/book?method=list">購買書籍列表</a> </body> </html>
5. 效果展示頁



