今天學習的主要內容是在IntelliJ IDEA開發環境中,通過部署Tomcat服務器并連接MySQL數據庫,實現了一個完整的留言板系統。這個項目涵蓋了前后端開發的全流程,具體包括以下關鍵環節:
- 開發環境搭建
- 使用IntelliJ IDEA Ultimate版(2023.3)作為開發工具
- 配置Tomcat 9.0服務器
- 建立MySQL 8.0數據庫連接
- 前端開發
- 采用JSP+HTML+CSS技術棧
- 設計留言板界面包含:
- 留言展示區域(展示已有留言列表)
- 留言表單(包含用戶名、留言內容輸入框)
- 提交按鈕
- 后端開發
- 使用Java Servlet處理HTTP請求
- 實現的主要功能點:
- GET請求處理:從數據庫查詢留言列表并返回給前端
- POST請求處理:接收前端提交的留言數據并存入數據庫
- 采用JDBC連接池技術實現數據庫操作
- 數據庫設計
- 創建message表,包含字段:
- id(主鍵,自增)
- username(varchar,留言者姓名)
- content(text,留言內容)
- create_time(timestamp,留言時間)
- 功能實現細節
- 查看功能:
- 通過SELECT語句查詢所有留言
- 按時間倒序排列顯示
- 將查詢結果封裝為List<Message>對象返回前端
- 保存功能:
- 接收前端表單提交的username和content參數
- 執行INSERT語句將數據存入數據庫
- 添加事務處理確保數據一致性
- 測試驗證
- 通過瀏覽器訪問留言板頁面
- 測試留言提交和展示功能
- 驗證數據庫記錄的增刪改查操作
這個項目雖然基礎,但完整實現了從用戶界面到數據存儲的整個流程,對于理解Web應用開發的基本原理和流程有很好的實踐意義。
代碼如下:
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbutils.QueryRunner;import javax.sql.DataSource;public class DButil {public static HikariDataSource getDataSource() {HikariDataSource dataSource = new HikariDataSource();dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/javawebday1");dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUsername("root");dataSource.setPassword("admin123");return dataSource;}
}import java.time.LocalDateTime;public class message {private Integer id;private String nickname;private String content;private String ip;private LocalDateTime mtime;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public String getIp() {return ip;}public void setIp(String ip) {this.ip = ip;}public LocalDateTime getMtime() {return mtime;}public void setMtime(LocalDateTime mtime) {this.mtime = mtime;}
}import com.coder.message;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;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.io.PrintWriter;
import java.sql.SQLException;
import java.util.List;@WebServlet("/view")
public class ViewMessageBoardServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=UTF-8");PrintWriter out = resp.getWriter();//查詢數據庫HikariDataSource dataSource = new HikariDataSource();dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/szb");dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUsername("root");dataSource.setPassword("admin123");QueryRunner runner = new QueryRunner(dataSource);String sql = "select id,nickname,content,ip,mtime from message order by mtime desc";try {List<message> list = runner.query(sql,new BeanListHandler<message>(message.class));StringBuffer sbf = new StringBuffer();sbf.append("<table width = '800' border = '1'> align = ‘center'").append("<tr><td>序號</td>").append("<td>昵稱</td>").append("<td>留言</td>").append("<td>IP</td>").append("<td>時間</td></td>");int index = 1;for (message message : list) {sbf.append("<tr>").append("<td>").append(index++).append("</td>").append("<td>").append(message.getNickname()).append("</td>").append("<td>").append(message.getContent()).append("</td>").append("<td>").append(message.getIp()).append("</td>").append("<td>").append(message.getMtime()).append("</td>").append("</tr>");}sbf.append("</table>");out.println("<a href = 'buy.html'>繼續留言</a>");out.println(sbf);} catch (SQLException e) {throw new RuntimeException(e);}}
}import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbutils.QueryRunner;
import util.DButil;import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.time.LocalDateTime;/*** @author MSI-NB* @date 2025/8/6 22:41*/
@WebServlet(name = "messageBoardServlet", urlPatterns = "/x")
public class messageBoardServlet extends HttpServlet {private static final long serialVersionUID = 1L;/*** @see HttpServlet#HttpServlet()*/public messageBoardServlet() {super();}/*** @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)*/protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=UTF-8");}/*** @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)*/protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 設置請求編碼request.setCharacterEncoding("UTF-8");response.setContentType("text/html");response.setCharacterEncoding("UTF-8");String nickname = request.getParameter("nickname");String content = request.getParameter("content");String ip = request.getRemoteAddr();PrintWriter out = response.getWriter();// out.println("您的名稱是:" + nickname + "<br>");
// out.println("您的留言是:" + content + "<br>");QueryRunner runner = new QueryRunner(DButil.getDataSource());String sql = "insert into message(nickname,content,ip,mtime) values(default,?,?,?,?)";try {int update = runner.update(sql,nickname,content,ip, LocalDateTime.now());System.out.println(update>0?"留言成功":"留言失敗");} catch (SQLException e) {e.printStackTrace();}}
}
message.html:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="x" method="post"><div>昵稱:<input type="text" name="nickName"></div><div>留言:<textarea name="content"></textarea></div><div><button type="submit">提交留言</button></div></form>
</body>
</html>
通過實踐,我總結出幾個重要的經驗教訓:
獲取客戶端 IP 時,應該使用
String ip = req.getRemoteAddr()
,而不是getParameter
方法。當數據庫表buy_recorders
的 ip 字段設為 NOT NULL 時,插入 null 值會直接引發 SQL 異常。即使 ip 字段允許為 null,在查詢時使用
where ip = null
也會導致語法錯誤,正確的寫法應該是where ip is null
,否則同樣會觸發 500 錯誤。在開發留言板功能時,我直接復制了之前的代碼,但忘記修改新數據庫的 SQL 語句,這又導致了 500 錯誤。這個疏忽讓我意識到復制代碼時需要格外謹慎。