news 2026/11/4 23:52:00

SpringBoot+Uniapp前后端分离校园项目实战:从源码到部署避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot+Uniapp前后端分离校园项目实战:从源码到部署避坑指南

简介:基于 SpringBoot 与 Uniapp 做前后端分离的校园社区项目,覆盖校园集市、表白墙、论坛、失物招领、校园墙和跳蚤市场等日常场景,适合高校课程设计、毕业设计以及校园信息化实践参考。技术实现上采用 MyBatisPlus 管理数据层,SpringSecurity 保证接口安全,Quartz 处理定时任务,MinIO 提供文件存储,Redis 负责缓存,MongoDB 存储文档类信息,前端配合 uView 组件库完成跨端页面,展示了权限控制、缓存、对象存储、定时任务等企业级开发中的常见问题与解决方案。

压缩包共 564 个文件,约 1.85MB,包括 113 个 Java 后端类、253 个 JS 与 127 个 Vue 前端页面,以及 SCSS 样式、SQL 数据库脚本、YML 配置和说明文档。目录结构按业务模块划分,便于学习时快速找到对应代码;邮件模板、工具类、认证与发帖服务等文件也一并提供,能帮助读者了解完整的工程化组织方式。

目前已有 75 人学习。下载后可直接获得完整源代码和数据库脚本,适合想完整跑通项目、理解前后端分离架构以及中间件整合方式的开发者,也可作为二次开发或课程报告的基础材料。

1. 校园圈项目到底是什么:从一套源码看清 SpringBoot + Uniapp 的前后端分离套路

校园圈这类全栈项目,几乎每个做毕设或接私活的开发者都绕不开。它的名字很多,有人叫校园集市,有人叫校园墙,本质都是用 SpringBoot 提供接口,用 Uniapp 做用户端,把校园里的信息流、商品流和社交需求放进一个应用。你拿到的“源代码+数据库”,不是两个文件夹那么简单,而是一条完整的数据链路:MySQL 存业务数据,SpringBoot 处理增删改查,Uniapp 在 H5、微信小程序、App 三端共用一套代码。

很多第一次接触前后端分离的读者,习惯把后端 Controller 当页面用,把前端当成静态文件丢进 SpringBoot 的 static 目录。分离的核心是接口约定、Token 鉴权和跨域配置,我后面所有步骤也围绕这三个点展开。如果你是计算机专业学生、转行做全栈的开发,或者想接校园类私单,这套方案能让你少走很多弯路。

2. 项目拆解:SpringBoot 后端服务、Uniapp 前端模块与 MySQL 数据库的映射关系

2.1 五个业务模块如何对应后端接口和核心表

先看后端结构。常见做法是 controller/service/mapper 三层,再加上 config、interceptor、common 几个包。校园圈虽然有五个功能入口,但后端接口并不需要各自为政,很多逻辑可以复用。

我拆解过这类项目,核心表一般是这样:

业务模块核心表关键字段复用点
校园集市/跳蚤市场goodsid, user_id, title, description, price, images, status商品上下架、搜索、分类
表白墙/校园墙wall_postid, user_id, content, is_anonymous, status, audit_reason匿名逻辑、审核状态机
论坛forum_topic / forum_replyid, user_id, title, content, view_count评论回复、点赞
失物招领lost_foundid, type(0丢/1捡), title, place, contact, status与商品共用图片上传
用户userid, openid, nickname, avatar, role登录鉴权所有模块共用

一张 user 表贯穿所有业务,status 字段在四张业务表里都表示“是否审核通过”,只是字段名可能叫 status 或 audit_status。数据库里真正需要重点设计的是 goods 和 wall_post,因为前者有图片、有价格,后者有匿名和审核两个特殊需求。

接口上,每个模块基本是标准的增删改查:列表带分页、详情、新增、修改、删除。但要注意,表白墙和失物招领的删除权限通常要给管理员,前端按钮要通过 role 字段控制。不能简单复用同一个删除接口。

运营后台是另一个常见的隐藏需求。很多源码会在 admin 包里单独放一套 Controller,比如审核表白墙、下架违规商品。这套接口和用户端接口共用同一个 service,只是通过注解校验管理员身份。后面讲 Token 鉴权时会具体说。

SpringBoot 项目结构上,我一般建议把“通用返回体”“分页请求参数”“异常处理”这三个东西放到 common 包。像 Result 类统一返回 code、msg、data,避免每个 Controller 自己拼 Map。项目里常见的翻车是登录接口返回的字段名和前端 request.js 里解构的字段对不上,所以定好返回体结构后再写业务,能省很多联调时间。

2.2 前后端分离的鉴权方案:用拦截器统一校验 Token

前后端分离最常见的问题是接口裸奔。如果所有接口都能直接访问,那数据库里的表白墙投稿、商品信息随便就能被爬走。所以一般项目里会有一个全局拦截器校验 Token。

看一段典型的 Java 代码:

@Component public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); // 放行登录接口和静态资源 if (request.getRequestURI().contains("/user/login") || request.getRequestURI().contains("/images/")) { return true; } if (token == null || token.isEmpty()) { response.setStatus(401); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("{\"code\":401,\"msg\":\"未登录,请先登录\"}"); return false; } // 用 Redis 或 JWT 解析 token,这里以 JWT 为例 try { Claims claims = Jwts.parser().setSigningKey("yourSecretKey").parseClaimsJws(token.replace("Bearer ", "")).getBody(); request.setAttribute("userId", claims.get("userId")); return true; } catch (Exception e) { response.setStatus(401); response.getWriter().write("{\"code\":401,\"msg\":\"登录已过期,请重新登录\"}"); return false; } } }

逻辑说明:拦截器先放行登录和图片访问,剩下的接口统一取 Authorization 请求头里的 Token,用 JWT 解析 userId,最后放进 request 属性,Controller 里直接用。这样各业务接口就不需要自己重复写登录判断。

参数说明:yourSecretKey是 JWT 的签名密钥,实际项目里要放到 application.yml 里,用@Value读取,不要写死在代码里。Bearer前缀是可选的,但前端在请求拦截器里统一加上,后端保持一致即可。如果有 Redis 作单点登录,可以把 JWT 的 jti 作为 key 存一份,退出登录时删掉,实现真正踢人。

配置拦截器时,还需要一个 WebMvcConfig 注册它,并设置 excludePathPatterns:

@Configuration public class WebConfig implements WebMvcConfigurer { @Resource private AuthInterceptor authInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authInterceptor) .addPathPatterns("/api/**") .excludePathPatterns("/api/user/login", "/api/user/register", "/api/goods/list"); } }

注意:这里 excludePathPatterns 是把列表接口放行了,因为游客也要看商品列表。如果是表白墙投稿,就必须登录才能发。这需要你在 controller 层用 userId 参数进一步判断,拦截器只保证“有人登录”,不保证“这个人能不能访问某个数据”。我在实际项目里还会加一层角色判断,把管理员接口路径放在一个独立前缀下,比如/admin/**,单独拦截。

2.3 数据库初始化:SQL 脚本里必须改的 3 个地方

拿到源码后第一步不是启动项目,而是建库。大多数源码会带一个 .sql 文件或者 db 文件夹。直接导入很可能会出问题,我一般会打开脚本改三个地方。

第一,字符集。脚本里如果写的是DEFAULT CHARSET=utf8,建议改成utf8mb4,否则表白墙里用户发个 emoji 表情,MySQL 直接报错不写入。一条核心建表语句大概是:

CREATE TABLE `wall_post` ( `id` int NOT NULL AUTO_INCREMENT, `user_id` int DEFAULT NULL, `content` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `is_anonymous` tinyint(1) DEFAULT '0', `status` tinyint(1) DEFAULT '0', `audit_reason` varchar(255) DEFAULT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

第二,自增起始值。如果源码附带的 SQL 是从开发者的测试库导出的,表里会带着一堆测试数据,而且 AUTO_INCREMENT 已经被推进到几百甚至几千。你在本地演示没问题,但是交作业或者部署上线时,想让 id 从 1 开始,就得把每张表的 AUTO_INCREMENT 改回 1。一条命令重置所有表比较麻烦,我通常是直接在建表语句里把 AUTO_INCREMENT 改成 1,或者导入后用ALTER TABLE wall_post AUTO_INCREMENT = 1;逐表改。

第三,管理员账号。很多脚本里的 admin 密码是明文或者 MD5 加密,而且 openid 是开发者测试时的小程序 appid。你本地登录不了后台,往往不是代码 bug,而是种子数据里的 openid 和你的微信小程序 appid 对不上。解决方案是改 SQL 里的种子数据,或者在登录接口里临时打日志,看实际查出的 openid 是什么。

数据库连接串也要注意。application.yml 里的 url 至少是这种标准写法:

spring: datasource: url: jdbc:mysql://127.0.0.1:3306/campus-circle?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver

参数说明:useUnicode=true&characterEncoding=utf8mb4是解决中文和 emoji 乱码的关键,serverTimezone=Asia/Shanghai是 MySQL 8.x 的必填参数,不写会直接报时区异常。username 和 password 一定要换成自己本地的数据库账号。

改完配置后,我建议先执行一个最简单的查询接口看数据库通没通。如果接口能返回用户列表,说明连接没问题;如果报Communications link failure,优先检查 MySQL 服务是否启动、端口是不是 3306、账号有没有 IP 访问权限。

3. 本地跑通最小闭环:后端启动、Uniapp 编译到 H5 和微信小程序

3.1 后端启动前的配置:application.yml 里端口、数据源和上传路径

在跑后端之前,先确认三个配置:端口、数据源、文件上传路径。很多源码自带的配置是开发者的本机环境,你直接启动大概率会报错。

server: port: 8080 servlet: context-path: /api spring: servlet: multipart: max-file-size: 5MB max-request-size: 20MB file: upload-dir: /var/www/campus-circle/images

这段配置里,context-path: /api意味着所有接口都被加了一层前缀,访问地址是http://localhost:8080/api/user/login。Uniapp 前端请求的时候,baseURL 必须写成http://localhost:8080/api。很多人卡在启动后白屏,就是因为这里前缀不一致。

multipart配置是给图片上传用的。表白墙配图、集市商品图都走这个配置,max-file-size控制单张大小,一般 5MB 够用。file.upload-dir是自定义属性,Controller 里通过@Value("${file.upload-dir}")注入,上传的文件就写到这个目录。Windows 本地上传路径建议用D:/upload这种盘符路径,不要写C:/,因为项目放到别的机器会迁移。

启动 SpringBoot 时,我习惯用 IDE 里的 Application 主类右键启动,而不是mvn spring-boot:run,后者在 Windows 控制台如果编码是 GBK,Maven 日志里的中文会乱码,容易干扰判断。启动成功后看到Tomcat started on port(s): 8080再继续配前端。

3.2 用 HBuilderX 导入 Uniapp 前端并编译到 H5

拿到 Uniapp 前端源码后,最常见的打开方式是用 HBuilderX,直接“文件 -> 导入 -> 从本地目录导入”。导入后先别急着运行,先打开 manifest.json 看三个配置:

  1. H5 配置的 router base 和 devServer 端口,默认是 8080,如果和后端接口端口冲突,要改成比如 8081。
  2. 微信小程序配置的 appid,如果是空或者别人的,换成你自己的测试号 appid,否则开发者工具里会报错。
  3. 要检查 request 工具里的 baseURL。大多数源码会在utils/request.js里统一处理。
// utils/request.js const BASE_URL = 'http://localhost:8080/api' export function request(options) { return new Promise((resolve, reject) => { uni.request({ url: BASE_URL + options.url, method: options.method || 'GET', data: options.data || {}, header: { 'Content-Type': 'application/json', 'Authorization': uni.getStorageSync('token') ? 'Bearer ' + uni.getStorageSync('token') : '' }, success: (res) => { if (res.data.code === 401) { uni.navigateTo({ url: '/pages/login/login' }) } else { resolve(res.data) } }, fail: reject }) }) }

逻辑说明:request 封装把 token 从本地存储取出,统一加到请求头里,服务端 401 时跳到登录页。这套逻辑是前后端分离的关键,后端拦截器能拿到 Authorization,全靠这行 header。

参数说明:BASE_URL需要根据你的编译环境动态改。在 H5 开发时,浏览器访问的是http://localhost:8080,在微信小程序里,本地开发可以填你电脑的局域网 IP,比如http://192.168.1.100:8080/api,并勾选开发者工具里的“不校验合法域名”。真机预览时,必须保证手机和电脑在同一局域网。

编译到 H5 很简单:HBuilderX 菜单栏 “运行 -> 运行到浏览器 -> Chrome”,如果一切正常,你会看到登录页。如果 network 里显示请求失败,优先排查跨域和端口冲突。

3.3 微信小程序打包时:2MB 超限和不打印日志怎么处理

Uniapp 编译到微信小程序,最常遇到的是“source size 2612kb exceed max limit 2mb”。这不是项目跑不起来,而是包体积超了微信的限制。常见处理思路有三个:

  1. 把图片和静态资源改成网络路径,不要放本地 static。
  2. 开启分包:pages 里按模块分成 main 包和 subpackages,比如集市、论坛、失物招领各自一个分包。
  3. 在 manifest.json 里勾选“运行时的压缩代码”,并在微信开发者工具里勾选“上传代码时压缩样式文件”。

还有一个让新手头疼的现象是,Uniapp 编译到小程序后 console.log 不打印。这不是代码问题,而是开发者工具的“调试器”里默认过滤了 info 级别日志。把日志级别调整为“All”或者“Verbose”,就能看到 uni.request 的日志。很多老手排查接口问题前,会先确认这一步,不然以为代码没执行。

打包上架安卓应用市场是另一个方向。Uniapp 项目在 HBuilderX 里可以发行“原生 App-云打包”,前提是你的 DCloud 账号有打包证书。注意云打包时,manifest.json 里的 App 模块配置勾选定位、地图等模块,如果代码里用了uni.getLocation但没配权限,打包后功能会静默失败。

到这里,你可以成功跑通前后端分离的最小闭环。但离做完还差一件事:把核心业务逻辑的边界看清楚。

4. 核心业务实现:匿名发布、审核状态机和图片上传的落地方式

4.1 表白墙匿名发布:表里存 user_id,接口返回时抹掉身份

校园表白墙最核心的诉求是匿名。但匿名不等于不记录。为了后续审核和管理员能追溯,数据库里必须存真实的 user_id,只是在接口返回给前台时,把 user 表关联查询出来的昵称和头像换成默认值。

后端实现上,查询列表的 SQL 要小心。很多新手直接联表查 user,然后select *,导致匿名贴把昵称带出来了。正确做法是:

SELECT wp.id, wp.content, wp.create_time, CASE WHEN wp.is_anonymous = 1 THEN '匿名' ELSE u.nickname END AS nickname, CASE WHEN wp.is_anonymous = 1 THEN 'https://example.com/default-avatar.png' ELSE u.avatar END AS avatar FROM wall_post wp LEFT JOIN user u ON wp.user_id = u.id WHERE wp.status = 1 ORDER BY wp.create_time DESC LIMIT #{offset}, #{pageSize}

逻辑说明:用 CASE WHEN 在 SQL 层判断,is_anonymous 为 1 时,昵称显示“匿名”,头像用默认占位图。这样即使前端直接联表展示,也拿不到真实昵称。注意这里默认头像的 URL 不要写死,最好放到配置表或常量类里。我在项目里习惯把这类常量放一个CommonConstants类,避免每个 mapper 里各写各的。

4.2 审核状态机:待审、通过、拒绝三态怎么闭环

表白墙和失物招领都有审核。通常库里的 status 字段是 0 待审、1 通过、2 拒绝。前端用户端只查 status=1,管理端能查所有状态并修改。

审核接口的 Java 实现,可以在 Service 层写一个方法:

public boolean audit(Integer id, Integer status, String reason) { if (status != 1 && status != 2) { throw new RuntimeException("审核状态不合法"); } WallPost post = wallPostMapper.selectById(id); if (post == null) { throw new RuntimeException("记录不存在"); } WallPost update = new WallPost(); update.setId(id); update.setStatus(status); if (status == 2) { update.setAuditReason(reason); } return wallPostMapper.updateById(update) > 0; }

逻辑说明:这个 service 方法至少包含了三个防御点:非法状态值、数据不存在、拒绝时必须填原因。实际项目里还会加一个“审核记录表”,存操作人、操作时间、前后状态,但学校项目里一张 status 字段就够用了。

参数说明:reason只有拒绝时才有意义,通过时传 null。前端审核页面要根据返回的 reason 展示拒绝原因,所以接口返回值里的 auditReason 字段在 status=0 时要给空字符串,避免小程序端 json 解析 null 报错。

这里要特别注意:审核操作必须写进事务里。如果 update 前还要给用户发通知,比如插入一条站内信,发送失败会导致审核状态已改但用户没收到通知。我给这类方法都会加@Transactional(rollbackFor = Exception.class),让两步操作要么都成功,要么都回滚。

4.3 图片上传:本地存储目录和 Nginx 访问映射

图片上传是校园集市里最容易出的 bug。后端接收上传后,存到本地磁盘,同时返回一个可访问的 URL。

先看 Controller 代码:

@RestController @RequestMapping("/api/upload") public class UploadController { @Value("${file.upload-dir}") private String uploadDir; @PostMapping("/image") public Result upload(@RequestParam("file") MultipartFile file) { if (file.isEmpty() || file.getSize() > 5 * 1024 * 1024) { return Result.error("文件不能为空且大小不能超过5MB"); } String ext = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); String fileName = System.currentTimeMillis() + "_" + UUID.randomUUID().toString().replace("-", "") + ext; File dest = new File(uploadDir + "/" + fileName); if (!dest.getParentFile().exists()) { dest.getParentFile().mkdirs(); } try { file.transferTo(dest); } catch (IOException e) { throw new RuntimeException("文件上传失败", e); } return Result.success("http://localhost:8080/images/" + fileName); } }

逻辑说明:用时间戳+UUID 生成文件名,防止重名和路径穿越,然后转移到 upload-dir 完成落盘。

参数说明:这里返回的 URL 是给前端直接用于 标签的。要让这个 URL 能被访问,SpringBoot 必须增加一个静态资源映射:

@Configuration public class FileConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/images/**") .addResourceLocations("file:" + uploadDir + "/"); } }

这个映射的意思是,浏览器访问/images/abc.jpg时,从本地磁盘的 uploadDir 目录下找文件。如果你部署到服务器,通常会用 Nginx 直接代理这个目录,而不再经过 SpringBoot,这样静态资源请求不会打到 Java 进程,内存占用更低。Nginx 配置片段是:

location /images/ { alias /var/www/campus-circle/images/; expires 7d; }

注意:如果后端配了context-path: /api,那么上传接口是/api/upload/image,但图片访问地址不要带/api前缀,因为 Nginx 里的 location /images/ 是独立于 SpringBoot 的。我在这上面栽过一次:上传成功、返回 URL 也正确,但 Nginx 一直 404,最后发现是 location 的路径和 alias 最后的斜杠不匹配。

5. 避坑:前后端分离校园项目最容易翻车的 5 个现场

5.1 现象:接口请求返回 404,前端一直白屏

现象:前端页面能打开,但请求/api/user/login返回 404,控制台显示 Failed to load resource。

原因:后端配置了server.servlet.context-path=/api,但 Uniapp 的 BASE_URL 也写了/api,两个前缀叠加,实际请求变成了/api/api/user/login。或者反过来,后端没配 context-path,但前端 BASE_URL 写成了/api,也会 404。

解决:统一约定一个标准。我习惯后端不配context-path,所有 Controller 的 RequestMapping 都带/api前缀,前端 BASE_URL 只写协议+IP+端口,即http://localhost:8080。这样就算之后拆成独立网关,改动也更小。

5.2 现象:H5 请求跨域,浏览器报 CORS error

现象:用 HBuilderX 运行到浏览器,登录接口返回 200,但浏览器控制台报 No 'Access-Control-Allow-Origin' header is present。

原因:H5 页面跑在http://localhost:8081,接口跑在 8080 端口,浏览器同源策略拦截。很多源码只在后端加了@CrossOrigin注解,但这个注解默认允许的源不包含 8081 端口,或者没加allowedHeaders,导致携带 Authorization 头的请求被拒。

解决:后端加一个全局 CORS 配置,而不是在每个 Controller 上零散加注解。

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }

注意:.allowedOriginPatterns("*")是 SpringBoot 2.4+ 的写法,低版本用.allowedOrigins("*"),但后者和allowCredentials(true)一起用可能报错,所以用 Patterns 更省事。如果你不想在代码里放开所有源,也可以在开发阶段用 HBuilderX 的 devServer 代理,正式上线后同域部署或走 Nginx 反代。

5.3 现象:数据库写入中文变成问号,小程序里发个表情直接报错

现象:表白墙投稿内容保存到 MySQL 后是???,或者插入 emoji 时抛Incorrect string value。

原因:表结构、连接串、前端请求三处字符集不一致。最常见的是表是 utf8,但 emoji 需要 utf8mb4;或者 SpringBoot 连接串没写 characterEncoding。

解决:把表字符集改成 utf8mb4,连接串里加characterEncoding=utf8mb4,前端请求头保持 utf-8。如果数据已经变成问号,只能删掉重插。这个问题的隐蔽点在于,后端代码里明明写了content = new String(content.getBytes("ISO-8859-1"), "UTF-8")这种错误转码代码,应该删掉。这种转码在本地偶尔碰巧能跑,换到 Linux 服务器上就是灾难。

5.4 现象:图片上传成功,但前端图片裂开

现象:上传接口返回 200,服务器上也能看到文件,但小程序或 H5 里image标签显示不了。

原因:返回的图片地址写成了localhost,手机真机访问不到;或者静态资源映射没加;或者文件权限不对,Nginx 启动用户读不了/var/www下的文件。

解决:本地调试用局域网 IP 替换 localhost;部署到服务器后用绝对路径访问验证。getOriginalFilename()拿到完整路径时,要先用File.separator处理反斜杠,否则在 Windows 上能跑、Linux 上找不到目录。我自己的习惯是上传文件名里只保留扩展名,时间戳+UUID 自己生成,这样完全避免路径分隔符问题。

5.5 现象:微信开发者工具提示包体积超过 2MB,无法预览

现象:编译成功,但点击预览或上传时提示source size 2612kb exceed max limit 2mb。

原因:Uniapp 默认把整个 vue 组件和静态资源打进主包。很多源码会把 default 头像、封面图、tabBar 图标放在 static 里,一张图几百 KB,两个循环图就超了。

解决:按页面拆分分包,tabBar 页面必须在主包,其他模块如论坛、失物招领放 subPackages。再把静态图片压缩后传到 OSS 或用外链。一条经验:本地图片总大小控制在 200KB 以内。关闭 HBuilderX 自带的“代码混淆压缩”开关有时能省一点,但真正治本的是分包。

以上 5 个现象,基本都是我接手这类源码时逐个踩过的。每次排查,我都会先把请求的完整 URL 复制到浏览器直接访问,再用 Postman 测试接口,最后才怀疑前端。这套排查顺序能帮你从黑匣子里跳出来。

6. 再进一步:从能跑到能交付,验证校园圈项目的四个指标

如果你已经跑通,下面四个点决定这个项目能不能拿去答辩或上线。

先用一份接口自测表过一遍:登录后拿 Token、未登录访问需要鉴权的接口应返回 401、发布表白墙后管理员能审核、审核拒绝后前端不展示。这些是业务闭环的硬指标,最好写进自己的测试清单里。

然后是异常数据验证。给wall_post.is_anonymous传 0 和 1 各测一次,确认匿名用户的昵称字段能正确替换。给商品价格传负数,看后端有没有校验;后端通常在goodsServiceImpl里写了if (price.compareTo(BigDecimal.ZERO) < 0) throw new RuntimeException("价格不能为负数")。如果没有,你可以自己补上,这是很多人会忽略的健壮性问题。

还有一个很实用的验证方式:把数据库的 SQL 打开,手动执行一遍核心查询,看返回行数和前端页面是否一致。如果列表页和数据库行数对不上,多半是查询条件里status = 1的过滤漏了,或者分页 SQL 的LIMIT参数写错。我会习惯在 MyBatis 的 mapper XML 里给每个查询加order by create_time desc,避免列表顺序在多次分页时跳跃。

拿我自己交付过的项目来说,最后一步一定是把项目里的测试数据清掉、admin 密码改成强密码、把 application.yml 里的环境配置确认一遍。很多答辩时,老师最在意的是你能不能说清楚“匿名是真的匿名吗”“审核状态怎么流转”“图片存在哪里”。你把这三个问题答清楚,比会背 SpringBoot 原理更管用。

这个方向是否值得投入?我的判断是值得。SpringBoot + Uniapp 的组合覆盖了后端接口、前端多端打包、数据库设计、上线部署一整条链路,你只要完整跟通一遍,再去看其他前后端分离项目,会发现结构都类似。但别贪多,先把最核心的登录、发布、审核、图片上传四个流程做到不出纰漏,再谈加功能。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/5 5:49:06

洞庭湖水系shp在ArcGIS中的使用:坐标系与几何修复避坑指南

简介&#xff1a;这是一份面向ArcGIS用户的长江流域洞庭湖水系地形图数据包&#xff0c;内含湖泊、河网等shp格式矢量文件及配套地形栅格&#xff0c;适用于流域制图、空间分析与科研展示。包内共61个文件&#xff0c;除shp、dbf、prj等基础矢量文件外&#xff0c;还提供mxd地图…

作者头像 李华
网站建设 2026/11/4 15:20:02

松翰UVC TestAP:从H.264调试到产测自动化的完整指南

简介&#xff1a;SONiX UVC摄像头驱动测试程序源码包r1.0.21&#xff0c;面向嵌入式驱动开发者和摄像头模组测试人员&#xff0c;核心用途是验证SONiX摄像头在UVC协议下的H.264硬编码功能是否正常&#xff0c;帮助定位驱动与硬件之间的兼容性问题。H.264硬编码依赖摄像头内置编…

作者头像 李华
网站建设 2026/11/1 11:46:07

多模态情感分析实战:BERT+ResNet融合与部署指南

简介&#xff1a;面向计算机相关专业毕设学生与项目实战学习者&#xff0c;基于BERTResNet的多模态情感分析完整项目&#xff0c;提供源码与配套文档说明。项目实现多种特征融合方法&#xff0c;包括朴素拼接、跨模态注意力、基于Transformer编码器的不同融合策略&#xff0c;适…

作者头像 李华
网站建设 2026/10/23 6:04:47

Flutter OpenHarmony迁移实战:Flex弹性布局原理与踩坑总结

从一次让我印象极深的移植事故说起吧。去年底部门把一套跑了三年的 Flutter 电商客户端往 OpenHarmony 平台迁移&#xff0c;编译、依赖、签名全部打通之后&#xff0c;满心欢喜地在 Orange Pi 5 Pro 上启动应用&#xff0c;结果首页瀑布流一出来&#xff0c;整个团队都沉默了&…

作者头像 李华
网站建设 2026/10/24 7:46:57

AI内容创作中容易被忽略的关键环节

为什么提示词很重要&#xff1f;AI内容创作中容易被忽略的关键环节 随着 AI 被广泛应用于写作、图片、视频和跨境电商&#xff0c;很多人开始关注模型、工具和生成速度&#xff0c;却忽略了一个基础问题&#xff1a;提示词是否写得清楚。 同一个 AI 工具&#xff0c;有人只能得…

作者头像 李华
网站建设 2026/10/24 3:59:50

8465132

我重新按代码核对了。下面只讲刚交付的“航向结束版”&#xff0c;数值以这版 [planner.yaml](C:/Users/35341/Documents/Codex/2026-10-05/new-chat/outputs/urinay_local_planner/config/planner.yaml) 为准。先记住&#xff1a;车辆按 route_order 顺序走&#xff0c;每一段…

作者头像 李华