资讯详情

微信小程序名片管理系统:Java后端+小程序完整实战

📅 2026/10/30 16:37:06 | 华诺云谱 👁 阅读
微信小程序名片管理系统:Java后端+小程序完整实战
简介这是一套面向计算机专业本科生课程设计与毕业设计的微信小程序名片管理系统实战项目基于Java后端与小程序前端协同开发解决个人或小型团队数字化名片存储、检索与管理的实际需求。资源包共736个文件涵盖103个JS逻辑脚本、71个Java业务类、74个Class编译文件、71个PNG图标资源、42个CSS/WXSS样式文件及1个核心SQL数据库脚本完整呈现前后端分离架构下的模块化实现压缩包仅11.2MB轻量易部署。已有200人学习下载适合Java初学者通过可运行项目理解SSM/SpringBoot整合、MySQL数据建模、小程序API调用及Tomcat部署全流程。项目含用户注册、名片增删改查、联系人分类、留言反馈、系统公告等完整功能模块Controller层命名清晰如KehumingpianInfoController、LianxirenmingpianInfoController便于源码阅读与二次开发配套Navicat可视化操作与IDEA微信开发者工具调试环境说明显著降低上手门槛。1. 微信小程序名片管理系统Java后端小程序前端的完整课程设计闭环不是Demo而是可交付的最小可行系统你花三天搭了个“Hello World”小程序连数据库都没连上别人交毕业设计时已经跑通了微信登录、名片增删改查、搜索排序、导出Excel、管理员后台权限分离——这套「微信小程序-基于小程序的名片管理系统Java」就是后者。它不是教你怎么写wx:for的入门示例而是一个真实压缩包含完整Spring Boot后端源码含JWT鉴权、MyBatis动态SQL、文件上传接口、MySQL建库脚本含用户表、名片表、角色表三张核心表、微信小程序前端源码WXML/WXSS/JS全量含tabBar导航、列表分页、表单校验、扫码添加、配套PDF图文教程从环境搭建→数据库导入→后端启动→小程序配置→真机调试共17步。适合计算机专业本科生做课程设计或毕业设计选题也适合作为Java Web 小程序双栈开发的实操锚点——所有模块都经过真机扫码验证不是“理论上能跑”而是“你照着步骤走完手机扫二维码就能用”。提示这不是uni-app或Taro跨端方案是原生微信小程序Spring Boot标准组合技术栈干净、边界清晰、调试链路短。如果你正被“毕设选题没方向”“Java后端和小程序怎么串起来”“部署后接口404”卡住这套资源就是为你准备的“可拆解、可替换、可答辩”的实体参考。2. 后端架构解析与Spring Boot工程落地为什么选MyBatis而非JPA以及JWT鉴权如何嵌入业务流2.1 工程结构与模块划分看清三层分层的真实意图项目后端采用标准Maven结构根目录下src/main/java/com/example/businesscard为包名起点严格遵循Controller → Service → Mapper三层分层controller包仅处理HTTP协议层如CardController.java中PostMapping(/api/card)接收JSON调用Service方法返回统一ResultT封装体service包包含业务逻辑与事务控制如CardService.java中saveCard()方法内嵌Transactional确保新增名片更新用户统计数原子性mapper包MyBatis XML映射文件CardMapper.xml与接口CardMapper.java分离SQL语句集中管理便于审计与性能优化。注意application.yml中数据库配置使用spring.datasource.urljdbc:mysql://localhost:3306/bizcard?useSSLfalseserverTimezoneGMT%2B8allowPublicKeyRetrievaltrue明确指定时区与SSL策略——这是本地MySQL 8.0连接的刚需漏掉serverTimezone会导致时间字段乱码漏掉allowPublicKeyRetrievaltrue会报Public Key Retrieval is not allowed错误。2.2 MyBatis动态SQL实战解决名片搜索的多条件组合难题名片搜索需支持“按姓名模糊匹配按公司筛选按标签筛选按创建时间范围”若用硬编码SQL拼接极易引发SQL注入。本项目采用MyBatiswhereif动态标签实现安全组合查询!-- CardMapper.xml -- select idsearchCards resultTypecom.example.businesscard.entity.Card SELECT * FROM card where if testname ! null and name ! AND name LIKE CONCAT(%, #{name}, %) /if if testcompany ! null and company ! AND company #{company} /if if testtag ! null and tag ! AND tag #{tag} /if if teststartTime ! null AND create_time #{startTime} /if if testendTime ! null AND create_time #{endTime} /if /where ORDER BY create_time DESC /select逻辑说明where标签自动处理首条件前的AND冗余问题每个if判断参数非空再拼接SQL片段CONCAT(%, #{name}, %)实现模糊查询避免在Java层拼接字符串引入注入风险。参数说明#{}是预编译占位符比${}安全startTime/endTime为LocalDateTime类型MyBatis自动映射为MySQL DATETIME。2.3 JWT鉴权集成从登录到接口拦截的完整链路系统未用Session而是采用无状态JWT方案。流程如下小程序调用/api/login传{ code: xxx }微信登录临时code后端用https://api.weixin.qq.com/sns/jscode2session换取openid生成JWT Token有效期2小时Token存入Rediskeytoken:${userId}valuejwt字符串过期时间同步JWT后续请求携带Authorization: Bearer xxxJwtAuthenticationFilter拦截并校验签名、过期时间、Redis是否存在。关键代码片段JwtAuthenticationFilter.javapublic class JwtAuthenticationFilter extends OncePerRequestFilter { Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token getTokenFromRequest(request); if (token ! null jwtUtil.validateToken(token)) { String userId jwtUtil.getUserIdFromToken(token); // 从Redis校验Token有效性防登出后Token仍可用 if (redisTemplate.hasKey(token: userId) Objects.equals(redisTemplate.opsForValue().get(token: userId), token)) { SecurityContextHolder.getContext() .setAuthentication(new UsernamePasswordAuthenticationToken(userId, null, new ArrayList())); } } filterChain.doFilter(request, response); } }参数说明jwtUtil.validateToken()校验签名与过期redisTemplate.hasKey()二次校验防止Token盗用SecurityContextHolder注入Spring Security上下文后续PreAuthorize(hasRole(USER))注解即可生效。3. 小程序前端功能实现与微信能力调用从扫码添加到本地缓存策略3.1 扫码添加名片wx.scanCode与后端API的协同设计小程序首页“”按钮触发扫码核心逻辑在pages/index/index.js中// pages/index/index.js addByScan() { wx.scanCode({ success: (res) { // 假设扫码内容为vCard格式文本如BEGIN:VCARD\nFN:张三\nTEL:138****1234\nEMAIL:zhangexample.com\nEND:VCARD const vcardText res.result; const parsed this.parseVCard(vcardText); // 解析vCard文本为对象 wx.request({ url: https://your-domain.com/api/card, method: POST, data: parsed, header: { Authorization: Bearer getApp().globalData.token }, success: (r) { wx.showToast({ title: 添加成功 }); this.loadCards(); // 刷新列表 } }); } }); }, parseVCard(text) { const lines text.split(\n); let card { name: , phone: , email: , company: }; lines.forEach(line { if (line.startsWith(FN:)) card.name line.substring(3).trim(); if (line.startsWith(TEL:)) card.phone line.substring(4).trim(); if (line.startsWith(EMAIL:)) card.email line.substring(6).trim(); if (line.startsWith(ORG:)) card.company line.substring(4).trim(); }); return card; }逻辑说明wx.scanCode返回res.result为原始文本需自行解析vCard格式本项目仅支持基础字段不依赖第三方库header中携带JWT Token完成鉴权this.loadCards()调用分页接口刷新UI。注意真机测试必须在app.json中声明requiredPrivateInfos: [scanCode]否则iOS会拒绝调用。3.2 列表分页加载wx:for与onReachBottom的性能平衡点名片列表采用下拉触底加载更多但未用无限滚动易卡顿而是分页节流控制// pages/list/list.js data: { cards: [], page: 1, pageSize: 10, hasMore: true, loading: false }, onReachBottom() { if (this.data.loading || !this.data.hasMore) return; this.setData({ loading: true }); wx.request({ url: https://your-domain.com/api/card?page${this.data.page}size${this.data.pageSize}, success: (res) { const newCards res.data.data; if (newCards.length this.data.pageSize) { this.setData({ hasMore: false }); } this.setData({ cards: this.data.cards.concat(newCards), page: this.data.page 1, loading: false }); } }); }参数说明pageSize10是经测试的平衡值——小于5页数过多影响首屏速度大于20单次请求数据量大易超时hasMore标志位避免重复请求空数据loading状态防止快速滑动触发多次请求。实测在低端安卓机上10条/页加载响应300ms。3.3 本地缓存策略wx.setStorageSync与敏感信息隔离用户登录态Token不存wx.setStorageSync明文而是加密存储// utils/storage.js const KEY_TOKEN bizcard_token; const KEY_USER_INFO bizcard_user; function setToken(token) { const encrypted wx.getFileSystemManager().encrypt({ key: bizcard_2024_key, // 硬编码密钥仅作示意生产应动态生成 data: token }); wx.setStorageSync(KEY_TOKEN, encrypted); } function getToken() { const encrypted wx.getStorageSync(KEY_TOKEN); if (!encrypted) return null; return wx.getFileSystemManager().decrypt({ key: bizcard_2024_key, data: encrypted }); }逻辑说明wx.getFileSystemManager().encrypt/decrypt为小程序提供的轻量级加解密API比Base64更安全KEY_TOKEN与KEY_USER_INFO分离存储避免一次泄露全部凭证wx.setStorageSync容量上限10MB本项目单个Token约200B完全无压力。4. 数据库设计与SQL脚本执行三张表如何支撑权限、搜索、统计核心需求4.1 核心表结构设计为什么名片表要冗余user_id而非外键关联card表结构如下摘自db_init.sqlCREATE TABLE card ( id bigint NOT NULL AUTO_INCREMENT, user_id bigint NOT NULL COMMENT 所属用户ID冗余字段提升查询效率, name varchar(50) NOT NULL COMMENT 姓名, phone varchar(20) DEFAULT NULL COMMENT 手机号, email varchar(100) DEFAULT NULL COMMENT 邮箱, company varchar(100) DEFAULT NULL COMMENT 公司, tag varchar(20) DEFAULT NULL COMMENT 标签如客户同事, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_id (user_id), KEY idx_name (name), KEY idx_company (company) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT名片表;设计理由user_id冗余而非外键避免联表查询SELECT * FROM card JOIN user ON card.user_iduser.id带来的性能损耗小程序列表页只需查card表复合索引缺失当前仅单列索引若高频查询“某用户某公司”应补充KEY idx_user_company (user_id, company)tag字段未建字典表因标签值固定客户/同事/合作伙伴直接VARCHAR存储简化CRUD符合课程设计轻量原则。4.2 权限控制表设计role与user_role如何实现RBAC最小集系统仅需“管理员”与“普通用户”两角色采用经典RBAC四表精简版-- 角色表 CREATE TABLE role ( id bigint NOT NULL AUTO_INCREMENT, name varchar(20) NOT NULL COMMENT 角色名如ADMIN, USER, PRIMARY KEY (id) ); -- 用户表含密码加密存储 CREATE TABLE user ( id bigint NOT NULL AUTO_INCREMENT, openid varchar(100) NOT NULL COMMENT 微信openid唯一标识, nickname varchar(50) DEFAULT NULL, password varchar(100) NOT NULL COMMENT BCrypt加密密码用于后台登录, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ); -- 用户角色关联表 CREATE TABLE user_role ( user_id bigint NOT NULL, role_id bigint NOT NULL, PRIMARY KEY (user_id,role_id), KEY fk_role_id (role_id), CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE, CONSTRAINT fk_role_id FOREIGN KEY (role_id) REFERENCES role (id) ON DELETE CASCADE );关键点user.openid作为主业务IDuser.password仅用于管理员后台登录非微信登录user_role为联合主键删除用户时自动级联删除角色关系ON DELETE CASCADE保障数据一致性。4.3 初始化脚本执行db_init.sql导入后的三步验证法导入db_init.sql后必须执行以下验证否则后端启动必报错检查字符集SHOW CREATE TABLE card;确认DEFAULT CHARSETutf8mb4否则中文插入报错验证索引存在SHOW INDEX FROM card;确认idx_user_id等索引已创建缺失则搜索变全表扫描测试基础数据执行INSERT INTO role(name) VALUES(ADMIN),(USER);再查SELECT * FROM role;确认ID为1、2——后端代码中role_id1硬编码为管理员ID错则权限失效。提示MySQL 8.0默认认证插件为caching_sha2_password若连接报错Client does not support authentication protocol需执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY your_password;切换回旧插件。5. 避坑指南五个血泪经验总结覆盖从环境配置到真机调试的全链路翻车点5.1 现象后端启动报Failed to configure a DataSource原因application.yml数据库配置未取消注释解决打开src/main/resources/application.yml找到# spring: datasource:区块删除整段#符号并填入本地MySQL账号密码。5.2 现象小程序wx.request返回401 Unauthorized原因未在request的header中传Authorization字段或Token过期未刷新解决在app.js的onLaunch中检查wx.getStorageSync(token)是否存在且未过期可用Date.now() expireTime粗略判断过期则跳转登录页。5.3 现象扫码添加后名片列表不更新原因onReachBottom触发时this.data.page未递增导致反复请求第1页解决检查onReachBottom函数末尾是否有this.setData({ page: this.data.page 1 })且该行不能被if条件包裹遗漏执行。5.4 现象真机调试时wx.scanCode提示“未授权”原因未在微信公众平台后台配置scope权限或小程序版本未发布解决登录 微信公众平台 → 开发管理 → 接口权限 → 开通“扫码”权限开发版需点击“体验版”生成二维码供真机扫码正式版需提交审核。5.5 现象导出Excel功能下载空白文件原因后端ExportController.java中response.setContentType(application/vnd.ms-excel)未设置Content-Disposition响应头浏览器无法识别文件名解决在response.setHeader(Content-Disposition, attachment; filenamecontacts.xlsx);后追加response.getOutputStream().write(bytes);确保字节流写入响应体。6. 进阶技巧用Postman批量验证接口 自定义小程序云开发替代方案6.1 Postman接口验证清单五类核心请求模板为避免每次改代码都得启小程序调试我习惯用Postman预验后端接口。以下是本项目必须验证的5类请求模板保存为Postman Collection请求类型URLMethodBody/Params预期Status关键校验点微信登录/api/loginPOST{code:xxx}200返回token字段非空名片新增/api/cardPOST{name:张三,phone:138****1234}200data.id为数字名片分页/api/card?page1size10GET—200data.list长度≤10名片搜索/api/card/search?name张GET—200data.list含name含“张”的记录管理员导出/api/exportGET—200Content-Type含application/vnd.ms-excel提示Postman中设置Authorization为Bearer {{token}}{{token}}为环境变量登录后从响应中提取并保存后续请求自动携带。6.2 云开发平替方案当不想搭Java后端时如何用云函数云数据库重构若你只想聚焦小程序前端或服务器运维能力有限可用微信云开发替代Java后端。重构要点如下云数据库替代MySQL将card表迁移到云数据库集合名card字段保持一致name,phone,user_openid云函数替代Controller新建addCard云函数接收event参数调用db.collection(card).add()插入数据权限控制简化云数据库设置user_openid event.userInfo.openId为读写权限无需JWT鉴权导出Excel改造云函数中用node-xlsx库生成Buffer通过cloud.downloadFile返回临时链接。代码片段云函数addCard/index.jsconst cloud require(wx-server-sdk); cloud.init(); const db cloud.database(); exports.main async (event, context) { try { const { name, phone, email } event; await db.collection(card).add({ data: { name, phone, email, user_openid: event.userInfo.openId, create_time: new Date() } }); return { success: true }; } catch (e) { return { success: false, error: e.message }; } };参数说明event.userInfo.openId由微信自动注入无需前端传递db.collection().add()自动返回_id无需手动维护ID云函数免费额度足够课程设计使用。从那以后我每次接手新小程序项目都会先用Postman跑通这5个接口模板再写前端页面——省去90%的“接口不通”排查时间。云开发方案则作为保底选项当导师突然要求“两天内演示”时它能让我把精力100%放在UI交互打磨上。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑