上訂餐系統(tǒng):源碼解析與部署實戰(zhàn)指南)
簡介這是一份基于 Java、JSP 和 MySQL 的簡單網(wǎng)上訂餐系統(tǒng)源碼面向 Java Web 初學者、課程設(shè)計或小型實戰(zhàn)項目開發(fā)者。它完整演示了 JSP 動態(tài)頁面展示菜品與購物車、Servlet 接收并處理訂餐請求、MySQL 持久化用戶、訂單和商品數(shù)據(jù)的典型流程同時貫穿 MVC 分層設(shè)計思想。資源壓縮包共 1262 個文件、約 47.38MB包含 48 個 JSP 動態(tài)頁面、44 個 Java 源文件、44 個編譯后的 class 文件以及 SQL 數(shù)據(jù)庫初始化腳本、jar 依賴庫、CSS/JS/PNG/GIF/JPG 等靜態(tài)資源并含 .classpath、.project 等工程配置可直接導入 Eclipse 或 IntelliJ IDEA 運行。從文件構(gòu)成看項目同時覆蓋后端邏輯、前端頁面與界面素材數(shù)據(jù)庫腳本還能快速建立用戶、菜品、訂單等核心表并填充初始數(shù)據(jù)。目錄中 src 源碼、WebContent 頁面和 build 輸出分工清晰配合必讀說明能幫助讀者理解訂單、用戶、商品等模塊的完整交互鏈路適合自學、二次開發(fā)或畢業(yè)設(shè)計參考目前已有 384 人學習下載。1. 為什么“簡單網(wǎng)上訂餐系統(tǒng)”反而值得拆開看java jsp mysql 這套組合在技術(shù)討論里經(jīng)常被說成“過時技術(shù)棧”但它在兩個場景里依然高頻出現(xiàn)課程設(shè)計選題和 Java Web 面試準備。矛盾點在于找源碼的人很多能把這套代碼講清楚的人很少。一個“簡單網(wǎng)上訂餐系統(tǒng)”的源碼 zip里面通常只有幾十個文件、四五張表但 Servlet 怎么接請求、JSP 怎么渲染數(shù)據(jù)、JDBC 怎么操作 MySQL一條鏈完整閉環(huán)。對還沒整體跑通過 Web 項目的人來說把它完整跑起來再改兩個功能比看十遍教程有用。需要先說清邊界它適合學習和內(nèi)部小系統(tǒng)不適合高并發(fā)業(yè)務。往下讀之前把這個預期擺正。2. 這套系統(tǒng)在講什么三個技術(shù)棧的分工和一次請求的完整路徑2.1 Servlet、JSP、MySQL 各管一段為什么這個組合至今還有人用先拆開名字。jsp 是 Java Server Pages本質(zhì)是在 HTML 里嵌 Java 代碼由容器編譯成 Servlet 來執(zhí)行Servlet 是處理請求和響應邏輯的 Java 類mysql 負責把用戶、菜品、訂單這些數(shù)據(jù)持久化下來。三層職責很清楚Servlet 處理“要做什么”JSP 處理“長什么樣”MySQL 處理“記在哪”。選型理由也藏在這三個職責里。有人會問為什么不直接用 Servlet 輸出 HTML那樣代碼里全是字符串拼接改一個頁面樣式要重編譯維護成本高為什么不直接用靜態(tài) HTML因為訂餐系統(tǒng)的菜品、庫存、訂單都在數(shù)據(jù)庫里HTML 拿不到動態(tài)數(shù)據(jù)為什么不把數(shù)據(jù)寫在文件里因為查詢、并發(fā)、事務、回滾這些需求文件系統(tǒng)給不了。所以 jsp 負責展示、Servlet 負責控制、mysql 負責存儲是這套小系統(tǒng)里成本最低的合理分工。這個組合在 Spring MVC 出現(xiàn)以前就是 Java Web 的默認形態(tài)。放到當下它的價值不在“先進”而在“簡單”項目小、依賴少、一條請求鏈路能在幾百行代碼里看完。對一個剛開始接觸 Web 的開發(fā)者這是把基礎(chǔ)概念串起來的最短路徑對一個維護過老系統(tǒng)的開發(fā)者看懂它也就讀懂了 jsp、Servlet、JDBC 之間那些約定俗成的關(guān)系。也要說清楚邊界。這套東西不支持前后端分離不適合高并發(fā)業(yè)務jsp 頁面里如果寫大量 Scriptlet 會很亂。真正生產(chǎn)環(huán)境里服務端渲染這塊已被 Spring Boot Thymeleaf 或前端工程化方案替代。所以把它當作“Java Web 底層原理的解剖樣本”來用收獲最大指望它支撐線上流量方向就偏了。2.2 一個訂餐請求從瀏覽器走到 MySQL 再返回請求生命周期看源碼之前先在腦子里建一條請求路徑。以“用戶點了‘加入菜品’”為例完整經(jīng)過是這樣瀏覽器把請求發(fā)給 Tomcat容器Tomcat 根據(jù) URL 找到 web.xml 里配置的 servlet-mapping命中對應的 Servlet 類。Servlet 的 doGet 或 doPost 里拿到參數(shù)比如菜品 id、用戶 id。Servlet 調(diào)用 DAO 類的方法DAO 通過 JDBC 連接 MySQL執(zhí)行 SELECT 或 INSERT。拿到結(jié)果后把數(shù)據(jù)放進 request 對象或 session 對象。請求轉(zhuǎn)發(fā)到 JSP 頁面JSP 在服務端把 JavaBean 數(shù)據(jù)渲染進 HTML。Tomcat 把最終 HTML 返回瀏覽器用戶看到頁面更新。這里最容易忽略的是第 1 步的映射關(guān)系。這些課程設(shè)計項目里Servlet 不是靠注解生效更多是靠 web.xml 里的servlet和servlet-mapping配出來的。解壓 zip 后第一件事就是看 web.xml確認 URL 和類名對不對得上否則啟動不報錯一訪問就是 404。另一個值得記住的點是 JSP 的“服務端渲染”。JSP 文件第一次訪問會被編譯成 Servlet所以 jsp 頁面里的% %、EL 表達式${}、JSTL 標簽都是在服務端執(zhí)行完再把純 HTML 送回瀏覽器。這意味著頁面源碼里看不到 Java 邏輯也意味著如果 JSP 編譯出問題瀏覽器看到的就是 500。2.3 拿到 zip 先看這四個位置比直接點運行重要很多人解壓后立刻導入 IDE 點運行然后被一連串報錯勸退。我的習慣是先看四處再決定怎么跑位置要確認的事web.xmlServlet 映射是否齊全、歡迎頁配的是哪個文件、有沒有配 filtersrc 里的 DBUtil 或 JDBC 工具類數(shù)據(jù)庫地址、用戶名、密碼寫在哪能不能直連SQL 腳本建庫建表語句是什么字符集、表引擎是不是 InnoDB、有沒有初始數(shù)據(jù)WEB-INF/libJDBC 驅(qū)動 jar 在不在版本是 5.x 還是 8.x這四處在絕大多數(shù)訂餐系統(tǒng)源碼里都存在只是文件名可能不同。數(shù)據(jù)庫腳本一般叫 init.sql 或 order.sql放根目錄或 sql 目錄連接工具類多半叫 DBUtil.java、JdbcUtil.java、BaseDao.java 中的一個。一上來先讀這四個文件能避免 80% 的啟動故障。真正動手前再看看數(shù)據(jù)表訂餐系統(tǒng)核心表就那么幾張user用戶、food/menu菜品、orders訂單主表、order_item訂單明細。表之間的關(guān)系是后面讀代碼的主線把它們的關(guān)系寫在一張紙上user 1—n ordersorders 1—n order_item。后面看 Servlet 時只要代碼往這張表上對應思路就不會亂。3. 最小運行環(huán)境JDK 8 Tomcat 8.5 MySQL 5.7 怎么搭最穩(wěn)3.1 版本選型老項目對版本敏感別盲目用新版“簡單網(wǎng)上訂餐系統(tǒng)”這類源碼大多出自 2015–2020 年間用 JDK 7/8 寫、跑在 Tomcat 7/8 上。放到今天最穩(wěn)的組合是 JDK 8 Tomcat 8.5 MySQL 5.7。這個組合不是我拍腦袋定的是這幾年的血淚經(jīng)驗組件推薦版本原因JDK1.88u 系列jsp/Servlet 編譯行為穩(wěn)定和老代碼兼容最好Tomcat8.5.x支持 JDK 8Servlet 規(guī)范是 3.1老項目無需改代碼MySQL5.7.xutf8mb4 支持好和 mysql-connector-java 5.1.49 驅(qū)動兼容連接驅(qū)動mysql-connector-java 5.1.49適合 MySQL 5.7驅(qū)動類名和連接串都簡單如果是 Windows 環(huán)境三個都裝 64 位版本。要注意別裝 MySQL 8.0 然后拿 5.x 驅(qū)動去連那樣會報一個讓人摸不著頭腦的認證協(xié)議錯誤Unable to load authentication plugin caching_sha2_password。另外提醒一句去官網(wǎng)找安裝包時認準官方入口別在第三方下載站隨便點捆綁軟件比項目本身的坑還多。裝完順序也有講究先裝 MySQL 并初始化再裝 JDK最后裝 Tomcat。Tomcat 啟動時要找 JAVA_HOME所以 JDK 和 JAVA_HOME 必須先配好而數(shù)據(jù)庫連接串要預先在本地建好后面導數(shù)據(jù)時才不會手忙腳亂。至于用 Eclipse 還是 idea 新建 jsp 項目這個階段無所謂直接把解壓出的源碼作為項目導入就行。3.2 數(shù)據(jù)庫初始化三步建庫、導表、看初始數(shù)據(jù)源碼里的 SQL 腳本大多數(shù)只建了表和初始數(shù)據(jù)不會自動建庫。所以要先手動建庫再把腳本導進去。我一般用命令行因為不依賴客戶端工具版本。打開終端進入 mysqlmysql -uroot -p然后依次執(zhí)行CREATE DATABASE IF NOT EXISTS food_order DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE food_order; SOURCE /絕對路徑/init.sql;邏輯說明CREATE DATABASE建立名為 food_order 的庫IF NOT EXISTS避免重復執(zhí)行報錯DEFAULT CHARACTER SET utf8mb4指定中文存儲編碼這一步直接關(guān)系到后面菜單名字會不會亂碼。SOURCE是 mysql 客戶端內(nèi)置命令后面跟腳本的絕對路徑逐條執(zhí)行腳本里的建表語句和插入語句。參數(shù)說明字符集建議用 utf8mb4 而不是舊版 utf8因為 utf8mb4 能完整支持四字節(jié)表情符號和生僻字雖然是訂餐系統(tǒng)用不到表情但統(tǒng)一成 utf8mb4 能避免“菜名里有個特殊字符就寫入失敗”的情況。SOURCE路徑里不要用 Windows 的反斜杠換成/否則客戶端可能解析失敗。導入完查兩張表確認一下USE food_order; SHOW TABLES; SELECT * FROM user;SHOW TABLES看到幾張表說明導入成功SELECT * FROM user是為了確認管理員賬號是否在初始化數(shù)據(jù)里很多系統(tǒng)默認塞了一個 admin/admin123這組賬號后面測試管理端要用。3.3 必改的兩個連接參數(shù)時區(qū)、編碼改完先本地驗證數(shù)據(jù)庫腳本導完第二步改源碼里的連接串。幾乎所有這類項目的連接串都集中在 DBUtil.java 里靜態(tài)代碼塊里做Class.forName再拿連接。典型代碼長這樣public class DBUtil { private static final String DRIVER com.mysql.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/food_order ?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD root; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }邏輯說明Class.forName把驅(qū)動類加載進來這一步是 JDBC 4.0 之前的標準寫法老項目必須有。DriverManager.getConnection每次請求都新建連接學習項目夠用后面我會講怎么換成連接池。參數(shù)說明useUnicodetruecharacterEncodingutf8保證 Java 往 MySQL 寫中文時按 UTF-8 編碼不配的話中文就變成問號。useSSLfalse關(guān)閉 SSL 握手本地開發(fā)沒必要開啟開著反而慢。serverTimezoneAsia/Shanghai是 MySQ L5.7 以上和 JDBC 8 之間最容易踩的時區(qū)坑不配可能直接報The server time zone value ?D1ú±ê×?ê±?? is unrecognized配了之后就清靜了。改完密碼之后不要急著啟動 Tomcat先單獨測試連接。最簡單的方式是寫個臨時 JSP 頁面放在 web 目錄下或者直接寫一個 Java 類 main 方法里調(diào)用DBUtil.getConnection()打印一下能拿到連接對象就說明 DB 鏈路通了。這個前置驗證能幫你把“數(shù)據(jù)庫問題”和“Web 問題”隔離開后面排查報錯的范圍會小很多。4. 讀源碼從這里下手登錄、購物車、訂單三條線4.1 登錄與 Session會話維持的兩種寫法登錄是第一個看起來簡單但坑最多的模塊。常見實現(xiàn)是JSP 頁面提交表單到 LoginServletServlet 里查數(shù)據(jù)庫成功后把 user 對象放進 session再重定向到首頁失敗則回登錄頁帶錯誤提示。WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username request.getParameter(username); String password request.getParameter(password); User user userDao.findByUsernameAndPassword(username, password); if (user ! null) { HttpSession session request.getSession(); session.setAttribute(user, user); response.sendRedirect(request.getContextPath() /index.jsp); } else { request.setAttribute(error, 用戶名或密碼錯誤); request.getRequestDispatcher(/login.jsp).forward(request, response); } } }邏輯說明request.getParameter拿表單值userDao.findByUsernameAndPassword是 Dao 層查數(shù)據(jù)庫查到了就session.setAttribute把用戶對象整個存進會話sendRedirect是重定向地址欄會變失敗則用forward轉(zhuǎn)發(fā)回登錄頁error存在 request 里在 JSP 用${error}顯示。參數(shù)說明getSession()默認是true如果客戶端沒有會話會自動創(chuàng)建一個所以在登錄 Servlet 里直接用沒問題。想判斷當前用戶是否已登錄通常在 JSP 里這么寫c:if test${empty sessionScope.user}為空就跳登錄頁防止有人不登錄直接訪問下單頁面。這套登錄方案有個老生常談的問題密碼沒做哈希直接明文比對。進階改法是把數(shù)據(jù)庫里的密碼換成加鹽的 MD5/SHA-256 摘要登錄時對輸入做同樣摘要再比。不過要提醒如果源碼里注冊功能也是明文存儲要連注冊、登錄兩處一起改否則老數(shù)據(jù)全部登不進去。4.2 購物車需求里“簡單”二字怎么體現(xiàn)在數(shù)據(jù)設(shè)計里購物車是對比“成熟系統(tǒng)”和“課程設(shè)計系統(tǒng)”差異的好地方。成熟電商的購物車在后端有專門表按用戶 ID 存購物車行。但在一個“簡單”訂餐系統(tǒng)里最常見做法是用 session 存一個ListCartItem加菜就是往 list 里塞退出來購物車就沒了。這種設(shè)計的好處是少建兩張表、少寫一套 CRUD代價是用戶換設(shè)備購物車不同步。先判斷你手上這份源碼是哪種。搜索“Cart”關(guān)鍵字如果只有 CartItem、CartServlet那多半是 session 方案如果建表腳本里有 cart 表那是落庫方案。以 session 方案為例加菜邏輯通常長這樣ListCartItem cart (ListCartItem) session.getAttribute(cart); if (cart null) { cart new ArrayList(); } boolean found false; for (CartItem item : cart) { if (item.getFoodId() foodId) { item.setCount(item.getCount() 1); found true; break; } } if (!found) { cart.add(new CartItem(foodId, foodName, price, 1)); } session.setAttribute(cart, cart);邏輯說明第一次加菜時 session 里沒有 cart就 new 一個 list。遍歷列表同一道菜數(shù)量加一不同菜品追加新項最后重新放回 session。這里注意session.setAttribute那行不能省因為 list 是可變對象雖然內(nèi)容變了但引用沒變不重新放回去也不會丟數(shù)據(jù)但每份源碼寫法習慣不同確認 set 的位置能避免改代碼時踩空。參數(shù)說明購物車在 session 里的存活時間由 Tomcat 的session-timeout控制默認 30 分鐘。30 分鐘沒操作購物車直接沒了這在管理端看訂單的人眼里是“用戶加菜加到一半被登出”。如果演示時想寬松點在 web.xml 里把時間改長但上線不建議這么干session 活太久占內(nèi)存。4.3 下單事務訂單表和明細表為什么必須同生共死購物車看完加菜下一個重點就是結(jié)算下單。訂單在訂餐系統(tǒng)里由兩張表組成orders 主表記錄總價、下單時間、用戶 IDorder_item 明細表記錄每一道菜的 ID、數(shù)量、單價。這兩張表的寫入必須在一個事務里否則會出現(xiàn)“主表有單、明細是空的”這種臟數(shù)據(jù)。下面這段是典型的下單 Service 方法public boolean createOrder(int userId, ListCartItem cart) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); double total 0; for (CartItem item : cart) { total item.getPrice() * item.getCount(); } PreparedStatement ps1 conn.prepareStatement( INSERT INTO orders (user_id, total_price, create_time, status) VALUES (?,?,NOW(),0), Statement.RETURN_GENERATED_KEYS); ps1.setInt(1, userId); ps1.setDouble(2, total); ps1.executeUpdate(); ResultSet rs ps1.getGeneratedKeys(); int orderId 0; if (rs.next()) { orderId rs.getInt(1); } PreparedStatement ps2 conn.prepareStatement( INSERT INTO order_item (order_id, food_id, count, price) VALUES (?,?,?,?)); for (CartItem item : cart) { ps2.setInt(1, orderId); ps2.setInt(2, item.getFoodId()); ps2.setInt(3, item.getCount()); ps2.setDouble(4, item.getPrice()); ps2.addBatch(); } ps2.executeBatch(); conn.commit(); return true; } catch (Exception e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); return false; } finally { DBUtil.close(conn); } }邏輯說明核心是setAutoCommit(false)開啟手動事務兩條插入語句執(zhí)行成功后統(tǒng)一commit()任何一步拋異常就rollback()保證訂單和明細要么都寫上、要么都不寫。getGeneratedKeys()拿自增主鍵這是細節(jié)但很重要明細表的外鍵 order_id 必須來自主表剛生成的 ID不能用SELECT MAX(id)并發(fā)下會串。參數(shù)說明Statement.RETURN_GENERATED_KEYS是 prepareStatement 的第二個參數(shù)告訴 MySQL 執(zhí)行插入后把自增 ID 返回給 JavaaddBatch()和executeBatch()把多條插入提交成一次往返數(shù)據(jù)庫避免循環(huán)一行一遍網(wǎng)絡開銷。這套寫法放到以后的任何 JDBC 項目里都成立建議直接背下來。5. 傳統(tǒng) jsp 項目怎么打包成 war 并部署五個高頻問題排查5.1 兩種打包方式IDE 可視化和 jar 命令課程設(shè)計源碼大多不帶 Maven所以別在項目里找 pom.xml。打包傳統(tǒng) jsp 項目主要是兩條路。第一條路是用 IDEA 打包。打開 Project Structure快捷鍵 CtrlShiftAltS選 Artifacts點加號選 Web Application: Exploded再點加號選 Web Application: Archive構(gòu)建后會在 out 目錄生成 war 包。Eclipse 類似右鍵項目選擇 Export - WAR file。生成后把 war 文件拷到 Tomcat 的 webapps 目錄啟動 Tomcat 時會自動解壓。第二條路是不開 IDE直接用 JDK 的 jar 命令。前提是項目已被編譯出 classes 目錄并且 web 資源結(jié)構(gòu)完整cd /path/to/project jar cvf food_order.war -C webroot/ .邏輯說明jar是 JDK 自帶的打包工具cvf三個參數(shù)分別表示創(chuàng)建新包、顯示打包過程、指定輸出文件名。-C webroot/先進入 web 目錄再打包這樣 war 包里的結(jié)構(gòu)才是標準的 web 應用結(jié)構(gòu)含 WEB-INFWEB-INF 里有 classes 和 web.xml。.表示把當前目錄所有內(nèi)容打進去。參數(shù)說明war 包名會直接決定訪問路徑。food_order.war 部署后訪問入口是http://localhost:8080/food_order/如果包名改成order.war路徑也要跟著變。我習慣把包名和項目名保持一致省得路徑對不上排查半天。生產(chǎn)環(huán)境如果要掛 nginx 做反向代理記住一點nginx 本身不解析 jsp它只轉(zhuǎn)發(fā)請求。proxy_pass http://127.0.0.1:8080;后面記得加一句proxy_set_header Host $host;否則后端 Servlet 拿到的域名不對做重定向時容易產(chǎn)生詭異的跳轉(zhuǎn)。5.2 五個高頻故障現(xiàn)象、原因、解決第一個坑啟動 Tomcat 后訪問項目路徑直接 404。原因多半是 web.xml 里 servlet-mapping 的 URL 和訪問路徑不匹配或者是 war 包名導致的上下文路徑不對。解決先訪問http://localhost:8080/food_order/index.jsp能打開說明部署成功再打開 web.xml 逐個比對url-pattern例如/login對應的路徑一定是http://localhost:8080/food_order/login。第二個坑頁面報java.lang.ClassNotFoundException: com.mysql.jdbc.Driver?,F(xiàn)象很明確原因也單純驅(qū)動 jar 沒在 WEB-INF/lib 下。解決下載 mysql-connector-java-5.1.49.jar 放進WEB-INF/lib不是tomcat/lib更不是 JDK 的 lib。如果數(shù)據(jù)庫是 MySQL 8.x驅(qū)動類名要改成com.mysql.cj.jdbc.Driver兩個版本驅(qū)動的包名差異是翻車重災區(qū)。第三個坑菜單、用戶名全是中文亂碼。這是典型的三處編碼不一致JSP 頁面的pageEncoding、JDBC 連接串里的characterEncoding、數(shù)據(jù)表的字符集三個地方必須統(tǒng)一。優(yōu)先把三處都改成 UTF-8頁面頭部寫% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%連接串帶characterEncodingutf8表結(jié)構(gòu)用SHOW CREATE TABLE food\G確認字符集。第四個坑數(shù)據(jù)庫能登錄但程序里連接報Access denied for user rootlocalhost。原因往往是源碼里寫死的密碼和本地 MySQL 不一致或者 root 只允許本機登錄而代碼里寫的 host 不對。解決登錄 MySQL 改掉連接串里的密碼用ALTER USER rootlocalhost IDENTIFIED BY 新密碼; FLUSH PRIVILEGES;。如果只想給訂餐系統(tǒng)建獨立賬號可以新建一個專用用戶并只授權(quán) food_order 庫。第五個坑Tomcat 10 上運行老項目編譯不報錯訪問時拋NoClassDefFoundError: javax/servlet/...。原因是 Tomcat 10 起把 Java EE 包名從javax.*換成了jakarta.*老代碼全是import javax.servlet所以跑不動。解決別掙扎換回 Tomcat 8.5 或 9.0。這類源碼不值得為它做包名遷移本地開發(fā)和課程演示用 8.5 最省事。6. 驗證與進階讓系統(tǒng)可靠跑一周再做兩個小改造6.1 三條驗證命令和一張檢查表部署完不要只看首頁能打開就宣布完成。我一般按下面的表逐項驗證全部通過才認為“能演示”檢查對象操作預期結(jié)果Tomcat 日志tail -f logs/catalina.out啟動無異常訪問時無 SQLException數(shù)據(jù)庫狀態(tài)Navicat 打開 food_order 庫表數(shù)據(jù)完整新訂單能寫入用戶完整流程注冊、登錄、加菜、結(jié)算、退出每一步頁面有反饋訂單表新增記錄管理端流程用源碼里的 admin 賬號登錄、查看訂單列表能看到用戶下的單明細金額對得上驗證時注意看管理端訂單列表的金額是否與明細表單價乘以數(shù)量一致這類系統(tǒng)最容易在金額精度上出問題。如果總價對不上去查 JSP 頁面里的金額顯示格式常見毛病是 Double 直接拼接導致19.9顯示成19.899999。6.2 一個值得做的改造給訂單加狀態(tài)把下單改成連接池第一個改造是給訂單加狀態(tài)機。建表腳本里 orders 表一般只有 id、user_id、total_price、create_time缺一個status字段。加一個TINYINT類型0 待支付、1 已支付、2 已取消管理端列表按狀態(tài)篩選整個系統(tǒng)馬上就有一個“訂單流轉(zhuǎn)”的概念。改動很小但價值很大面試被問“訂單狀態(tài)怎么設(shè)計”時你有現(xiàn)成實踐。第二個改造是把 DBUtil 換成連接池。原項目每次請求都DriverManager.getConnection并發(fā)一高就頻繁建連、斷連性能很差。常見做法是引入 Druid 或 HikariCP配一個druid.properties文件把最大連接數(shù)設(shè) 10、最小空閑設(shè) 2driverClassNamecom.mysql.jdbc.Driver urljdbc:mysql://localhost:3306/food_order?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai usernameroot password你的密碼 initialSize2 maxActive10然后在 DBUtil 里用DruidDataSourceFactory.createDataSource(props)替代原來的靜態(tài)代碼塊業(yè)務代碼調(diào)getConnection()的地方一行都不用改。這一步做完項目就從小白代碼向生產(chǎn)習慣靠攏了。我拆過十幾套課程設(shè)計源碼第一件事永遠不是跑起來而是看建表腳本建了幾張表、管理員賬號在哪、servlet 映射有沒有寫錯。這個順序幫我省下很多晚上。希望幫到你。本文還有配套的精品資源點擊獲取