Java全栈实战:基于SpringBoot3+Vue3的法律文书模板共享平台开发
2026/9/5 18:22:54 网站建设 项目流程

在做正式的 Java 全栈项目之前,要先有一个判断:法律文书模板共享平台表面上只解决“模板文件分享”的问题,底层其实是一个内容管理 + 用户权限 + 审核流程 + 搜索下载的完整系统。这次我们看的这套技术选型很直接:后端用 SpringBoot3,前端用 Vue.js3,数据库用 MySQL,前后端分离,所有核心功能都能通过这套组合落地。

先把结论放前面。这套平台能实现的能力包括用户注册登录、JWT 鉴权、文书分类展示、模板上传与审核发布、关键词搜索、下载次数统计、收藏评论、后台用户管理、模板上下架和基础数据看板。相比只写 CRUD 的练习项目,它更贴近真实的“资源共享 + 平台运营”场景,不管是用作律所内部工具、给企业法务做合同模板库,还是拿来作为 Java 全栈开发的学习项目和毕设选题,都合适。

这篇文章会从架构和技术栈开始,依次梳理核心能力、适用边界、本地部署环境、MySQL 数据库设计、SpringBoot3 后端启动、Vue3 前端联调、功能测试、API 调用与批量数据导入、资源占用与性能观察,最后是排错清单和最佳实践。所有命令、配置和 SQL 都按通用工程模板给出,落地到自己项目里时,以实际包结构和路径为准。

1. 核心能力速览

先把项目画像整理出来,方便快速判断它是否满足你当前的需求。

能力项说明
项目类型Java Web 前后端分离系统,属于模板共享 / 内容管理平台
后端框架SpringBoot3,JDK 17 及以上
前端框架Vue.js3 + Vite,组件库可用 Element Plus
数据库MySQL 8.x,建议使用 utf8mb4 字符集
认证方案JWT 无状态认证,普通用户 / 管理员双角色
核心功能注册登录、模板分类、模板上传、后台审核、搜索筛选、下载统计、收藏评论
是否支持批量任务支持批量模板导入,建议分批写入数据库
是否需要 GPU不需要,属于常规 Web 应用,关注 CPU、内存、磁盘和数据库连接
部署方式本地 IDE 运行、Maven 打包 jar、前端 build 后 Nginx 托管
适合场景律所知识库、法务合同管理、法律文书模板共享站、毕业设计

从技术角度看,这是一个典型的“管理后台 + 门户前台”结构。前台展示模板列表、详情、下载和评论,后台负责模板审核、分类维护、用户状态管理和数据查看。主流配置的笔记本或服务器都能运行,没有特殊硬件门槛。

整个平台表结构也比较清晰:用户表、分类表、模板表、审核记录表、收藏表、评论表、下载日志表。模板本身既可以直接存正文,也可以保存文件链接。如果是纯正文模式,搜索方便;如果是上传 Word/PDF 模式,需要另外做文件管理。推荐的做法是二选一或同时保留:模板详情页展示富文本正文,附件下载存文件路径。

2. 适用场景与使用边界

2.1 适用场景

这类平台在以下几个场景里是真实需求的:

  • 律所内部使用:把常用的民事起诉状、答辩状、劳动合同、律师函模板统一管理,避免不同律师各自保存一份,版本不一致。
  • 企业法务部门:合同模板、告知函、催款函等文件集中沉淀,员工按需查看下载,降低重复起草成本。
  • 法学院校或培训机构:作为模拟法庭、法律文书写作课程的案例库和素材库。
  • Java 学习者和应届生:把该系统作为 SpringBoot3 + Vue3 + MySQL 全栈练习项目,覆盖用户认证、RBAC、文件上传、审核流、搜索、图表统计等常见开发点。

2.2 使用边界与合规提醒

这里必须重点说清楚边界:

  • 模板内容只能作为“参考框架”,不能替代执业律师的意见。涉及重大财产、人身权益或具体争议的案件,仍要有专业律师审查把关。
  • 上传者不能随意上传他人享有著作权的文书、合同范本或内部材料,要确保自己有权复制、修改和分发。
  • 平台如果保存用户上传的案件材料,涉及隐私和商业秘密,要做好权限隔离和脱敏处理,不能把非公开文书随意展示。
  • 如果计划商用,要在用户协议和内容审核规则里明确禁止违禁、歧视、虚假或有损第三方权益的内容。
  • 开发者在展示系统时,也应该避免上传真实当事人信息,建议使用脱敏数据和公开范本做演示。

总的来说,这个平台适合承担“模板资产的沉淀和共享”,不适合代替法律专业判断。

3. 法律文书模板共享平台本地部署环境准备

在写代码和跑项目之前,先把环境检查一遍。推荐环境如下:

软件版本建议作用
JDKJDK 17 及以上运行 SpringBoot3
MavenMaven 3.8+后端依赖管理和打包
Node.jsNode.js 18 或 20 稳定版运行 Vue3 前端工程
MySQLMySQL 8.0+数据存储
数据库客户端Navicat、DBeaver 等导入 SQL、查看数据
IDEAIntelliJ IDEA 2023+后端开发调试,也可以直接用 VS Code 开发前端

3.1 JDK 与 Maven 环境配置

如果机器上没有 JDK,需要先下载对应平台的 JDK 17 或更高版本。Windows 下配置环境变量时,可以新建系统变量:

JAVA_HOME=C:\Program Files\Java\jdk-17.0.12

然后在 Path 中追加:

%JAVA_HOME%\bin

配置完成后,重新打开终端,执行下面命令验证:

java -version mvn -v

能够正常输出版本号,说明 Java 环境已经可用。

macOS 或 Linux 下可以更简单地在当前 shell 中导出:

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home export PATH=$JAVA_HOME/bin:$PATH

这里要注意的是:SpringBoot3 最低要求 JDK 17。如果本机还是 JDK 8,项目连编译都过不去,不要想着降级硬跑。

3.2 MySQL 安装与连接准备

数据库可以选择本机安装,也可以使用 Docker 快速启动一份 MySQL 8。比较推荐在开发阶段用 Docker,因为卸载和重置都方便。例如:

docker pull mysql:8.0 docker run -d \ --name legal-mysql \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=root123456 \ -e MYSQL_DATABASE=legal_template \ -v /data/mysql:/var/lib/mysql \ mysql:8.0

实际使用时,把root123456替换成自己的密码,3306如果被占用也要调整。

如果选择本机安装 MySQL,安装完成后可以用数据库客户端连接测试。这一步经常遇到两个问题:

  • 通过 Navicat 连接 MySQL 提示Authentication plugin 'caching_sha2_password' cannot be loaded,通常是 MySQL 8 默认认证插件和客户端版本不匹配,升级客户端到较新版本即可,或者创建用户时指定mysql_native_password
  • 通过命令行连接时提示ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock',大概率是 MySQL 服务没有启动或 socket 路径和客户端预期不一致。先确认服务状态,再检查/etc/my.cnf/usr/local/etc/my.cnf里的 socket 配置。

数据库创建完成之后,建议执行一次简单查询:

SELECT VERSION();

能输出 MySQL 版本,说明后端服务可以后续正常连接。

4. 法律文书模板平台 MySQL 数据库设计

这一节给出一个可以直接落地的数据库设计参考。表结构不是一个严格标准,但它覆盖了平台核心功能,可以根据实际业务调整。

4.1 用户表

用户表保存登录账号和角色。角色字段可以直接用字符串,简单项目不建议拆出多张角色表,除非以后需要复杂的按钮级权限控制。

CREATE TABLE sys_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID', username VARCHAR(50) NOT NULL COMMENT '登录名', password VARCHAR(120) NOT NULL COMMENT 'BCrypt加密后的密码', nickname VARCHAR(50) DEFAULT '' COMMENT '昵称', avatar VARCHAR(255) DEFAULT '' COMMENT '头像', role VARCHAR(20) NOT NULL DEFAULT 'USER' COMMENT 'USER / ADMIN', status TINYINT NOT NULL DEFAULT 1 COMMENT '1正常 0禁用', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_username (username) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表';

密码不能明文保存,后端在注册时统一使用 BCrypt 加密。

4.2 分类表与模板表

分类表用来维护起诉状、合同协议、答辩状、申请书、律师函等文书分类。

模板表是整个平台的核心表,里面需要记录标题、摘要、正文或文件路径、上传人、审核状态、下载量、浏览量。

CREATE TABLE legal_category ( id BIGINT PRIMARY KEY AUTO_INCREMENT, parent_id BIGINT DEFAULT 0 COMMENT '父分类ID,0表示根分类', name VARCHAR(100) NOT NULL, sort INT DEFAULT 0, status TINYINT DEFAULT 1, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='法律文书分类表'; CREATE TABLE legal_template ( id BIGINT PRIMARY KEY AUTO_INCREMENT, category_id BIGINT NOT NULL COMMENT '分类ID', title VARCHAR(200) NOT NULL COMMENT '模板标题', summary VARCHAR(500) DEFAULT '' COMMENT '摘要', content MEDIUMTEXT COMMENT '模板正文,支持富文本', file_path VARCHAR(255) DEFAULT '' COMMENT '附件相对路径', file_name VARCHAR(255) DEFAULT '' COMMENT '原始文件名', author_id BIGINT NOT NULL COMMENT '上传用户ID', view_count BIGINT DEFAULT 0, download_count BIGINT DEFAULT 0, status VARCHAR(20) DEFAULT 'PENDING' COMMENT 'DRAFT草稿/PENDING待审/PUBLISHED已发布/REJECTED已驳回', reject_reason VARCHAR(255) DEFAULT '' COMMENT '驳回原因', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_category (category_id), KEY idx_status (status), KEY idx_title (title) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='法律文书模板表';

注意,下载量字段建议直接用BIGINT,避免INT溢出。在 MySQL 里对 INT 做累加操作并不是永远安全,文档数量大、刷量明显时很容易接近上限,中途再改字段类型会很麻烦。

4.3 收藏、评论、审核、下载日志表

收藏和评论属于用户与模板的交互数据。审核记录表可以保留每一次的审核意见,下载日志表则用于后续统计数据。

CREATE TABLE favorite_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, template_id BIGINT NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_user_template (user_id, template_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='收藏记录表'; CREATE TABLE comment_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, template_id BIGINT NOT NULL, user_id BIGINT NOT NULL, content VARCHAR(1000) NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_template (template_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评论表'; CREATE TABLE template_review ( id BIGINT PRIMARY KEY AUTO_INCREMENT, template_id BIGINT NOT NULL, reviewer_id BIGINT NOT NULL, audit_status VARCHAR(20) NOT NULL, reject_reason VARCHAR(255) DEFAULT '', audit_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='模板审核记录表'; CREATE TABLE download_log ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, template_id BIGINT NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_template (template_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='模板下载日志表';

4.4 模板查询中的排序与统计

模板广场一般需要按“最新”和“热门”排序。最常用的语句是:

SELECT id, title, summary, author_id, view_count, download_count FROM legal_template WHERE status = 'PUBLISHED' ORDER BY download_count DESC, update_time DESC LIMIT 20;

要确保返回速度稳定,需要关注status + create_time的联合索引。如果需要按分类统计模板数,可以使用分组查询:

SELECT category_id, COUNT(*) AS total FROM legal_template WHERE status = 'PUBLISHED' GROUP BY category_id ORDER BY total DESC;

如果是给后端看板提供统计报表,在数据量不大时用 GROUP BY 已经足够,不需要提前引入复杂报表组件。

5. SpringBoot3 后端启动与常用配置

5.1 工程目录参考

一个常见的 SpringBoot3 + MyBatis-Plus 后端工程结构如下:

backend/ ├── pom.xml └── src/main/ ├── java/com/example/legal/ │ ├── LegalTemplateApplication.java │ ├── config/ │ ├── controller/ │ ├── service/ │ ├── mapper/ │ ├── entity/ │ ├── dto/ │ ├── security/ │ └── common/ └── resources/ ├── application.yml └── mapper/

实际包名由项目决定,通常保持com.xxx.legal之类的结构。

5.2 数据源与 MyBatis-Plus 配置

application.yml中配置 MySQL 连接:

server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/legal_template?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: root123456 mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0

如果模板表要支持逻辑删除,可以自行加deleted字段,但上面的建表 SQL 没有包含该字段,保持精简。

5.3 引入核心依赖

pom.xml中至少需要引入 Spring Boot Starter Web、Spring Security、MyBatis-Plus、MySQL Driver、JWT 工具库等依赖。MyBatis-Plus 和 SpringBoot3 整合时要注意引入适配 SpringBoot3 的 starter:

<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.5</version> </dependency>

版本号建议以 Maven 仓库最新稳定版为准。SpringBoot3 的旧版本 MyBatis-Plus 可能会因为包结构调整而启动失败,遇到这种情况优先检查依赖版本是否匹配。

5.4 启动类与安全配置

启动类保持最简:

package com.example.legal; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.example.legal.mapper") public class LegalTemplateApplication { public static void main(String[] args) { SpringApplication.run(LegalTemplateApplication.class, args); } }

如果引入 Spring Security,需要自定义 SecurityFilterChain。JWT 认证的核心逻辑是先放行注册登录接口,再校验请求头里的Authorization: Bearer token

package com.example.legal.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/login", "/api/auth/register").permitAll() .requestMatchers("/api/templates/**", "/api/categories/**").permitAll() .requestMatchers("/api/admin/**").hasRole("ADMIN") .anyRequest().authenticated()); return http.build(); } }

这个配置只是示例,真实的 JWT 过滤器、UserDetailsService、异常处理还需要按项目需要补齐。配置放行时不要把所有接口都放开,否则后台管理就失去了意义。

5.5 后端启动验证

在配置并写好代码后,使用 IDEA 直接运行LegalTemplateApplication,或者使用命令行启动:

mvn spring-boot:run

启动成功后,控制台会看到类似 “Started LegalTemplateApplication” 的日志。如果项目里加了健康检查接口,可以请求:

curl http://localhost:8080/api/health

如果返回正常 JSON,说明后端服务已经可以访问。此时可以先不改动前端,用 Postman、Apifox 或 curl 验证几个核心接口。

6. Vue.js3 前端启动与前后端联调

6.1 创建前端工程

Vue3 工程推荐用 Vite 构建。如果已有前端源码,直接在项目根目录执行依赖安装即可:

npm install npm run dev

如果没有项目基础,只讨论目录设计,则前端常见的结构如下:

frontend/ ├── index.html ├── package.json ├── vite.config.js └── src/ ├── main.js ├── App.vue ├── api/ ├── router/ ├── store/ ├── views/ │ ├── login/ │ ├── template/ │ ├── admin/ │ └── profile/ ├── components/ └── layout/

6.2 前端关键依赖

一个最小可运行的 Vue3 前端依赖大概是这样:

{ "name": "legal-frontend", "version": "1.0.0", "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }, "dependencies": { "axios": "^1.6.0", "element-plus": "^2.6.0", "pinia": "^2.1.7", "vue": "^3.4.0", "vue-router": "^4.3.0" }, "devDependencies": { "@vitejs/plugin-vue": "^5.0.0", "vite": "^5.1.0" } }

版本号只是参考,最终以实际安装为准。

6.3 路由与状态管理

路由可以这样组织:

/login 登录页 / 前台首页,模板列表 /category/:id 分类页 /template/:id 模板详情 /user/profile 个人资料 /admin/template 后台模板管理 /admin/review 后台审核

Pinia 用来保存登录用户信息和 token,刷新页面后可以通过 token 重新拉取用户信息。

6.4 axios 封装与 Token 注入

在 Vue3 中,请求后端接口必须统一处理 token。如果登录成功后将 JWT 保存到了 localStorage,可以通过 axios 拦截器自动注入:

import axios from 'axios' const http = axios.create({ baseURL: '/api', timeout: 15000 }) http.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) http.interceptors.response.use( response => response.data, error => { if (error.response && error.response.status === 401) { localStorage.removeItem('token') window.location.href = '/login' } return Promise.reject(error) } ) export default http

6.5 Vite 代理配置

前端开发服务器默认运行在 5173 端口,如果直接请求localhost:8080,会触发跨域问题。最简单的处理是使用 Vite 代理,把所有/api请求转发到后端:

import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } })

设置完成后,前端只需要请求/api/templates,请求就会被转发到http://localhost:8080/api/templates

6.6 前端启动验证

npm run dev

浏览器访问http://localhost:5173,如果能看到登录页和模板首页,并且后端日志数据同时打印出来,说明前后端已经成功联通。

7. 核心功能测试与效果验证

这里整理一套不依赖生产数据的测试方法,适合本地开发时快速验证系统是否正常。

7.1 用户注册与登录测试

测试目标是确认账号注册、密码加密和 JWT 返回是否正常。

操作步骤为:先调用注册接口创建测试用户,再调用登录接口拿到 token,最后用该 token 请求受保护的接口。

预期结果是:注册成功后 MySQL 的sys_user表新增一条记录,密码是 BCrypt 加密串,不是明文。登录接口返回token字段,携带 token 访问接口能得到当前用户信息。

7.2 模板上传与审核流程测试

测试目标是验证普通用户上传的模板不会立刻出现在公开列表,管理员审核后才会被前台搜索到。

常见角色链路如下:

  1. 普通用户登录,提交一个新模板,设置status = PENDING
  2. 普通用户查询前台列表,看不到自己刚提交的 PENDING 模板。
  3. 管理员登录后台,在待审核列表看到该模板,点击发布。
  4. 普通用户再次查询前台列表,模板已经可见。

如果审核状态没有按流程切换,优先排查legal_template.status是否更新成功,以及后台审核接口是否通过权限校验。

7.3 关键词搜索与分类筛选测试

在模板广场输入关键词,例如“劳动合同”“劳动仲裁”,系统返回标题或摘要中包含该关键词的模板。分类筛选则按左侧分类树过滤出指定分类下的已发布模板。

验证标准是:返回的模板中,status必须都是PUBLISHED,并且分类 ID 或关键词与查询条件匹配。如果出现已驳回模板,需要检查查询 SQL 中是否漏掉了status = 'PUBLISHED'条件。

7.4 下载与收藏测试

下载按钮点击后,模板下载量加 1,并写入download_log表。收藏按钮点击后,则记录在favorite_record表中。

这里要重点测试并发场景。多个用户同时点击下载时,不能因为并发问题导致下载量统计不准。相关 SQL 应使用原子自增:

UPDATE legal_template SET download_count = download_count + 1 WHERE id = ?;

如果先查询再在 Java 代码里做+1后更新,高并发下容易出现丢失更新问题。

7.5 后台管理与数据看板测试

管理员可以查看模板总数、用户总数、分类排行等数据。看板数据可以简单实现为统计 SQL,也可以按日期分组展示新增量。

验证标准是页面显示的统计口径与数据库一致。这里比较容易出问题的是 MySQL 时区。如果数据库和应用服务器时区不一致,按天统计时会差 8 小时,建议连接串统一使用serverTimezone=Asia/Shanghai

8. 法律文书共享平台接口 API 与批量数据导入

8.1 接口调用示例

平台后端提供的是一套 RESTful JSON 接口。以登录接口为例,通过 curl 调用:

curl -X POST http://localhost:8080/api/auth/login \ -H "Content-Type: application/json" \ -d '{ "username": "admin", "password": "123456" }'

正常会返回 token 和用户基本信息:

{ "code": 200, "message": "success", "data": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "userId": 1, "nickname": "管理员", "role": "ADMIN" } }

后续请求模板详情或点赞收藏时,把 token 放到请求头:

curl -X GET http://localhost:8080/api/templates?keyword=%E5%90%88%E5%90%8C \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

如果是 Java 后端之间互相调用,可以使用 JDK 自带的HttpClient,也可以使用 Spring 的RestTemplateWebClient。这里是简单的 Java HTTP 调用示例:

import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class ApiClient { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://localhost:8080/api/templates?keyword=起诉状")) .header("Authorization", "Bearer 你的token") .GET() .build(); HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } }

8.2 批量导入设计

法律文书模板数量通常不是几千上万条起步,但运营过程中会遇到把 Excel、历史 Word 文档、旧系统数据导入新库的需求。批量导入时要把任务拆成“读取、校验、入库”三个步骤:

  • 读取:使用 EasyExcel 或 Apache POI 解析 Excel 文件。
  • 校验:检查标题是否为空、分类是否存在、正文内容是否合规。
  • 入库:分批调用 MyBatis-Plus 的批量插入能力。

如果使用 MyBatis-Plus,推荐直接使用IService.saveBatch,但要注意数据量较大时一次性 saveBatch 也可能触发内存问题。通用做法是手动分批:

List<LegalTemplate> templates = parseExcel(file); int batchSize = 500; for (int i = 0; i < templates.size(); i += batchSize) { int end = Math.min(i + batchSize, templates.size()); List<LegalTemplate> batch = templates.subList(i, end); legalTemplateService.saveBatch(batch); log.info("已导入 {} / {}", end, templates.size()); }

如果要从旧 MySQL 实例同步大批量数据到新库,可以用 DataX 这类离线同步工具。DataX 会把任务拆成分片,并按可配置的 channel、batchSize 参数控制速率,比手写 JDBC 批量插入更稳。

8.3 批量导入中的常见坑

  • 大批量数据一次性INSERT会导致 SQL 超过max_allowed_packet,MySQL 直接拒绝执行。
  • 解析 Excel 时将所有行一次性 readAll 到 List,遇到超大文件会发生java: outofmemoryerror: insufficient memory
  • 内容字段中包含超长文本或特殊字符时,需要按MEDIUMTEXTLONGTEXT存储,不能盲目使用varchar
  • 标题和正文包含敏感信息时需要过滤,否则导入即上线,审核链路失效。

9. JVM 与 MySQL 资源占用观察

法律文书平台不涉及 GPU 推理,资源占用重点在于 JVM 内存、MySQL 连接数和慢查询。

9.1 JVM 资源观测方式

后端服务启动后,可以通过 JDK 自带工具查看 Java 进程状态:

jps -l jcmd <pid> VM.native_memory

也可以通过jconsolevisualvm观察堆内存使用状况。遇到高并发或大量模板导入时,如果日志出现java.lang.OutOfMemoryError,优先调整 JVM 启动参数,而不是先怀疑代码逻辑。例如:

java -jar legal-template-platform.jar -Xms512m -Xmx1024m

9.2 前端构建静态资源

Vue3 项目开发完以后需要执行:

npm run build

构建产物会输出到dist目录。此时可以把dist托管到 Nginx,并将/api反向代理到 SpringBoot3 服务:

server { listen 80; server_name localhost; root /opt/legal-frontend/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

这时前端已经不再依赖 5173 代理,生产环境的静态资源和后端接口被 Nginx 托管在一起,避免跨域问题。

9.3 MySQL 慢查询与索引优化

模板搜索最容易出现性能瓶颈的是LIKE模糊查询:

SELECT * FROM legal_template WHERE status = 'PUBLISHED' AND title LIKE '%劳动%' ORDER BY update_time DESC;

数据量较小时,这条 SQL 可以正常工作。但当模板数量上升到几十万甚至百万级别,LIKE '%关键词%'无法走索引,会导致全表扫描。此时可以先用EXPLAIN查看执行计划:

EXPLAIN SELECT id, title FROM legal_template WHERE status = 'PUBLISHED' ORDER BY update_time DESC LIMIT 10;

如果发现 type 是ALL并且扫描行数很大,说明需要优化。方案有几种:增加搜索字段的组合索引、限制查询范围,或后续引入 Elasticsearch / MeiliSearch 做全文检索。对于起步阶段的模板平台,建议先把分页和简单筛选做好,不要过早引入重型中间件。

10. 常见问题与排查方法

下面把本地开发和测试阶段最容易出现的问题整理成一个排查清单:

问题现象可能原因排查方式解决方案
后端启动失败JDK 版本低于 17 或端口被占用查看启动日志,检查java -versionlsof -i:8080安装 JDK 17+,更换端口
MySQL 命令行连接失败,提示 ERROR 2002MySQL 服务未启动,或 socket 路径不对查看服务状态和 my.cnf启动 MySQL,统一 socket 路径
Navicat 无法连接 MySQL 8账号密码错误或认证插件问题检查用户表和连接参数更新客户端,或授权新用户
前端页面打不开npm 依赖未安装或开发服务未启动执行npm run dev看终端日志重新安装依赖
浏览器请求 /api 返回 404Vite 代理没有生效或后端没有对应接口打开 Network 查看请求地址修改 vite.config.js 代理配置
请求接口返回 401token 未传或 token 过期查看请求头是否带 Authorization重新登录,检查 axios 拦截器
模板上传后不显示数据库 status 不是 PUBLISHED查询 legal_template 表走审核流程,发布模板
批量导入报内存不足一次性读取大量 Excel 数据检查 Java 堆内存和代码读取方式分批读取、分页插入、增大堆内存
搜索结果慢表上没有合适索引使用 EXPLAIN 分析增加索引或改造查询条件
接口返回中文乱码数据库字符集或连接串缺少 utf8检查表字符集和连接 URL统一 utf8mb4

如果遇到“模板上传后文件不显示”的问题,还要看附件是否存储到正确目录。后端如果使用本地磁盘保存 Word/PDF,建议配置文件路径为绝对路径,并把文件读写目录与 Java 包目录分开。开发环境可以使用${user.home}/legal-upload,生产环境使用独立数据盘目录。

11. 最佳实践与使用建议

11.1 上线前先跑通最小可用链路

不需要把页面设计得特别复杂,先把以下链路跑通:

用户注册 -> 登录 -> 获取 token -> 浏览模板列表 -> 查看详情 -> 上传待审模板 -> 管理员审核发布 -> 再次登录搜索到该模板 -> 点击下载 -> 下载量增加 -> 后台看板能看到数据。

这条链路能跑通,平台的核心骨架就是完整的。

11.2 做好审核与水印设计

法律文书的权威性比较强,不能像普通 UGC 社区那样一上传就直接对所有人可见。建议后台审核保留三个状态:待审核、已发布、已驳回。驳回时填写理由,例如“标题含敏感信息”“模板版权归属不明”“缺少使用提示说明”。

如果是企业内使用,可以在下载页面或导出的 PDF 正文里加水印,记录下载用户和下载时间。没有强制要求时,至少要在下载日志中记录用户 ID。

11.3 分类与文件存储要预留扩展空间

分类表使用父 ID 字段设计可以支持多级分类。当以后新增“婚姻家庭类”“公司商事类”“刑事法律文书类”等一级分类,不需要改表结构。

模板附件建议统一用 UUID 重命名,并单独保存原始文件名:

/upload/2025/03/05/uuid_原始文件.pdf

上传接口要校验文件后缀和大小,禁止上传.jsp.exe等危险文件,防止非法文件被直接访问。

11.4 权限安全与数据隔离

后端在查询模板详情时,要判断当前用户是否有权限。普通用户看不到已驳回和下架的模板;非作者不能修改他人上传的模板;管理员只能审核,也不能随意删改重要记录。待审核的模板不应出现在前台首页列表。

如果平台未来向法人团队开放更多模块,可以考虑在用户表增加org_id,让不同机构之间数据隔离,避免用户 A 律所看到用户 B 律所的内部合同。

11.5 数据备份与日志审计

MySQL 数据建议每天备份一次,模板文件也同时备份。开发阶段可以用最简单的 mysqldump:

mysqldump -uroot -p legal_template > legal_backup_$(date +%Y%m%d).sql

对法律文书平台而言,记录“谁在什么时间上传了哪份文件、谁审核通过、谁下载了哪份模板”非常重要,一旦出现版权争议或信息安全问题,可以依靠日志回溯。不要只保留几张业务表就认为系统完成了。

12. 总结里直接给可执行建议

这套法律文书模板共享平台的技术实现并不神秘。SpringBoot3 解决后端接口和权限,Vue3 负责前端交互和后台管理页面,MySQL 负责持久化模板和用户数据。真正的难点在于内容和审核链路:如何保证上传的法律文书模板完整可用、权属清楚、发布前经过必要审核、下载和访问有迹可循。

如果你是从零搭建,先把数据库表和 JWT 登录跑通,再完成前台模板列表和详情页,最后补上管理员审核页面。这个顺序开发阻力最小。最容易踩的坑通常集中在三处:SpringBoot3 与 MyBatis-Plus 的依赖版本不匹配、MySQL 8 连接参数或时区配置错误、前端代理和 token 注入没有统一处理。

平台后续可以继续扩展的方向包括:使用 Elasticsearch 替换模糊搜索、使用 MinIO 或云对象存储管理模板附件、使用 Redis 缓存热门模板和用户 Token、集成在线文档预览组件、增加模板版本管理功能,让每次修改都保留历史记录。只要基础表结构和审核流程设计合理,给这个项目增加新模块不会太难。建议先收藏这篇文章,后面做同类型模板管理或文档共享项目时,可以直接对照这个结构走一遍。

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

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

立即咨询