微信小程序+SSM后端联调实战:专利服务系统开发踩坑记

45 0
土土老师 发表于 2026-8-17 15:13:57 | 查看全部 阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
微信小程序+SSM后端联调实战:专利服务系统开发踩坑记
本文导读

做小程序+后端的项目,最折磨人的不是写代码,而是前后端联调——小程序端报个错,你不知道是前端参数传错了、后端接口有问题、还是网络配置不对。这篇文章我以一套"专利服务系统"为例(微信小程序端+SSM后端管理),把开发过程中踩过的6个大坑完整记录下来,每个坑都有现象、原因分析和解决方案。不管你是做课程设计、毕业设计,还是第一次接触小程序全栈开发,这些坑你大概率也会遇到,提前避坑能省不少时间。
一、项目概述:专利服务系统是什么

ssm_idea.jpg
1 微信开发者工具界面(小程序端开发用微信官方开发者工具,支持模拟器+调试器+编辑器三合一)
这套系统是面向专利申请人和知识产权服务机构的轻量化服务平台,分为两个端:微信小程序端(给普通用户用)和SSM后台管理端(给管理员用)。
img_0.jpg img_1.jpg img_2.jpg
技术栈
核心功能
目标用户

微信小程序端

微信小程序原生框架(WXML+WXSS+JS)

专利申请提交、专利查询、业务指导信息浏览、个人中心

专利申请人、企业、个人发明者

SSM后台管理端

Spring+SpringMVC+MyBatis+JSP+MySQL

用户管理、专利申请审核、业务信息管理、数据统计

系统管理员、专利服务机构人员
开发环境:JDK 1.8 + Tomcat 8.5 + MySQL 5.7 + IDEA + 微信开发者工具。数据库用MySQL,后端用SSM框架,前端小程序用原生开发,前后端通过HTTP接口(JSON格式)交互。
二、系统架构设计

postman_api.jpg
2 IDEA中SSM项目结构(Maven管理依赖,Spring+SpringMVC+MyBatis分层架构)
整体架构是典型的前后端分离(虽然后台管理端还是JSP,但小程序端是纯前端通过API和后端交互):
小程序端 → HTTPS请求 → SSM后端Controller → Service → MyBatis Mapper → MySQL数据库
后端分层:Controller层接收请求、参数校验、返回JSON;Service层处理业务逻辑;Mapper层操作数据库。小程序端不直接访问数据库,所有数据都通过后端API获取,保证了数据安全。
2.1 小程序端功能模块

模块
页面
功能说明

首页

index

轮播图、业务指导信息列表、快捷入口

专利申请

apply

填写专利信息(类型、申请人、说明书、图片),提交申请

专利查询

patent

查看已提交的专利申请列表和审核状态

个人中心

mine

用户信息、我的申请、设置、退出登录
2.2 后台管理端功能模块

模块
功能说明

用户管理

用户列表、新增/编辑/删除用户、用户类型管理

专利管理

专利申请列表、审核(通过/驳回)、专利详情查看

业务信息管理

业务指导信息的增删改查、轮播图管理

数据统计

申请量统计、用户量统计、按类型/时间筛选

img_5.jpg img_6.jpg img_7.jpg
三、联调踩坑实录:6个大坑及解决方案

miniprogram_dev.jpg
3 Postman接口调试(联调时先用Postman测后端接口,确认接口没问题再对接小程序端,能快速定位问题)
1:小程序request合法域名与HTTPS

现象:小程序端调用wx.request时,开发工具里能正常请求,但手机预览时报错"request:fail url not in domain list"或者直接请求失败。
原因:微信小程序对网络请求有严格的域名校验。正式版和体验版只能请求在微信公众平台配置过的"request合法域名",而且必须是HTTPS协议。开发工具里可以勾选"不校验合法域名",所以能跑通,但真机上不行。
解决方案:
① 买一个域名,备案(国内服务器必须备案),配置SSL证书(可以用免费的Let's Encrypt或阿里云免费证书);
② 登录微信公众平台 → 开发 → 开发管理 → 开发设置 → 服务器域名,把你的域名加到"request合法域名"里;
③ 开发阶段可以在开发者工具里勾选"不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书",但上线前必须配置好。
避坑提示:域名一个月只能修改5次,所以配置前想清楚。另外,域名不能带端口号(默认443),如果后端跑在8080端口,要用Nginx反向代理到443。
2:SSM后端跨域CORS问题


img_9.jpg img_10.jpg img_11.jpg
现象:小程序端请求后端接口,控制台报"Access-Control-Allow-Origin"相关错误,或者请求能发出去但拿不到响应数据。
原因:浏览器(包括小程序的webview内核)有同源策略限制。小程序端的"源"和后端服务器的"源"不同(域名、端口、协议任一不同就算跨域),后端如果没有设置CORS响应头,浏览器会拦截响应。
解决方案(SSM项目三种方式,推荐第一种):
方式一:SpringMVC配置类全局跨域(推荐)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowedOriginPatterns("*")
            .allowedMethods("GET","POST","PUT","DELETE","OPTIONS")
            .allowedHeaders("*")
            .allowCredentials(true)
            .maxAge(3600);
    }
}
方式二:在Controller类或方法上加@CrossOrigin注解
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/patent")
public class PatentController { ... }
方式三:写一个CORS过滤器(Filter),手动设置响应头。
避坑提示:SpringBoot和SSM的CORS配置方式不一样,SSM要确认Spring版本是否支持allowedOriginPatterns(Spring 5.3+才有),低版本用allowedOrigins("*")配合allowCredentials(false)。
3:文件上传(说明书PDF、专利图片)

现象:小程序端用wx.uploadFile上传文件,后端接收不到,或者报"Current request is not a multipart request"。
原因:小程序的wx.uploadFile和普通的wx.request不一样,它发送的是multipart/form-data请求。SSM后端需要配置MultipartResolver才能解析文件上传请求,而且Controller方法要用MultipartFile接收。
解决方案:
① Spring配置文件里配置MultipartResolver:
<bean id="multipartResolver"
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10485760"/> <!-- 10MB -->
    <property name="defaultEncoding" value="UTF-8"/>
</bean>
② pom.xml引入commons-fileupload依赖:
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
③ Controller接收文件:
@RequestMapping("/upload")
@ResponseBody
public Map<String,Object> upload(
    @RequestParam("file") MultipartFile file,
    HttpServletRequest request) throws IOException {
    String path = request.getSession().getServletContext()
        .getRealPath("/upload/");
    String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
    File dest = new File(path, fileName);
    if(!dest.getParentFile().exists()) dest.getParentFile().mkdirs();
    file.transferTo(dest);
    Map<String,Object> result = new HashMap<>();
    result.put("code", 200);
    result.put("url", "/upload/" + fileName);
    return result;
}
④ 小程序端上传:
wx.uploadFile({
  url: 'https://your-domain.com/api/patent/upload',
  filePath: tempFilePath,
  name: 'file',  // 必须和后端@RequestParam的name一致
  formData: { userId: '123' },
  success(res) {
    const data = JSON.parse(res.data);
    console.log('上传成功', data.url);
  }
});
避坑提示:wx.uploadFile的name参数必须和后端@RequestParam的value一致,否则后端接收不到。另外,上传文件也受域名校验,必须是HTTPS。
4:微信登录与自有用户体系对接

现象:小程序端调用wx.login拿到code,传给后端换openid,后端请求微信接口报"invalid code"或者返回的openid为空。
原因:wx.login拿到的code只能用一次,而且有效期5分钟。如果前端把code存起来重复使用,或者后端请求微信接口时AppID/AppSecret配错了,就会报错。另外,code必须是当前小程序的,不能用其他小程序的code。
解决方案:
① 小程序端登录流程:wx.login获取code → 调用后端登录接口传code → 后端用code+AppID+AppSecret请求微信接口换openid和session_key → 后端生成自定义token返回给小程序 → 小程序把token存在本地,后续请求带在header里。
② 后端请求微信接口(用HttpClient或RestTemplate):
String url = "https://api.weixin.qq.com/sns/jscode2session"
    + "?appid=" + APPID
    + "&secret=" + SECRET
    + "&js_code=" + code
    + "&grant_type=authorization_code";
// 发送GET请求,解析返回的JSON获取openid
③ 后端维护自己的用户表,用openid作为唯一标识关联微信用户和系统用户。第一次登录自动注册,后续登录直接查用户表。
避坑提示:AppID和AppSecret存在后端配置文件里,不要写死在代码里,更不要传到前端。session_key不要返回给前端,存在后端用于解密用户敏感数据(如手机号)。
5:前后端数据格式不一致

现象:小程序端提交表单,后端收到的日期是null或者格式不对;枚举值前端传的是中文,后端存的是数字;后端返回的null字段前端显示"null"字符串。
原因:前后端没有约定好数据格式,各搞各的。日期格式前端传"2024-01-01",后端用Date接收可能解析失败;枚举值前端传"发明专利",后端用Integer接收直接报错;Jackson序列化null字段时默认输出null,前端直接渲染就显示"null"。
解决方案:
① 日期统一用字符串传递("yyyy-MM-dd"或"yyyy-MM-dd HH:mm:ss"),后端用@DateTimeFormat注解接收:
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date applyDate;
② 枚举值统一用数字编码(1=发明专利,2=实用新型,3=外观设计),前后端维护一份编码对照表,前端显示时做映射。
③ 后端统一返回格式,null字段处理:Jackson配置@JsonInclude(JsonInclude.Include.NON_NULL),null字段不序列化;或者前端做容错处理:
// 前端容错
const name = res.data.name || '';
const list = res.data.list || [];
避坑提示:项目开始前一定要写接口文档(可以用Swagger或Postman文档),约定好每个字段的类型、格式、是否必填、示例值。前后端对着文档开发,能避免80%的联调问题。
6:小程序审核与发布注意事项

现象:小程序提交审核被拒,理由是"涉及专利代理/知识产权服务,需要特殊资质"或者"内容不符合平台规范"。
原因:微信对涉及专业服务(法律、知识产权、医疗等)的小程序有资质要求,需要提供相关许可证或营业执照。另外,小程序不能有诱导分享、虚拟支付(iOS)等违规行为。
解决方案:
① 确认小程序的服务类目,专利服务可能需要选择"商业服务-知识产权"或"工具-效率"类目,按要求上传资质;
② 毕业设计/课程设计用的小程序,可以选"工具"类目,功能描述写得简单一些,避免触发资质审核;
③ 提交审核前仔细阅读《微信小程序平台运营规范》,不要有敏感词、外部链接、诱导分享等内容;
④ 如果只是演示用,可以用"体验版"分享给指定用户(最多100人),不需要提交审核。
避坑提示:审核被拒后看清楚拒绝理由,针对性修改后再提交。反复被拒可能会影响账号信用。毕业设计项目建议直接用体验版演示,不一定要发布正式版。
四、核心代码实现

4.1 小程序端请求封装

每个页面都写wx.request太啰嗦,封装一个通用的请求方法,统一处理baseURL、token、错误提示:
// utils/request.js
const BASE_URL = 'https://your-domain.com/api';

function request(options) {
  return new Promise((resolve, reject) => {
    wx.request({
      url: BASE_URL + options.url,
      method: options.method || 'GET',
      data: options.data || {},
      header: {
        'content-type': 'application/json',
        'token': wx.getStorageSync('token') || ''
      },
      success(res) {
        if (res.data.code === 200) {
          resolve(res.data);
        } else if (res.data.code === 401) {
          wx.showToast({ title: '请先登录', icon: 'none' });
          wx.navigateTo({ url: '/pages/login/login' });
          reject(res.data);
        } else {
          wx.showToast({ title: res.data.msg || '请求失败', icon: 'none' });
          reject(res.data);
        }
      },
      fail(err) {
        wx.showToast({ title: '网络错误', icon: 'none' });
        reject(err);
      }
    });
  });
}
module.exports = { request };
4.2 SSM后端统一返回格式

后端所有接口统一返回格式,前端处理起来方便:
public class Result<T> {
    private int code;     // 200成功,401未登录,500错误
    private String msg;   // 提示信息
    private T data;       // 返回数据

    public static <T> Result<T> success(T data) {
        Result<T> r = new Result<>();
        r.setCode(200); r.setMsg("success"); r.setData(data);
        return r;
    }
    public static <T> Result<T> error(int code, String msg) {
        Result<T> r = new Result<>();
        r.setCode(code); r.setMsg(msg);
        return r;
    }
}
4.3 专利申请Controller


@RestController
@RequestMapping("/api/patent")
public class PatentController {
    @Autowired
    private PatentService patentService;

    @RequestMapping("/list")
    public Result<List<Patent>> list(
        @RequestParam(defaultValue="1") int page,
        @RequestParam(defaultValue="10") int size,
        @RequestParam(required=false) Integer userId) {
        List<Patent> list = patentService.findByPage(page, size, userId);
        return Result.success(list);
    }

    @RequestMapping(value="/apply", method=RequestMethod.POST)
    public Result<String> apply(@RequestBody Patent patent) {
        patent.setApplyTime(new Date());
        patent.setStatus(0); // 0待审核
        patentService.save(patent);
        return Result.success("申请提交成功");
    }

    @RequestMapping("/detail")
    public Result<Patent> detail(@RequestParam int id) {
        Patent patent = patentService.findById(id);
        return Result.success(patent);
    }
}
五、数据库设计要点

表名
核心字段
说明

user

id, username, password, openid, phone, userType, createTime

用户表,userType区分普通用户和管理员

patent

id, userId, title, patentType, applyType, coAuthor, categoryNo, keywords, description, fileUrl, imageUrl, status, applyTime, auditTime, auditRemark

专利申请表,status状态:0待审核1通过2驳回

news

id, title, content, image, type, createTime

业务指导信息表,首页展示的资讯内容

banner

id, imageUrl, linkUrl, sort

轮播图表,首页顶部轮播
设计要点:一是patent表的status字段用数字编码,配合字典表或前端映射显示中文状态;二是fileUrl和imageUrl存相对路径,前端拼接域名访问;三是所有表加createTime和updateTime字段,方便数据追溯;四是用户表的openid字段加唯一索引,防止重复注册。
六、部署与上线

开发完成后要部署到服务器,小程序才能真机访问。部署步骤:
1. 后端打包:IDEA里Maven打包成war包,上传到服务器Tomcat的webapps目录;
2. 数据库导入:本地MySQL导出sql脚本,在服务器MySQL里执行;
3. 域名和SSL:域名解析到服务器IP,配置Nginx反向代理,HTTPS证书配置好;
4. 小程序配置:微信公众平台配置request合法域名、uploadFile合法域名、downloadFile合法域名;
5. 上传体验版:微信开发者工具点击"上传",在公众平台设为体验版,扫码测试;
6. 提交审核(可选):确认没问题后提交审核,审核通过后发布正式版。
避坑提示:服务器时间要和北京时间一致,否则微信登录的timestamp校验会失败。Tomcat的URIEncoding要设为UTF-8,否则中文参数会乱码。
七、常见问题FAQ

Q:小程序端和后台管理端可以共用一套后端吗?
A:可以,而且推荐共用。后端Controller分两个路径前缀,/api/给小程序端用(返回JSON),/admin/给后台管理端用(返回JSP页面或JSON)。Service层和Mapper层完全复用,只是Controller层分开。这样一套后端维护两份前端,效率最高。
Q:SSM和SpringBoot选哪个?
A:如果是新项目,强烈推荐SpringBoot——自动配置、内嵌Tomcat、开发效率高。但如果学校课程要求用SSM,或者老项目维护,那就用SSM。SSM的核心是XML配置多一些,理解了IoC和AOP的原理,两者切换很容易。这篇文章的项目是SSM,因为很多高校的毕业设计要求用SSM。
Q:小程序原生开发和uni-app/Taro怎么选?
A:只做微信小程序,原生开发最稳定、性能最好、官方文档最全。如果要同时发布到支付宝、百度、抖音小程序,或者转H5/App,用uni-app(Vue语法)或Taro(React语法)更高效。毕业设计如果只要求微信小程序,用原生就行,学习成本低。
Q:联调时怎么快速定位是前端还是后端的问题?
A:三步定位法:① 用Postman直接调用后端接口,如果Postman也报错,那是后端问题;② Postman正常但小程序报错,看小程序控制台的Network面板,检查请求参数和响应;③ 参数对但数据不对,大概率是前后端字段名或格式不一致。养成先测后端再联调前端的习惯,能省很多时间。
Q:专利服务系统需要对接国家知识产权局的真实接口吗?
A:毕业设计/课程设计不需要,自己模拟数据就行。真实的专利查询和申请要对接国家知识产权局的系统,有严格的资质和接口规范。学生项目做一个模拟的专利申请流程和管理后台就够了,重点是展示技术实现能力,而不是业务真实性。
八、总结与延伸学习路径

小程序+SSM后端的项目,技术本身不难,难的是前后端联调的细节——域名、跨域、文件上传、登录鉴权、数据格式,每一个都可能卡住你。这篇文章总结的6个坑,是我做这类项目时反复遇到的,提前知道解决方案,开发效率能提升一倍。
如果想继续深入全栈开发,可以按这个路径学习:
1. 小程序进阶:自定义组件、云开发、性能优化、分包加载;
2. 后端进阶:SpringBoot、SpringSecurity/JWT鉴权、Redis缓存、MyBatis-Plus;
3. 工程化:Maven多模块、Docker部署、CI/CD、Nginx反向代理;
4. 接口文档:Swagger/Knife4j自动生成接口文档,前后端协作更高效;
5. 项目实战:多做几个完整项目,从需求分析到部署上线全流程走一遍,比看教程有用。

—— 全栈开发的核心不是什么都会,而是出了问题能快速定位在哪一层。

有问题欢迎评论区交流,需要更多小程序+后端项目实战案例可以关注后续更新~

img_3.jpg
img_4.jpg
img_8.jpg
img_12.jpg
img_13.jpg
img_14.jpg
img_15.jpg
img_16.jpg
img_17.jpg
img_18.jpg
img_19.jpg
img_20.jpg
回复 转播

使用道具 举报

回复

高级模式
B Color Image Link Quote Code Smilies |上传

本版积分规则

学研领航向全体高校师生打造的一站式综合交流与资源服务平台,集知识学习、经验分享、资源下载、互动问答、职场成长、兼职实践于一体,覆盖校园生活、专业学习、求职就业、兴趣发展等全场景需求。

快捷导航

小黑屋
Copyright © 2026 学研领航 版权所有 陕ICP备2025077879号-1
关灯 在本版发帖 返回顶部
快速回复 返回顶部 返回列表