☰
律师事务所案件管理系统:SpringBoot+Vue+MySQL全栈落地实践
2026/10/9 5:57:42 网站建设 项目流程

每年毕业季都有大量学生拿“管理系统”当课题,但同样叫管理系统,SpringBoot+Vue+MySQL这套技术栈放在律师事务所案件管理这个场景下,就显得特别有说头。原因很简单:它不是一个纯粹的增删改查,而是带着业务主线的——从收案、分案、立案、开庭到结案归档,中间还夹着客户信息、律师分配、案件费用、状态流转和统计报表。用这个题目做毕业设计,既能展示后端对状态机、权限、多条件查询的处理能力,又能在前端做出时间线、报表这类有视觉感的东西,数据库设计也天然有多表关联,工作量很容易撑起来。

我当时带过好几个用这个题目的学生,自己也动手把整个系统从零搭过一遍。这篇文章就把整个项目的落地方案拆开讲:从功能范围怎么定、数据库表怎么设计,到后端的关键代码怎么写、前端页面怎么组织,再到论文和部署文档怎么准备,全部按实际动手的顺序走。不管你是刚拿到这个题目的本科生,还是想帮学生把系统做得更完整的指导老师,照着这条线走,能省掉很多弯路上的时间。

1. 选型评估:这类课题为什么值得做,又容易在哪里翻车

1.1 业务域优势:案件有生命周期,系统才不是空壳

普通的管理系统,比如图书管理、商品管理,核心就是一张表的CRUD,做完一点成就感都没有。案件管理不一样,一个案件从咨询到收案,再到结案归档,中间有明确的状态变迁:登记、分案、立案、审理、结案、归档。这意味着系统里必须有一张状态字段,甚至是一张状态流转日志表。有了这条业务主线,你的后台逻辑就不是简单的save和update,而是要根据当前状态判断下一步能做什么。答辩的时候,这一块是最容易展开讲“系统设计”的地方。

另外,案件系统天然有角色区分。前台接待员负责录入客户和案件基础信息,合伙人负责分案,律师负责查看自己名下的案件并更新进展,管理员能看到全部数据。这种多角色的权限控制,是毕业设计评分表里“功能完整性”和“系统设计”两个维度的高频加分项。

1.2 技术栈合理性:学校教程覆盖率高,风险最低

SpringBoot+Vue+MySQL这个组合,几乎是国内高校软件工程专业的标准配置。Spring Boot把SSM那套繁琐的配置压缩到了极简,Vue 2或Vue 3配合Element UI/Element Plus做后台界面,效率极高,MySQL是各个学校机房都熟悉的数据库。三个技术点在网上都有海量教程,遇到问题搜索成本很低。对需要同时写论文和准备答辩的学生来说,选一套资料多、踩坑记录全的技术栈,比选一个“看起来很前沿”但周围没人会用的方案重要得多。

1.3 真正容易翻车的点:把系统做成“堆菜单”

我见过好几个案件管理系统,功能菜单列得很满,客户管理、律师管理、案件管理、合同管理、统计报表样样都有,点进去全是表格,没有任何业务逻辑判断。这种系统看上去功能齐全,但答辩老师随便问一句“案件状态是怎么流转的”“结案之后还能不能改承办人”,学生就答不上来。

所以这篇文章后面讲功能设计、表结构和代码实现时,都会围绕状态流转和角色权限这两条主线展开。功能可以少,但业务逻辑必须成立。宁可做六个菜单,也不要凑二十个空壳菜单。

2. 功能范围怎么定:从收案到归档的闭环

我建议第一版系统不要贪多,把下面几个模块做扎实,就足够支撑一篇质量不错的毕业论文了。

2.1 基础数据模块

客户表:包括个人客户和单位客户。个人客户有姓名、电话、证件号,单位客户有单位名称、统一社会信用代码、法定代表人。设计时可以做成一张表,加一个客户类型字段区分。

律师表:姓名、执业证号、电话、专业方向(如民商事、刑事、行政)、所属合伙人。这里注意,律师表最好带上“是否可用”状态,因为分案时要判断这个律师手上案件数量是否过多,或者是否处于休假状态。

法律事务类型表:比如合同纠纷、劳动争议、刑事诉讼、知识产权、行政诉讼等。这个表不是必须的,但有了它可以做案由分类统计,前端报表能多一张饼图,工作量又好看一点。

2.2 案件主流程模块

收案登记:前台录入客户信息和案件基础信息,包括案件名称、案由、案件金额、对方当事人、受理法院等。系统自动生成案号,比如 2024-民初-001,案号必须唯一。

分案管理:合伙人或管理员,把一个案件分配给某个承办律师。分完之后要记录操作人和时间。

立案信息维护:律师拿到案件后,补充立案日期、案号(法院案号)、承办法官、审判庭等信息。

开庭记录:一个案件可能有多条开庭记录,包括开庭时间、地点、审理情况、调解结果等。这个用子表保存。

结案与归档:案件结束后,填写结案方式(判决、调解、撤诉等)、结案日期,然后进入归档状态。归档后的案件默认不可编辑,只能查看。这个“归档后锁定”的业务规则,是你后端的亮点。

2.3 辅助功能模块

费用管理:每个案件可以登记律师费、诉讼费、差旅费等收费记录,并区分是否已收。这里不做太复杂的财务逻辑,弄一张费用记录表就行。

文档上传:给案件挂附件,比如起诉状、判决书PDF、证据材料扫描件。文件上传后保存到服务器目录,数据库只存文件路径和名称。这个功能实现起来简单,但对律师事务所场景非常贴合。

统计报表:按月份统计收案数量,按案由类型统计案件占比,按律师统计在办案件数量。用ECharts画柱状图和饼图。

公告栏:管理员发布通知,用户登录后能看到。这个小模块主要是为了让首页不空着。

2.4 角色与权限设计

我的建议是设三种角色:管理员(admin)、合伙人(partner)、律师(lawyer)、前台(receptionist)。实际上前台也可以用律师角色账号,但为了论文好写,我常建议四个角色分开。

权限控制策略说简单点:管理员全功能;前台可以登记案件、查看客户,但不能分案和结案;合伙人可以分案、查看全所案件;律师只能看到分配给自己的案件,并维护立案、开庭、结案信息。后端用拦截器检查角色权限,前端菜单根据角色动态渲染,两侧都要做,不能只隐藏按钮。

3. 数据库设计实战:表关系是第一道门槛

数据库设计是这类毕业设计论文里占篇幅最多的部分,也是实际开发中返工最频繁的部分。我直接把最终版本的表结构分享出来,并解释每一张表存在的原因。

3.1 核心表清单

表名用途对应用户角色
sys_user登录用户admin/partner/lawyer/receptionist
client客户信息前台、律师
lawyer律师信息合伙人
case_info案件主表所有角色
case_status_log案件状态流转日志后台自动
court_record开庭记录律师
fee_record费用记录律师、前台
case_doc案件附件律师
case_type案由类型基础数据

把sys_user和lawyer拆开,是因为律师可能在某个时间点离职或停职,但账号还存在,所以用户和律师信息不要强关联,用user_id字段对应即可。

3.2 案件主表的字段设计

CREATE TABLE case_info ( id BIGINT AUTO_INCREMENT PRIMARY KEY, case_no VARCHAR(64) NOT NULL UNIQUE COMMENT '律所内部案号', case_name VARCHAR(200) NOT NULL COMMENT '案件名称', case_type_id BIGINT NOT NULL COMMENT '案由类型id', client_id BIGINT NOT NULL COMMENT '客户id', client_name VARCHAR(100) NOT NULL COMMENT '冗余客户姓名,列表显示用', opparty_name VARCHAR(200) NULL COMMENT '对方当事人', court_name VARCHAR(200) NULL COMMENT '受理法院', case_amount DECIMAL(14,2) NULL DEFAULT 0 COMMENT '涉案金额', lawyer_id BIGINT NULL COMMENT '承办律师id', assign_time DATETIME NULL COMMENT '分案时间', status TINYINT NOT NULL DEFAULT 0 COMMENT '0草稿 1待分案 2在办 3结案 4归档', -- 法院立案信息也可放主表,简化设计 court_case_no VARCHAR(64) NULL COMMENT '法院案号', judge_name VARCHAR(50) NULL COMMENT '承办法官', filing_time DATE NULL COMMENT '立案日期', close_type VARCHAR(32) NULL COMMENT '结案方式', close_time DATETIME NULL COMMENT '结案时间', create_time DATETIME NOT NULL, update_time DATETIME NOT NULL );

这里有几个细节值得说明。

案号是唯一标识,必须做UNIQUE约束,否则前后端校验拦不住并发插入时数据库层面的重复。case_name和client_id相比,我更推荐在列表页增加一个client_name冗余字段,因为多表关联查询在数据量大时会拖慢速度,冗余一个名字字段在毕业设计里不算违规,反而体现了对查询性能的考虑。

律师不是必填字段,因为一个案件在刚登记时可能还没有分案。status字段用TINYINT,不要用VARCHAR存中文状态,因为程序里判断状态用数字更可靠,页面展示时再映射成中文。

3.3 状态流转日志表

案件为什么要单独一张状态日志表?这个问题值得在论文里大写特写。因为业务上需要追踪每个关键节点是什么时候、由谁操作的。比如一个案件在3月1日结案了,但后来被律师撤销结案重新打开,那到底结案过几次?都发生在什么时候?如果不记录日志,这种事情永远讲不清楚。

CREATE TABLE case_status_log ( id BIGINT AUTO_INCREMENT PRIMARY KEY, case_id BIGINT NOT NULL, from_status TINYINT NULL, to_status TINYINT NOT NULL, operator_id BIGINT NOT NULL COMMENT '操作人user_id', operator_name VARCHAR(50) NOT NULL, remark VARCHAR(255) NULL, create_time DATETIME NOT NULL, INDEX idx_case_id (case_id) );

这张表在插入时由后端service统一写入,不在mapper里散落着写。后面讲后端时会给出具体代码。

3.4 用户表、客户表、费用表的设计要点

用户表就是标准的id、username、password、real_name、role_id、status、create_time。密码存储建议用BCrypt加密,不是明文。毕业设计用MD5也不是不行,但懂行一点的答辩老师看到明文密码会觉得不太舒服,我建议用Spring Security自带的BCryptPasswordEncoder,代码量很少。

客户表预留一个contact_phone和id_card字段,方便论文里写“客户信息唯一性校验”。费用表带上case_id外键和pay_status字段。附件表带上file_path、original_name和file_size。注意,文件上传后建议把文件存放在部署目录之外的uploads文件夹,数据表里只记录相对路径,避免打包jar之后找不到路径。

3.5 索引设计的思路

除了主键索引,建议在case_info表上建这些索引:case_no(唯一索引)、status、lawyer_id、client_id。在case_status_log表上建case_id索引。创建关联查询时尽量走索引。

4. SpringBoot后端落地:不是会写CRUD就行

4.1 分层与项目结构

后端我习惯用标准的三层结构加controller包装:

com.example.lawfirm ├── controller ├── service ├── mapper ├── entity ├── dto ├── common └── config

entity放数据库映射实体,dto放前端交互对象,比如登录请求、分页查询条件。common里放统一返回结果Result和异常处理类。这里需要注意:分页查询的入参建议单独建一个QueryDTO,不要直接在Controller里接收Page、Size、Keyword一堆散参数,那样后续加过滤条件会很痛苦。

4.2 统一返回体和异常处理

前端Vue里请求接口,最舒服的是所有接口都返回同一个结构体。我通常定义成这样:

public class Result<T> { private Integer code; private String msg; private T data; public static <T> Result<T> ok(T data) { ... } public static <T> Result<T> error(String msg) { ... } }

然后写一个全局异常处理器,用@RestControllerAdvice捕获业务异常和参数校验异常,统一包装成Result返回,不要在每个Controller里写try-catch。这个做法在论文里可以写在“系统异常处理模块设计”章节,是一个实打实的设计点。

4.3 登录认证:JWT加拦截器

Spring Security配置起来复杂,如果是毕业设计,我认为用JWT加HandlerInterceptor是完全够的,而且代码更直观,答辩时容易讲清楚。

核心逻辑分三步:

  1. 用户登录成功后,根据用户ID、用户名、角色id生成token,用JWT工具类签名。
  2. 写一个AuthInterceptor,在preHandle中从请求头Authorization取出token,解析并放入ThreadLocal。
  3. 注册拦截器,拦截不需要放行的路径,如除/login、/register以外的所有/api/**请求。

ThreadLocal存储当前登录用户信息,Controller里通过UserContext.get()获取当前用户,再判断角色权限。这样写起来非常简洁。

4.4 多条件分页查询:案号、客户、承办人、状态组合过滤

案件列表是系统最核心的查询接口,用MyBatis(或MyBatis-Plus)写一个动态SQL。这里给出MyBatis-Plus的LambdaQueryWrapper版本,代码量最少:

@Override public IPage<CaseInfo> queryCasePage(CaseQueryDTO dto) { Page<CaseInfo> page = new Page<>(dto.getPageNum(), dto.getPageSize()); LambdaQueryWrapper<CaseInfo> wrapper = Wrappers.lambdaQuery(CaseInfo.class); wrapper.like(StringUtils.hasText(dto.getCaseNo()), CaseInfo::getCaseNo, dto.getCaseNo()); wrapper.like(StringUtils.hasText(dto.getClientName()), CaseInfo::getClientName, dto.getClientName()); wrapper.eq(dto.getStatus() != null, CaseInfo::getStatus, dto.getStatus()); wrapper.eq(dto.getLawyerId() != null, CaseInfo::getLawyerId, dto.getLawyerId()); // 非管理员只能看到自己名下的案件 wrapper.apply(handleDataScope()); wrapper.orderByDesc(CaseInfo::getCreateTime); return baseMapper.selectPage(page, wrapper); }

注意注释里提到“非管理员只能看到自己名下的案件”。这里就是数据权限控制,不是简单地查询全部再在前端过滤。后端务必做这个过滤,否则前端改一下接口参数就能看到别人的案件,这在答辩时会被指出安全隐患。我的做法是:在service层判断当前登录用户的角色id,如果是律师,就在wrapper上加eq条件lawyer_id=当前用户关联的律师id;如果是前台,则限制为只能看到status为草稿和待分案的案件;管理员和合伙人不限制。

4.5 状态流转的实现:更新主表加写日志,两步走

案件状态不能直接update status了事。正确做法是在service里定义状态流转方法,比如submit(草稿->待分案)、assign(待分案->在办)、close(在办->结案)、archive(结案->归档)。

以分案为例,核心逻辑:

@Transactional public void assignCase(Long caseId, Long lawyerId) { CaseInfo dbCase = getById(caseId); if (dbCase == null) throw new BizException("案件不存在"); if (dbCase.getStatus() != CASE_STATUS_UNASSIGNED) { throw new BizException("当前状态不能分案"); } Lawyer lawyer = lawyerMapper.selectById(lawyerId); if (lawyer == null || lawyer.getStatus() != 1) { throw new BizException("承办律师不可用"); } CaseInfo update = new CaseInfo(); update.setId(caseId); update.setLawyerId(lawyerId); update.setAssignTime(new Date()); update.setStatus(CASE_STATUS_IN_PROGRESS); updateById(update); CaseStatusLog log = new CaseStatusLog(); log.setCaseId(caseId); log.setFromStatus(CASE_STATUS_UNASSIGNED); log.setToStatus(CASE_STATUS_IN_PROGRESS); log.setOperatorId(UserContext.getUser().getId()); log.setOperatorName(UserContext.getUser().getRealName()); log.setRemark("分案给:" + lawyer.getName()); caseStatusLogMapper.insert(log); }

@Transactional一定要加,因为更新主表状态和插入日志表必须作为一个原子操作。String state if update fails, log shouldn't remain.

结案同理,在办状态才能结案,结案时要校验开庭记录是否已登记(业务规则)。归档操作则限制为只有管理员和合伙人能操作。这些规则在答辩时都是极好的防守点。

4.6 文件上传与预览

文件上传使用MultipartFile接口,保存到服务器固定目录,文件名用UUID重命名。预览时直接返回文件流并设置Content-Type。注意上传接口要限制文件大小,SpringBoot的配置文件里设置spring.servlet.multipart.max-file-size=10MB即可。还有一个坑是部署到服务器后localhost路径问题,建议前端保存出的访问地址用相对路径拼接,否则换服务器就裂了。

5. Vue前端开发:让页面真正能用起来

前端我推荐用Vue 2加Element UI,如果你对Vue 3熟悉,就选Vue 3加Element Plus。两者写法差别不大,重点是别混着用组件库。下面以Vue 2为例说明。

5.1 项目起始结构与路由守卫

前端项目结构大概是views(页面)、router(路由)、api(axios请求封装)、components(组件)、store(Vuex,用于保存用户信息和token)。

路由需要做登录守卫:在main.js里配置beforeEach,检查本地localStorage有没有token;没有token又进入了需要登录的页面,就跳转到/login。这个用一句话就能完成:

router.beforeEach((to, from, next) => { const token = localStorage.getItem('token'); if (to.path === '/login') { next(); } else { if (!token) { next('/login'); } else { next(); } } });

要记住,前端守卫只是体验优化,真正的安全校验在后端拦截器。

5.2 axios封装与token携带

axios实例需要统一设置baseURL和请求头。建议把baseURL配在env环境变量里,或者通过vue.config.js的proxy代理到后端,避免开发时跨域。

拦截器统一做两件事:请求前带token,响应后统一处理401和业务错误。

service.interceptors.request.use(config => { if (localStorage.getItem('token')) { config.headers['Authorization'] = localStorage.getItem('token'); } return config; }); service.interceptors.response.use( res => { if (res.data.code === 401) { router.push('/login'); return Promise.reject(res.data); } return res.data; }, err => { return Promise.reject(err); } );

5.3 案件列表页:表格加条件查询加操作按钮

案件列表是前端工作量最大的页面,包含搜索区、案件表格、分页器和操作按钮。搜索区条件有案号、客户姓名、案件状态、承办律师。操作按钮根据状态显示不同内容:待分案显示“分案”,在办显示“结案”,结案显示“归档”。这里用到el-table的列render函数或通过template判断:

<el-table-column label="操作" width="240"> <template slot-scope="scope"> <el-button v-if="scope.row.status===1" type="warning" @click="openAssignDialog(scope.row)">分案</el-button> <el-button v-if="scope.row.status===2" type="success" @click="closeCase(scope.row.id)">结案</el-button> <el-button v-if="scope.row.status===3 && isAdmin" type="info" @click="archive(scope.row.id)">归档</el-button> </template> </el-table-column>

这个条件按钮的设计,后端一定也要有对应的状态校验,不能只靠前端隐藏。

5.4 案件详情页:时间线展示状态流转

案件详情页除了基本信息表单外,强烈建议加一个时间线,展示案件从登记到当前每一步操作记录。正好对应后端case_status_log表。

Element UI自带el-timeline组件:

<el-timeline> <el-timeline-item v-for="(log, index) in statusLogs" :key="index" :timestamp="log.createTime" :type="index === 0 ? 'primary' : ''"> {{ log.operatorName }} 将案件状态从 {{ statusText(log.fromStatus) }} 变更为 {{ statusText(log.toStatus) }},备注:{{ log.remark }} </el-timeline-item> </el-timeline>

这个页面在答辩演示时扫一眼就能看到“这个系统的状态流转是真实记录的”,比任何口头解释都有说服力。

5.5 统计报表:ECharts图表

首页放两张图:一个柱状图展示最近6个月收案数量变化,一个饼图展示案由分布。接口后端做聚合查询,返回两个数组;前端用ECharts渲染。ECharts的引入建议通过npm安装,不要用CDN,因为答辩现场如果没有网络,图表会直接空白。

5.6 前端环境配置的几个大坑

第一个坑是Node版本过高导致node-sass安装失败,如果是Vue2项目,建议Node 14或16,或者干脆改用sass(dart-sass)替代node-sass。第二个坑是vue.config.js的devServer.proxy没有配置,前端请求后端出现跨域报错。下面是一段可用的配置:

module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } };

把后端的Controller统一加一个/api前缀,开发时就不会有跨域问题。

6. 交付物怎么准备:数据库脚本、部署文档、论文与答辩防守

6.1 数据库脚本必须包含初始化和演示数据

交付的数据库脚本不能只有建表语句,还要插入测试数据,否则老师导入数据库后打开系统,所有列表都是空白的,体验非常差。测试数据建议覆盖多个状态:几条草稿案件、几条在办案件、一条结案案件、一条归档案件,并把律师、客户、费用记录、状态日志都补齐。这样演示时可以直接演示“分案”和“结案”的完整流程,不用先录入数据。

账号方面至少准备四个:admin、partner、lawyer、receptionist,密码统一初始化为123456,并在部署文档里写清楚。

6.2 部署文档怎么写

一份合格的部署文档要包含:环境要求(JDK 1.8+、Node 14+、MySQL 5.7/8.0、Maven 3.6+)、数据库导入步骤、后端启动步骤、前端启动步骤、默认账号清单。我特别建议把后端和前端启动命令都写在文档里,并且注明端口,比如后端8080,前端80或8081。如果你是打包成jar部署,记得写清楚jar包启动命令和前端build后的静态资源配置。很多学生在部署环节栽跟头,往往就是没写清楚MySQL是否需要新建一个专用用户、数据库字符集是utf8mb4还是utf8。

6.3 论文结构建议

论文题目就可以叫《基于SpringBoot和Vue的律师事务所案件管理系统的设计与实现》。章节结构按标准来:

  • 第1章 绪论:背景、国内外研究现状、目的意义。重点写“当前很多律所仍用Excel管理案件,存在信息孤岛、统计困难、状态不透明”等痛点。
  • 第2章 相关技术介绍:Spring Boot、Vue、MySQL、MyBatis-Plus、JWT。不要抄博客,用自己的话写。
  • 第3章 需求分析:功能需求、角色需求、用例图。
  • 第4章 系统设计:总体架构、功能模块划分、数据库表设计、类设计。
  • 第5章 系统实现:每块功能的核心代码截图加解释。
  • 第6章 系统测试:测试用例表、结果分析。

答辩演示环节,两个问题要提前准备:一是“归档后的案件数据怎么查”,可以答“归档只是锁定编辑权限,查询列表仍可查,并可在统计报表中纳入归档案件”;二是“如果同一个案号重复录入怎么办”,可以答“数据库唯一约束+后端主动查重+前端即时提示,三层保障”。这两个问题都直接对应你设计里的细节,答得越具体越好。

6.4 容易被忽略的安全与异常处理点

最后提醒三个收尾细节。一是统一异常处理必须覆盖参数校验失败的情况,不能直接抛500给前端,要返回友好提示。二是对密码进行加密存储,登录接口返回token时不要把密码字段序列化进JSON,可以在实体类密码字段上标注@JsonIgnore。三是所有文件上传接口要校验文件扩展名,防止上传jsp、exe这类危险文件。这些点都是论文“系统实现”章节的加分素材,答辩时主动提出来,比被动问出来强太多。

我在实际带项目的过程中,发现学生最容易把时间耗在系统中那些“锦上添花”的部分,比如公告栏的富文本编辑、消息通知、复杂的权限粒度设计。我的建议是先把案件管理主流程跑通,再把统计报表和时间线做出来,最后有余力再考虑美化页面。毕业设计的核心是逻辑闭环清晰可见,而不是功能数量无限膨胀。按这条路线走,大约一周多的时间就能完成从建表到答辩文档的全部工作量。希望这份拆解能让你少走几段弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询