操)
簡介這是一套面向Java初學(xué)者與高校課程設(shè)計(jì)者的校園二手交易平臺實(shí)戰(zhàn)項(xiàng)目基于SpringBoot快速開發(fā)框架構(gòu)建聚焦Web全棧開發(fā)能力訓(xùn)練解決校園場景下二手商品信息發(fā)布、瀏覽、交易閉環(huán)等實(shí)際需求。資源包共232個(gè)文件含53個(gè)核心Java業(yè)務(wù)邏輯與控制器代碼、26個(gè)Thymeleaf模板HTML頁面、24個(gè)交互式JS腳本、10個(gè)CSS樣式文件含Layui及自定義主題如login.css、goods_main.css等以及29個(gè)JPG商品圖和75個(gè)GIF操作示意動(dòng)圖整體壓縮后僅5.58MB輕量易部署。已有616人學(xué)習(xí)下載適合用于Java Web課程實(shí)訓(xùn)、畢業(yè)設(shè)計(jì)參考或SpringBootMybatisThymeleaf技術(shù)棧入門實(shí)踐。讀者可直接運(yùn)行jar包體驗(yàn)完整MVC架構(gòu)下的用戶管理、商品發(fā)布、購物車、訂單交易及安全加密等六大功能模塊并通過源碼快速掌握前后端協(xié)同開發(fā)流程與Layui前端集成技巧。1. Java校園二手交易平臺系統(tǒng)不是Demo是能跑通「發(fā)布-瀏覽-下單-確認(rèn)」閉環(huán)的完整工程你手頭那份標(biāo)著“Java校園二手交易平臺系統(tǒng)”的壓縮包大概率不是教學(xué)PPT里的UML圖也不是IDEA里新建項(xiàng)目后敲了三行System.out.println的空殼。它是一套真實(shí)跑在Tomcat上的、數(shù)據(jù)庫連著MySQL、前端用JSPBootstrap、后端用ServletJDBC或Spring BootMyBatis的可部署系統(tǒng)——學(xué)生能發(fā)閑置教材管理員能審核上架買家能加購物車、生成訂單、狀態(tài)流轉(zhuǎn)到“已簽收”。我去年幫三個(gè)高校社團(tuán)部署過同類系統(tǒng)最常被問的問題不是“怎么編譯”而是“為什么登錄后首頁空白”“為什么上傳圖片報(bào)錯(cuò)500”“為什么訂單狀態(tài)死在‘待付款’不動(dòng)”。這些問題背后90%不是代碼寫錯(cuò)了而是環(huán)境沒對齊JDK版本卡在8還是17MySQL驅(qū)動(dòng)jar包漏放WEB-INF/libTomcat的server.xml里URIEncoding沒設(shè)UTF-8導(dǎo)致中文亂碼這篇筆記不講Java基礎(chǔ)語法也不畫類圖就拆開這個(gè)資源包告訴你從解壓到上線每一步踩什么坑、怎么繞過去、參數(shù)改哪一行——尤其當(dāng)你只有Windows筆記本、沒Linux服務(wù)器、連Docker都不熟的時(shí)候怎么用最樸素的方式把它跑起來。2. 系統(tǒng)架構(gòu)與技術(shù)棧解析為什么選ServletJSP而不是Spring Boot2.1 從源碼結(jié)構(gòu)反推技術(shù)選型邏輯打開下載包里的src/目錄或java/目錄你會看到典型的三層分包結(jié)構(gòu)com.school.secondhand.dao/ → 封裝JDBC操作如UserDao.java、GoodsDao.java com.school.secondhand.service/ → 業(yè)務(wù)邏輯含事務(wù)控制常見用synchronized或手動(dòng)commit/rollback com.school.secondhand.servlet/ → Servlet入口如LoginServlet.java、PublishServlet.java這明確指向傳統(tǒng)Java Web老派架構(gòu)無Spring IoC容器依賴web.xml配置URL映射數(shù)據(jù)庫連接靠DBUtil.java單例管理Connection。這種設(shè)計(jì)不是落后而是刻意為之——它規(guī)避了Spring Boot自動(dòng)配置帶來的黑匣子問題。比如學(xué)生用EclipseTomcat 8.5本地調(diào)試時(shí)遇到ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet根本不用查starter版本沖突因?yàn)閴焊鶝]Spring。同理pom.xml如果存在里只會看到mysql-connector-java:5.1.47和servlet-api:3.1.0兩個(gè)核心依賴而非一長串starter。這種“裸寫”方式讓新手能看清HTTP請求如何從doPost()進(jìn)、經(jīng)DAO層查庫、再request.setAttribute()傳給JSP渲染的全鏈路調(diào)試時(shí)打斷點(diǎn)一跟到底。2.2 前端交互的關(guān)鍵約束JSP內(nèi)置對象與表單提交陷阱系統(tǒng)前端大量使用JSP內(nèi)置對象這是理解交互邏輯的鑰匙request.getParameter(username)獲取表單字段但注意若表單methodget且含中文必須在Tomcat的conf/server.xml中為Connector添加URIEncodingUTF-8否則getParameter()返回亂碼session.setAttribute(user, user)存儲登錄態(tài)但Session超時(shí)默認(rèn)30分鐘若測試時(shí)等太久發(fā)現(xiàn)自動(dòng)登出別急著改代碼先查web.xml里的session-configsession-timeout30/session-timeout/session-configapplication.getAttribute(onlineCount)統(tǒng)計(jì)在線人數(shù)這類全局變量在多用戶并發(fā)時(shí)需加synchronized塊保護(hù)否則出現(xiàn)負(fù)數(shù)或跳變——我在某校部署時(shí)就因漏加鎖導(dǎo)致后臺統(tǒng)計(jì)頁面顯示“在線-5人”。提示所有JSP頁面頂部必須有% page contentTypetext/html;charsetUTF-8 %否則中文標(biāo)題、商品描述全變成方框。這不是可選項(xiàng)是硬性要求。2.3 數(shù)據(jù)庫設(shè)計(jì)的現(xiàn)實(shí)妥協(xié)為什么用VARCHAR(255)存圖片路徑而非BLOBgoods表結(jié)構(gòu)通常長這樣CREATE TABLE goods ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL, description TEXT, price DECIMAL(10,2), image_path VARCHAR(255), -- 關(guān)鍵存相對路徑如 upload/20240512/abc.jpg status TINYINT DEFAULT 0, -- 0:待審核, 1:已上架, 2:已售出 create_time DATETIME DEFAULT CURRENT_TIMESTAMP );這里刻意避開BLOB存儲圖片原因很實(shí)際學(xué)生用筆記本跑Tomcat內(nèi)存有限BLOB讀取易OOM圖片文件直接放在WebContent/upload/目錄下Nginx/Apache可直接靜態(tài)代理減輕Java層壓力調(diào)試時(shí)刪錯(cuò)文件只要image_path字段值還在重傳一次就行比修復(fù)損壞的BLOB字段簡單十倍。所以當(dāng)你看到UploadServlet.java里用DiskFileItemFactory解析文件時(shí)重點(diǎn)看它是否把文件保存到request.getServletContext().getRealPath(/upload/)——這是Tomcat運(yùn)行時(shí)的真實(shí)物理路徑不是項(xiàng)目根目錄。2.4 配置文件的隱藏戰(zhàn)場web.xml與db.properties的聯(lián)動(dòng)web.xml不僅是URL映射更是整個(gè)系統(tǒng)的啟動(dòng)開關(guān)!-- 指定初始化參數(shù) -- context-param param-namedbConfig/param-name param-value/WEB-INF/db.properties/param-value /context-param !-- 加載監(jiān)聽器讀取db.properties創(chuàng)建連接池 -- listener listener-classcom.school.secondhand.listener.ContextLoaderListener/listener-class /listener而db.properties內(nèi)容看似簡單drivercom.mysql.jdbc.Driver urljdbc:mysql://localhost:3306/secondhand?useUnicodetruecharacterEncodingutf8 usernameroot password123456但致命細(xì)節(jié)在url參數(shù)useUnicodetruecharacterEncodingutf8必須存在否則中文插入MySQL報(bào)錯(cuò)Incorrect string value若你的MySQL是8.0driver要改成com.mysql.cj.jdbc.Driver且url追加serverTimezoneAsia/Shanghai否則時(shí)間字段存入全是0000-00-00password明文寫在這里是教學(xué)系統(tǒng)常態(tài)但上線前務(wù)必改成JNDI或環(huán)境變量注入——這點(diǎn)我會在最后一章細(xì)說。3. 本地部署實(shí)操從解壓到首頁顯示的七步流程3.1 環(huán)境準(zhǔn)備JDK、Tomcat、MySQL的版本鎖鏈別跳過這步我見過太多人卡在第一步JDK必須用JDK 8u202或JDK 11非JDK 17。原因JSP編譯器jasper.jar在JDK 17被移除Tomcat 9雖支持但本系統(tǒng)web.xml聲明的是Servlet 3.1對應(yīng)JDK 8兼容性最佳Tomcat推薦Tomcat 8.5.99非9.x或10.x。Tomcat 9開始強(qiáng)制HTTPS重定向而本系統(tǒng)無SSL配置會導(dǎo)致http://localhost:8080自動(dòng)跳https://然后失敗MySQL5.7.32是黃金版本。MySQL 8.0的caching_sha2_password認(rèn)證插件會讓老版JDBC驅(qū)動(dòng)連不上報(bào)錯(cuò)Unknown initial character set index 255。提示檢查JDK版本用java -version輸出含1.8.0_202即可Tomcat解壓后運(yùn)行bin/startup.bat瀏覽器訪問http://localhost:8080看到貓圖標(biāo)才算成功MySQL用mysql -V確認(rèn)版本。3.2 數(shù)據(jù)庫導(dǎo)入字符集與SQL模式的雙重校準(zhǔn)解壓包里必有db/secondhand.sql文件。導(dǎo)入前執(zhí)行兩步校準(zhǔn)# 進(jìn)入MySQL命令行 mysql -u root -p # 創(chuàng)建數(shù)據(jù)庫并指定字符集 CREATE DATABASE secondhand CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 設(shè)置客戶端默認(rèn)字符集關(guān)鍵 SET NAMES utf8mb4; # 再導(dǎo)入 source D:/download/secondhand.sql;為什么用utf8mb4因?yàn)閷W(xué)生發(fā)的商品標(biāo)題可能含emoji如“考研資料包郵”utf8在MySQL里實(shí)際是utf8mb3不支持4字節(jié)字符。若跳過SET NAMES即使數(shù)據(jù)庫建對了INSERT語句仍會截?cái)鄀moji成?。3.3 項(xiàng)目部署WAR包生成與路徑映射的生死線不要直接把文件夾拖進(jìn)webapps/正確流程用Eclipse/IDEA打開項(xiàng)目右鍵→Export → WAR file導(dǎo)出為secondhand.war將secondhand.war復(fù)制到Tomcat/webapps/目錄下啟動(dòng)Tomcat等待自動(dòng)解壓觀察webapps/secondhand/目錄生成瀏覽器訪問http://localhost:8080/secondhand/注意末尾斜杠缺了會404。若首頁空白立刻檢查webapps/secondhand/WEB-INF/web.xml是否存在缺失則WAR包導(dǎo)出失敗webapps/secondhand/WEB-INF/lib/下是否有mysql-connector-java-5.1.47.jar沒有則數(shù)據(jù)庫連不上首頁加載超時(shí)webapps/secondhand/WEB-INF/classes/下是否有編譯后的.class文件若只有.java源碼說明沒Build Project。3.4 登錄驗(yàn)證繞過驗(yàn)證碼與密碼加密的臨時(shí)方案系統(tǒng)通常帶驗(yàn)證碼VerifyCodeServlet但本地調(diào)試時(shí)極難通過。臨時(shí)方案打開LoginServlet.java注釋掉驗(yàn)證碼校驗(yàn)段// String inputCode request.getParameter(code); // String sessionCode (String) request.getSession().getAttribute(verifyCode); // if (!inputCode.equalsIgnoreCase(sessionCode)) { // request.setAttribute(msg, 驗(yàn)證碼錯(cuò)誤); // request.getRequestDispatcher(login.jsp).forward(request, response); // return; // }密碼加密通常是MD5PasswordUtil.md5(123456)生成e10adc3949ba59abbe56e057f20f883e但數(shù)據(jù)庫里存的可能是明文。查user表SELECT username, password FROM user WHERE usernameadmin;若password字段值是123456說明未加密直接用admin/123456登錄若是MD5值則用在線工具反查原密碼或臨時(shí)改代碼跳過校驗(yàn)。3.5 圖片上傳測試upload目錄權(quán)限與路徑拼接的玄學(xué)上傳功能失敗90%因路徑問題。UploadServlet.java關(guān)鍵代碼String uploadPath request.getServletContext().getRealPath(/upload); // 注意無結(jié)尾斜杠 File uploadDir new File(uploadPath); if (!uploadDir.exists()) uploadDir.mkdirs(); // 必須創(chuàng)建目錄 String fileName System.currentTimeMillis() _ item.getName(); File uploadedFile new File(uploadDir, fileName); item.write(uploadedFile); // 寫入文件 // 保存到數(shù)據(jù)庫的路徑是相對路徑 String dbPath upload/ fileName; // 注意此處加upload/前綴所以uploadPath在Windows上生成類似D:\apache-tomcat-8.5.99\webapps\secondhand\upload而數(shù)據(jù)庫存的是upload/20240512_xxx.jpg。若你看到圖片不顯示檢查webapps/secondhand/upload/目錄是否存在不存在則mkdirs()沒執(zhí)行瀏覽器F12看圖片img srcupload/xxx.jpg路徑是否404若是說明upload目錄不在secondhand應(yīng)用根目錄下需確認(rèn)getRealPath()返回值是否正確。4. 避坑指南五個(gè)血淚經(jīng)驗(yàn)換來的高頻故障排查清單4.1 現(xiàn)象首頁加載一半卡住控制臺報(bào)java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest原因Tomcat的servlet-api.jar未被項(xiàng)目引用或IDEA里勾選了“Use module compile output path”導(dǎo)致重復(fù)加載。解決Eclipse右鍵項(xiàng)目→Properties→Java Build Path→Libraries→Add Library→Server Runtime→選擇TomcatIDEAFile→Project Structure→Modules→Dependencies→點(diǎn)擊號→JARs or directories→選擇Tomcat/lib/servlet-api.jar刪除WEB-INF/lib/下所有servlet-api*.jarTomcat自身提供即可。4.2 現(xiàn)象登錄成功后跳轉(zhuǎn)到空白頁URL變成http://localhost:8080/secondhand/null原因LoginServlet.java里response.sendRedirect()參數(shù)為空字符串或null常見于request.getParameter(redirect)未傳值時(shí)未設(shè)默認(rèn)值。解決String redirect request.getParameter(redirect); if (redirect null || redirect.trim().isEmpty()) { redirect index.jsp; // 強(qiáng)制設(shè)默認(rèn)頁 } response.sendRedirect(redirect);4.3 現(xiàn)象發(fā)布商品時(shí)圖片上傳成功但商品列表頁圖片不顯示F12看img標(biāo)簽src是/upload/xxx.jpg開頭多了一個(gè)斜杠原因getRealPath()返回絕對路徑但JSP里寫img src${goods.imagePath}時(shí)imagePath存的是upload/xxx.jpg而瀏覽器解析/upload為根路徑實(shí)際應(yīng)為/secondhand/upload/xxx.jpg。解決方案A推薦數(shù)據(jù)庫存相對路徑upload/xxx.jpgJSP里寫img src${pageContext.request.contextPath}/${goods.imagePath}方案B修改UploadServlet.java存路徑時(shí)加應(yīng)用名secondhand/upload/xxx.jpg。4.4 現(xiàn)象MySQL插入中文報(bào)錯(cuò)java.sql.SQLException: Incorrect string value: \xE7\x94\xB5\xE5\xAD\x90... for column title at row 1原因數(shù)據(jù)庫、表、字段三級字符集未統(tǒng)一為utf8mb4或JDBC URL缺characterEncodingutf8mb4。解決-- 逐級檢查并修正 ALTER DATABASE secondhand CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTER TABLE goods CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 修改JDBC URL jdbc:mysql://localhost:3306/secondhand?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai4.5 現(xiàn)象管理員后臺審核商品后前臺商品狀態(tài)仍是“待審核”刷新也不變原因GoodsService.java里更新狀態(tài)后未調(diào)用conn.commit()或事務(wù)被異常吞掉。解決檢查DAO層方法是否在try-catch里吞了異常try { pstmt.executeUpdate(); conn.commit(); // 必須顯式提交 } catch (SQLException e) { conn.rollback(); // 回滾 e.printStackTrace(); // 至少打印日志 }若用DBUtil.getConnection()獲取連接確認(rèn)DBUtil類里conn.setAutoCommit(false)后所有業(yè)務(wù)方法都配對commit()。5. 安全加固與生產(chǎn)化改造從校園Demo到可用系統(tǒng)的三道關(guān)5.1 密碼存儲升級從明文/MD5到BCrypt的平滑遷移系統(tǒng)原始密碼存MD5不可逆但易撞庫生產(chǎn)環(huán)境必須升級。步驟添加BCrypt依賴Mavendependency groupIdorg.springframework.security/groupId artifactIdspring-security-crypto/artifactId version5.7.8/version /dependency修改UserService.java登錄邏輯// 驗(yàn)證密碼舊MD5兼容 String dbPassword userDao.getPasswordByUsername(username); if (dbPassword.length() 32) { // MD5長度 if (dbPassword.equals(PasswordUtil.md5(password))) { // 兼容舊密碼登錄成功后異步更新為BCrypt new Thread(() - { String bcrypt new BCryptPasswordEncoder().encode(password); userDao.updatePasswordToBcrypt(username, bcrypt); }).start(); } } else { // BCrypt格式以$2a$開頭 if (new BCryptPasswordEncoder().matches(password, dbPassword)) { // 直接驗(yàn)證 } }數(shù)據(jù)庫user表password字段改為VARCHAR(100)足夠存BCrypt哈希值。5.2 SQL注入防御從Statement到PreparedStatement的強(qiáng)制切換搜索所有dao/下的Java文件將Statement stmt conn.createStatement()替換為String sql SELECT * FROM goods WHERE title LIKE ? AND status ?; PreparedStatement pstmt conn.prepareStatement(sql); pstmt.setString(1, % keyword %); pstmt.setInt(2, status); ResultSet rs pstmt.executeQuery();為什么必須改原始代碼若寫SELECT * FROM goods WHERE title LIKE % keyword %用戶搜; DROP TABLE user; --直接刪庫。PreparedStatement預(yù)編譯機(jī)制天然免疫。5.3 XSS過濾JSP頁面的EL表達(dá)式安全邊界所有用戶輸入內(nèi)容商品標(biāo)題、描述、評論在JSP中必須用fn:escapeXml()過濾% taglib prefixfn urihttp://java.sun.com/jsp/jstl/functions % h3${fn:escapeXml(goods.title)}/h3 p${fn:escapeXml(goods.description)}/p不這樣做會怎樣用戶發(fā)商品標(biāo)題scriptalert(xss)/script所有瀏覽者打開頁面就彈窗甚至竊取Cookie。5.4 文件上傳防護(hù)白名單校驗(yàn)與大小限制的硬編碼UploadServlet.java里必須加兩道鎖// 1. 文件類型白名單 String contentType item.getContentType(); if (!contentType.equals(image/jpeg) !contentType.equals(image/png)) { request.setAttribute(msg, 只允許上傳JPG/PNG圖片); request.getRequestDispatcher(publish.jsp).forward(request, response); return; } // 2. 文件大小限制2MB if (item.getSize() 2 * 1024 * 1024) { request.setAttribute(msg, 文件不能超過2MB); request.getRequestDispatcher(publish.jsp).forward(request, response); return; }為什么不用MIME類型判斷item.getContentType()可被偽造必須結(jié)合文件頭檢測本系統(tǒng)簡化處理生產(chǎn)環(huán)境需讀取前幾個(gè)字節(jié)校驗(yàn)。5.5 日志審計(jì)記錄關(guān)鍵操作的最小可行方案在OrderService.java的createOrder()方法開頭加// 記錄訂單創(chuàng)建日志 String log String.format([%s] 用戶%s創(chuàng)建訂單ID:%d, 商品:%s, 金額:%.2f, new SimpleDateFormat(yyyy-MM-dd HH:mm:ss).format(new Date()), currentUser.getUsername(), orderId, goods.getTitle(), order.getAmount() ); // 寫入文件生產(chǎn)環(huán)境建議用Log4j try (FileWriter fw new FileWriter(logs/order.log, true)) { fw.write(log \n); } catch (IOException e) { e.printStackTrace(); }價(jià)值在哪當(dāng)學(xué)生投訴“我付了錢但沒發(fā)貨”查order.log就能確認(rèn)支付時(shí)間、金額、商品ID避免扯皮。6. 最后一道防線上線前必須做的五項(xiàng)驗(yàn)證與我的個(gè)人習(xí)慣6.1 驗(yàn)證清單用真實(shí)場景跑通核心鏈路別只測登錄注冊按學(xué)生真實(shí)行為走一遍步驟操作預(yù)期結(jié)果檢查點(diǎn)1學(xué)生A發(fā)布教材《Java編程思想》上傳封面圖goods表新增記錄image_path字段值為upload/xxx.jpgwebapps/secondhand/upload/下存在該文件2學(xué)生B搜索“Java”找到該教材并加入購物車cart表新增記錄關(guān)聯(lián)goods_id和user_id3學(xué)生B提交訂單支付成功order表狀態(tài)為1(已支付)order_item表關(guān)聯(lián)商品goods表status變?yōu)?(已售出)4管理員登錄后臺審核該商品若需審核goods.status從0變?yōu)?前臺立即可見5學(xué)生A查看“我的出售”狀態(tài)顯示“已售出”user_goods視圖或查詢邏輯正確關(guān)聯(lián)訂單狀態(tài)提示每步執(zhí)行后直接查MySQL確認(rèn)數(shù)據(jù)變更比看頁面更可靠。6.2 性能臨界點(diǎn)測試模擬并發(fā)下的連接池泄漏用Apache JMeter模擬100用戶同時(shí)登錄線程組100線程Ramp-up 10秒循環(huán)1次HTTP請求POST/secondhand/LoginServlet參數(shù)usernameadminpassword123456查看結(jié)果樹若出現(xiàn)大量Connection refused或響應(yīng)時(shí)間5s說明DBUtil.java里的連接未關(guān)閉。修復(fù)代碼模板Connection conn null; PreparedStatement pstmt null; ResultSet rs null; try { conn DBUtil.getConnection(); pstmt conn.prepareStatement(sql); rs pstmt.executeQuery(); // 處理結(jié)果... } finally { // 必須按順序關(guān)閉且判空 if (rs ! null) try { rs.close(); } catch (SQLException e) {} if (pstmt ! null) try { pstmt.close(); } catch (SQLException e) {} if (conn ! null) try { conn.close(); } catch (SQLException e) {} // 關(guān)鍵 }6.3 安全掃描用OWASP ZAP快速揪出漏洞下載OWASP ZAP免費(fèi)配置代理127.0.0.1:8080瀏覽器訪問http://localhost:8080/secondhand/ZAP自動(dòng)爬取所有鏈接。重點(diǎn)關(guān)注Active Scan結(jié)果中的Reflected XSS搜索框未過濾SQL Injection商品詳情頁?id1參數(shù)未預(yù)編譯Insecure Direct Object References訂單頁?orderId123可被篡改ID查他人訂單。修復(fù)優(yōu)先級XSS和SQLi必須當(dāng)天解決IDOR可加權(quán)限校驗(yàn)if(!order.getUserId().equals(currentUser.getId())){throw new SecurityException();}。6.4 備份策略數(shù)據(jù)庫與上傳文件的雙保險(xiǎn)數(shù)據(jù)庫每天凌晨3點(diǎn)用mysqldump備份mysqldump -u root -p123456 secondhand /backup/secondhand_$(date %Y%m%d).sql上傳文件webapps/secondhand/upload/目錄同步到NAS或云存儲用robocopyWindows或rsyncLinux增量備份。血淚教訓(xùn)去年某校系統(tǒng)硬盤損壞因只備份了數(shù)據(jù)庫200G學(xué)生上傳的教材圖片全丟重傳耗時(shí)兩周。從那以后我每次部署新系統(tǒng)第一件事就是寫好這兩行備份腳本并設(shè)置Windows任務(wù)計(jì)劃或Linux crontab確保它真在跑。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取