ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SpringBoot+Vue律所案件管理系统:从架构到部署全解析

SpringBoot+Vue律所案件管理系统:从架构到部署全解析 每年到了毕设季一批又一批学生开始到处找“能直接跑起来的系统源码”。我后台私信被问得最多的就是SpringBootVue系列的律师事务所案件管理系统。这套项目名字很长但定位非常清晰前端Vue后端SpringBoot数据层用Java搭配MySQL把律所里从立案、分案、办理、开庭到结案归档的完整流程做成一套前后端分离的管理平台。它不是那种只堆CRUD的玩具项目而是真正能对应到实际业务场景、能讲出设计逻辑、能在答辩现场站得住脚的系统。你如果正在选毕设或课设题目或者想找一套既能练手又能直接改造的JavaWeb完整案例这套案件管理系统是典型的高性价比选择。原因也不复杂律所的业务边界清楚角色权限关系明确案件状态流转天然适合做流程设计再加上文档、日程、统计报表这些功能点几乎覆盖了企业级管理系统常见的所有套路。你把它吃透不只是交差后面找工作面试时讲SpringBoot和Vue的实战经验也有东西可聊。这篇文章我会从业务拆解、技术选型、数据库设计、后端核心实现、前端Vue要点、部署联调、常见坑位七个角度把整套系统的玩法和盘托出尤其会讲很多源码里看不到的取舍细节。1. 项目定位与业务需求拆解1.1 为什么案件管理系统是“友好型”毕设选题先聊一个很多人忽略的问题选毕设题目不是越难越好而是“难度能被评委看见”最好。律师事务所案件管理系统恰好属于这一档。它的业务模型非常稳定。律师办案有清晰的流程当事人来咨询、律所接受委托、登记立案、主任分配承办律师、律师跟进办理、记录会见和开庭情况、最后结案归档。每个环节都对应数据表里的状态字段和操作记录。这意味着你可以光明正大地在论文里画业务流程图、状态图而不是硬凑内容。它的功能粒度也适中。比图书管理、学生信息管理这类纯增删改查要丰富又比电商、秒杀、高并发这类需要分布式中间件的项目容易落地。案件有列表查询、多条件筛选、分页展示、关联客户和律师这些是后端面试最爱问的“分页查询”“多表关联”现场还有权限控制、文件上传、定时提醒又是简历上能写的亮点。最关键的一点是它的领域知识不需要你花大量时间学习。你不需要懂法律条文只需要把“案件、客户、律师、文档、日程”这几个核心实体理清楚就能画出整套系统的模型。对毕设来说时间成本低反而更容易做出完成度。1.2 核心业务模块与角色权限设计拿到“律师事务所案件管理系统”这个题目第一件事不是建工程而是把业务模块拆出来。我按实际源码常见的结构把系统拆成下面几个大块案件管理案件登记、审批分案、办案过程跟踪、结案归档。这是整个系统的绝对核心。客户管理维护委托人/当事人信息包括自然人和企业客户客户可以关联多个案件。律师与人员管理律所内部成员账号、角色、职务信息管理员统一维护。文书与卷宗管理案件相关的委托合同、起诉状、证据材料、判决书等文件的上传、下载和预览。日程与提醒管理开庭日期、立案期限、会见安排、缴费节点等系统到期提醒。统计报表案件数量按状态、类型、承办人维度统计用图表展示。功能定了接着就要定“谁能干什么”。这套系统的用户角色我建议至少设计四种角色核心权限系统管理员用户管理、角色权限分配、系统字典配置、全量数据查看律所主任/合伙人案件审批分案、查看全所统计报表、管理律师承办律师办理分配到自己名下的案件、上传文书、维护日程助理/行政录入客户信息、登记案件、归档卷宗为什么要单独花力气设计角色因为权限控制是答辩时的高频问题。如果你不设计角色只做登录和增删改查评委大概率会追问“不同身份的人看到的数据为什么是一样的”。有了RBAC基于角色的访问控制你就可以讲清楚用户属于角色角色绑定菜单权限后端接口再按角色做数据范围过滤律师只能看自己的案件主任能看全所案件。这套逻辑无论用Shiro还是JWT拦截器实现都是一段非常扎实的谈资。2. 技术栈选型与架构设计思路2.1 为什么锁定SpringBootVueJavaMySQL这套组合在毕设领域用得最多不是没有道理。SpringBoot解决的是Java后端开发中繁琐配置的问题内嵌Tomcat一个main方法就能把服务跑起来项目结构也足够整洁。相比老一代SSH框架或者纯ServletJSPSpringBoot的学习曲线平缓得多而且现在的教程和面试题储量极大遇到问题一搜就有答案。Vue负责前端页面和数据展示。Vue的优势是组件化开发和响应式数据绑定操作表格、表单、弹窗都有成熟的UI组件库直接用。更重要的是“前后端分离”本身就是当前行业主流开发模式拿这套项目出去面试你可以直接说“我熟悉前后端分离开发流程会封装Axios请求会处理跨域和Token鉴权”这都是实打实的工作技能。MySQL在这里承担数据持久化。Java配合MySQL是经典中的经典JDBC也好、MyBatis也好面试官问到底层原理你都能答上来。MySQL 8的安装和配置在Windows和Linux下都有一大把教程Navicat或者DataGrip连上之后建库建表、看数据、调试SQL都很直观。对毕设而言MySQL的稳定性和上手速度都是最优选。2.2 ORM框架到底选MyBatis还是MyBatis-Plus这个问题很多学生纠结过。源码也好教程也好两种方案都有人用。我的个人建议分情况看如果你希望答辩时被问到“这个SQL是你自己写的吗”能理直气壮说“是”那就用纯MyBatis加XML把复杂查询全部手写展示你的SQL功底如果你时间紧还剩两星期就要交系统那就用MyBatis-Plus它的BaseMapper直接提供单表CRUDLambdaQueryWrapper写条件查询非常快能省下大量时间。我接触过的毕设源码里用MyBatis-Plus的还是多一些但它有个问题很多学生全程只用了selectPage和saveOrUpdate一旦面试官问“分页底层怎么实现的”就答不上来。所以我的处理方式是折中单表简单操作交给MyBatis-Plus多表关联、统计报表这类有含金量的SQL全部手写写在XML里。这样既保证开发效率又能展现“我会写复杂SQL”的能力。对比一下两种方案对比项MyBatisMyBatis-Plus开发效率中需手写大量XML高CRUD开箱即用SQL可控性完全可控简单SQL自动生成复杂SQL仍需手写答辩难度相对安全需要额外解释封装原理适用情况时间充足、想学底层时间紧、追求系统完整度2.3 前端Vue版本与UI组件库怎么搭配Vue现在有Vue2和Vue3两个大版本配套的UI库也分Element UI和Element Plus。这件事别跟风得看你的基础和目标环境。如果你之前一直学的是Vue2学校课程也讲的Vue2那就踏实用Vue2Element UI生态非常成熟你遇到的坑网上都有答案。如果从零开始学建议直接上Vue3Element Plus毕竟新项目用新版本是大方向就业市场也更认可。有一点必须提醒Node.js版本一定要匹配Vue2老项目配Node 16没问题Vue3的Vite项目最好用Node 18以上否则依赖装不上、构建报错会非常痛苦。还有一个容易被忽略的点UI组件库的表格、表单、弹窗、分页组件一定要用到极致。不要什么按钮都自己用button写Element的el-table、el-form、el-dialog、el-pagination组合起来一个标准管理页面半小时就能搭完。另外Vue里的插槽slot很实用比如表格操作列、弹窗底部按钮用插槽可以让代码复用性更好这也是面试官喜欢问的Vue知识点。3. 数据库设计表结构不是堆字段3.1 核心数据表清单与关系梳理这套系统的数据库设计本质是围绕着“案件”这个核心实体展开的。我从实际源码中提炼了一组非常经典的表清单sys_user系统用户表字段包括用户名、密码BCrypt密文、姓名、手机号、头像、状态、创建时间。sys_role角色表包含角色名称和角色编码如ADMIN、DIRECTOR、LAWYER、CLERK。sys_user_role用户角色关联表一个用户可多角色多对多。case_info案件主表这是全系统信息量最大的表。case_type案件类型字典表民事、刑事、行政、非诉等或者直接用数据字典字段。case_client当事人与案件关联表一个案件可有多个当事人原告、被告、委托方。client_info客户档案表自然人客户和企业客户都放在这里加一个客户类型字段区分。case_document文书卷宗表记录案件下上传的文件元数据原始文件名、存储路径、文件大小、上传人。schedule_info日程安排表存放开庭、会见、期限提醒等时间节点。sys_dict_data数据字典表兜底维护案件状态、案件类型、性别等枚举值。这些表之间的核心关系是case_info关联sys_user承办律师、关联client_info客户、通过case_document挂接多个文件、通过schedule_info挂接多个日程。多对多关系一律用中间表解耦不要出现用逗号拼接用户ID这种操作否则后面统计和联查会把人逼疯。3.2 案件主表的字段设计与状态机案件主表是整张数据库的“门面”字段设计好坏直接决定系统能不能讲出深度。我列出关键字段字段名类型说明case_novarchar(32)案件编号唯一按规则自动生成case_titlevarchar(200)案件名称如“张三诉李四合同纠纷”case_typevarchar(20)案件类型关联字典表case_statustinyint案件状态待分案、办理中、已结案、已归档client_idbigint委托客户IDopponent_namevarchar(100)对方当事人名称accept_datedatetime受理日期court_datedatetime开庭时间可空lawyer_idbigint承办律师用户IDamountdecimal(12,2)诉讼标的金额result_desctext结案结果描述create_bybigint登记人case_status这个字段值得单独强调。不要用一个无意义的status字符串随随便便存“1”“2”“3”最好定义成枚举或者常量类在Java代码里用常量名去比较。更重要的是案件状态之间不是随意的它是一个状态机待分案只能流转到办理中办理中才能结案结案后才能归档。你可以在Service层写一个changeCaseStatus方法先校验当前状态是否允许目标状态再执行更新。这个设计在论文里写成“案件状态流转设计”答辩时非常加分。3.3 索引、时间字段和通用字段的设计细节数据库设计的坑往往不在表多而在细节。我这里提三个最常见的细节问题。第一个是索引。case_no必须建唯一索引lawyer_id和case_status要建普通索引因为列表页最常按它们过滤。accept_date如果要按月份统计可以建索引但不要对字段做函数运算比如DATE_FORMAT(accept_date)否则索引会失效。这是MySQL面试的老考点也是实际查询性能的关键。第二个是时间字段。MySQL的datetime和timestamp要选对。案件受理日期、开庭日期这类业务时间用datetime创建时间create_time和更新时间update_time建议统一用datetime在MyBatis-Plus里还能用自动填充功能省去手动赋值。查询日期范围时前端传过来的日期不带时分秒容易查出“当天数据查不全”的诡异问题稳妥做法是查询时把结束日期手动加上23:59:59或者用start ? AND start DATE_ADD(?, INTERVAL 1 DAY)的写法。第三个是通用字段。每张业务表尽量保留create_by、create_time、update_time、deleted这几个字段。deleted用逻辑删除而不是物理删除这样误删案件还能找回同时MyBatis-Plus的TableLogic能自动处理非常省事。别小看这几个字段答辩时“你数据库设计考虑了哪些规范”这个问题它们就是答案。4. 后端SpringBoot核心实现拆解4.1 登录认证与基于JWT的RBAC权限控制登录认证这块最常见的成熟方案就是JWTJSON Web Token。流程不复杂用户提交用户名密码后端校验通过后生成一个带过期时间的Token返回给前端前端把Token存在localStorage里每次请求在请求头带上Authorization: Bearer token后端通过拦截器解析Token拿到当前登录用户信息进而做权限判断。具体的实现要点有三个。第一密码不能明文存。用BCryptPasswordEncoder对用户密码做哈希。密码加密的好处是即使数据库泄露别人也拿不到明文密码。这一点是Java面试题里经常出现的知识点评委问到的时候你要能说清楚BCrypt为什么比MD5安全。第二写一个拦截器或过滤器统一处理Token校验。放行登录接口、放行静态资源其余接口都校验。解析出来的用户ID放到ThreadLocal或者放到Request的Attribute里后续Service层随时可以取。第三菜单权限不要写死在前端。用户登录成功后后端根据用户角色返回他可以看到的菜单列表前端再用Vue Router动态添加路由。这样不同角色登录进去看到的侧边栏天然不同加上后端接口按角色校验数据范围“越权访问”这关就算守住了。关于JWT实现推荐用io.jsonwebtoken:jjwt注意0.9.1版本在JDK9以上会报ClassNotFoundError: javax.xml.bind.DatatypeConverter解决办法是引入javax.xml.bind:jaxb-api依赖或者直接换io.jsonwebtoken:jjwt-api/impl/jackson这三个新版坐标避免在版本兼容上浪费时间。4.2 案件分页与多条件组合查询的落地写法案件列表页是这套系统最核心的接口它不只是select * from case_info而是要支持按案件编号、案件名称、案件类型、状态、承办律师、受理日期范围任意组合查询。我通常建议用MyBatis-Plus的分页插件一行配置注入分页拦截器然后在Service层用LambdaQueryWrapper拼条件。组合查询里最容易出错的是“空值判断”。前端不传某个条件时该条件不能参与拼接。用LambdaQueryWrapper的写法示例LambdaQueryWrapperCaseInfo wrapper new LambdaQueryWrapper(); wrapper.eq(StringUtils.hasText(query.getCaseNo()), CaseInfo::getCaseNo, query.getCaseNo()); wrapper.like(StringUtils.hasText(query.getCaseTitle()), CaseInfo::getCaseTitle, query.getCaseTitle()); wrapper.eq(query.getCaseStatus() ! null, CaseInfo::getCaseStatus, query.getCaseStatus()); wrapper.eq(query.getLawyerId() ! null, CaseInfo::getLawyerId, query.getLawyerId()); wrapper.ge(query.getAcceptDateStart() ! null, CaseInfo::getAcceptDate, query.getAcceptDateStart()); wrapper.le(query.getAcceptDateEnd() ! null, CaseInfo::getAcceptDate, query.getAcceptDateEnd()); wrapper.orderByDesc(CaseInfo::getCreateTime);然后配合PageHelper或者MP的Page对象做分页返回给前端的数据结构统一是{ records, total, current, size }格式。前端拿到total渲染分页组件records渲染表格切换页码时再把current和size传给后端。这套逻辑无论什么管理系统都通用写熟之后你写任何列表都是一模一样的套路。这里补充一个很多人栽过的坑分页查询之后如果还要根据查询结果做二次计算比如统计合计金额不要循环去查数据库直接在SQL里用SUM、COUNT带条件聚合一次查出来效率差好几倍。列表页接口一定要关注响应时间做毕设还好一旦数据量到五万条以上N1查询的问题立刻暴露。4.3 文件上传与卷宗管理的功能设计律所案件要传的文件不少委托合同、起诉状、证据材料、判决书PDF、Word、图片都有。文件上传功能在后端实现的思路是接收MultipartFile生成UUID文件名保存到服务器指定目录然后把文件原始名、存储路径、大小、上传时间写入case_document表。这里有几个关键细节。文件名必须处理。用户上传的文件名可能是中文可能包含特殊字符直接存到磁盘会引发乱码甚至路径穿越风险。我的做法是磁盘保存名用UUID.randomUUID()加上原始文件的扩展名原始文件名单独存数据库字段下载时再通过响应头把原始名返回给前端。展示和存储分离安全又干净。上传目录要可配置。在application.yml里配置一个upload.path属性不要写死绝对路径。Windows和Linux路径分隔符不同用System.getProperty(file.separator)或者Java的Paths.get()来拼接部署到服务器才不会踩反斜杠的坑。预览方面图片可以直接通过URL访问PDF在Chrome里也可以用浏览器插件预览Word文件一般不建议在线预览直接提供下载即可。有学生问“Vue里el-image能显示PDF吗”答案是不行el-image只支持图片格式PDF要么走window.open要么用专门的vue-pdf组件。毕设不要太过纠结文件能上传、能下载、列表能展示文件信息就已经满足需求了。4.4 定时提醒开庭日期自动提醒的实现提醒功能是这套系统的隐藏亮点。它不复杂但很能体现“你考虑了实际业务”。实现方式就是Spring的定时任务在启动类加EnableScheduling写一个方法标Scheduled(cron 0 0 8 * * ?)每天早上8点扫描一次案件表找出开庭日期在未来三天内且状态还在办理中的案件为承办律师生成一条待办提醒。提醒的存储可以是单独一张notify_info表也可以复用日程表。后台登录后页面右上角显示未读消息数量点击可以查看详情。这一步做完成品感一下就上来了而且答辩时可以讲“我用Spring的Scheduled实现了定时扫描用cron表达式控制执行频率”这又是一个非常标准的SpringBoot面试考点。有一点要提醒定时任务不要写在Controller里也不要和普通请求逻辑混在一起。独立一个schedule包里面放定时任务类方法逻辑尽量短。如果担心cron表达式写错可以用在线cron生成器验证一下比如0 0 8 * * ?就是每天早上8点触发。定时任务执行的时候注意和数据库交互的事务控制扫描和插入提醒建议放在同一个事务里避免扫描出了案件但提醒没插入成功导致数据不一致。5. 前端Vue工程重点实现与展示5.1 初始化前端项目与目录结构划分前端工程搭建我建议用Vue CLI或Vite。创建好项目后先别急着写页面把目录结构规划好。我自己习惯的模块划分是src/ api/ # 接口请求模块按业务拆分如case.js、client.js、user.js assets/ # 静态资源 components/ # 公共组件如UploadFile.vue、PaginationBar.vue layout/ # 整体布局侧边栏、顶栏、面包屑 router/ # 前端路由配置 store/ # 状态管理Vuex/Pinia存放用户信息和菜单 utils/ # axios封装、token工具、日期格式化 views/ # 页面组件业务模块的页面都放这这样的好处是每个文件职责单一写代码的时候不用满项目找文件答辩讲项目结构也清晰。很多源码一开始目录就乱糟糟Controller、Service、Mapper的命名前后不一致后面越改越乱。你拿到任何源码第一步都建议先梳理结构再动手改功能。5.2 Axios封装与请求拦截器的正确姿势前端和后端联调最忌讳每个页面直接axios.get不带统一处理。我建议在utils/request.js里封装一个Axios实例统一配置baseURL、超时时间然后通过请求拦截器把Token塞进请求头通过响应拦截器统一处理后端返回的状态码。响应拦截器里做的事情很固定后端的返回结构如果是{ code, msg, data }拦截器判断code是否为200不是就抛消息并提示如果是401说明Token失效清掉本地用户信息并跳回登录页如果是500统一弹出后端返回的msg消息。这样业务代码里写请求时一行就能拿data不需要每个页面重复处理异常。// 响应拦截器核心逻辑 service.interceptors.response.use( (response) { const res response.data if (res.code ! 200) { Message.error(res.msg || 请求失败) if (res.code 401) { store.dispatch(logout) router.push(/login) } return Promise.reject(new Error(res.msg)) } return res.data }, (error) { Message.error(error.message || 网络异常) return Promise.reject(error) } )注意封装之后业务页面里写的api/case.js导出的函数最终返回的就是res.data页面里直接.then(res { ... })拿到data代码非常干净。这个封装是面试里“前端如何统一处理鉴权和异常”的最佳答案。5.3 动态菜单与路由权限控制前面后端部分讲到不同角色登录看到的菜单应该不同。前端实现方案是这样用户登录后后端返回这个角色允许访问的菜单列表菜单项里包含路由路径和组件名称前端把菜单列表存到Vuex/Pinia里同时根据它动态注册路由。Vue Router的addRoute方法可以动态添加路由这是实现动态菜单的关键。核心思路// 根据后端菜单数据动态生成路由 const menuList res.data // 后端返回的菜单列表 menuList.forEach(menu { const component () import(/views/${menu.componentPath}) router.addRoute(Layout, { path: menu.path, name: menu.name, component: component, meta: { title: menu.title, icon: menu.icon } }) })这里有个经典坑动态添加的路由refresh页面之后会丢失。因为Vuex里的状态是内存中的数据刷新浏览器就没了但路由已经根据旧数据注册过了。解决方案是把菜单数据同步存到localStorage刷新后在路由守卫里判断Vuex里没有菜单就去localStorage读取再重新执行addRoute。这个坑在源码里经常被忽略很多学生部署后一刷新就白屏或跳404原因就在这。5.4 列表页、表单页和弹窗复用套路管理系统的页面形态其实是高度重复的左侧是搜索条件中间是表格右侧或下方是分页点击新增或编辑弹出dialog。你只要完整写好一个页面后面所有页面都可以复制改造。搜索区的数据模型是一个普通对象比如searchForm: { caseNo: , caseType: , caseStatus: , lawyerId: }点击查询时把searchForm传给请求函数点击重置时清空对象再刷一遍列表。表格列用el-table-column渲染状态列可以加标签颜色增强可读性。操作列固定宽度放查看、编辑、删除、提交按钮这些按钮的权限可以结合v-permission指令或者v-if控制。新增和编辑弹窗建议共用一个子组件组件里放el-form和校验规则通过props接收一个editForm对象通过this.$emit通知父组件保存。表单校验规则用Element内置的required和自定义验证器手机号、日期格式都能拦住。这个“新增编辑共用一套弹窗、插槽自定义按钮”的做法既减少代码量又是Vue组件通信很好的练手场景。5.5 利用ECharts做统计报表可视化统计报表是让系统看起来“高级”的捷径。直接在views/dashboard页面引入ECharts用柱状图展示每月的收案数量用饼图展示案件类型占比用横向柱状图展示各律师在办案件数量。后端对应提供几个统计接口SQL使用分组聚合-- 按状态统计案件数量 SELECT case_status, COUNT(*) AS num FROM case_info WHERE deleted 0 GROUP BY case_status;前端拿到数据之后把数据转换成ECharts需要的{ name, value }数组格式再用setOption渲染。这里注意ECharts的图表容器必须设置高度否则图表显示不出来或者显示0px高度数据更新后要记得调用chart.resize()或者重新setOption。另外一个常见问题是折线图和柱状图的Y轴单位金额类数据最好格式化1.2万这样的显示这些细节能看出你真把页面用心做了。6. 环境搭建、项目部署与前后端联调6.1 本地开发工具与版本搭配推荐老生常谈但必须说清楚版本搭配不对项目跑不起来是分分钟的事。我个人推荐一套经过大量实践验证的稳定组合组件推荐版本JDK1.8 或 11SpringBoot2.7.xMyBatis-Plus3.5.xMySQL8.0Node.js16.xVue2/ 18.xVue3Maven3.6或以上如果你的电脑是新装的JDK 17甚至21建议SpringBoot用2.7.x能兼容如果手抖选了SpringBoot 3.xJDK 1.8是带不动的必须JDK17以上而且很多第三方整合包还不兼容这就是网上大量“SpringBoot版本太高导致启动报错”的根源。毕设追求的是稳不要追新。MySQL安装上Windows直接下载MSI安装包或者用压缩包解压后手动初始化都行注意修改root密码MySQL 8默认的加密规则是caching_sha2_password如果连接工具或驱动版本太旧会报认证错误连接串里加useSSLfalseallowPublicKeyRetrievaltrue能解决一部分奇奇怪怪的连接问题。可视化工具用Navicat或者DataGrip都行不用破解官方有免费版试用DataGrip也有30天试用期毕设期间足够用了。6.2 后端项目启动步骤与配置要点启动后端前先把application.yml里几项关键配置改好server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/law_firm?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 20MB max-request-size: 100MB mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这里有三点值得说明。第一serverTimezoneAsia/Shanghai不写会导致日期差8小时这是最常见的经典坑。第二useSSLfalse是告诉MySQL不需要走SSL握手否则连接速度慢且报SSL警告。第三max-file-size是上传文件上限如果后面传大文件一直失败先看看是不是这个没配置。启动步骤很简单用IDEA打开Maven项目等待依赖下载完运行主类里的main方法看到Spring Boot启动成功的Banner和Started日志就说明后端起来了。如果Maven下载依赖慢在settings.xml里配置阿里云镜像速度能提升好几倍。6.3 前端启动与跨域代理配置前端开发时最大的问题是跨域。前端跑在http://localhost:8081后端跑在http://localhost:8080端口不同就存在跨域。开发环境的解决方案有两种一种是在后端写CrossOrigin或者全局CORS配置类另一种更推荐的是前端配置代理。Vue CLI项目的vue.config.js里配置代理module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: } } } } }Vite项目的vite.config.js里是server.proxy语法类似。配置好代理后前端请求/api/case/list会被转发到后端的/case/list浏览器层面没有跨域问题。注意后端接口的baseURL相对路径要写成/api开头和生产环境保持一致。这样做的好处是本地没跨域部署成一个端口后也不需要改前端代码。6.4 打包部署把Vue构建产物放进SpringBoot演示给老师看的时候最省事的方案是只启动一个Java进程。做法是把前端打出来的dist目录内容复制到SpringBoot项目的src/main/resources/static目录下然后重新打包成jar。启动jar后浏览器访问http://localhost:8080后端服务和前端页面同端口提供。这里有几个必须注意的细节。第一Vue项目里vue.config.js的publicPath要改成./相对路径否则打出来的包在非根路径下访问会白屏资源全部404。第二如果Vue Router用的是history模式打包放进SpringBoot后刷新子页面会404因为SpringBoot找不到对应的后端路由。解决方案是后端写一个Web配置类把非接口路径都转发到index.html或者无脑省事直接把路由模式改成hash。第三dist里的index.html如果被放到了static根目录访问登录页就能直接看到如果浏览器强制缓存了旧页面记得CtrlF5硬刷新。7. 高频问题与避坑实录速查表问题现象根本原因解决方案启动报ClassNotFoundError: javax.xml.bind.DatatypeConverterjjwt 0.9.1在JDK9缺少依赖类引入jaxb-api依赖或换jjwt新版坐标MySQL连接报Public Key Retrieval is not allowedMySQL 8加密规则导致连接串加allowPublicKeyRetrievaltrueuseSSLfalse前后端联调接口访问不到浏览器控制台报跨域端口不同没有做代理或CORS配置Vue devServer代理或后端加CORS配置Vue打包后页面白屏控制台资源404publicPath使用了绝对根路径把publicPath改成./或将路由改成hash模式刷新页面跳404或空白动态路由没有持久化刷新后丢失菜单列表存localStorage刷新时重新addRoute列表页“今天的数据查不出来”日期查询结束时间缺少时分秒结束日期加23:59:59或用和DATE_ADD处理上传文件报MaxUploadSizeExceededException默认文件大小上限只有1MB在配置中调大multipart.max-file-size中文文件名下载乱码响应头没有设置文件名编码对文件名做URL编码用URLEncoder.encode处理npm install长时间卡住或报错网络源太慢或依赖版本冲突切换淘宝镜像源检查Node版本是否匹配生产环境接口返回404接口路径和前端请求路径不一致检查Controller的RequestMapping和前端api的baseURL7.1 时间、状态、文件三个高频盲区再强调一遍日期问题我再多说一句不要嫌啰嗦。前后端分离的项目里前端传yyyy-MM-dd给后端后端按这个日期直接查datetime字段一定是查不全的因为数据库里存的是2025-06-10 14:30:00而前端传的是2025-06-10 00:00:00查询条件把凌晨之后的全排除了。遇到这种问题不要怀疑数据库先看看条件里的时间范围。我一般处理方式是统一在后端把结束时间补到23:59:59一劳永逸。案件状态的修改也再提醒一遍不要在Mapper里写一堆update case_info set status1 where id?满天飞。收口到一个Service方法里方法内用一个switch判断当前状态和目标状态是否允许流转允许再更新。这个设计短期看是“多写了一层”但答辩的时候你能噼里啪啦讲清楚状态机架构比背概念有力得多。文件上传还有个小坑用MultipartFile接收文件时前端FormData的字段名要和RequestParam(file)保持一致名字对不上会报Required request part file is not present。如果你用的Element的el-upload默认的name属性就是file但传递额外参数时记得放data对象里。7.2 毕设答辩时怎么讲这套系统最加分最后聊几句答辩技巧这是很多人忽略但极其重要的环节。评委不指望你做一个生产级产品他想听到的是“你为什么这么设计”。所以你讲的时候不要照着PPT念功能清单而是抓住三个故事线。第一主线案件状态怎么流转的。开讲你每天早上拿到新案件状态是待分案主任审批分案后变成办理中律师在办理中阶段更新动态、上传文书、记录开庭结案后填写结果最后归档。这条线串起来后系统的一切功能都是为流程服务的。第二主线权限是怎么控制的。登录之后不同角色看到不同的菜单律师改不了别人的案件主任能看统计数据。解释清楚RBAC模型和JWT登录。第三主线数据库怎么设计的。重点突出三张核心表用户角色表、案件表、档案文件表以及它们之间的关联关系。说明你考虑到了逻辑删除、字典表、索引这些细节就是高分来源。还有一个小建议演示的时候准备一套好看的数据不要全部名字叫“测试1”“测试2”。造几十条像样的模拟案件数据客户姓名、案件名称、金额、开庭日期都有模有样页面一打开董监高级的质感就出来了。这比任何口头描述都管用。8. 这套源码做完之后还能往哪里扩展如果你做完毕设还有余力或者想拿这套系统去丰富简历有几个低成本的扩展方向非常值得做。第一是把文件上传从本地磁盘切换到对象存储如MinIO。MinIO是一个开源的对象存储服务接口兼容亚马逊S3Java端用SDK就能接入。这样做的好处是文件管理和业务系统解耦也顺便把“对象存储”这个词写进简历。网上关于MinIO加入SpringBoot的教程很多环境起来之后一天就能接完。第二是加一个公告通知模块或者敏感操作日志模块。操作日志记录谁在什么时间改了什么案件字段这是企业系统的标配能力。用Spring AOP写一个切面拦截Controller方法记录接口路径、操作人、耗时。这个功能代码量不大但讲起来非常加分因为涉及AOP核心概念。第三是案件统计分析报表细化增加Excel导出功能。你可以在后端用EasyExcel或者POI把案件列表导出成Excel前端加一个“导出”按钮。毕业设计演示时当场导出一份Excel视觉效果拉满而且Excel导出也是工作中非常常见的技术需求。对我个人而言做这套系统的过程最大的收获不是某个框架API背得多熟而是真正理解了一个业务系统是怎么从需求分析一步步落地成代码的。你会慢慢意识到CRUD只是外壳状态流转、权限控制、数据一致性才是内核。如果你能沿着这个思路把案件状态机讲清楚把用户角色和数据隔离讲明白这套毕设源码的含金量就真正被你消化吸收了。最后再分享一个实操层面的心得拿到这套源码或者任何毕设源码第一天别着急启动先花两小时把表结构看一遍把核心表的字段关系画出来。你画出了案件、客户、律师、文件、日程之间的关系图整个系统的骨架就在你脑子里了后面不管是改Bug还是加功能都只是往骨架上填肉而已。
返回列表