實戰(zhàn):基于JSP的網(wǎng)上訂餐管理系統(tǒng)開發(fā)全流程)
簡介基于JSP的網(wǎng)上訂餐管理系統(tǒng)畢業(yè)設(shè)計資源包面向計算機(jī)相關(guān)專業(yè)畢業(yè)生、Java Web學(xué)習(xí)者及需要完成課程設(shè)計的在校生提供從系統(tǒng)設(shè)計到部署上線的完整參考。項目覆蓋JSP動態(tài)網(wǎng)頁開發(fā)、Servlet后臺處理、數(shù)據(jù)庫ER模型設(shè)計、軟件工程流程以及用戶體驗優(yōu)化等關(guān)鍵知識點適合用來掌握Web應(yīng)用開發(fā)全流程。壓縮包約95.81MB內(nèi)含項目報告、答辯PPT、源代碼、數(shù)據(jù)庫腳本、系統(tǒng)截圖及部署視頻其中報告和PPT可直接用于文檔參考視頻則演示Tomcat配置與發(fā)布步驟。已有919人學(xué)習(xí)下載資源按文檔、代碼、視頻分類存放便于對照研讀是一份兼具實戰(zhàn)性和展示價值的畢業(yè)設(shè)計參考資料。1. 基于jsp的網(wǎng)上訂餐管理系統(tǒng)一套畢設(shè)材料包到底該怎么用如果你正在為JavaWeb方向的畢設(shè)選題發(fā)愁估計見過這個標(biāo)題基于jsp的網(wǎng)上訂餐管理系統(tǒng)畢業(yè)設(shè)計壓縮包里項目報告、答辯PPT、源代碼、數(shù)據(jù)庫、截圖、部署視頻全都齊。它講的是最經(jīng)典的JSPServletJavaBeanMySQL三層架構(gòu)前臺做注冊登錄、瀏覽菜品、加購下單后臺做菜品維護(hù)和訂單處理代碼量不大卻把JavaWeb必考的知識點全帶上了。這種選題的價值不在于系統(tǒng)多復(fù)雜而在于能讓你在有限時間內(nèi)把“能跑的完整系統(tǒng)”和“能講的完整邏輯”同時握在手里。適合兩類人一類是手里攥著源碼卻跑不起來、只能干著急的另一類是剛完成jsp入門、想借成熟案例理清自己畢設(shè)結(jié)構(gòu)的。我按驗收路徑拆先看懂需求與表結(jié)構(gòu)再本地跑通最后知道答辯該講什么。2. 網(wǎng)上訂餐管理系統(tǒng)的需求拆解從用例到頁面流轉(zhuǎn)2.1 兩類角色與六個核心用例功能邊界在哪里一個合格的網(wǎng)上訂餐管理系統(tǒng)功能不用貪多但兩條業(yè)務(wù)線必須閉合用戶能完成“注冊-點餐-下單-查看訂單”的完整鏈路管理員能對菜品和訂單做增刪改查。畢業(yè)設(shè)計評審看的是閉環(huán)不是功能數(shù)量。很多同學(xué)在報告里畫了十幾個用例真正實現(xiàn)的只有登出和改密碼答辯時一演示就露餡。與其這樣不如把六個核心用例做扎實。角色用例觸發(fā)動作落庫表用戶注冊與登錄提交用戶名、密碼、手機(jī)號、地址user用戶瀏覽菜品打開首頁查看菜品列表與價格dish用戶加入購物車在菜品卡片點擊“加入購物車”無HttpSession用戶提交訂單從購物車跳結(jié)算頁并確認(rèn)orders、order_item用戶查看我的訂單查看歷史訂單及狀態(tài)orders管理員菜品管理后臺新增、上下架、刪除菜品dish管理員訂單管理將訂單狀態(tài)從“待處理”改為“已完成”orders購物車不落庫是JSP畢設(shè)里很常見的取舍把購物車放在HttpSession里用戶關(guān)瀏覽器即清空省去一張表答辯時又能引出“為什么不用數(shù)據(jù)庫存購物車”的討論回答成“臨時數(shù)據(jù)放Session更符合購物車生命周期”就很加分。訂單狀態(tài)用tinyint存0和10表示待處理、1表示已完成簡單直觀報告里畫狀態(tài)圖也只兩個節(jié)點不會給自己挖坑。還有一類同學(xué)喜歡加“接單自動打印小票”“騎手配送軌跡”這類功能在畢設(shè)階段往往做不完全就爛尾。判斷一個功能該不該加就看它能否用一張表或一個Servlet表述完表述不完的要么拆出去要么干脆砍掉。網(wǎng)上訂餐管理系統(tǒng)的評分點從來都是基礎(chǔ)CRUD是否閉環(huán)、是否用了連接池和事務(wù)而不是功能多花哨。2.2 JSP頁面規(guī)劃與目錄結(jié)構(gòu)先畫地圖再寫代碼拿到一套源碼先別急著點運(yùn)行重建出它的頁面地圖后續(xù)改代碼才有坐標(biāo)。最常見的頁面流轉(zhuǎn)是login.jsp驗身份后跳index.jsp菜品列表點菜品進(jìn)cart.jsp購物車結(jié)算后到orderList.jsp我的訂單管理員單獨一套adminLogin.jsp進(jìn)入admin/dishManage.jsp。每個頁面只干一件事JSP盡量只做展示業(yè)務(wù)邏輯放進(jìn)Servlet這是三層架構(gòu)的基本盤。src/main/ ├── java/com/order/ │ ├── bean/ User.java、Dish.java、Orders.java、OrderItem.java │ ├── dao/ UserDao.java、DishDao.java、OrderDao.java │ ├── servlet/ LoginServlet、CartServlet、OrderServlet、AdminServlet │ ├── util/ DBUtils.java │ └── filter/ EncodingFilter.java ├── webapp/ │ ├── index.jsp 菜品列表首頁 │ ├── login.jsp 用戶登錄/注冊入口 │ ├── user.jsp 個人信息展示與修改 │ ├── cart.jsp 購物車與結(jié)算 │ ├── orderList.jsp 我的訂單 │ ├── admin/ │ │ ├── adminLogin.jsp │ │ ├── dishManage.jsp │ │ └── orderManage.jsp │ ├── css/ js/ images/ │ └── WEB-INF/web.xmluser.jsp這類個人信息展示頁面多數(shù)時候就是把user表里的phone和address字段拿出來渲染成表單再提交給UserServlet更新邏輯和登錄一樣屬于湊用例數(shù)的性價比之王——報告里“個人信息維護(hù)”用例就有著落了。admin目錄單獨放后臺頁面和前臺分離URL帶/admin前綴演示時好識別。JSP放在webapp根目錄下Servlet通過/cart?actionadd這類地址跳轉(zhuǎn)頁面之間不直接跳jsp而是“頁面提交給ServletServlet干完活再forward或redirect回JSP”這樣URL里能看到請求去向出問題時一眼定位是哪個Servlet沒配對。還有一個容易被忽略的點登錄狀態(tài)檢查。除login.jsp和register.jsp外每個頁面都應(yīng)該在Servlet入口處取Session里的loginUser取不到就重定向回登錄頁。這個邏輯寫進(jìn)一個BaseServlet基類或由Filter統(tǒng)一做比在每個Servlet里復(fù)制粘貼三行代碼更值得寫進(jìn)報告。DAO層是唯一的SQL出口哪怕Demo項目我也建議所有JDBC代碼集中在DAOServlet里不要出現(xiàn)Statement。理由很簡單報告里“分層設(shè)計”章節(jié)畫了圖如果你代碼里到處是Connection答辯老師翻代碼一眼就能看出圖和實現(xiàn)是兩回事。3. 從建表到連庫MySQL表設(shè)計與連接池參數(shù)落地3.1 四張核心表的建表SQL金額用decimal狀態(tài)用tinyint先建庫再建表。常見的數(shù)據(jù)庫名是order_db字符集選utf8對這類不含emoji的畢設(shè)項目足夠用。四張核心表的字段設(shè)計遵循一個原則能表達(dá)業(yè)務(wù)、能畫ER圖、不刻意加冗余字段。CREATE DATABASE IF NOT EXISTS order_db DEFAULT CHARSET utf8; USE order_db; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(20) NOT NULL UNIQUE, password VARCHAR(32) NOT NULL, phone VARCHAR(11), address VARCHAR(100), regtime DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE dish ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, type VARCHAR(20) COMMENT 分類主食/飲品/套餐, price DECIMAL(10,2) NOT NULL, pic VARCHAR(100) COMMENT 圖片相對路徑, intro VARCHAR(200) ) ENGINEInnoDB; CREATE TABLE orders ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, total DECIMAL(10,2) NOT NULL, status TINYINT DEFAULT 0 COMMENT 0待處理 1已完成, ordertime DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE order_item ( id INT PRIMARY KEY AUTO_INCREMENT, order_id INT NOT NULL, dish_id INT NOT NULL, count INT NOT NULL, price DECIMAL(10,2) NOT NULL COMMENT 下單時的單價快照 ) ENGINEInnoDB;金額必須用DECIMAL(10,2)。float在累計運(yùn)算時會出現(xiàn)0.1加0.2不等于0.3的浮點誤差答辯被追問“為什么不用double”時會很被動而DECIMAL是定點數(shù)專治金額場景。order_item里的price字段是下單時刻的單價快照菜品日后漲價也不影響歷史訂單金額這個設(shè)計點寫進(jìn)報告屬于加分項。外鍵建議只在ER圖里畫物理表不建FOREIGN KEYInnoDB加外鍵會影響刪除效率畢設(shè)數(shù)據(jù)量小無所謂但真建了外鍵往order_item插數(shù)據(jù)時要先主表后子表出錯環(huán)節(jié)會變多。種子數(shù)據(jù)一并寫進(jìn)初始化腳本三到五道菜品用戶密碼用MD5摘要存儲報告里寫“密碼經(jīng)過摘要存儲不存明文”能體現(xiàn)一點安全意思。常見做法是把建庫、建表、插入初始數(shù)據(jù)全部串進(jìn)一個init.sql后面部署時在Navicat里一次性執(zhí)行。想順手驗證數(shù)據(jù)源可用跑一條SELECT COUNT(*) FROM dish;能返回結(jié)果就說明這張表和連接串都沒問題。3.2 用c3p0連接池接MySQL配置文件與常用參數(shù)說明初學(xué)者連接數(shù)據(jù)庫的第一反應(yīng)是DriverManager.getConnection畢設(shè)里能跑但答辯幾乎必問“連接池是什么、為什么不用DriverManager”。回答思路是DriverManager每次請求都新建物理連接高并發(fā)下頻繁建連釋放連接池預(yù)先建好一批連接放在池里用的時候借、用完還避免反復(fù)握手。這個解釋里最好帶一個具體參數(shù)證明你真配過比如checkoutTimeout。?xml version1.0 encodingUTF-8? c3p0-config named-config namemysql property namedriverClasscom.mysql.jdbc.Driver/property property namejdbcUrljdbc:mysql://localhost:3306/order_db?useUnicodetrueamp;characterEncodingutf8/property property nameuserroot/property property namepassword123456/property property nameinitialPoolSize3/property property namemaxPoolSize10/property property namecheckoutTimeout3000/property /named-config /c3p0-config這個文件放到src/main/resources/c3p0-config.xmlc3p0啟動時會自動掃描類路徑。driverClass和jdbcUrl是必須寫對的兩個屬性MySQL 5.x用com.mysql.jdbc.Driver如果換MySQL 8.x要改成com.mysql.cj.jdbc.Driver并追加serverTimezoneAsia/Shanghai這是數(shù)據(jù)庫連接失敗里排名第一的坑。jdbcUrl里的在XML里必須轉(zhuǎn)義成amp;漏了會直接報XML解析錯誤。連接數(shù)不用調(diào)太大畢設(shè)場景初始3個、最大10個足夠checkoutTimeout設(shè)3000毫秒表示借連接最多等3秒超時算失敗防止并發(fā)等不到連接時無限掛起。有了配置再寫一個工具類把數(shù)據(jù)源封裝起來所有DAO共用一個靜態(tài)數(shù)據(jù)源package com.order.util; import com.mchange.v2.c3p0.ComboPooledDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; public class DBUtils { // 靜態(tài)代碼塊里初始化一次整個應(yīng)用共用同一個連接池 private static DataSource ds; static { ds new ComboPooledDataSource(mysql); } public static Connection getConnection() throws SQLException { return ds.getConnection(); } }邏輯說明new ComboPooledDataSource(mysql)會讀取c3p0-config.xml里name為“mysql”的named-config靜態(tài)代碼塊保證類加載時只初始化一次。DAO層調(diào)DBUtils.getConnection()拿到的是池里的連接使用后必須close()還給池這不是真正斷開連接所以千萬不能漏掉close——和裸JDBC一樣finally里關(guān)連接是基本修養(yǎng)。如果實際項目偏好druid只需要換數(shù)據(jù)源實現(xiàn)類和配置項DAO層完全不用改這也能解釋“面向接口編程”的價值。4. 用IDEA把JSP項目搭起來Maven骨架、購物車與核心Servlet4.1 IDEA新建JSP項目Maven骨架與依賴選型現(xiàn)在的主流做法是IDEA里新建Maven Webapp項目勾選模板生成web.xml比傳統(tǒng)手動建Web目錄再拷j(luò)ar更不容易漏依賴。注意不要順手把Spring引進(jìn)來JSP畢設(shè)一旦混進(jìn)SpringMVC結(jié)構(gòu)復(fù)雜一倍報告和答辯難度跟著漲。保持原汁原味的ServletJSP即可。properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties dependencies dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version3.1.0/version scopeprovided/scope /dependency dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.49/version /dependency dependency groupIdc3p0/groupId artifactIdc3p0/artifactId version0.9.1.2/version /dependency /dependenciesservlet-api的scope設(shè)置成provided很關(guān)鍵Tomcat自帶Servlet容器實現(xiàn)如果打包進(jìn)war會和容器沖突可能在啟動時直接報重復(fù)類加載錯誤c3p0和MySQL驅(qū)動則必須打進(jìn)去因為Tomcat不會平白提供這些庫。JDK建議鎖在1.8對應(yīng)Tomcat 8.5或9.x這套組合是JSP項目的舒適區(qū)。JDK 17以上跑老版本Tomcat經(jīng)常出現(xiàn)模塊化權(quán)限問題屬于能解決但沒必要折騰的玄學(xué)坑。4.2 購物車與下單兩個必看的核心Servlet購物車的常見實現(xiàn)是把一個Map掛在Session上key是菜品idvalue是數(shù)量下單時再拿著id去查菜品表拿最新價格。有一個新手容易翻車的點如果在加購時就把Dish對象整個塞進(jìn)購物車下單算的是當(dāng)時的“緩存價格”而菜品表價格可能已被管理員改過。WebServlet(/cart) public class CartServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action req.getParameter(action); if (add.equals(action)) { addToCart(req, resp); } else if (clear.equals(action)) { req.getSession().removeAttribute(cart); resp.sendRedirect(req.getContextPath() /cart.jsp); } } private void addToCart(HttpServletRequest req, HttpServletResponse resp) throws IOException { int dishId Integer.parseInt(req.getParameter(dishId)); HttpSession session req.getSession(); MapInteger, Integer cart (MapInteger, Integer) session.getAttribute(cart); if (cart null) { cart new HashMapInteger, Integer(); } Integer count cart.getOrDefault(dishId, 0); cart.put(dishId, count 1); session.setAttribute(cart, cart); resp.sendRedirect(req.getContextPath() /cart.jsp); } }CartServlet只維護(hù)“購物車?yán)镉袔讉€什么菜”不碰價格價格統(tǒng)一在下單時查庫保證訂單金額永遠(yuǎn)和菜品表一致。用sendRedirect(req.getContextPath() ...)而不寫死/cart.jsp是為了兼容不同contextPath部署否則部署成帶版本號的war時URL會全斷。action參數(shù)分不同分支后續(xù)想加“刪除單個菜品”就加一個else if擴(kuò)展成本很低。下單邏輯是整套系統(tǒng)的核心必須處理事務(wù)。一個訂單要同時寫orders主表和order_item明細(xì)表兩步之間任何一步失敗都不允許出現(xiàn)“主表有訂單、明細(xì)沒有”的臟數(shù)據(jù)WebServlet(/order) public class OrderServlet extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session req.getSession(); MapInteger, Integer cart (MapInteger, Integer) session.getAttribute(cart); if (cart null || cart.isEmpty()) { resp.sendRedirect(req.getContextPath() /cart.jsp); return; } Connection conn null; try { conn DBUtils.getConnection(); conn.setAutoCommit(false); // 開啟事務(wù) User user (User) session.getAttribute(loginUser); double total 0; for (Map.EntryInteger, Integer e : cart.entrySet()) { Dish dish new DishDao().findById(e.getKey()); total dish.getPrice() * e.getValue(); } int orderId new OrderDao().insertOrder(conn, user.getId(), total); for (Map.EntryInteger, Integer e : cart.entrySet()) { Dish dish new DishDao().findById(e.getKey()); new OrderDao().insertItem(conn, orderId, dish.getId(), e.getValue(), dish.getPrice()); } conn.commit(); // 全部成功才提交 session.removeAttribute(cart); resp.sendRedirect(req.getContextPath() /orderList.jsp); } catch (Exception ex) { if (conn ! null) { try { conn.rollback(); } catch (SQLException exc) { /* ignore */ } } ex.printStackTrace(); resp.sendRedirect(req.getContextPath() /cart.jsp?error1); } finally { if (conn ! null) { try { conn.setAutoCommit(true); // 還原連接還給池 conn.close(); } catch (SQLException exc) { /* ignore */ } } } } }事務(wù)的關(guān)鍵就三行setAutoCommit(false)之后所有SQL在同一個事務(wù)里執(zhí)行全部成功commit()任何一個異常rollback()。finally里先把a(bǔ)utoCommit還原成true再close否則連接還回池后還帶著“手動提交”的舊狀態(tài)下一個人拿到這條連接時事務(wù)行為是錯的這是連接池場景下非常隱蔽的坑。代碼里兩次findById查價格雖然多了一次查詢但保證了total和明細(xì)的單價來自同一個庫表來源。4.3 菜品列表頁的JSP寫法EL表達(dá)式與JSTL替代scriptlet菜品列表頁是最有代表性的JSP頁面。常見錯誤寫法是在JSP里堆一堆% for(...) { %的scriptlet能跑但報告里“視圖層只負(fù)責(zé)展示”這句話就圓不回來。用c:forEach加EL表達(dá)式頁面干凈答辯也好講。% page contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html body h2菜單/h2 div classdish-list c:forEach items${dishList} vard div classdish-card img src${d.pic} alt${d.name} width120 height120/ p${d.name} ${d.price}/p a href${pageContext.request.contextPath}/cart?actionadddishId${d.id}加入購物車/a /div /c:forEach /div /body /html${dishList}是Servlet執(zhí)行req.setAttribute(dishList, list)之后從EL容器里取出的集合${d.name}調(diào)用的是Dish類的getName()方法所以bean必須提供getter否則EL取不到值但頁面不報錯只顯示空白這是EL表達(dá)式的經(jīng)典疑難雜癥。taglib的uri必須和實際引入的JSTL版本一致http://java.sun.com/jsp/jstl/core對應(yīng)老版JSTL 1.2換成新版要用jakarta.tags.core之類版本不匹配屏幕會直接拋Unable to find taglib。頁面里的${pageContext.request.contextPath}動態(tài)拿到項目根路徑比寫死/order_war_exploded/強(qiáng)得多。整個JSP里盡量只出現(xiàn)EL表達(dá)式和JSTL標(biāo)簽需要復(fù)雜邏輯就寫Servlet頁面保持一眼看懂。5. 打包部署與避坑復(fù)盤war包在Tomcat上的完整閉環(huán)5.1 傳統(tǒng)JSP項目打包war一條命令出部署包畢設(shè)最終要交一個能跑的系統(tǒng)最穩(wěn)的方式是把項目打成war包丟進(jìn)Tomcat的webapps目錄而不是讓人在IDEA里配Tomcat演示。前一陣經(jīng)常有人問“nginx 支持jsp嗎”nginx本身不解析Servlet和JSP它只能把請求反向代理給Tomcat真正干活的是Tomcat所以畢設(shè)階段讓Tomcat直跑8080端口就好不必引入nginx。mvn clean package # 在項目根目錄運(yùn)行產(chǎn)出 target/order.war cp target/order.war /opt/tomcat8.5/webapps/ cd /opt/tomcat8.5/bin ./startup.sh # 看到 Tomcat started 后瀏覽器訪問 # http://localhost:8080/order/mvn clean package會先clean再重新構(gòu)建避免舊class殘留導(dǎo)致的“改了代碼但不生效”。war丟進(jìn)webapps后Tomcat會自動解壓成同名目錄訪問路徑里的/order/就是war包名也就是說包名直接決定URL。建議在pom.xml的build段里寫死finalNameorder/finalName同時所有JSP跳轉(zhuǎn)都用${pageContext.request.contextPath}拼路徑雙保險。startup.sh啟動后注意看logs/catalina.out末尾的Server startup in XXX ms看到這行才算真起來光看窗口彈出來不夠。改代碼想重啟先shutdown.sh再startup不要開著舊進(jìn)程直接覆蓋war否則端口占用和解壓沖突會一起炸。5.2 高頻踩坑記錄五個必看現(xiàn)象與解法第一條頁面中文全部變成問號?,F(xiàn)象菜品名、用戶名顯示成???或?。原因字符集鏈路斷了一環(huán)可能是數(shù)據(jù)庫表不是utf8、JDBC連接串沒帶characterEncoding、JSP沒寫pageEncoding、Servlet沒設(shè)置request編碼。解決四端統(tǒng)一UTF-8——建庫用DEFAULT CHARSET utf8jdbcUrl里加characterEncodingutf8JSP頭部寫pageEncodingUTF-8再用一個EncodingFilter統(tǒng)一設(shè)置request和response編碼。這里最容易漏的是POST請求的編碼過濾器里req.setCharacterEncoding(UTF-8)是必寫項。第二條ClassNotFoundException: com.mysql.jdbc.Driver。現(xiàn)象啟動或第一次查詢直接拋類找不到。原因MySQL驅(qū)動jar沒進(jìn)war包或者你的MySQL是8.x但驅(qū)動包和driverClass都還按5.x寫。解決確認(rèn)pom里mysql-connector-java依賴存在且沒有provided scope如果MySQL是8.xdriverClass改成com.mysql.cj.jdbc.DriverjdbcUrl追加serverTimezoneAsia/Shanghai。這兩個版本的差異是MySQL連接問題里最高頻的原因。第三條查詢報Public Key Retrieval is not allowed?,F(xiàn)象MySQL 8.x下驅(qū)動報這個錯。原因連接串沒允許客戶端獲取公鑰。解決jdbcUrl追加allowPublicKeyRetrievaltrue。第四條部署后訪問404地址欄出現(xiàn)/xxx_war_exploded/。現(xiàn)象IDEA內(nèi)嵌Tomcat能跑換成獨立Tomcat就404。原因開發(fā)時瀏覽器用的是IDEA生成的exploded目錄路徑和包名不一致部署到webapps后路徑變成war包名。解決pom里固定finalName頁面跳轉(zhuǎn)一律用${pageContext.request.contextPath}拼接不手寫絕對路徑。第五條JSP改了不生效。現(xiàn)象改完jsp刷新還是舊內(nèi)容。原因IDEA默認(rèn)沒把修改同步到target/out目錄或者Tomcat開了緩存。解決Build菜單選“Rebuild Project”強(qiáng)制重建確認(rèn)target下的jsp確實更新后再重啟Tomcat。這套操作不復(fù)雜但不少新手會卡在這一步以為是代碼寫錯其實是沒重新構(gòu)建。提示連接池參數(shù)別照抄網(wǎng)上配置就完事。c3p0的maxPoolSize設(shè)個10就好除非真做過壓測否則調(diào)成幾百只會讓答辯被追問“你怎么知道要設(shè)多少”。5.3 驗收清單怎樣才算真的跑通了跑通不等于“頁面上有字”。按這個表逐項走一遍每一項都出預(yù)期結(jié)果才算站穩(wěn)了。驗收項操作步驟預(yù)期結(jié)果注冊登錄注冊新用戶并登錄登錄后首頁顯示用戶名Session生效加購下單加入兩道菜進(jìn)購物車提交訂單訂單列表多一條記錄購物車清空數(shù)據(jù)落庫Navicat查orders和order_item訂單金額與明細(xì)條數(shù)正確后臺管理后臺新增菜品回首頁看新菜品立即出現(xiàn)在菜品列表代碼可講解打包war在一臺干凈機(jī)器跑通按部署視頻重演成功記得把驗證過程完整錄一段視頻從啟動MySQL到打開后臺改價、再回首頁刷新看到新價格。這份錄屏既是自查的憑據(jù)也是答辯時被質(zhì)疑“是不是真能跑”時最有說服力的證據(jù)。到這一步基于jsp的網(wǎng)上訂餐管理系統(tǒng)在你手里就是活的不再是壓縮包里的一堆文件。6. 答辯怎么講演示順序、報告結(jié)構(gòu)與三個必答問題6.1 答辯演示的黃金兩分鐘先說演示順序這是最常見的丟分點。進(jìn)答辯間先別講背景和意義直接花一分鐘把系統(tǒng)跑給老師看登錄進(jìn)首頁加一道菜下單打開后臺把訂單狀態(tài)改掉。演示完再講設(shè)計老師的注意力才會落在這個系統(tǒng)本身。報告按需求分析、概要設(shè)計、詳細(xì)設(shè)計、測試四段走ER圖放概要設(shè)計購物車和下單流程圖放詳細(xì)設(shè)計測試一章把5.3那張驗收表改寫成文字放進(jìn)報告。PPT壓到15頁以內(nèi)一頁只講一張架構(gòu)圖、一張ER圖、一頁核心代碼每頁停留時間控制在兩三分鐘以內(nèi)。6.2 三個必答問題與交付自檢老師最可能追問的三個問題提前備好JSP和Servlet的區(qū)別回答“JSP側(cè)重視圖渲染Servlet側(cè)重邏輯控制二者最終都編譯成Servlet”為什么用連接池回答時帶上checkoutTimeout參數(shù)下單事務(wù)怎么保證一致性把價格快照和Session購物車這兩個設(shè)計點主動拋出去等于把老師往你準(zhǔn)備過的地方引。我自己帶過的學(xué)生里源碼跑通卻答不上“如果兩個用戶同時下單會發(fā)生什么”的不少先把事務(wù)那條線背熟這題就不會丟分。最后提醒一句交付前找一臺干凈電腦照著部署視頻從裝JDK開始完整走一遍能走通你心里就有底了別把“能跑”押在環(huán)境玄學(xué)上。希望幫到你。本文還有配套的精品資源點擊獲取