首页 / 资讯中心 / 文章详情

SpringBoot+Vue公共法律服务平台JavaWeb项目实战详解

SpringBoot+Vue公共法律服务平台JavaWeb项目实战详解 ★ FEATURED ARTICLE
做公共法律服务平台这个选题不是因为它热门而是它把很多 JavaWeb 的基础点都串起来了。SpringBoot、MyBatis Plus、MySQL、Redis、JWT、Vue这些技术在毕业设计里几乎是标配但真正要把一个类似“智慧法务在线服务与咨询系统”的需求落地还得老老实实走一遍需求分析、表结构设计、状态流转、权限控制这些步骤。这篇文章把我从零到一实现这个项目的过程、关键代码、踩过的坑以及答辩时常被追问的细节都拆开讲准备选同类型题目的同学可以直接拿来当参考。1. 项目概述与需求拆解1.1 项目定位与核心需求解析公共法律服务平台本质上是一个信息中介和业务流程管理平台。普通用户需要找律师做法律咨询申请法律援助律师需要接收咨询单、回复问题、管理案件管理员需要审核律师资质、审核援助申请、维护法律资源。只做一个静态页面显然不够必须有一整套用户体系、业务流转数据和权限控制。我从需求分析开始把项目拆成在线法律咨询、法律援助申请、法律资源管理、律师入驻审核、后台数据统计五个功能域。标题里提到的“智慧法务在线服务与咨询系统”核心就是把咨询、援助、资源这三个主要业务信息化而“数字化法律援助与资源管理平台”强调的是审核、指派、资源沉淀这些管理操作。这个定位决定了系统不是简单的 CMS而是有明确状态流转的业务系统。需求分析阶段最容易犯的错是一上来就写代码。我做这个项目时先列了用户故事比如“作为普通用户我希望发布一个法律咨询单后能看到律师接单进度”“作为律师我希望系统只推送平台审核通过后的咨询单”。把这些用户故事整理成功能清单再倒推数据库表后面编码会顺利很多。1.2 用户角色与核心业务流程系统主要有三类角色他们的操作边界差异很大。普通用户是求助者律师是服务提供方管理员是审核方。我用一张表把角色、核心操作和权限边界固定下来角色核心操作权限边界普通用户发布咨询、回复咨询、申请法律援助、查看资源只能管理自己的数据不能审核、不能指派律师律师接单、回复咨询、查看指派给自己的援助案件不能编辑资源、不能查看其他律师的私密咨询管理员审核律师入驻、审核援助申请、指派律师、维护资源分类不能代替用户发起咨询、不能干预具体咨询内容核心业务闭环可以用一条流程串起来用户注册登录浏览公开的法律资源遇到具体问题后发布咨询单律师接单并回复如果符合法律援助条件用户可以填写援助申请管理员审核后指派律师律师进行线下服务最后用户在线上确认结果。此外还有一条辅助流程是律师入驻。普通用户申请成为律师时需要提交姓名、执业证号、专业领域、执业年限管理员审核通过后该用户才会在角色上拥有律师权限。这里的核心技巧是不要把“律师”简单做成一个布尔字段而要把“申请-审核-通过”这个过程记录下来方便管理员追溯。2. 技术选型与整体架构设计2.1 后端框架选型SpringBoot 的取舍我选择 SpringBoot 而不是传统 SSM 框架最关键的原因是 SpringBoot 把 Spring 的很多配置自动化了内嵌 Tomcat打一个 jar 包就能跑对毕业设计来说部署和演示都非常方便。更重要的是SpringBoot 生态很完整MyBatis Plus、Spring Data Redis、JWT 这些组件都能快速整合不用像 SSM 那样写一堆 XML 配置。也有同学问为什么不直接用 Spring Cloud 微服务。做这个项目时我认真想过单机应用场景下拆微服务纯粹是增加复杂度。公共法律服务平台的数据一致性要求高比如审核指派、律师接单一旦拆成多个服务事务和部署难度都会上升答辩时反而容易被评委追问“你这个场景有必要用消息队列吗”。技术选型要匹配业务规模这也是一个值得在论文里写的观点。2.2 技术栈清单与关键依赖完整的后端技术栈如下技术版本参考主要作用Spring Boot2.7.14后端基础框架自动配置内嵌TomcatMyBatis Plus3.5.3ORM框架提供BaseMapper和分页插件MySQL8.0业务数据持久化Redis2.xSpring Data Redis缓存登录状态或验证码提升热点资源访问速度JWT0.11.5登录令牌签发与校验Lombok1.18.x减少实体类getter/setter代码Hutool5.x加密、日期处理等工具集前端用的是 Vue 3 Element Plus Axios通过 Vite 构建。前后端分离是现在比较主流的做法也是这个题目比较合理的呈现方式。Maven 关键依赖片段如下dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId version0.11.5/version scoperuntime/scope /dependency这里特别注意 JWT 依赖版本。很多老教程还在用 0.9.1那个版本在 JDK8 以上容易出现jjwt依赖冲突而且新版 API 变化比较大。用 0.11.5 之后Jwts.builder()和Jwts.parserBuilder()的用法更清晰答辩讲起来也更有底气。2.3 整体架构与项目目录规划系统采用前后端分离架构后端提供 RESTful 接口前端通过 Axios 调用接口。后端目录按职责分层每一个包只干一件事这样答辩时能清晰地讲出每一层的职责后续加功能也容易定位。后端项目的代码结构如下src/main/java/com/legal/platform ├── controller # 接口层 ├── service # 业务逻辑层 ├── mapper # 数据访问层 ├── entity # 实体类 ├── dto # 请求和响应对象 ├── common # 统一返回结果、异常处理、常量 ├── config # MyBatis Plus、Redis等配置 └── security # JWT工具、拦截器、注解前端目录相对简单views按模块放页面api里统一封装请求方法router配置路由和导航守卫。路由守卫很重要比如没有管理员权限的用户访问后台页面时前端要直接跳转到 403 页面而不是等后端接口报错。整体架构上我没有做 Nginx 负载均衡因为单机部署足够。但我在前端打包后使用 Nginx 托管静态页面再把后端接口通过反向代理转发到 8080 端口这样演示时只需要暴露一个 80 端口体验更接近真实上线环境。3. 核心功能设计与数据模型3.1 数据表规划与关联关系数据库设计是毕业设计的重头戏也是评委会盯着看的部分。我先梳理实体关系用户与律师资料是 1 对 1用户与咨询单是 1 对多咨询单与回复是 1 对多用户与法律援助申请是 1 对多法律援助申请与律师是 多 对 1。核心表规划如下表名作用关键字段sys_user用户账号表username、password、role、statuslawyer_profile律师资料扩展表user_id、real_name、license_no、specialty、audit_statusconsultation咨询单表user_id、lawyer_id、title、content、statusconsultation_reply咨询回复表consultation_id、from_user_id、contentlegal_aid_apply法律援助申请表user_id、apply_type、case_desc、status、assign_lawyer_idlegal_resource法律资源表title、category、content、view_count建表时一定要加create_time和update_time这是 MyBatis Plus 自动填充的好帮手也可以作为论文里“时间维度审计”的素材。咨询单表的核心建表语句我写在这里CREATE TABLE consultation ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL COMMENT 提问用户ID, lawyer_id BIGINT DEFAULT NULL COMMENT 接单律师ID, title VARCHAR(100) NOT NULL COMMENT 咨询标题, content TEXT NOT NULL COMMENT 咨询内容, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待受理 1已接单 2已回复 3已关闭, is_public TINYINT DEFAULT 1 COMMENT 是否允许公开展示, create_time DATETIME NOT NULL, update_time DATETIME NOT NULL, KEY idx_user_id (user_id), KEY idx_status (status) );这里我没有设置外键而是用索引来关联业务关系。实际项目中使用物理外键会导致删除、更新很麻烦也不利于分库分表所以通过逻辑外键来维护关系是更常见的实践。这一点可以在论文的数据设计部分专门说明。3.2 认证授权与角色权限设计认证授权这块我没有直接引入 Spring Security而是用 JWT 加自定义拦截器实现。这样做的原因有两个第一需求里只涉及三种固定角色不需要动态权限模型第二自己实现拦截器能把“登录态校验-角色判定”讲得非常清楚答辩时更容易展示你对权限控制的理解。用户登录成功后后端签发一个 JWT里面放入userId和role两个自定义声明。后续请求在请求头带上Authorization: Bearer token拦截器会解析 token把用户信息放入ThreadLocal业务代码里通过一个静态方法获取当前登录用户。密码用 BCrypt 加密存储。BCrypt 每次生成的哈希值不同同一密码在不同时间的密文都不一样可以有效防止彩虹表破解。即使数据库泄露攻击者也没办法直接还原明文密码。这是安全设计中必须写进文档的一点。角色权限通过注解和拦截器配合完成。我自定义了一个RequireRole注解标注在 Controller 方法上。拦截器在进入方法前先判断当前用户角色是否匹配如果不匹配直接返回 403。比如GetMapping(/admin/audit/list) RequireRole(ADMIN) public Result auditList(...) { return Result.ok(); }这种写法的好处是权限控制和业务代码分离看代码的人一眼就能知道接口是否限制角色。前端侧再配合路由守卫控制页面跳转形成双重防护。3.3 咨询与法律援助状态机设计状态机是公共法律服务平台里最容易讲出亮点的设计点。咨询单不能随意从“待受理”跳到“已关闭”必须按照业务流程逐步流转。我用状态字段加操作接口的方式把合法流转路径固定下来。咨询单状态如下状态值含义可执行操作0待受理律师接单用户取消1已接单律师回复用户回复关闭2已回复继续回复关闭3已关闭无法律援助申请状态如下状态值含义可执行操作0待审核管理员审核通过/驳回1审核通过管理员指派律师2已指派律师确认接收用户查看结果3已完成无4已驳回用户重新申请为什么一定要用状态机因为如果普通用户直接调用接口把自己的申请改成“已完成”业务流程就乱了。后端的每一次修改都必须校验前置状态比如“指派律师”只能在“审核通过”状态下执行。我在代码里统一封装了状态变更服务避免散落在各个 Controller 里出现逻辑漏洞。4. 核心模块实现与实操要点4.1 登录认证与 JWT 拦截器登录模块是整个系统的入口实现起来并不复杂但容易忽略细节。用户提交用户名和密码后后端从数据库查出用户用 BCrypt 校验密码成功后签发 token。JWT 工具类的核心方法如下public String generateToken(Long userId, String role) { return Jwts.builder() .claim(userId, userId) .claim(role, role) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() 24 * 60 * 60 * 1000)) .signWith(key, SignatureAlgorithm.HS256) .compact(); }登录接口PostMapping(/login) public Result login(RequestBody LoginDTO dto) { User user userService.lambdaQuery() .eq(User::getUsername, dto.getUsername()) .one(); if (user null || !PasswordEncoder.matches(dto.getPassword(), user.getPassword())) { return Result.error(用户名或密码错误); } String token jwtUtil.generateToken(user.getId(), user.getRole()); return Result.ok().put(token, token).put(role, user.getRole()); }拦截器在preHandle中解析 token如果 token 非法或过期直接返回未登录的错误码。同时要放行登录接口、公共资源查询接口等白名单路径。这里有一个容易被忽视的点需要处理前后端跨域问题。如果前端和后端不在同一个端口请求会被浏览器拦截因此需要配置CorsFilter允许前端地址跨域访问。4.2 在线咨询与回复模块在线咨询是这个平台的核心模块也是并发问题最明显的地方。用户发布咨询单以后平台可能会推送给多个律师但一个咨询单只能被一个律师接走。如果不在数据库层面做并发控制两个律师同时点击接单就有可能都成功造成重复指派。解决这个问题最可靠的做法不是先把数据查出来判断状态再执行更新而是直接用带条件的更新语句boolean updated consultationService.update( new LambdaUpdateWrapperConsultation() .eq(Consultation::getId, id) .eq(Consultation::getStatus, 0) .set(Consultation::getStatus, 1) .set(Consultation::getLawyerId, currentUserId) ); if (!updated) { return Result.error(该咨询单已被其他律师接单); }这段代码的核心在于WHERE status 0。即使两个请求同时到达数据库的行锁也会保证只有一个更新语句影响行数为 1另一个更新影响行数为 0从而被判断为失败。这是“乐观锁”思想的一种实现方式不需要额外加版本号字段也比先查询再更新更安全。用户和律师的回复记录都写入consultation_reply表插入回复后需要把咨询单状态改成“已回复”。回复操作必须加事务因为要么回复记录插入成功并且状态更新成功要么两者都不变。使用Transactional可以保证这一点。常见问题是事务不生效很多情况是同类中方法直接调用导致代理失效解决办法是把事务方法放到另一个 Service 类中或者通过注入自身代理对象调用。4.3 法律援助申请与审核模块法律援助申请模块涉及实名信息和材料上传我把用户身份证号码和手机号做了脱敏处理在后台列表中默认显示中间四位打码。用户提交申请时可以选择类型比如民事援助、劳动仲裁援助等并上传证明材料图片。申请流程中文件上传是一个实操重点。我使用本地磁盘存储上传文件把物理路径保存到数据库文件访问通过虚拟路径映射。前端上传时限制文件类型和大小后端也要再次校验。如果我写的是MultipartFile上传接口会同时校验文件后缀名和 MIME 类型防止把恶意文件传到服务器。管理员审核通过后需要给申请指派律师。指派操作和律师接单是类似的场景同样要防止两个管理员同时对同一个申请指派。所以我使用了跟接单一样的条件更新boolean assigned legalAidService.update( new LambdaUpdateWrapperLegalAidApply() .eq(LegalAidApply::getId, aidId) .eq(LegalAidApply::getStatus, 1) .set(LegalAidApply::getStatus, 2) .set(LegalAidApply::getAssignLawyerId, lawyerId) );指派成功后用户可以查看援助进度律师也能在“我的援助案件”列表中看到分配下来的申请。这里还需要加入一个提醒机制我使用了简单的站内消息表在审核通过、指派成功等关键节点生成一条消息通知比每次都手动查询业务表要符合用户习惯也让系统看起来更有“智慧”感。4.4 法律资源管理与前台展示法律资源模块实现了分类管理、列表分页、详情查看和搜索。管理员在后台维护资源分类比如“婚姻家庭”“劳动纠纷”“合同债务”发布资源时使用富文本编辑器内容以 HTML 形式保存。重点是前端展示时要做好 XSS 过滤我引入了一个简单的 HTML 白名单过滤器只允许ph2ul这类标签通过避免用户提交恶意脚本。资源列表使用 MyBatis Plus 分页插件查询条件包含标题关键字、分类、创建时间。分页插件配置很简单创建MybatisPlusInterceptor并添加PaginationInnerInterceptor即可。因为题目中“资源管理平台”这个定位除了增加浏览量还可以增加“点赞”或者“收藏”功能丰富系统的可讲内容。前台页面展示法律资源时需要把咨询单和资源分开。公开的咨询回复内容如果设置为is_public 1可以匿名脱敏展示在类似“普法问答”栏目这样既能保护用户隐私又增加了平台内容厚度是一个低成本高收益的设计。5. 常见问题与排查技巧实录5.1 项目启动阶段的坑我遇到的第一个问题是 MySQL 连接报时区错误The server time zone value ???ú±ê׼ʱ¼ä is unrecognized。解决方式是连接串中加上serverTimezoneAsia/Shanghai同时使用useSSLfalse来避免无用的安全警告。第二个常见问题是 Redis 闪退导致登录验证码接口不可用。如果功能没有强依赖 Redis最好在配置中允许降级或者简单一点先不集成 Redis用 JWT 本身去维持登录态也能完成毕业设计核心要求。但如果加了 Redis答辩时可以讲“热点法律资源缓存到 Redis”前提是配置和依赖都要调通。第三个坑是 Maven 依赖冲突。尤其是 JWT 库与老版本 Spring Boot 整合时容易出现NoClassDefFoundError。我建议使用 0.11.5 版本的jjwt-api和jjwt-impl并在启动后立即测试登录接口遇到报错直接看Caused by定位是哪个类找不到。项目启动时端口被占用也是高频问题。Windows 下可以用netstat -ano | findstr 8080找到占用进程然后到任务管理器结束进程。Linux 下用lsof -i:8080。别直接改端口逃避因为前端代理和后端配置都要联动修改。5.2 并发与数据一致性问题除了接单和指派用户重复提交表单也会造成脏数据。比如用户快速连续点击“提交法律援助申请”会插入两条相同记录。解决方法是后端在插入前增加幂等校验或者在表上增加唯一约束。最直接的方式是前端提交后立刻禁用按钮后端再根据申请类型、身份证号和时间窗口做一次查重双保险。另外要特别留意Transactional失效的情况。我在调试时发现同一个类中一个方法调用另一个带事务注解的方法事务可能不生效因为 Spring 的 AOP 代理默认是外部调用才生效。例如在ConsultationService的closeConsultation()中直接调用updateStatus()后者虽然标了Transactional但不走代理事务不会正常回滚。解决方案是把事务方法放到独立的 Service 类中或者在当前类中注入自身代理。5.3 答辩前需要准备的关键点答辩时评委很少会一句一句看代码更多是围绕设计和技术决策提问。我准备了几个高频问题第一为什么表结构要用逻辑外键而不是物理外键。我会回答物理外键在插入和删除时开销更大也限制表结构的调整逻辑外键搭配数据库索引足够满足当前系统并发的需求而且更符合实际项目的规范。第二为什么选择自定义 JWT 拦截器而不使用 Spring Security。我会说当前系统角色少需求简单自定义方案能精确控制权限逻辑如果未来需要复杂权限模型可以再平滑迁移到 Spring Security不影响业务层代码。第三如何保证数据安全。我会从密码 BCrypt 加密、JWT 过期时间、SQL 预编译、XSS 过滤四个层面分别说明。别只答“用了某某加密”要讲清楚解决了什么问题。第四系统如何部署。我会讲后端打包jar、前端npm run build生成静态资源再放到 Nginx 下由 Nginx 反向代理到后端接口。如果评委问“能不能直接访问”我会把localhost:80的演示地址说明一遍。5.4 给做这个题目的同学一些额外建议我个人做完这个项目的最大感受是先把最核心的闭环跑通再谈扩展。很多同学一开始就想着做在线聊天、视频咨询、智能问答结果核心的业务流程都没理顺最后论文拼凑痕迹严重。公共法律服务平台最值得投入精力的是咨询单状态流转和援助指派逻辑这两个地方能体现系统设计能力。还有一个小技巧是开发过程中坚持记录问题和解决方案。我建了一个简单的文档表格每次遇到报错、修复过程、是否复发都记下来。最后写论文时这些记录直接变成“系统调试与测试”章节的素材比临时回忆可靠得多。最后在合理参考开源项目时要带着问题去看代码比如“接单这段如果不用条件更新会怎样”“这个接口不加权限会怎样”。只有把别人的设计转化成自己能讲清楚的知识答辩时才不会心虚。公共法律服务这个方向后续还有很多扩展空间比如对接第三方电子签章、短信提醒、案例库检索如果时间允许挑一个点深入做进去项目还会有更大的加分空间。
阅读完成 · 觉得有帮助?
咨询建站