ARTICLE DETAIL

资讯详情

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

SpringBoot+微信小程序搭建摄影作品分享社区:从登录到发布全流程避坑指南

SpringBoot+微信小程序搭建摄影作品分享社区:从登录到发布全流程避坑指南 做摄影作品分享交流平台这个项目时我踩过不少坑也积累了不少经验。今天把这套 SpringBoot 加微信小程序的完整实现过程拆开讲一遍从需求分析到后端接口设计再到小程序端的联调避坑尽量还原我当时真实的开发路径。如果你正在做类似的项目或者准备接手一个分享社区类的毕设、课设这篇应该能帮你少走很多弯路。1. 项目概述与需求拆解1.1 这个项目到底在解决什么问题在动手写代码之前我花了大量时间在理清“摄影作品分享交流平台”这个标题背后的真实需求。先说结论这不是一个单纯的相册展示应用而是一个典型的 UGC 社区产品核心是“分享”和“交流”两个动作。分享指的是用户可以上传自己的摄影作品附上标题与描述形成一条带图片、带作者信息的内容流。交流则是指围绕这些作品产生的互动行为点赞、评论、收藏、关注以及后续的消息通知。如果把这两个关键词拆开整个系统的功能边界就非常清晰了。我见过不少项目把需求写成了“大而全”的功能清单其实这是开发的大忌。就拿这个平台来说真正核心的闭环只有一条用户通过微信登录进入平台上传摄影作品其他用户浏览作品并互动作品作者收到互动通知。围绕这个闭环再衍生出个人主页、作品详情页、关注流、搜索等模块。只有先把这个主链路定下来后续的数据库设计和接口设计才有章可循。1.2 功能模块的拆分思路我把项目分成了四个端侧的模块用户端、内容端、社交端、管理端。用户端相对简单负责微信授权登录、个人信息维护、关注列表、我的作品、我的收藏、我的消息。这一侧的核心难点其实不在页面多少而在于“登录态”怎么管理以及用户信息更新后小程序端缓存怎么同步。内容端是最重的模块。作品发布要有图片上传、标题、描述、拍摄地点、拍摄器材等元信息作品广场要有排序规则、分页加载作品详情页要有大图预览、作者信息、评论列表、点赞收藏按钮。这一侧的核心难点是图片存储方案、列表分页性能和富文本内容的展示。社交端包括点赞、收藏、评论、关注以及系统通知。这一侧很多人会忽略一个关键点互动行为的数据一致性。比如点赞数、评论数一定不能靠前端展示的数字去写库而是要以数据库里的关系记录为准再配合计数缓存。否则很容易出现用户刷了几次页面计数就对不上了。管理端在毕设或课程设计里经常被弱化但实际上是一个平台的底线能力。包括用户管理、作品管理、评论管理、敏感词过滤、数据统计。建议至少做一个简单的后台统计接口看看每日作品上传量、互动量这样答辩或写论文的时候也有数据支撑。1.3 用户关键路径与场景还原我在设计阶段会习惯性地走一遍用户关键路径用来校验功能设计是否闭环。第一个场景是“新用户进入”用户打开小程序看到的是作品广场被某张照片吸引点进详情页想点赞或评论此时系统引导用户触发微信授权登录。登录成功回到原来的页面点赞动作继续完成。第二个场景是“老用户发布”用户点击发布按钮选择本地图片上传成功后填写标题和描述点击发布作品进入广场流。随后关注他的粉丝会收到一条动态通知打开关注页就能看到这条新作品。第三个场景是“互动回流”用户 A 评论了用户 B 的作品B 在小程序的“消息”页看到未读通知点进去可以查看文章处于哪个作品下,并直接回复评论。这三个场景跑通这个项目就已经是一个“能用的平台”了。后面的优化都建立在这个基础上。2. 技术选型与架构设计2.1 后端为什么选 SpringBoot这个项目的技术选型其实很常规后端用 SpringBoot前端用微信小程序原生开发。但“常规”不代表没有讲究。SpringBoot 最大的价值在于“约定优于配置”。让我不用花大量时间折腾 Tomcat 配置、Spring 容器的 XML 配置一个SpringBootApplication注解加一个spring-boot-starter-web依赖就能把 Web 服务跑起来。对于这种以 CRUD 为主、附带一些并发控制需求的社区类项目SpringBoot 的生态完整度和开发效率是最舒服的。考虑到项目规模我使用的是 SpringBoot 2.7.x搭配 Java 8。很多人会用最新的 SpringBoot 3.x 加 Java 17这里我建议如果做毕设或者企业老项目优先选 2.7.x。原因很简单网上能找到的第三方博客、依赖版本、踩坑记录几乎都是基于 2.x 的3.x 版本的 Jakarta EE 迁移、Spring Security 配置方式变化会让调试成本无端增加。用“版本太高”的框架去展示学习成果反而容易卡在环境问题上。ORM 层面选了 MyBatis-Plus。它内置了分页插件、代码生成器、条件构造器对于这种表单密集型的项目可以省掉大量重复的 SQL 编写。尤其是我要动态拼接查询条件的时候比如作品广场的城市筛选、器材筛选LambdaQueryWrapper比手写一堆if标签舒服得多。数据库使用 MySQL 8.0缓存使用 Redis。Redis 在这个项目里主要干两件事缓存热门作品的详情数据以及保存点赞计数、用户会话的临时状态。如果项目简单到不需要缓存也可以只依赖 MySQL但我建议既然用了 SpringBoot就顺手把 Spring Cache 或 RedisTemplate 接进来后续扩展会自由很多。图片存储这块我用的是阿里云 OSS。单纯把图片存到服务器本地磁盘不是不可以但有两个问题很实际第一小程序要求的线上环境必须是 HTTPS服务器本地图片服务也要走 HTTPS 域名配置起来比较繁琐第二服务器磁盘容量有限图片多了必然出问题。OSS 自带 CDN 加速、容灾、防盗链虽然要花几分钱但在项目演示和真实部署上是最稳妥的路线。2.2 数据库表结构设计要点我花了整整一个下午去设计这几张核心表这里直接说结论。用户表user字段包括id、openid微信唯一标识、nickname、avatar_url、gender、city、signature、create_time、update_time。其中openid必须建唯一索引这是微信登录后查询用户身份的依据。需要注意openid属于敏感信息任何接口响应里都不应该直接返回给前端防止被别人拿去批量查询用户。作品表photo字段包括id、user_id、title、description、image_url、image_width、image_height、location、camera_info、like_count、comment_count、collection_count、status0 表示正常1 表示被删除或下架、create_time、update_time。create_time要建索引因为广场流的排序和分页几乎都依赖它。like_count这类计数可以在作品表里冗余一份方便列表展示不用走子查询。评论表comment字段包括id、photo_id、user_id、content、parent_id、reply_user_id、create_time。parent_id用于支持“回复某条评论”的场景为 0 时表示顶级评论。photo_id和create_time要建联合索引因为评论列表是“先按作品过滤再按时间排序”。互动关系表其实可以拆成三张like_record用户 id、作品 id、创建时间、collection_record同样结构、follow_relation用户 id、被关注用户 id。这三张表都必须在“用户 id 目标 id”上建唯一索引从数据库层面防止重复操作。消息通知表notice字段包括id、user_id接收者、actor_id触发者、notice_type点赞、评论、关注、系统、target_id关联作品或评论 id、content、is_read、create_time。接收者 id 和is_read要建索引否则消息列表越往后越慢。我在设计的时候会画一张简单的 ER 图把外键关系理清楚。但实际建表时建议不要直接加数据库级外键约束而是靠应用层保证一致性。理由有二一是外键会拖慢删除和插入的性能二是未来做分库分表或逻辑删除时外键会变成一个巨大的阻碍。所谓的“关联完整性”在代码里控制住即可。2.3 后端分层与统一响应结构后端代码结构我采用了最经典的四层结构Controller、Service、Mapper、Entity额外加一个 config 包和 dto 包。Controller 只做参数接收、参数校验、调用 Service 后包装返回值不写任何业务逻辑。Service 层承载业务规则比如点赞前判断作品是否存在、作品是否已被下架、用户是否已经点赞过。Mapper 层就是 MyBatis-Plus 的 BaseMapper主要的复杂查询我直接用注解 SQL或 XML 写在里面。所有接口的返回结构必须统一。我定义了一个ResultT类包含 code、message、data 三个字段。200 表示成功400 表示参数错误401 表示未登录或登录过期500 表示服务异常。这样小程序端只需要对 code 做一次统一判断不用每个接口单独处理异常形态。另一个关键点是全局异常处理。我写了一个GlobalExceptionHandler用RestControllerAdvice捕获业务异常、参数校验异常、兜底的 Exception。这样代码里可以放心地抛出BizException(作品不存在)前端拿到的永远是结构化的错误信息而不是一堆堆栈。这里再提一个容易被忽略的点跨域配置。虽然微信小程序请求后端并不存在浏览器跨域问题但如果你是本地调试的时候用了 H5 页面或者用 Swagger 调试接口跨域问题就会出现。我的做法是在 config 包下写一个CorsConfig注册WebMvcConfigurer全局放行所有来源。生产环境如果限制域名再收紧allowedOriginPatterns即可。3. 核心功能实操实现3.1 微信登录与 JWT 会话管理这是整个系统里最容易出问题、也最容易被答辩老师追问的环节。我先把流程捋一遍。小程序端调用wx.login()拿到一个临时code把 code 传给后端接口/api/auth/login。后端拿着这个 code 和 appId、appSecret 去请求微信官方的jscode2session接口换取openid和session_key。这一步我建议用 OkHttp 或 Spring 的RestTemplate实现代码大概长这样public WxLoginResult code2Session(String code) { String url https://api.weixin.qq.com/sns/jscode2session?appid appId secret appSecret js_code code grant_typeauthorization_code; String resp restTemplate.getForObject(url, String.class); return JSON.parseObject(resp, WxLoginResult.class); }拿到openid后去user表查这个用户是否存在。不存在就自动注册一个新用户昵称头像先用默认值存在则直接走登录成功流程。这里不需要用户手动输入用户名密码因为微信已经帮我们完成了身份核验。但要注意后端不能直接把openid返回给小程序也不能用openid作为后续请求的凭证。正确做法是后端生成一个自定义登录态一般是 JWT。我采用 JJWT 库生成 JWT把userId和nickname放进 token 的 claims 里设置一个合理的过期时间实际操作中我设置为 7 天。每次请求需要登录的接口时前端在请求头Authorization: Bearer token里携带 JWT。后端用一个拦截器统一校验解析出userId后放进ThreadLocal供 Service 层直接获取当前用户。关于登录态过期我用了一个比较顺手的小方案在拦截器里判断 JWT 剩余有效时间当剩余时间短于一个阈值时响应头中返回一个新的 token小程序端在响应拦截器里检测到新 token 就自动替换本地存储。这样用户即使连续使用超过 7 天体验也是很顺畅的。这个方案叫“token 续期”社区项目普遍在用。一个必须提醒的细节微信官方明确要求所有敏感信息必须通过后端中转绝对不能在客户端直接调用jscode2session接口。也就是说appSecret只能存在于后端环境变量或配置中心每次发布小程序前都要自查一遍代码确认没有把appSecret硬编码到前端文件里。3.2 作品图片上传与 OSS 接入小程序上传图片的流程很直接前端用wx.chooseMedia选择图片然后wx.uploadFile把文件以multipart/form-data的方式提交给后端接口后端再把文件转存到 OSS。我这里的后端接口长这样PostMapping(/api/photo/upload) public ResultString upload(RequestParam(file) MultipartFile file) { if (file.isEmpty()) { throw new BizException(文件不能为空); } return Result.success(ossService.upload(file)); }OSS 接入的要点有三个。第一是存储路径规划我建议按日期和用户维度划分比如photos/{yyyyMMdd}/{userId}_{timestamp}.jpg这样可以避免单目录文件过多也方便后续做冷热数据迁移。第二是文件名不能直接用用户上传的原始文件名要用UUID或时间戳重命名防止中文名或特殊字符引起的 URL 编解码问题。第三是上传成功后要返回完整的 CDN 访问 URL而不是只返回 object key。图片的类型校验也很重要。后端不能只信前端的contentType因为这是可以由客户端伪造的。我习惯读取文件的魔数前缀来判断真正的类型比如 JPEG 的文件头是FF D8 FFPNG 的是89 50 4E 47。这能有效杜绝用户把恶意文件伪装成图片上传。关于图片尺寸和大小限制我在 OSS 上传时做了两层约束第一层是接口层限制文件不超过 10MB第二层是压缩。小程序端拍照的照片经常是 3MB 到 5MB直接上传既慢又浪费流量。我的做法是在小程序端用 Canvas 压缩到最大宽度 1440 像素、质量 0.8再上传。后端收到的基本都在 500KB 以内加载速度明显提升。还有一个细节OSS 的 URL 默认带了签名参数如果有效期太短小程序端图片会过期失效。我的处理方式是让 OSS 存储桶为公共读防盗链可以开启但不要限制空 Referer否则小程序端图片请求会被拒绝。对这个坑我确实踩过图片在浏览器能打开、小程序里空白就是防盗链设了不允许空 Referer 的原因。3.3 作品广场流与“加载更多”实现“加载更多”是微信小程序页面列表最常见的交互也是后端分页设计的分水岭。我上热搜里就看到很多人在纠结这个点这里把我的方案完整说出来。最传统的分页是pageNum和pageSize后端用 MyBatis-Plus 的Page对象SQL 底层对应LIMIT offset, size。优点是实现简单、前端理解成本低缺点是当翻页很深的时候offset越大查询性能越低而且如果翻页过程中新数据插入前一页的尾部数据可能重复出现在后一页。所以我选择了“游标分页”。作品广场流的接口参数不再是pageNum而是lastId加pageSize。后端查询条件是WHERE id #{lastId} ORDER BY id DESC LIMIT #{pageSize}第一次请求时lastId传0或最大值返回列表后把当前页最后一条记录的id作为下一次请求的lastId。这个方案的性能稳定也不存在重复数据的问题非常适合这种“分享社区大列表”。配合 MyBatis-Plus 的分页插件我能写到这样的代码PagePhoto page new Page(1, pageSize); LambdaQueryWrapperPhoto wrapper new LambdaQueryWrapper(); if (lastId ! null lastId 0) { wrapper.lt(Photo::getId, lastId); } wrapper.eq(Photo::getStatus, 0).orderByDesc(Photo::getId); photoMapper.selectPage(page, wrapper);如果列表还要按热度排序就不能纯用id做游标了可以改用“综合热度分”排序字段的游标。热度分可以是点赞数、评论数、时间衰减因子的加权组合定期后台更新这个字段。我在项目里先用了 id 倒序后来才加了热度字段但核心思路是一样的。小程序端要配合好这种分页。页面在onReachBottom时判断hasMore为 true 才继续请求请求成功后把新数据concat到已有列表末尾并用当前页最后一个id更新下一页参数。很多同学会把onReachBottom写错位置或者在页面没有滚动到底时重复触发需要在页面数据里维护一个loading状态防止并发请求。3.4 点赞、收藏与评论的并发与一致性处理点赞这个功能看起来只是“点一下”但设计稍有不慎就会出大问题。先处理“防重复点赞”。数据库层建了like_record(user_id, photo_id)的唯一索引即使前端点了两次、网络重试第二次插入也会因为唯一约束失败。业务层则在插入前先查询一次该用户是否已点赞已点赞再点击就执行取消点赞逻辑。这里注意查询和插入之间天然存在竞态所以必须依赖数据库唯一索引兜底不能只靠代码判断。再处理“计数一致性”。我的做法是点赞操作发生在事务中先插入like_record成功后执行UPDATE photo SET like_count like_count 1 WHERE id ?。这种计数累加的方式比直接读出来再加一写回去快得多也不会被并发覆盖。收藏和评论数量同理。但这样有个问题每次查询作品列表都要去photo表拿计数当列表量上来以后数据库压力会比较大。我的优化方案是在 Redis 里缓存热门作品的计数用like:count:{photoId}这样的 key点赞操作先更新缓存再异步更新数据库列表接口优先读缓存。这个优化对课程项目来说不是必须的但如果答辩时被问到“高并发下如何设计计数”你能答上这套思路会显得很有深度。评论模块相对简单但有一个细节删除评论时不能直接物理删除。如果一条评论已经被其他用户回复物理删除会导致子评论悬挂。我的方案是逻辑删除给comment表加一个deleted字段查询时自动过滤但保留记录供后台审核追溯。关于消息通知我在点赞、评论、关注发生时通过 Spring 事件机制发送一个异步任务往notice表插入一条记录。这里不建议在业务代码里同步插入因为如果通知表写入失败不应该影响到主操作。我用Async加线程池跑通知写入业务主流程和通知流程解耦。如果项目里已经引入了 RabbitMQ那更合理但对于课程项目事件机制绰绰有余。4. 微信小程序端落地要点4.1 页面结构、自定义导航栏与安全区适配我一开始是用微信开发者工具默认的导航栏页面顶部直接显示“摄影分享”标题。后来发现两个问题一是默认导航栏样式很难跟设计稿统一二是 iPhone 的刘海屏和底部横条会导致内容被遮挡。所以我改成了自定义导航栏。自定义导航栏第一步是在页面的json配置里设置navigationStyle: custom然后在小程序端获取状态栏高度和菜单按钮位置const systemInfo wx.getWindowInfo() const menuButton wx.getMenuButtonBoundingClientRect()这里的menuButton给出了右上角胶囊按钮的 top、bottom、height通常用menuButton.top作为导航栏的 top导航栏高度等于(menuButton.top - statusBarHeight) * 2 menuButton.height。反正写一次调好后面所有页面复制这套样式就行。首页我用了自定义头部区域放入 logo 和“摄影者说”的 slogan下面就是可滚动的作品广场列表。底部导航栏是原生的tabBar配置了“首页、关注、发布、消息、我的”五个 tab。这里需要留意tabBar的pagePath必须是一级页面不能嵌套到目录过深否则编译不通过。页面从上到下的层级我习惯拆成搜索栏 分类筛选栏 作品瀑布流。分类筛选栏用横向滚动标签实现比如“全部 / 人像 / 风光 / 街拍 / 动物 / 建筑”。点击标签会触发广场接口重新拉取带上category参数。4.2 列表加载更多的完整实现小程序列表加载更多除了后端分页方案前端也有几个容易踩坑的点。我在页面的data里维护这样几个字段photoList、lastId、hasMore、loading、refreshing。初始请求getPhotoList(true)会重置列表和lastId。onReachBottom触发加载更多时先判断loading和hasMore避免重复请求。这里的坑在于微信小程序的onReachBottom触发阈值是页面底部 50px 以内如果页面内容不足一屏可能进入页面就直接触发加载更多。我的处理是请求完第一页后判断返回列表是否已达到pageSize达到才把hasMore设为 true否则直接 false这样空列表就不会发无效请求。下拉刷新用的是enablePullDownRefresh开启后用户下拉会重载第一页。这里记得在刷新完成后调用wx.stopPullDownRefresh()否则顶部加载动画会一直转。我在一个小细节上吃过亏lastId在没有新数据时必须保留上一次的值不能重置为 0否则 loading more 和 pull down refresh 会互相打架。图片加载的体验优化也不能忽略。作品列表里每张图片都是大图我用lazy-load属性让它按需加载同时在小程序端根据屏幕宽度和两列布局提前计算图片的展示高度避免图片加载后列表跳动。两列瀑布流没有用第三方组件就用wx:for把数据分成左列和右列两个数组模拟出瀑布流效果。4.3 小程序包体积超标与加载优化有段时间我的开发者工具一直报错内容是source size 2612kb exceed max limit 2mb一眼就看出是主包体积超过了 2MB 限制。查了下资源最大头的是组件库文件、预先写好的图表库、还有几张本地背景图每张都接近 300KB。项目纯原生开发的包体积一般不会太大但如果你用 uniapp 打包这个问题几乎必然出现。我的处理办法有三个方向。第一个方向是分包。把“发布作品流程、消息中心、个人设置、关于我们”这些非核心页面放到subpackage下面主包只保留首页、关注页、作品详情页和个人中心四个核心页面。微信小程序的分包加载是运行时按需下载的主包体积瞬间降到 1.2MB 左右。第二个方向是压缩本地静态资源。所有本地图片经过在线压缩工具或 tinypng 压缩后再放进来大图背景尽量只保留一张渐变或纯色底其余用远端 OSS 图片。第三个方向是组件库瘦身。如果用了 vant 或 colorui 这类组件库通过按需引入的方式导入不要全量 import。我的原生页面干脆核心组件都自己写了这样体积最可控。4.4 真机调试、体验版分发与收集反馈开发完的下一步就是真机预览。开发者工具里点击“预览”会生成一个二维码但这个二维码只在开发者本人微信里有效。要让别人试用正确路径是点击“上传”版本填好版本号和项目备注然后在微信公众号后台或小程序管理后台的“版本管理”里把该版本设为体验版再把体验版二维码发给要试用的微信用户。体验版只有把对方微信号加入体验成员名单后才有效这个在“成员管理-体验成员”页面配置。收集反馈时我比较推荐两步一是体验成员边点边在微信里直接发语音或截图给你二是在小程序里埋了一个简单的意见反馈页面用户点击提交后调后端接口写入一条反馈记录。这样收到的反馈更结构化也方便答辩时展示“我根据用户反馈做了迭代”。我会建议大家尽量在微信开发者工具里开启“真机调试”模式在手机上直接看 Console 输出和网络请求。这里有个很常见的现象开发者工具里一切正常真机上白屏最常见的原因是wx.request请求的接口地址没有在小程序后台配置合法域名或者本地开发时盒子里跨域拦截了。真机调试对排查这类问题了特别有效率。5. 常见问题与排查技巧实录5.1 SpringBoot 版本与依赖冲突排查项目里我最痛苦的时期之一是引入 MyBatis-Plus 后启动直接报错Property sqlSessionFactory or sqlSessionTemplate are required。排查半天发现是spring-boot-starter的版本与mybatis-plus-boot-starter版本不兼容。根因在于 SpringBoot 2.x 和 MyBatis-Plus 3.5.x 的配合没问题但如果你用了 SpringBoot 3.x就必须换成mybatis-plus-spring-boot3-starter。如果懒得查版本建议直接锁定 SpringBoot 2.7.x mybatis-plus 3.5.3.1 这套组合兼容性最佳。另一个经典问题是接口返回时LocalDateTime字段串行化格式不对。默认是2024-01-01T12:00:00小程序端解析很别扭。我在配置里加了一个 Jackson 全局配置把LocalDateTime统一格式化为yyyy-MM-dd HH:mm:ssBean public Jackson2ObjectMapperBuilderCustomizer customizer() { return builder - builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss))); }还要记住一个容易被忽视的点SpringBoot 里Configuration类默认使用 CGLIB 代理这是为了确保单例 Bean 的行为一致。如果配置类里有普通内部调用比如Bean方法调用另一个Bean方法CGLIB 代理会保证返回的仍是同一个 Bean不会出现单例失效。这个知识点在面试里也很常问我特意验证了一下。5.2 小程序请求不通与 Charles 抓包分析本地联调阶段的小程序请求失败十次有八次是域名校验问题。开发者工具里“详情-本地设置-不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”这一项必须勾上否则本地http://localhost:8080的接口会被拦截。等走到真机或者体验版阶段wx.request只能访问 HTTPS 且在小程序后台配置过的合法域名。IP 地址端口不一定是 443 的接口基本都不能用这属于平台规则限制不能靠代码绕过。如果还是排查不出问题建议抓包。普通开发人员用 Charles 就能把小程序请求看得很清楚。在我的实际经验中配置好 Charles 的 SSL 代理后手机代理指向电脑的 8888 端口就能看到小程序的请求头、请求体、响应体以及具体的报错原因。排查问题最好用的场景是“小程序端收到的响应和开发者工具里面看到的不一致”抓包能立刻确认真正的服务端返回。不要以为抓包只有排查问题这一个用途。调试 JWT 过期、确认 401 响应头的 set-cookie、验证上传图片的 multipart 格式都离不开它。我建议每位同学在开发期间都要学会至少一种抓包工具。5.3 登录态失效与用户切换问题调试过程中很典型的一个场景用开发者工具登录后把代码重新编译再把微信账号切换成另一个测试账号这时候发现接口偶尔还能拿到上一个用户的信息。原因在于小程序的 Storage 是跟着微信账号缓存走的但开发者工具的“清除缓存”并不会自动清空 Storage。我处理的方式是在登录接口成功之前先读取本地 token 并主动调用一次 “获取当前用户” 接口如果返回 401 就立刻清空 Storage回到未登录状态。另一个是用户手动退出登录后除了删除本地 token还要把后端的 Redis 会话标识做一次删除双端清理才干净。我也在项目里做了个兜底机制后端拦截器校验 JWT 失败时会返回 code 401小程序端请求拦截器统一处理清空 token 并强制跳转到引导登录页。这个方案比每个页面单独处理 401 要省很多事。5.4 本地图片无法预览与 OSS 防盗链问题作品详情页有个大图预览功能我使用微信原生的wx.previewImage。上线后有人反馈有些图片在列表里能看见进入预览却黑屏。排查了几个案例最后定位到是 OSS 防盗链的 Referer 校验问题。wx.previewImage在部分情况下发起的请求 Referer 为空或者和列表页不同如果 OSS 的防盗链规则设置了“不允许空 Referer”预览请求就会被返回 403。解决办法是在 OSS 防盗链配置里允许空 Referer或者针对小程序请求的特定 Header 加白名单。这个坑很隐蔽当时花了两天才定位到写出来希望能帮你省事。5.5 其他几个高频小坑微信小程序的“页面栈”限制是十层如果用户像我这样连续跳转首页 - 分类 - 详情 - 作者主页 - 详情很容易触顶。超过十层后wx.navigateTo会直接失败页面看起来像没反应。我的处理方案是作者主页从详情页跳转时使用wx.redirectTo代替wx.navigateTo把上一个详情页顶掉。关于“H5 唤起微信小程序链接无法访问”如果你的平台推出了 H5 分享页想通过 URL Link 唤起小程序需要在微信公众平台配置 URL Scheme 或 URL Link并且确保链接域名在业务域名白名单里。这套机制同时要求已完成微信认证个人开发者经常卡在这里只能做降级方案引导用户复制文字去微信内搜索小程序名称。发布时的图片数量限制和文字长度限制也要提前定好。我限制一次最多发布 9 张图实际展示时做成一张封面主图加多图小缩略图。如果你一次上传超过 9 张微信的小程序端chooseMedia会直接截断选择结果。6. 扩展方向和个人体会项目基本功能做完后我沉淀出几个向纵深扩展的思路。这里简单列一下顺带说说我的看法。内容推荐方面当前广场排序是“最新 热度”如果想让平台更有“社区感”可以引入简单的用户偏好标签。比如根据用户历史点赞的作品分类给用户打标签在广场流里做加权排序甚至用协同过滤算法给用户推荐同风格摄影师作品。SpringBoot 整合 Flink 做实时流计算在这种小规模场景下是杀鸡用牛刀但如果只是想在论文里写“推荐系统设计思路”完全可以走轻量的离线召回路线。数据统计方面后端可以加一个定时任务每晚统计每个作品的点赞增量、评论增量、用户活跃度生成一份热榜。小程序端做一个“每周热榜”页面用榜单刺激用户创作是很多摄影社区验证过的有效运营手段。后台管理方面我的项目里做了一个非常简易的 Web 管理端用 SpringBoot 自带模板或 Vue 都行。管理员可以下架违规作品、封禁恶意用户、查看数据大盘。这块在答辩演示时很加分因为体现了你不仅会写前台还考虑了平台治理。搜索方面可以用 Elasticsearch也可以先靠 MySQL 的LIKE模糊查询撑住小数据量。等到图片描述、作者昵称、拍摄地点的检索需求复杂了再切换全文检索引擎。我在调研时看到有人提到 HanLP 分词结合 Elasticsearch 的思路这对中文内容搜索是合理的但项目初版完全不必上这么重。最后说点个人的真实体会。开发这个项目的过程里我认为最大的收获不是学会了 SpringBoot 或小程序的某个 API而是建立了一个“以用户路径驱动开发”的思维习惯。每写一个功能我会先问自己用户在什么场景下会走到这个页面他点这个按钮的预期是什么这个操作失败了我怎么让他知道这个习惯直接决定了一个项目是“能跑”还是“好用”。摄影作品分享交流平台本身的技术难度并不高它的核心竞争力在于内容流体验是否顺滑、互动反馈是否及时、图片加载是否舒适这些没有一项是纯粹堆代码能解决的都要回到对用户需求的理解上。如果你也准备做类似的项目建议先把用户路径画明白再动手这会比后面对着一堆零散的 CRUD 接口拼命补逻辑要轻松得多。
返回列表