戰(zhàn):Java畢業(yè)設(shè)計(jì)會(huì)議管理系統(tǒng)核心實(shí)現(xiàn)與避坑指南)
簡(jiǎn)介本資源為基于SSM框架的會(huì)議管理系統(tǒng)畢業(yè)設(shè)計(jì)完整項(xiàng)目包面向高校計(jì)算機(jī)相關(guān)專業(yè)學(xué)生及Java初學(xué)者可用于畢業(yè)設(shè)計(jì)、課程設(shè)計(jì)或期末大作業(yè)。項(xiàng)目采用SSM后臺(tái)框架前端使用HTML/JSP/Vue數(shù)據(jù)庫(kù)為MySQL開發(fā)環(huán)境為IDEA部署依賴Tomcat與Maven代碼注釋詳盡新手也能看懂。壓縮包共1068個(gè)文件約77.99MB涵蓋178個(gè)Java源文件、124個(gè)Vue組件、322個(gè)SVG圖標(biāo)、44個(gè)XML配置及SQL腳本等前后端代碼與數(shù)據(jù)庫(kù)腳本一應(yīng)俱全。系統(tǒng)功能完善、界面美觀、操作簡(jiǎn)單涵蓋會(huì)議管理核心業(yè)務(wù)模塊經(jīng)過嚴(yán)格調(diào)試可穩(wěn)定運(yùn)行。已有69人學(xué)習(xí)關(guān)注下載后簡(jiǎn)單部署即可使用適合作為高分畢設(shè)參考幫助讀者快速掌握SSM整合開發(fā)流程與項(xiàng)目部署思路。1. 會(huì)議管理系統(tǒng)到底在管什么從一場(chǎng)跨部門周會(huì)說(shuō)起很多同學(xué)做 Java 畢業(yè)設(shè)計(jì)時(shí)一看到“會(huì)議管理系統(tǒng)”就覺得沒什么技術(shù)含量無(wú)非是增刪改查。但真正動(dòng)手寫起來(lái)你會(huì)發(fā)現(xiàn)這個(gè)題目的復(fù)雜度被嚴(yán)重低估了。一場(chǎng)跨部門周會(huì)從發(fā)起預(yù)約、審批會(huì)議室、通知參會(huì)人、簽到、記錄紀(jì)要、跟蹤待辦到會(huì)后歸檔整條鏈路涉及角色權(quán)限、時(shí)間沖突檢測(cè)、狀態(tài)流轉(zhuǎn)、消息觸達(dá)等多個(gè)工程問題?;?SSMSpring SpringMVC MyBatis來(lái)實(shí)現(xiàn)這套系統(tǒng)恰好能把 Java Web 開發(fā)的核心能力串起來(lái)控制層路由、業(yè)務(wù)層事務(wù)、持久層映射、前后端數(shù)據(jù)交互一個(gè)都跑不掉。這篇文章面向正在做 Java 畢業(yè)設(shè)計(jì)、選了會(huì)議管理系統(tǒng)這個(gè)題目的同學(xué)也面向想用 SSM 練手一個(gè)完整業(yè)務(wù)系統(tǒng)的開發(fā)者。我會(huì)把需求拆解、數(shù)據(jù)庫(kù)設(shè)計(jì)、核心代碼實(shí)現(xiàn)、常見踩坑點(diǎn)講清楚讓你看完能直接動(dòng)手復(fù)現(xiàn)而不是停留在“知道有這么個(gè)東西”的層面。選 SSM 而不是 Spring Boot理由也很實(shí)際很多高校的畢設(shè)答辯環(huán)境對(duì)版本和依賴有固定要求SSM 的 XML 配置方式雖然繁瑣但勝在可控、可解釋答辯時(shí)你能說(shuō)清楚每一層在干什么。2. 需求拆解與數(shù)據(jù)庫(kù)設(shè)計(jì)先想清楚再建表2.1 三類角色與核心用例會(huì)議管理系統(tǒng)的角色通常分三種普通員工、部門管理員、系統(tǒng)管理員。普通員工能發(fā)起會(huì)議申請(qǐng)、查看自己被邀請(qǐng)的會(huì)議、簽到、查看紀(jì)要部門管理員多一個(gè)審批會(huì)議申請(qǐng)的權(quán)限以及管理本部門會(huì)議室系統(tǒng)管理員負(fù)責(zé)用戶管理、會(huì)議室資源管理、全局配置。核心用例可以歸納為六條主線用戶登錄與權(quán)限校驗(yàn)、會(huì)議申請(qǐng)與審批、會(huì)議室預(yù)約與沖突檢測(cè)、參會(huì)通知與簽到、會(huì)議紀(jì)要記錄與歸檔、待辦事項(xiàng)跟蹤。這六條線不是并列關(guān)系而是有先后依賴的。比如沖突檢測(cè)必須在審批通過之前完成否則會(huì)出現(xiàn)兩個(gè)會(huì)議搶同一間會(huì)議室的情況。我一般會(huì)先畫一張狀態(tài)流轉(zhuǎn)圖不用工具紙上畫就行把會(huì)議狀態(tài)定義為待審批 → 已通過 → 進(jìn)行中 → 已結(jié)束 → 已歸檔外加一個(gè)已駁回的旁支。狀態(tài)流轉(zhuǎn)清楚了后面寫業(yè)務(wù)代碼時(shí)就不會(huì)出現(xiàn)“這個(gè)字段到底該不該改”的猶豫。2.2 數(shù)據(jù)庫(kù)表設(shè)計(jì)與字段說(shuō)明數(shù)據(jù)庫(kù)設(shè)計(jì)是整個(gè)系統(tǒng)的地基。表建得合理后面寫 SQL 和業(yè)務(wù)代碼會(huì)順很多表建得隨意后面到處打補(bǔ)丁。下面是核心表的設(shè)計(jì)方案以 MySQL 為例。用戶表 t_user字段名類型說(shuō)明idbigint主鍵自增usernamevarchar(50)登錄名唯一索引passwordvarchar(128)密碼存 MD5 加鹽值real_namevarchar(50)真實(shí)姓名roletinyint角色1 員工2 部門管理員3 系統(tǒng)管理員dept_idbigint所屬部門 IDstatustinyint狀態(tài)1 正常0 禁用create_timedatetime創(chuàng)建時(shí)間會(huì)議室表 t_room字段名類型說(shuō)明idbigint主鍵room_namevarchar(100)會(huì)議室名稱capacityint容納人數(shù)locationvarchar(200)位置描述equipmentvarchar(500)設(shè)備清單逗號(hào)分隔statustinyint1 可用0 維護(hù)中會(huì)議表 t_meeting字段名類型說(shuō)明idbigint主鍵titlevarchar(200)會(huì)議主題room_idbigint會(huì)議室 IDinitiator_idbigint發(fā)起人 IDstart_timedatetime開始時(shí)間end_timedatetime結(jié)束時(shí)間statustinyint1 待審批2 已通過3 進(jìn)行中4 已結(jié)束5 已駁回6 已歸檔attendee_idstext參會(huì)人 ID 列表逗號(hào)分隔descriptiontext會(huì)議說(shuō)明create_timedatetime創(chuàng)建時(shí)間會(huì)議紀(jì)要表 t_minutes字段名類型說(shuō)明idbigint主鍵meeting_idbigint關(guān)聯(lián)會(huì)議 IDcontenttext紀(jì)要內(nèi)容recorder_idbigint記錄人 IDcreate_timedatetime記錄時(shí)間待辦表 t_todo字段名類型說(shuō)明idbigint主鍵meeting_idbigint關(guān)聯(lián)會(huì)議 IDassignee_idbigint負(fù)責(zé)人 IDcontentvarchar(500)待辦內(nèi)容deadlinedatetime截止時(shí)間statustinyint0 未完成1 已完成這里有一個(gè)設(shè)計(jì)決策值得展開說(shuō)參會(huì)人用逗號(hào)分隔存在一個(gè)字段里還是單獨(dú)建一張關(guān)聯(lián)表單獨(dú)建關(guān)聯(lián)表t_meeting_attendee在范式上更規(guī)范查詢也更靈活比如“查某人參加過的所有會(huì)議”用 JOIN 很直接。但逗號(hào)分隔的方式在插入和讀取時(shí)少一次關(guān)聯(lián)查詢對(duì)于畢設(shè)這種數(shù)據(jù)量不大的場(chǎng)景夠用。我的建議是如果你答辯時(shí)老師可能追問數(shù)據(jù)庫(kù)范式就用關(guān)聯(lián)表如果更關(guān)注開發(fā)速度逗號(hào)分隔也能接受但要在查詢時(shí)注意用 FIND_IN_SET 函數(shù)。-- 建庫(kù)語(yǔ)句 CREATE DATABASE meeting_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 用戶表 CREATE TABLE t_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(128) NOT NULL, real_name VARCHAR(50) NOT NULL, role TINYINT NOT NULL DEFAULT 1, dept_id BIGINT, status TINYINT NOT NULL DEFAULT 1, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; -- 會(huì)議表注意時(shí)間字段加索引沖突檢測(cè)會(huì)頻繁查詢 CREATE TABLE t_meeting ( id BIGINT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, room_id BIGINT NOT NULL, initiator_id BIGINT NOT NULL, start_time DATETIME NOT NULL, end_time DATETIME NOT NULL, status TINYINT NOT NULL DEFAULT 1, attendee_ids TEXT, description TEXT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_room_time (room_id, start_time, end_time) ) ENGINEInnoDB;上面建表語(yǔ)句里idx_room_time這個(gè)聯(lián)合索引是專門為沖突檢測(cè)查詢準(zhǔn)備的。沖突檢測(cè)的 SQL 邏輯是查同一間會(huì)議室、狀態(tài)不是已駁回或已歸檔、且時(shí)間段有重疊的記錄。沒有這個(gè)索引每次檢測(cè)都全表掃描數(shù)據(jù)量一上來(lái)就慢。2.3 沖突檢測(cè)的 SQL 邏輯時(shí)間沖突的判斷條件是已有會(huì)議的 start_time 小于新會(huì)議的 end_time且已有會(huì)議的 end_time 大于新會(huì)議的 start_time。這個(gè)條件覆蓋了三種重疊情況完全包含、部分重疊、被包含。SELECT COUNT(*) FROM t_meeting WHERE room_id #{roomId} AND status NOT IN (5, 6) AND start_time #{endTime} AND end_time #{startTime}參數(shù)說(shuō)明roomId 是待預(yù)約的會(huì)議室 IDstartTime 和 endTime 是新會(huì)議的時(shí)間段。status NOT IN (5, 6) 排除了已駁回和已歸檔的會(huì)議這兩種狀態(tài)不占用會(huì)議室資源。返回 COUNT 大于 0 就說(shuō)明有沖突需要提示用戶換時(shí)間或換會(huì)議室。3. SSM 三層架構(gòu)落地從 Controller 到 Mapper 的完整鏈路3.1 項(xiàng)目結(jié)構(gòu)與依賴配置SSM 項(xiàng)目的標(biāo)準(zhǔn)結(jié)構(gòu)是controller 層負(fù)責(zé)接收請(qǐng)求和返回響應(yīng)service 層寫業(yè)務(wù)邏輯和事務(wù)控制daomapper層負(fù)責(zé)數(shù)據(jù)庫(kù)操作。配置文件包括 spring-dao.xml數(shù)據(jù)源和 MyBatis 整合、spring-service.xml事務(wù)和 service 掃描、spring-mvc.xmlMVC 注解驅(qū)動(dòng)和視圖解析器、web.xml前端控制器和監(jiān)聽器。Maven 依賴的核心坐標(biāo)包括spring-webmvc、spring-jdbc、spring-tx、mybatis、mybatis-spring、mysql-connector-java、druid連接池、jstl、servlet-api。版本選擇上Spring 用 5.xMyBatis 用 3.5.xMySQL 驅(qū)動(dòng)用 8.x注意驅(qū)動(dòng)類名是 com.mysql.cj.jdbc.Driver。!-- pom.xml 核心依賴片段 -- dependencies dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.3.30/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.1.2/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.20/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency /dependencies這段依賴配置里druid 連接池不是必須的但用它比用 Spring 自帶的 DriverManagerDataSource 要好因?yàn)?druid 提供了連接監(jiān)控和 SQL 統(tǒng)計(jì)功能調(diào)試階段能幫你看清楚哪些 SQL 執(zhí)行慢。mybatis-spring 的版本要和 mybatis 主包版本匹配否則可能出現(xiàn) NoSuchMethodError。3.2 會(huì)議申請(qǐng)與沖突檢測(cè)的 Service 實(shí)現(xiàn)Service 層是業(yè)務(wù)邏輯的核心。會(huì)議申請(qǐng)這個(gè)操作涉及三個(gè)步驟校驗(yàn)時(shí)間合法性、檢測(cè)會(huì)議室沖突、插入會(huì)議記錄。這三個(gè)步驟必須在同一個(gè)事務(wù)里否則可能出現(xiàn)沖突檢測(cè)通過了但插入失敗、或者插入成功了但沖突檢測(cè)沒做完的情況。Service public class MeetingServiceImpl implements MeetingService { Autowired private MeetingMapper meetingMapper; Override Transactional(rollbackFor Exception.class) public Result createMeeting(Meeting meeting) { // 1. 基礎(chǔ)校驗(yàn)結(jié)束時(shí)間必須晚于開始時(shí)間 if (meeting.getEndTime().before(meeting.getStartTime())) { return Result.fail(結(jié)束時(shí)間不能早于開始時(shí)間); } // 2. 沖突檢測(cè) int conflictCount meetingMapper.countConflict( meeting.getRoomId(), meeting.getStartTime(), meeting.getEndTime() ); if (conflictCount 0) { return Result.fail(該時(shí)間段會(huì)議室已被占用請(qǐng)調(diào)整時(shí)間或更換會(huì)議室); } // 3. 插入記錄狀態(tài)設(shè)為待審批 meeting.setStatus(1); meeting.setCreateTime(new Date()); meetingMapper.insert(meeting); return Result.success(申請(qǐng)已提交等待審批); } }這段代碼的關(guān)鍵點(diǎn)有三個(gè)。第一Transactional(rollbackFor Exception.class)指定了回滾異常類型默認(rèn)只回滾 RuntimeException加上 rollbackFor 后受檢異常也會(huì)觸發(fā)回滾。第二沖突檢測(cè)放在插入之前但即使這樣在高并發(fā)場(chǎng)景下仍可能出現(xiàn)兩個(gè)請(qǐng)求同時(shí)通過檢測(cè)然后都插入的情況這就是所謂的“幻讀”問題。解決辦法是在 countConflict 查詢時(shí)加FOR UPDATE鎖或者對(duì)會(huì)議室 ID 加分布式鎖。畢設(shè)場(chǎng)景下并發(fā)量不大但答辯時(shí)老師可能會(huì)問這個(gè)問題提前想好答案。第三返回結(jié)果用統(tǒng)一的 Result 對(duì)象封裝包含 code、msg、data 三個(gè)字段前端根據(jù) code 判斷成功還是失敗。3.3 MyBatis Mapper XML 的編寫要點(diǎn)Mapper XML 是 SSM 里最容易出問題的地方。常見錯(cuò)誤包括namespace 寫錯(cuò)導(dǎo)致綁定不上、resultMap 字段映射不對(duì)導(dǎo)致查出來(lái)是 null、動(dòng)態(tài) SQL 的 if 條件拼錯(cuò)導(dǎo)致 SQL 語(yǔ)法錯(cuò)誤。mapper namespacecom.demo.dao.MeetingMapper resultMap idmeetingMap typecom.demo.entity.Meeting id columnid propertyid/ result columntitle propertytitle/ result columnroom_id propertyroomId/ result columnstart_time propertystartTime/ result columnend_time propertyendTime/ result columnstatus propertystatus/ /resultMap select idcountConflict resultTypeint SELECT COUNT(*) FROM t_meeting WHERE room_id #{roomId} AND status NOT IN (5, 6) AND start_time lt; #{endTime} AND end_time gt; #{startTime} /select insert idinsert parameterTypecom.demo.entity.Meeting useGeneratedKeystrue keyPropertyid INSERT INTO t_meeting (title, room_id, initiator_id, start_time, end_time, status, attendee_ids, description) VALUES (#{title}, #{roomId}, #{initiatorId}, #{startTime}, #{endTime}, #{status}, #{attendeeIds}, #{description}) /insert /mapperXML 里和必須轉(zhuǎn)義為lt;和gt;這是新手最容易翻車的地方不轉(zhuǎn)義直接報(bào) SQL 語(yǔ)法錯(cuò)誤。useGeneratedKeystrue keyPropertyid讓插入后能把自增主鍵回填到實(shí)體對(duì)象里后面如果需要用這個(gè) ID 關(guān)聯(lián)其他表就靠它。resultMap 里 column 是數(shù)據(jù)庫(kù)字段名property 是 Java 實(shí)體屬性名下劃線和駝峰之間的轉(zhuǎn)換必須手動(dòng)配或者開啟 MyBatis 的 mapUnderscoreToCamelCase 配置。3.4 Controller 層與前后端數(shù)據(jù)交互Controller 層負(fù)責(zé)接收前端請(qǐng)求、調(diào)用 Service、返回 JSON 數(shù)據(jù)。SSM 里用 RestController 或 Controller ResponseBody 來(lái)返回 JSON。RestController RequestMapping(/meeting) public class MeetingController { Autowired private MeetingService meetingService; PostMapping(/create) public Result create(RequestBody Meeting meeting, HttpSession session) { User user (User) session.getAttribute(loginUser); if (user null) { return Result.fail(請(qǐng)先登錄); } meeting.setInitiatorId(user.getId()); return meetingService.createMeeting(meeting); } GetMapping(/list) public Result list(RequestParam(defaultValue 1) int page, RequestParam(defaultValue 10) int size, HttpSession session) { User user (User) session.getAttribute(loginUser); PageInfoMeeting pageInfo meetingService.listByUser(user.getId(), page, size); return Result.success(pageInfo); } }這里用 HttpSession 存登錄用戶信息是最簡(jiǎn)單的權(quán)限控制方式。攔截器里檢查 session 中是否有 loginUser沒有就跳轉(zhuǎn)登錄頁(yè)。分頁(yè)查詢用 PageHelper 插件在 Service 里調(diào)PageHelper.startPage(page, size)再執(zhí)行查詢返回的 list 會(huì)被自動(dòng)包裝成 PageInfo 對(duì)象包含總記錄數(shù)、總頁(yè)數(shù)等信息。4. 避坑指南那些讓我熬夜的報(bào)錯(cuò)和排查思路4.1 中文亂碼問題現(xiàn)象前端提交的中文數(shù)據(jù)存到數(shù)據(jù)庫(kù)變成問號(hào)或者頁(yè)面顯示亂碼。原因通常有三層數(shù)據(jù)庫(kù)字符集不是 utf8mb4、連接 URL 沒指定字符編碼、Tomcat 的 URIEncoding 沒配。解決方法是逐層排查先確認(rèn)建庫(kù)時(shí)用了 utf8mb4再檢查 JDBC URL 里加了useUnicodetruecharacterEncodingutf8最后在 web.xml 里配 CharacterEncodingFilter 強(qiáng)制請(qǐng)求和響應(yīng)都用 UTF-8。4.2 事務(wù)不生效現(xiàn)象Service 方法上加了 Transactional但插入失敗后前面的操作沒有回滾。原因通常是 Spring 配置里沒有開啟事務(wù)注解驅(qū)動(dòng)或者 Service 類沒有被 Spring 掃描到。檢查 spring-service.xml 里是否有tx:annotation-driven transaction-managertransactionManager/以及包掃描路徑是否覆蓋了 Service 所在包。另一個(gè)常見原因是方法不是 public 的Spring AOP 默認(rèn)只代理 public 方法。4.3 MyBatis 綁定異常現(xiàn)象啟動(dòng)時(shí)報(bào)Invalid bound statement (not found)。原因通常是 Mapper XML 的 namespace 和 Mapper 接口的全限定名不一致或者 XML 文件沒有放在 resources 目錄下對(duì)應(yīng)的包路徑里。SSM 項(xiàng)目里 Mapper XML 一般放在src/main/resources/mapper/目錄下需要在 spring-dao.xml 里配置mapperLocations屬性指定掃描路徑。4.4 時(shí)間格式前后端不一致現(xiàn)象前端傳2024-01-15 09:00:00后端接收時(shí)報(bào)格式轉(zhuǎn)換錯(cuò)誤。原因是 SpringMVC 默認(rèn)不支持這種格式的字符串轉(zhuǎn) Date。解決辦法是在實(shí)體類的日期字段上加DateTimeFormat(pattern yyyy-MM-dd HH:mm:ss)注解或者在 spring-mvc.xml 里注冊(cè)自定義的 Converter。返回 JSON 時(shí)用JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8)保證序列化格式一致。4.5 靜態(tài)資源被攔截現(xiàn)象CSS、JS、圖片加載不出來(lái)瀏覽器控制臺(tái)報(bào) 404。原因是 spring-mvc.xml 里配置的 DispatcherServlet 攔截了所有請(qǐng)求包括靜態(tài)資源。解決辦法是在 spring-mvc.xml 里加mvc:default-servlet-handler/或mvc:resources mapping/static/** location/static//把靜態(tài)資源請(qǐng)求交給默認(rèn) Servlet 處理。5. 進(jìn)階技巧讓系統(tǒng)更穩(wěn)、更好演示5.1 用攔截器做統(tǒng)一權(quán)限校驗(yàn)與其在每個(gè) Controller 方法里手動(dòng)檢查 session不如寫一個(gè) HandlerInterceptor在 preHandle 方法里統(tǒng)一判斷登錄狀態(tài)和角色權(quán)限。這樣代碼更干凈也不容易漏掉某個(gè)接口。public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); User user (User) session.getAttribute(loginUser); if (user null) { response.sendRedirect(request.getContextPath() /login.jsp); return false; } return true; } }攔截器注冊(cè)在 spring-mvc.xml 里通過mvc:interceptors配置攔截路徑和排除路徑。登錄接口和靜態(tài)資源要排除掉否則會(huì)死循環(huán)。5.2 會(huì)議狀態(tài)自動(dòng)流轉(zhuǎn)會(huì)議狀態(tài)從“已通過”到“進(jìn)行中”再到“已結(jié)束”如果全靠人工點(diǎn)擊按鈕來(lái)改演示時(shí)容易忘??梢詫懸粋€(gè)定時(shí)任務(wù)每分鐘掃描一次 t_meeting 表把 start_time 已到且狀態(tài)為 2 的記錄改成 3把 end_time 已過且狀態(tài)為 3 的記錄改成 4。Spring 的 Scheduled 注解就能實(shí)現(xiàn)在 spring-service.xml 里開啟task:annotation-driven/即可。Component public class MeetingStatusTask { Autowired private MeetingMapper meetingMapper; Scheduled(fixedRate 60000) public void autoUpdateStatus() { meetingMapper.updateToOngoing(); meetingMapper.updateToFinished(); } }對(duì)應(yīng)的 SQL 是UPDATE t_meeting SET status 3 WHERE status 2 AND start_time NOW()和UPDATE t_meeting SET status 4 WHERE status 3 AND end_time NOW()。這個(gè)技巧在答辯演示時(shí)很加分老師能看到系統(tǒng)有“自動(dòng)運(yùn)轉(zhuǎn)”的能力。5.3 答辯演示的加分項(xiàng)演示時(shí)不要只走一遍增刪改查。建議按這個(gè)順序先用普通員工賬號(hào)發(fā)起一個(gè)會(huì)議申請(qǐng)?zhí)匾膺x一個(gè)已被占用的時(shí)間段展示沖突檢測(cè)的提示然后換部門管理員賬號(hào)審批通過再展示會(huì)議列表里狀態(tài)的變化最后打開會(huì)議紀(jì)要頁(yè)面寫一條紀(jì)要并添加待辦。整個(gè)流程走完老師能看到你對(duì)業(yè)務(wù)閉環(huán)的理解而不只是代碼堆砌。另外提前準(zhǔn)備兩個(gè)問題的答案一是“如果兩個(gè)人同時(shí)預(yù)約同一間會(huì)議室怎么辦”回答用數(shù)據(jù)庫(kù)唯一索引或悲觀鎖二是“密碼為什么不能明文存”回答用 MD5 加鹽或 BCrypt。這兩個(gè)問題被問到的概率很高。我在做這類系統(tǒng)時(shí)養(yǎng)成了一個(gè)習(xí)慣每寫完一個(gè)模塊就手動(dòng)構(gòu)造三條異常數(shù)據(jù)測(cè)一下比如結(jié)束時(shí)間早于開始時(shí)間、參會(huì)人 ID 不存在、會(huì)議室已停用。這些邊界情況才是真正讓系統(tǒng)“能用”和“好用”的分界線。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取