實(shí)戰(zhàn):Servlet+JSP+JDBC全流程部署指南)
簡(jiǎn)介本資源是一套面向Java初學(xué)者與高校實(shí)訓(xùn)學(xué)生的醫(yī)院藥品管理系統(tǒng)實(shí)戰(zhàn)項(xiàng)目適用于JavaWeb課程設(shè)計(jì)、期末大作業(yè)及本科畢業(yè)設(shè)計(jì)。系統(tǒng)采用B/S架構(gòu)基于Java語言開發(fā)融合JSP前端展示、Servlet業(yè)務(wù)邏輯與MySQL數(shù)據(jù)庫持久化覆蓋藥品入庫、庫存查詢、用戶管理、權(quán)限控制等核心醫(yī)療管理場(chǎng)景助力學(xué)習(xí)者扎實(shí)掌握MVC分層開發(fā)與Web應(yīng)用部署全流程。壓縮包共422個(gè)文件含96個(gè)HTML頁面、54個(gè)JS交互腳本、44個(gè)編譯后Class文件、22個(gè)Java源碼、14個(gè)Jar依賴庫、10個(gè)CSS樣式表及1個(gè)完整SQL建庫腳本總大小10.21MB結(jié)構(gòu)規(guī)范、模塊清晰開箱即用。已有499人學(xué)習(xí)下載所有代碼經(jīng)嚴(yán)格調(diào)試可直接導(dǎo)入IDE運(yùn)行配套數(shù)據(jù)庫腳本一鍵初始化顯著降低環(huán)境配置門檻是JavaWeb入門到進(jìn)階的高分實(shí)踐范例。1. 這不是又一個(gè)“學(xué)生作業(yè)式”JavaWeb項(xiàng)目它真能跑通藥品入庫、出庫、庫存預(yù)警、采購(gòu)計(jì)劃生成全流程且數(shù)據(jù)庫腳本已預(yù)置MySQL 5.7兼容結(jié)構(gòu)適合剛學(xué)完ServletJSPJDBC但卡在「連不上數(shù)據(jù)庫」或「增刪改查總少一行SQL」的實(shí)戰(zhàn)者你可能已經(jīng)下載過十幾個(gè)標(biāo)著“JavaWeb醫(yī)院管理系統(tǒng)”的壓縮包解壓后發(fā)現(xiàn)Tomcat啟動(dòng)報(bào)404、MySQL連接失敗、登錄頁面空白、后臺(tái)管理頁點(diǎn)不動(dòng)——最后默默刪掉懷疑自己是不是不適合寫Java。這個(gè)javaweb實(shí)訓(xùn)-基于javaweb的醫(yī)院藥品管理系統(tǒng)源碼數(shù)據(jù)庫.zip不是PPT演示工程也不是只跑通登錄頁的半成品。它包含完整可部署的三層結(jié)構(gòu)表現(xiàn)層JSPServlet、業(yè)務(wù)層Service、數(shù)據(jù)訪問層DAO數(shù)據(jù)庫腳本hospital_drug.sql已按MySQL 5.7語法建好8張表藥品表、供應(yīng)商表、入庫單、出庫單、庫存表、用戶表、角色表、操作日志表所有SQL語句經(jīng)實(shí)測(cè)通過含事務(wù)回滾邏輯和庫存扣減原子性處理。它不依賴Spring Boot自動(dòng)裝配純?cè)鶭avaWeb技術(shù)棧但做了關(guān)鍵加固連接池用DBCP2而非手動(dòng)new ConnectionJSP中EL表達(dá)式全啟用Servlet里統(tǒng)一處理中文亂碼連最讓人頭疼的“藥品名稱帶括號(hào)/斜杠導(dǎo)致入庫失敗”都加了字符串轉(zhuǎn)義過濾。如果你正卡在“寫了三天DAO層卻始終查不到數(shù)據(jù)”或者想用真實(shí)業(yè)務(wù)場(chǎng)景比如按有效期自動(dòng)標(biāo)紅近效期藥品反向吃透JDBC事務(wù)與SQL注入防護(hù)這份資源就是為你留的調(diào)試靶場(chǎng)——不是教你怎么寫Hello World而是教你寫完之后怎么讓系統(tǒng)在Tomcat里穩(wěn)穩(wěn)跑滿一整天。2. 從零部署解壓→配環(huán)境→啟服務(wù)→驗(yàn)功能四步閉環(huán)驗(yàn)證是否真正“開箱即用”2.1 解壓后目錄結(jié)構(gòu)解析看清哪些文件是“動(dòng)不得”的核心資產(chǎn)哪些是“必須改”的配置入口解壓javaweb實(shí)訓(xùn)-基于javaweb的醫(yī)院藥品管理系統(tǒng)源碼數(shù)據(jù)庫.zip后你會(huì)看到標(biāo)準(zhǔn)的JavaWeb項(xiàng)目結(jié)構(gòu)hospital-drug-system/ ├── src/ # Java源碼根目錄 │ ├── com/hospital/drug/ # 主包名含servlet、service、dao、entity、util │ └── db.properties # 數(shù)據(jù)庫連接配置關(guān)鍵必須改 ├── WebContent/ # Web資源根目錄等同于傳統(tǒng)WebRoot │ ├── WEB-INF/ │ │ ├── web.xml # Servlet注冊(cè)與歡迎頁配置勿刪 │ │ └── lib/ # JAR包存放處含mysql-connector-java-5.1.47.jar、commons-dbcp-1.4.jar等 │ ├── index.jsp # 系統(tǒng)首頁登錄入口 │ ├── admin/ # 后臺(tái)管理頁面含藥品管理、入庫單、出庫單等JSP │ └── css/js/images/ # 靜態(tài)資源 ├── hospital_drug.sql # MySQL建庫建表初始化數(shù)據(jù)腳本直接執(zhí)行即可 └── README.md # 項(xiàng)目說明含默認(rèn)賬號(hào)密碼提示src/db.properties和hospital_drug.sql是唯二必須操作的文件。其他所有.java、.jsp、.xml文件均無需修改即可運(yùn)行——這是該資源區(qū)別于“教學(xué)Demo”的核心價(jià)值它把配置項(xiàng)收斂到最小集把業(yè)務(wù)邏輯固化在可驗(yàn)證路徑上。2.2 JDKTomcatMySQL環(huán)境三件套版本選擇有講究錯(cuò)一個(gè)就卡在ClassNotFoundException該項(xiàng)目基于Java SE 8JDK 1.8編譯嚴(yán)禁使用JDK 11。原因在于其Servlet API依賴javax.servlet.*包而JDK 9模塊化后需額外引入javaee-web-api極易引發(fā)NoClassDefFoundError: javax/servlet/Servlet。Tomcat必須選8.5.x或9.0.x親測(cè)Tomcat 8.5.93穩(wěn)定因Tomcat 10已全面切換至Jakarta EE命名空間jakarta.servlet.*會(huì)導(dǎo)致所有Servlet類編譯失敗。MySQL推薦5.7.32hospital_drug.sql中建表語句使用ENGINEInnoDB DEFAULT CHARSETutf8MySQL 8.0默認(rèn)字符集為utf8mb4雖兼容但需手動(dòng)改表。安裝順序嚴(yán)格為安裝JDK 1.8并配置JAVA_HOME安裝Tomcat 8.5.x解壓版即可無需安裝版安裝MySQL 5.7務(wù)必勾選“Add to PATH”啟動(dòng)MySQL服務(wù)用root賬號(hào)登錄驗(yàn)證mysql -u root -p。注意若你本地已裝MySQL 8.0不要卸載——只需在db.properties中將jdbc.url末尾追加?serverTimezoneGMT%2B8useUnicodetruecharacterEncodingutf8并在執(zhí)行hospital_drug.sql前手動(dòng)創(chuàng)建數(shù)據(jù)庫CREATE DATABASE hospital_drug CHARACTER SET utf8 COLLATE utf8_general_ci;2.3 數(shù)據(jù)庫初始化執(zhí)行SQL腳本時(shí)必須避開三個(gè)“靜默失敗”陷阱hospital_drug.sql文件包含建庫、建表、插入初始數(shù)據(jù)三部分。常見失敗并非語法錯(cuò)誤而是環(huán)境適配問題-- 正確執(zhí)行方式在MySQL命令行中逐行粘貼或用Navicat執(zhí)行 CREATE DATABASE IF NOT EXISTS hospital_drug CHARACTER SET utf8 COLLATE utf8_general_ci; USE hospital_drug; -- 下面是建表語句省略具體字段重點(diǎn)看ENGINE和CHARSET CREATE TABLE drug_info ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, spec VARCHAR(50), unit VARCHAR(20), price DECIMAL(10,2), valid_period DATE, stock_quantity INT DEFAULT 0, supplier_id INT, create_time DATETIME DEFAULT NOW() ) ENGINEInnoDB DEFAULT CHARSETutf8; -- 插入測(cè)試數(shù)據(jù)含中文必須確??蛻舳司幋a為utf8 INSERT INTO drug_info (name, spec, unit, price, valid_period, stock_quantity, supplier_id) VALUES (阿莫西林膠囊, 0.25g*24粒, 盒, 12.50, 2025-12-31, 150, 1);關(guān)鍵參數(shù)說明ENGINEInnoDB必須指定否則事務(wù)控制失效入庫/出庫需事務(wù)保證庫存一致性DEFAULT CHARSETutf8不是utf8mb4避免MySQL 5.7下utf8mb4不被識(shí)別DATETIME DEFAULT NOW()MySQL 5.7支持若用低版本需改為CURRENT_TIMESTAMP中文插入前先執(zhí)行SET NAMES utf8;否則出現(xiàn)亂碼導(dǎo)致登錄失敗。執(zhí)行后驗(yàn)證USE hospital_drug; SELECT COUNT(*) FROM drug_info; -- 應(yīng)返回≥5條初始含5種藥品 SELECT user_name, password FROM sys_user WHERE role_id 1; -- 查管理員賬號(hào)默認(rèn)admin/1234562.4 Tomcat部署與啟動(dòng)別再盲目復(fù)制war包用IDEA直接部署才是調(diào)試效率關(guān)鍵不要把整個(gè)WebContent文件夾復(fù)制到Tomcat/webapps/下——這種做法無法熱更新改一行JSP就要重啟Tomcat。正確做法是在IntelliJ IDEA中配置Artifact打開項(xiàng)目 →File → Project Structure → Artifacts點(diǎn)擊 → Web Application: Archive → For hospital-drug-system在Output Layout中確保WEB-INF/lib/下包含mysql-connector-java-5.1.47.jar數(shù)據(jù)庫驅(qū)動(dòng)commons-dbcp-1.4.jar連接池commons-pool-1.6.jarDBCP依賴jstl-1.2.jarJSP標(biāo)簽庫Build → Build Artifacts → Build生成hospital-drug-system.warRun → Edit Configurations → → Tomcat Server → Local在Deployment選項(xiàng)卡中點(diǎn)擊 → Artifact → hospital-drug-system:war exploded設(shè)置Application context為/drug訪問地址變?yōu)閔ttp://localhost:8080/drug點(diǎn)擊OK運(yùn)行Tomcat。啟動(dòng)后觀察控制臺(tái)若出現(xiàn)INFO: Server startup in [xxx] ms且無紅色ERROR則部署成功若報(bào)java.lang.ClassNotFoundException: org.apache.commons.dbcp.BasicDataSourceFactory說明commons-dbcp-1.4.jar未打入WAR包需檢查Artifact配置若報(bào)com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown database hospital_drug說明數(shù)據(jù)庫未創(chuàng)建或db.properties中URL寫錯(cuò)。3. 核心業(yè)務(wù)流程走查從藥品入庫單提交到庫存自動(dòng)扣減手把手跟蹤一條數(shù)據(jù)的全生命周期3.1 入庫單提交鏈路JSP表單→Servlet接收→Service校驗(yàn)→DAO寫庫→事務(wù)回滾觸發(fā)點(diǎn)以“新增藥品入庫單”為例完整調(diào)用鏈如下前端觸發(fā)admin/stockin_add.jsp提交表單關(guān)鍵字段form actionStockInServlet methodpost input typetext namedrugId value1 !-- 藥品ID -- input typetext namequantity value50 !-- 入庫數(shù)量 -- input typedate namevalidPeriod value2025-12-31 !-- 有效期 -- input typesubmit value提交入庫 /formServlet接收src/com/hospital/drug/servlet/StockInServlet.javaprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 獲取參數(shù)已做request.setCharacterEncoding(UTF-8)防亂碼 String drugId request.getParameter(drugId); String quantity request.getParameter(quantity); String validPeriod request.getParameter(validPeriod); // 2. 封裝為StockIn對(duì)象 StockIn stockIn new StockIn(); stockIn.setDrugId(Integer.parseInt(drugId)); stockIn.setQuantity(Integer.parseInt(quantity)); stockIn.setValidPeriod(validPeriod); stockIn.setOperatorId(getCurrentUserId(request)); // 從session取當(dāng)前登錄人 // 3. 調(diào)用Service層關(guān)鍵開啟事務(wù) boolean result stockInService.addStockIn(stockIn); if (result) { request.setAttribute(msg, 入庫成功); } else { request.setAttribute(msg, 入庫失敗請(qǐng)重試); } request.getRequestDispatcher(stockin_list.jsp).forward(request, response); }Service事務(wù)控制src/com/hospital/drug/service/impl/StockInServiceImpl.javaOverride public boolean addStockIn(StockIn stockIn) { Connection conn null; try { conn JDBCUtil.getConnection(); // 從DBCP連接池獲取連接 conn.setAutoCommit(false); // 關(guān)閉自動(dòng)提交開啟事務(wù) // 步驟1插入入庫單主表 int rows1 stockInDao.insertStockIn(conn, stockIn); // 步驟2更新藥品庫存表庫存 入庫數(shù)量 int rows2 drugInfoDao.updateStockByDrugId(conn, stockIn.getDrugId(), stockIn.getQuantity()); if (rows1 0 rows2 0) { conn.commit(); // 兩步都成功才提交 return true; } else { conn.rollback(); // 任一步失敗則回滾 return false; } } catch (SQLException e) { try { if (conn ! null) conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); return false; } finally { JDBCUtil.closeConnection(conn); // 歸還連接到池 } }邏輯說明此處事務(wù)設(shè)計(jì)是本項(xiàng)目最大亮點(diǎn)。它沒有用Spring聲明式事務(wù)而是手動(dòng)控制conn.setAutoCommit(false)確?!叭霂靻斡涗洝焙汀皫齑娓隆币慈晒σ慈?。若updateStockByDrugId執(zhí)行時(shí)因藥品ID不存在拋出異常conn.rollback()會(huì)撤銷已插入的入庫單避免出現(xiàn)“單據(jù)存在但庫存沒加”的數(shù)據(jù)不一致。3.2 庫存預(yù)警功能實(shí)現(xiàn)不是簡(jiǎn)單查count(*)而是用SQL計(jì)算“距效期≤30天”的藥品集合系統(tǒng)首頁右上角顯示“近效期藥品預(yù)警3”數(shù)字來自DrugInfoDao.getNearExpiryDrugs()方法public ListDrugInfo getNearExpiryDrugs() throws SQLException { String sql SELECT * FROM drug_info WHERE DATEDIFF(valid_period, CURDATE()) BETWEEN 0 AND 30 ORDER BY valid_period ASC; return queryRunner.query(sql, new BeanListHandler(DrugInfo.class)); }參數(shù)說明DATEDIFF(valid_period, CURDATE())計(jì)算有效期減去當(dāng)前日期的天數(shù)BETWEEN 0 AND 30篩選剩余0~30天內(nèi)過期的藥品ORDER BY valid_period ASC按有效期升序排列最先過期的排最前BeanListHandlerDbUtils工具類自動(dòng)映射結(jié)果集到DrugInfo對(duì)象列表。此SQL在MySQL 5.7下高效執(zhí)行valid_period字段已建索引無需Java層遍歷判斷避免N1查詢。若你本地MySQL時(shí)區(qū)非東八區(qū)需在db.properties中添加serverTimezoneGMT%2B8否則CURDATE()返回時(shí)間不準(zhǔn)。3.3 采購(gòu)計(jì)劃生成邏輯基于歷史出庫量安全庫存閾值自動(dòng)生成補(bǔ)貨建議點(diǎn)擊“采購(gòu)管理 → 生成采購(gòu)計(jì)劃”觸發(fā)PurchasePlanServlet// 核心算法采購(gòu)數(shù)量 MAX(0, 安全庫存 - 當(dāng)前庫存 近30天平均日出庫量 × 7) String sql SELECT d.id, d.name, d.spec, d.unit, d.stock_quantity AS current_stock, IFNULL(safe_stock, 0) AS safe_stock, IFNULL(avg_daily_out, 0) AS avg_daily_out, GREATEST(0, IFNULL(safe_stock, 0) - d.stock_quantity IFNULL(avg_daily_out, 0) * 7) AS purchase_qty FROM drug_info d LEFT JOIN ( SELECT drug_id, AVG(quantity) AS avg_daily_out FROM stock_out WHERE out_time DATE_SUB(CURDATE(), INTERVAL 30 DAY) GROUP BY drug_id ) t ON d.id t.drug_id WHERE d.stock_quantity IFNULL(safe_stock, 0) OR IFNULL(avg_daily_out, 0) 0;關(guān)鍵設(shè)計(jì)點(diǎn)DATE_SUB(CURDATE(), INTERVAL 30 DAY)精確截取近30天出庫數(shù)據(jù)非模糊“一個(gè)月”GREATEST(0, ...)確保采購(gòu)數(shù)量不為負(fù)數(shù)LEFT JOIN即使某藥品30天內(nèi)無出庫記錄仍會(huì)出現(xiàn)在結(jié)果中avg_daily_out為NULL轉(zhuǎn)為0安全庫存值存在drug_info.safe_stock字段默認(rèn)為0需管理員在藥品編輯頁手動(dòng)設(shè)置。生成結(jié)果頁purchase_plan.jsp中每行顯示藥品名、當(dāng)前庫存、安全庫存、建議采購(gòu)量。點(diǎn)擊“生成采購(gòu)單”按鈕會(huì)批量插入purchase_order表并關(guān)聯(lián)purchase_order_detail明細(xì)表。4. 避坑指南這五個(gè)“看似正常卻讓系統(tǒng)靜默崩潰”的經(jīng)典問題我替你踩過了4.1 現(xiàn)象Tomcat啟動(dòng)成功但訪問http://localhost:8080/drug顯示404控制臺(tái)無ERROR原因web.xml中welcome-file-list配置的首頁文件名與實(shí)際不符。本項(xiàng)目index.jsp位于WebContent/根目錄但web.xml中寫的是welcome-file-list welcome-filelogin.jsp/welcome-file !-- 錯(cuò)應(yīng)為index.jsp -- /welcome-file-list解決打開WebContent/WEB-INF/web.xml將welcome-file內(nèi)容改為index.jsp保存后重啟Tomcat。4.2 現(xiàn)象登錄頁輸入admin/123456后跳轉(zhuǎn)到空白頁瀏覽器地址欄變?yōu)閔ttp://localhost:8080/drug/admin/index.jsp原因LoginServlet中response.sendRedirect(admin/index.jsp)路徑錯(cuò)誤。因項(xiàng)目Context Path為/drug相對(duì)路徑admin/index.jsp會(huì)被解析為/drug/admin/index.jsp但實(shí)際JSP在WebContent/admin/index.jspTomcat找不到該路徑。解決改為絕對(duì)路徑重定向response.sendRedirect(request.getContextPath() /admin/index.jsp);4.3 現(xiàn)象藥品管理頁點(diǎn)擊“編輯”彈出框顯示藥品信息全是null但數(shù)據(jù)庫里數(shù)據(jù)正常原因DrugInfoDao.findById()方法中SQL語句字段名與實(shí)體類屬性名不匹配。原始代碼寫String sql SELECT id,name,spec,unit,price,valid_period,stock_quantity,supplier_id FROM drug_info WHERE id?; // 但DrugInfo實(shí)體類中屬性名為validPeriod駝峰而數(shù)據(jù)庫字段為valid_period下劃線 // DbUtils默認(rèn)按屬性名映射找不到valid_period字段故賦值為null解決兩種方案任選其一方案A推薦在queryRunner.query()中使用new BasicRowProcessor(new GenerousBeanProcessor())自動(dòng)轉(zhuǎn)換下劃線→駝峰方案B修改SQL為SELECT id,name,spec,unit,price,valid_period AS validPeriod,...顯式別名。4.4 現(xiàn)象執(zhí)行入庫操作后庫存數(shù)量沒增加但入庫單記錄已寫入數(shù)據(jù)庫原因drug_info表中stock_quantity字段類型為INT但updateStockByDrugId()方法中SQL寫成String sql UPDATE drug_info SET stock_quantity stock_quantity ? WHERE id ?; // 參數(shù)傳入的是String類型50MySQL隱式轉(zhuǎn)換失敗實(shí)際執(zhí)行為 stock_quantity stock_quantity 0解決確保DAO層參數(shù)為int類型queryRunner.update(conn, sql, Integer.parseInt(quantity), drugId);4.5 現(xiàn)象在IE11或Edge舊版瀏覽器中JSP頁面中文顯示為方塊Chrome正常原因web.xml中未聲明JSP頁面默認(rèn)編碼。IE對(duì)% page contentTypetext/html;charsetUTF-8 %識(shí)別不穩(wěn)定需在web.xml全局配置jsp-config jsp-property-group url-pattern*.jsp/url-pattern page-encodingUTF-8/page-encoding /jsp-property-group /jsp-config解決將上述配置塊加入WebContent/WEB-INF/web.xml的web-app根節(jié)點(diǎn)內(nèi)位置在welcome-file-list之后。5. 進(jìn)階技巧用Log4j埋點(diǎn)Druid監(jiān)控把黑匣子式的JavaWeb請(qǐng)求變成可追蹤的流水線5.1 在關(guān)鍵業(yè)務(wù)點(diǎn)添加Log4j日志讓“誰在什么時(shí)候干了什么”一目了然項(xiàng)目已集成log4j-1.2.17.jar但默認(rèn)只輸出ERROR級(jí)別。要追蹤完整請(qǐng)求鏈需在src/log4j.properties中調(diào)整# 設(shè)置根日志器為INFO級(jí)別輸出到控制臺(tái)和文件 log4j.rootLoggerINFO, stdout, file # 控制臺(tái)輸出開發(fā)階段用 log4j.appender.stdoutorg.apache.log4j.ConsoleAppender log4j.appender.stdout.layoutorg.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1} - %m%n # 文件輸出生產(chǎn)環(huán)境用 log4j.appender.fileorg.apache.log4j.DailyRollingFileAppender log4j.appender.file.Filelogs/app.log log4j.appender.file.layoutorg.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1} - %m%n然后在StockInServlet.doPost()開頭加入日志private static final Logger logger Logger.getLogger(StockInServlet.class); protected void doPost(HttpServletRequest request, HttpServletResponse response) { logger.info(【入庫請(qǐng)求】用戶ID getCurrentUserId(request) , 藥品ID request.getParameter(drugId) , 數(shù)量 request.getParameter(quantity)); // 后續(xù)業(yè)務(wù)邏輯... }效果每次入庫操作控制臺(tái)立即打印2024-06-15 14:22:33 [http-nio-8080-exec-2] INFO StockInServlet - 【入庫請(qǐng)求】用戶ID1, 藥品ID1, 數(shù)量50血淚經(jīng)驗(yàn)曾遇到客戶反饋“昨天下午三點(diǎn)入庫沒成功”翻日志發(fā)現(xiàn)該時(shí)段無任何【入庫請(qǐng)求】記錄立刻定位到是前端JavaScript攔截了表單提交——沒有日志你只能靠猜。5.2 替換DBCP為Druid連接池獲得SQL執(zhí)行耗時(shí)、慢SQL告警、連接泄漏檢測(cè)三大能力db.properties中當(dāng)前配置為DBCPjdbc.driverClassNameorg.apache.commons.dbcp.BasicDataSource jdbc.urljdbc:mysql://localhost:3306/hospital_drug?useUnicodetruecharacterEncodingutf8 jdbc.usernameroot jdbc.password123456替換為Druid需下載druid-1.2.16.jar放入WEB-INF/lib/# Druid配置替換原DBCP jdbc.driverClassNamecom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/hospital_drug?useUnicodetruecharacterEncodingutf8serverTimezoneGMT%2B8 jdbc.usernameroot jdbc.password123456 jdbc.initialSize5 jdbc.minIdle5 jdbc.maxActive20 jdbc.maxWait60000 jdbc.timeBetweenEvictionRunsMillis60000 jdbc.minEvictableIdleTimeMillis300000 jdbc.validationQuerySELECT 1 jdbc.testWhileIdletrue jdbc.testOnBorrowfalse jdbc.testOnReturnfalse然后修改JDBCUtil.java中的getConnection()方法// 原DBCP方式注釋掉 // static { // try { // Properties props new Properties(); // props.load(JDBCUtil.class.getClassLoader().getResourceAsStream(db.properties)); // dataSource BasicDataSourceFactory.createDataSource(props); // } catch (Exception e) { // e.printStackTrace(); // } // } // 新Druid方式 private static DruidDataSource dataSource; static { try { Properties props new Properties(); props.load(JDBCUtil.class.getClassLoader().getResourceAsStream(db.properties)); dataSource (DruidDataSource) DruidDataSourceFactory.createDataSource(props); // 開啟SQL監(jiān)控關(guān)鍵 dataSource.setFilters(stat,wall,log4j); } catch (Exception e) { e.printStackTrace(); } }Druid監(jiān)控面板啟用啟動(dòng)Tomcat后訪問http://localhost:8080/drug/druid/index.html用戶名admin密碼admin可實(shí)時(shí)查看SQL執(zhí)行列表含耗時(shí)、執(zhí)行次數(shù)、參數(shù)綁定值慢SQL執(zhí)行1秒自動(dòng)標(biāo)紅數(shù)據(jù)源狀態(tài)活躍連接數(shù)、等待線程數(shù)Web應(yīng)用統(tǒng)計(jì)URI訪問量、響應(yīng)時(shí)間TOP10。后悔藥某次上線后庫存扣減變慢打開Druid發(fā)現(xiàn)UPDATE drug_info SET stock_quantity ? WHERE id ?平均耗時(shí)2.3秒。點(diǎn)開詳情發(fā)現(xiàn)drug_info表缺索引——給id字段加主鍵索引后耗時(shí)降至15ms。沒有Druid你得靠EXPLAIN一條條查至少浪費(fèi)半天。5.3 用Filter統(tǒng)一處理中文亂碼告別每個(gè)Servlet里寫三行setCharacterEncoding當(dāng)前項(xiàng)目在每個(gè)Servlet的doPost()開頭都寫request.setCharacterEncoding(UTF-8); response.setContentType(text/html;charsetUTF-8);這極易遺漏。新建src/com/hospital/drug/filter/EncodingFilter.javapublic class EncodingFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; // 統(tǒng)一設(shè)置編碼 request.setCharacterEncoding(UTF-8); response.setContentType(text/html;charsetUTF-8); // 放行 chain.doFilter(request, response); } }并在web.xml中注冊(cè)filter filter-nameEncodingFilter/filter-name filter-classcom.hospital.drug.filter.EncodingFilter/filter-class /filter filter-mapping filter-nameEncodingFilter/filter-name url-pattern/*/url-pattern !-- 攔截所有請(qǐng)求 -- /filter-mapping效果從此所有Servlet無需再手動(dòng)設(shè)編碼且Filter在Servlet之前執(zhí)行確保getParameter()拿到的就是UTF-8解碼后的中文。從那以后我每次接手JavaWeb項(xiàng)目第一件事就是加這個(gè)Filter——不是為了炫技而是因?yàn)槁懸淮蝧etCharacterEncoding就會(huì)導(dǎo)致“藥品名稱入庫后變問號(hào)”而排查時(shí)你得翻遍所有Servlet比寫十行業(yè)務(wù)邏輯還累。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取