拓冰建站拓冰建站
首页 / 资讯中心 / 正文

SpringBoot + 微信小程序 + AI大模型校园导航毕设开发详解

SpringBoot 微信小程序 AI 大模型做一个能答辩的校园导航毕设每年毕业设计的答辩现场都有一批项目长得很像后台管理系统输入账号密码点几遍“新增、编辑、删除”再用 ECharts 放两张折线图评委问创新点在哪里只能说“用了 SpringBoot”。其实最近两年计算机毕设的选题方向已经悄悄变了。AI 大模型接口开放之后把传统信息系统和自然语言交互结合起来成了一个性价比极高的选题思路。今天要拆解的这套“SpringBoot 微信小程序 AI 大模型”智能校园导航系统就是这类项目里热度很高的一种。它不只做一个地图展示而是让用户直接用“图书馆怎么走”“从东门到行政楼哪条路最近”这样的自然语言完成导航。这个项目的关键不在“接了一个大模型聊天玩具”而在于把 AI 放在了导航场景的正确位置上意图理解、语义搜索、路径推荐。把这条主线想清楚做完之后你收获的就不只是一套能答辩的代码而是一套完整的前后端分离 第三方 AI 服务集成方法论。1. 这个选题为什么值得做1.1 传统毕设项目的通病先说一个扎心的事实每年毕业设计里至少有一半的项目是“管理系统”。学生管理、图书管理、酒店管理、超市管理……功能高度重合技术上也都是 CRUD。不是说 CRUD 不好而是这类项目做一个学期和做一个星期最终展示出来的效果差别不大。评委看多了以后第一句话往往是“这个项目你觉得哪里能体现出你的能力”于是很多同学开始堆技术栈SpringBoot Vue Redis RabbitMQ甚至 Docker K8s 都塞进去。但核心业务还是那张 CRUD 的表技术全都浮在表面一问细节就露馅。1.2 AI 大模型给了毕设一个新的加分方向2023 年以来中文大模型 API 越来越成熟开源模型也可以通过 Ollama 这类工具轻松本地跑起来。这给计算机毕设带来的变化是你可以低成本地做一个“传统系统 智能交互”的复合型项目。智能校园导航系统就是典型代表后端用 SpringBoot这是国内企业用的最多的 Java 框架之一。前端用微信小程序不用单独适配安卓和 iOS开发量可控。AI 大模型负责解析用户自然语言把“我想去图书馆但我现在在第一教学楼”变成结构化的起终点数据。路径规划可以自己实现最短路径算法这是算法能力的一个直观展示。相比纯管理系统这类项目的技术覆盖面更宽又有明确的场景创新点答辩的时候更容易讲出东西来。1.3 什么样的人适合选这个项目如果你符合下面几种情况这套选题值得认真考虑有 Java 基础至少能看懂 SpringBoot 的 Controller、Service、Mapper 分层。小程序端不要求精通但希望找一个移动端项目作为亮点。想把 AI 写进简历但不想只做过度的“API 包装盒子”。想要一个算法 工程 AI 应用都有体现的毕设项目。如果你是零基础也可以做但要预留出更多的时间补基础。这个项目真正的难点不在某个单点技术而在把几个环节串起来的过程。2. 系统总体架构与技术选型分析2.1 整体架构小程序端、后端服务、AI 服务、数据层整个系统可以拆成四层数据流向很清晰。第一层是微信小程序端负责地图展示、用户输入、路线绘制和 AI 对话界面。小程序运行在用户手机上通过 HTTPS 请求后端接口。第二层是SpringBoot 后端服务是整个系统的核心。它负责用户身份识别、建筑和路线数据查询、最短路径计算、AI 请求转发、导航历史记录保存。所有小程序发来的请求都先到这一层。第三层是AI 大模型服务通过第三方 API 接入。后端拿到用户自然语言后拼接好 Prompt 发送给大模型大模型返回结构化结果比如起点和终点名称再由后端去执行路径规划。之所以不让小程序直接调大模型是因为 API Key 放在前端会被抓包泄露而且后端还能统一做日志、限流和数据过滤。第四层是MySQL 数据库保存用户、建筑点POI、路网边、导航记录和对话记录。画成文字描述就是这样微信小程序端 -- SpringBoot 后端 -- MySQL | v AI 大模型 API2.2 技术栈对比与选型逻辑模块技术选型选型理由后端框架SpringBoot国内最主流生态成熟答辩认可度高持久层MyBatis-Plus单表 CRUD 不需要写 SQL节省大量时间数据库MySQL 8.x免费稳定教程多小程序端微信小程序原生框架无需额外构建工具微信开发者工具开箱即用AI 服务大模型 HTTP API接入成本低无需自己部署 GPU 服务路径规划Dijkstra 算法自建路网展示算法能力避免依赖第三方路线 API2.3 地图与路径规划服务商 API 方案 vs 自建路网方案这是决定工作量和技术亮点的一个关键选择需要重点说明。方案一调地图服务商的路线规划 API。比如使用腾讯地图或高德地图的 WebService API传入起点和终点坐标直接返回路径点集。优点是开发量小路径画出来非常准确还能自动避开围墙和建筑。缺点也很明显需要申请 Key学校区域的数据质量不太稳定最麻烦的是答辩现场一旦断网或 API 限流整场演示就翻车了。方案二自己建立校园路网数据后端实现最短路径算法。你需要把校园里的建筑、路口作为图的节点把可通行的道路作为边保存距离然后在前端把坐标点画到地图组件上。优点是技术含量高算法实现是答辩的加分项不依赖第三方路线 API网络波动影响小可以离线演示。缺点是前期要整理路网数据如果校园比较大建图会有一定工作量。从毕设的角度更推荐方案二为主方案一作为扩展加分点。先用自建路网把核心流程跑通如果时间和精力允许再补一个“第三方路线 API 兜底”的说明体现你对方案对比和工程取舍的思考。3. 数据库设计与核心功能模块3.1 功能模块划分整个系统的核心功能分成四块第一是用户身份与记录。小程序端使用 wx.login 静默登录后端调用微信接口换得 openid作为用户唯一标识。用户发起导航后可以保存历史记录。第二是建筑POI管理。也就是地图上的点包括教学楼、食堂、宿舍、行政楼、图书馆、打印店等。每个点要保存名称、分类、经纬度、楼层概况和一句话简介。第三是路网管理与路径规划。数据表保存点和点之间的连通关系以及距离。后端根据起点终点查图用 Dijkstra 算法计算最短路径返回途经节点坐标。第四是AI 对话导航。用户输入自然语言后端拼接 Prompt携带校园建筑库信息发送给大模型从中解析出起点、终点或关键词然后走路径规划链路。3.2 核心表设计先看建筑表。毕设系统一般不会做得特别庞大所以表设计在满足功能的前提下尽量精简。字段类型说明idBIGINT主键nameVARCHAR(100)建筑名称如“第一教学楼”categoryVARCHAR(50)分类如教学楼、食堂、宿舍、服务latitudeDECIMAL(10,6)纬度longitudeDECIMAL(10,6)经度descriptionVARCHAR(500)建筑简介可展示在详情页再看路网边表。这张表存的是“哪两个点之间有路可以走”这是路径规划的数据基础。字段类型说明idBIGINT主键start_node_idBIGINT起点建筑 IDend_node_idBIGINT终点建筑 IDdistanceDECIMAL(10,2)实际步行距离单位米walk_timeINT预估步行时间单位分钟最后是导航记录表。用户每次导航后插入一条记录后续可以在“我的记录”里查看历史。3.3 建表 SQL 示例CREATE TABLE building ( id BIGINT NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL COMMENT 建筑名称, category VARCHAR(50) DEFAULT other COMMENT 分类teaching/dining/dorm/service, latitude DECIMAL(10,6) NOT NULL COMMENT 纬度, longitude DECIMAL(10,6) NOT NULL COMMENT 经度, description VARCHAR(500) DEFAULT COMMENT 简介, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_category (category) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE road ( id BIGINT NOT NULL AUTO_INCREMENT, start_node_id BIGINT NOT NULL, end_node_id BIGINT NOT NULL, distance DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT 距离米, walk_time INT NOT NULL DEFAULT 0 COMMENT 步行时间分钟, PRIMARY KEY (id), KEY idx_start (start_node_id), KEY idx_end (end_node_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE navigation_record ( id BIGINT NOT NULL AUTO_INCREMENT, user_id BIGINT NOT NULL, start_name VARCHAR(100) DEFAULT , end_name VARCHAR(100) DEFAULT , path_json TEXT COMMENT 路线坐标点 JSON, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里要提醒一个容易踩的坑路网数据不能把所有建筑两两直接相连。否则路径规划算出来会横穿教学楼、宿舍甚至围墙答辩演示时非常尴尬。建路网时应该把校园的十字路口、拐角作为额外的节点让路径真的沿着路走。如果时间有限至少保证相邻建筑之间有合理连接不要为了省事把所有点都连起来。4. 开发环境准备与工程初始化4.1 环境清单开始写代码之前先把环境准备齐全。这里只列必备项版本以你本机安装为准。JDK 8 或 JDK 17。SpringBoot 2.x 用 8、3.x 用 17建议直接用 17。Maven 3.6 以上。MySQL 5.7 或 8.0。微信开发者工具。一个小程序 AppID可用测试号。一个大模型 API Key用国内云厂商的 Open AI 兼容接口即可。IDEA 或 Eclipse。4.2 后端工程初始化与依赖新建 SpringBoot 工程时只需要引入 Web、MySQL、MyBatis、Lombok 这几个核心依赖。下面是一份 pom.xml 的核心依赖片段版本号可根据你初始化项目时选定的版本来定dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.5/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies4.3 application.yml 配置数据库配置和大模型 API 配置都放在这里。大模型的 Key 不要硬编码在代码里建议读环境变量也可以用ConfigurationProperties做配置类。server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/campus_navigation?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver # 大模型配置endpoint 以你使用的平台文档为准 # 目前国内主流大模型平台基本都提供 OpenAI 兼容接口 ai: api-key: ${AI_API_KEY:please-set-your-api-key} model: your-model-name endpoint: https://api.example.com/v1/chat/completions如果你用的平台不提供 OpenAI 兼容接口也没关系请求体结构大同小异改一下参数名就行。5. SpringBoot 后端核心代码实现5.1 统一返回结构与全局异常处理写接口之前先把统一返回结构建好。所有接口都返回{ code, message, data }前端对接口的处理逻辑会变得非常一致。// 文件路径src/main/java/com/example/campus/common/R.java Data public class RT { private Integer code; private String message; private T data; public static T RT ok(T data) { RT r new R(); r.code 200; r.message success; r.data data; return r; } public static T RT fail(String message) { RT r new R(); r.code 500; r.message message; return r; } }再加一个全局异常处理器把常见的IllegalArgumentException和其他异常统一转成 R 结构前端就不会因为偶尔的一个异常导致整个页面崩溃。5.2 最短路径算法实现路径规划的核心是用 Dijkstra 算法。校园路网规模不大几十个节点Dijkstra 的性能完全够用代码也比 A* 简单。图的数据结构用MapLong, MapLong, Double表示意思是“从节点 A 出发可以到达哪些节点距离是多少”。// 文件路径src/main/java/com/example/campus/service/PathPlannerService.java Service public class PathPlannerService { private MapLong, MapLong, Double graph new HashMap(); public void buildGraph(ListRoad roads) { graph.clear(); for (Road road : roads) { graph.computeIfAbsent(road.getStartNodeId(), k - new HashMap()) .put(road.getEndNodeId(), road.getDistance().doubleValue()); graph.computeIfAbsent(road.getEndNodeId(), k - new HashMap()) .put(road.getStartNodeId(), road.getDistance().doubleValue()); } } public ListLong findShortestPath(Long start, Long end) { MapLong, Double dist new HashMap(); MapLong, Long prev new HashMap(); PriorityQueueMap.EntryLong, Double queue new PriorityQueue( Comparator.comparingDouble(Map.Entry::getValue) ); dist.put(start, 0.0); queue.offer(new AbstractMap.SimpleEntry(start, 0.0)); while (!queue.isEmpty()) { Long node queue.poll().getKey(); if (node.equals(end)) { break; } MapLong, Double neighbors graph.getOrDefault(node, Collections.emptyMap()); for (Map.EntryLong, Double edge : neighbors.entrySet()) { double newDist dist.getOrDefault(node, Double.MAX_VALUE) edge.getValue(); if (newDist dist.getOrDefault(edge.getKey(), Double.MAX_VALUE)) { dist.put(edge.getKey(), newDist); prev.put(edge.getKey(), node); queue.offer(new AbstractMap.SimpleEntry(edge.getKey(), newDist)); } } } ListLong path new LinkedList(); for (Long cur end; cur ! null; cur prev.get(cur)) { path.add(0, cur); } return path; } }注意buildGraph里加了一次graph.computeIfAbsent是为了保证节点存在这样findShortestPath里即使某个节点没有邻居也不会空指针。5.3 导航接口实现导航流程是这样的前端传起点名称和终点名称后端根据名称查建筑表拿到坐标再调用PathPlannerService算出路径点最后把建筑坐标和路径点一起返回。// 文件路径src/main/java/com/example/campus/controller/NavigationController.java RestController RequestMapping(/api/navigation) RequiredArgsConstructor public class NavigationController { private final BuildingMapper buildingMapper; private final RoadMapper roadMapper; private final PathPlannerService plannerService; PostMapping public RNavigationResult navigate(RequestBody NavigateRequest request) { Building start buildingMapper.selectByName(request.getStartName()); Building end buildingMapper.selectByName(request.getEndName()); if (start null || end null) { return R.fail(找不到对应的建筑请换个名称试试); } ListRoad roads roadMapper.selectList(null); plannerService.buildGraph(roads); ListLong nodeIds plannerService.findShortestPath(start.getId(), end.getId()); if (nodeIds.size() 2) { return R.fail(两条路暂时不连通); } ListBuilding routeBuildings buildingMapper.selectByIds(nodeIds); ListCoordinate coordinates routeBuildings.stream() .map(b - new Coordinate(b.getLongitude(), b.getLatitude())) .collect(Collectors.toList()); NavigationResult result new NavigationResult(); result.setRouteCoordinates(coordinates); result.setDistance(estimateDistance(nodeIds, roads)); return R.ok(result); } }这里estimateDistance就是把路径上每条边的 distance 累加。有了总距离小程序端就能展示“约 X 米步行约 Y 分钟”这一点对用户体验很关键。5.4 AI 服务调用封装AI 服务调用建议单独写一个 Service封装 HTTP 请求和解析逻辑。下面代码以 OpenAI 兼容接口为例请求体包含 model、messages 和 response_format解析时取choices[0].message.content。// 文件路径src/main/java/com/example/campus/service/AiService.java Service public class AiService { Value(${ai.api-key}) private String apiKey; Value(${ai.model}) private String model; Value(${ai.endpoint}) private String endpoint; private final RestTemplate restTemplate new RestTemplate(); public String chat(String systemPrompt, String userMessage) { MapString, Object request new HashMap(); request.put(model, model); ListMapString, String messages new ArrayList(); messages.add(Map.of(role, system, content, systemPrompt)); messages.add(Map.of(role, user, content, userMessage)); request.put(messages, messages); // 部分平台支持 response_format 强制 JSON 输出如果不支持可以去掉该参数 request.put(response_format, Map.of(type, json_object)); HttpHeaders headers new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setBearerAuth(apiKey); HttpEntityMapString, Object entity new HttpEntity(request, headers); MapString, Object response restTemplate.postForObject(endpoint, entity, Map.class); if (response null || response.get(choices) null) { throw new RuntimeException(AI 服务返回异常); } List? choices (List?) response.get(choices); Map?, ? first (Map?, ?) choices.get(0); Map?, ? message (Map?, ?) first.get(message); return String.valueOf(message.get(content)); } }这段代码给的是通用套路实际接入平台时可能有两个小差异一是鉴权头可能是Authorization: Bearer xxx也可能是X-API-KEY: xxx改成平台要求的方式即可二是部分平台不支持response_format把那一行注释掉就行改为在提示词里要求模型输出 JSON。6. 微信小程序端核心代码实现6.1 页面结构与地图组件小程序的页面建议分为三个 Tab地图导航、AI 问路、个人中心。地图页用微信原生的map组件它能渲染 marker 和 polyline满足路径展示需求。核心页面结构大概是这样!-- 文件路径pages/map/map.wxml -- view classpage map idcampusMap lat{{centerLat}} lng{{centerLng}} markers{{markers}} polyline{{routes}} taponMapTap stylewidth: 100%; height: 70vh;/ view classsearch-box input placeholder输入起点 bindinputonStartInput/ input placeholder输入终点 bindinputonEndInput/ button bindtaponNavigate开始导航/button /view /view地图组件加载后先把所有建筑点渲染成 marker。这里要注意踩点坐标要使用 GCJ-02 坐标系。微信小程序的地图组件默认使用 GCJ-02如果你用的是 GPS 原始坐标画上去会偏移几百米这个后面在常见问题里细说。6.2 导航请求与路线渲染用户点“开始导航”后小程序把起点和终点名称发给后端后端返回路线坐标数组小程序再设置 polyline。// 文件路径pages/map/map.js Page({ data: { markers: [], routes: [], startInput: , endInput: }, onLoad() { this.loadBuildings(); }, loadBuildings() { wx.request({ url: http://localhost:8080/api/building/list, method: GET, success: (res) { const list res.data.data || []; const markers list.map(b ({ id: b.id, latitude: b.latitude, longitude: b.longitude, title: b.name, callout: { content: b.name, display: ALWAYS } })); this.setData({ markers }); } }); }, onStartInput(e) { this.setData({ startInput: e.detail.value }); }, onEndInput(e) { this.setData({ endInput: e.detail.value }); }, onNavigate() { const { startInput, endInput } this.data; if (!startInput || !endInput) { wx.showToast({ title: 请填写起终点, icon: none }); return; } wx.request({ url: http://localhost:8080/api/navigation, method: POST, data: { startName: startInput, endName: endInput }, success: (res) { const data res.data.data; if (!data) { wx.showToast({ title: res.data.message || 导航失败, icon: none }); return; } const points data.routeCoordinates.map(p ({ latitude: p.latitude, longitude: p.longitude })); this.setData({ routes: [{ points, color: #007AFF, width: 4 }] }); } }); } });这里有两个开发阶段必须注意的点。第一localhost只能在微信开发者工具里使用而且要在工具右上角“详情-本地设置”中勾选“不校验合法域名”。第二手机真机预览时localhost是手机自己不是电脑所以要把地址改成电脑在局域网里的 IP并且后端要允许跨域或配置 HTTPS。6.3 AI 对话问答逻辑AI 问路页是一个简单的聊天界面用户输入一句话后端解析后既返回文本回答又返回可以直接跳转导航页的起终点参数。// 文件路径pages/ai/ai.js Page({ data: { messages: [], inputText: }, onInput(e) { this.setData({ inputText: e.detail.value }); }, onSend() { const text this.data.inputText.trim(); if (!text) return; this.setData({ messages: [...this.data.messages, { role: user, content: text }], inputText: }); wx.request({ url: http://localhost:8080/api/ai/navigate, method: POST, data: { message: text }, success: (res) { const reply res.data.data; this.setData({ messages: [...this.data.messages, { role: assistant, content: reply.reply || 没听明白换个说法试试 }] }); if (reply.startName reply.endName) { wx.navigateTo({ url: /pages/map/map?start${reply.startName}end${reply.endName} }); } } }); } });这个交互设计顺理成章AI 不只是陪聊而是真真切切帮用户完成了“自然语言 → 结构化导航请求”的转化。7. AI 大模型接入与 Prompt 设计7.1 公有云 API vs 本地部署很多同学纠结一个问题大模型部分到底应该调用公有云 API还是本地部署开源模型。本地部署的优点是数据不出校、不花钱。但缺点更明显需要一台配置不错的电脑7B 以上模型对内存要求很高答辩现场一旦模型加载慢或者显卡温度过高演示体验会大打折扣。更关键的是本地部署的难度主要在于环境配置而不是业务逻辑这对毕设核心内容的贡献并不大。从这套项目来看更建议使用公有云大模型 API。国内主流大模型平台都有免费额度或者很低的调用价格日常测试完全够用。API 接口通常兼容 OpenAI 格式接入成本低效果也比本地小模型稳定。把模型能力和 Prompt 设计作为创新点来讲比讲“我在本地部署了一个模型”更能体现你的工程能力。7.2 Prompt 设计让模型输出结构化结果接入大模型之后最常见的失败是返回内容“不像 JSON”。这不是模型笨而是你给它的指令不够清楚。在设计系统提示词时需要做三件事给出角色定义、给出可用建筑清单、给出输出格式示例。下面是一个可以直接使用的系统 Prompt 示例你是校园导航助手。你可以根据用户的话识别用户想去的地点以及用户的当前位置。 可用地点包括以下建筑第一教学楼、第二教学楼、图书馆、三号食堂、男生宿舍、女生宿舍、行政楼、校医院、打印文印中心、体育馆、东门、西门。 要求 1. 从用户的话中提取起点和终点。 2. 如果用户没有明确说起点默认起点为“当前位置”。 3. 只输出 JSON不要输出任何解释文字。 4. JSON 格式如下 {start: 起点名称或空, end: 终点名称, keyword: 用户提到的地点关键词} 示例 用户说从图书馆到校医院怎么走 输出{start: 图书馆, end: 校医院, keyword: } 用户说我想去打印 输出{start: , end: , keyword: 打印}把这份系统提示词和用户消息一起发给大模型返回内容再交给 JSON 解析工具处理。7.3 输出解析与降级策略大模型输出 JSON 偶尔会带着多余的 markdown 代码块标记比如 json这会导致解析失败。稳妥的做法是先做字符串清理把反引号和多余空格去掉再用ObjectMapper解析。// 文件路径src/main/java/com/example/campus/service/AiService.java 补充片段 public AiParseResult parseNavigateResult(String rawContent) { String json rawContent.trim(); if (json.startsWith()) { json json.replaceAll(json|, ).trim(); } try { ObjectMapper mapper new ObjectMapper(); return mapper.readValue(json, AiParseResult.class); } catch (JsonProcessingException e) { throw new RuntimeException(AI 输出解析失败原始内容 rawContent); } }还有一个更重要的设计降级策略。如果大模型服务超时、限流或者解析失败后端不能直接报错而是应该退回关键词匹配模式。比如把“打印”“复印”“文印”映射到“打印文印中心”把“食堂”“吃饭”“干饭”映射到“三号食堂”。这样一种简单的本地兜底逻辑保证了答辩现场即使 AI 服务暂时不可用导航主流程仍然能跑通。8. 运行验证、常见问题与排查方法8.1 后端启动与接口验证后端启动很简单在项目根目录执行mvn spring-boot:run启动成功后控制台会打印端口号。先不要急着接小程序先验证接口是否正常。建议导入一个接口测试工具或直接使用 curlcurl -X POST http://localhost:8080/api/navigation \ -H Content-Type: application/json \ -d {startName:图书馆,endName:校医院}如果返回结果包含 routeCoordinates 数组说明数据库连接、路径规划、接口返回三个环节都已经打通。如果第一次请求就报错先把application.yml里的 MySQL 密码和数据库名检查一遍再看控制台有没有打印 SQL 异常。8.2 小程序端运行验证用微信开发者工具导入小程序项目修改app.js里的后端地址为http://localhost:8080。注意在“详情-本地设置”里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”否则wx.request会被拦截。打开地图页如果 markers 显示出来说明后端接口通了。输入“第一教学楼”到“图书馆”点击导航如果能画出一条蓝色路线核心流程就完成了。再打开 AI 问路页输入“从图书馆到校医院怎么走”看它能不能识别并跳转地图页。8.3 常见问题与排查方法问题现象可能原因排查方式解决方案小程序请求后端失败未勾选“不校验合法域名”打开调试器的 Network 面板开发阶段勾选该项生产环境配置备案的 HTTPS 域名真机预览请求失败手机访问不到电脑的 localhost查看真机控制台错误把后端地址改成电脑局域网 IP地图 marker 位置偏移坐标系不一致对比经纬度与地图底图统一使用 GCJ-02 坐标或对 GPS 坐标做转换AI 返回内容解析失败大模型输出携带 markdown 或换行打印原始 content 日志清理反引号后解析并增加本地关键词降级路径规划穿墙穿楼路网图把所有建筑直接相连打印路径节点检查路网数据重新整理路网增加路口和拐角节点大模型接口超时网络波动或 Prompt 过长查看后端日志的耗时设置连接超时时间简化 Prompt必要时异步处理登录获取不到 openidAppID 或密钥配置错误打印后端请求微信接口的日志使用小程序测试号核对 AppSecret9. 最佳实践与答辩加分建议9.1 工程规范与安全建议这套系统虽然是一个毕设项目但代码规范会直接影响答辩印象分更会影响你后续找工作时的项目展示。接口路径建议规范成/api/模块/动作例如/api/navigation、/api/ai/chat。参数校验不能省起终点名称为空时直接返回提示而不是等数据库查不到才报错。日志至少打印请求和响应摘要方便排查问题。安全方面最需要注意的是AI API Key 的保密。Key 只能放在后端配置文件或环境变量里绝对不要写在小程序代码中。最佳实践是后端对 AI 接口调用做频率限制和内容长度限制比如每个用户每分钟最多调 10 次单次问题不超过 200 字避免 Key 被薅羊毛。数据库操作也要注意删除或更新操作必须带条件更不要在生产环境裸执行DELETE FROM这类语句。本地测试环境也需要给 MySQL 设置好密码策略这是基本的工程素养。9.2 答辩讲解思路答辩的时候建议按“场景 → 架构 → 算法 → AI 设计 → 验证”这条线来讲。开场先演示 AI 问路用户输入“从图书馆到校医院怎么走”系统自动识别起终点地图画出路线并显示距离和预计步行时间。演示结束后评委一定会对这个流程感兴趣接下来你就可以自然展开。架构部分重点讲四层链路小程序端负责交互SpringBoot 负责业务逻辑MySQL 负责数据AI 服务负责自然语言理解。算法部分重点讲 Dijkstra 的实现思路说明为什么选择它而不是 A*以及你是如何处理路网数据的。这里如果能画一张简单的路网图来解释效果会更好。AI 部分重点讲 Prompt 设计和降级策略。说明模型输出的不稳定点在哪里你用什么方式兜底。这种“知道哪里会出问题并且做了预案”的表达比空口说“我用了大模型”要有说服力得多。9.3 后续扩展方向如果学有余力可以考虑这些扩展点。第一把路网数据从数据库搬到 JSON 文件或图数据库中体现你对数据存储方案的理解。第二增加“当前人流量”“上课时间避开拥堵路段”这类动态权重让路径规划从“最短路径”升级成“最优路径”。第三对接语音转文字能力做成真正的语音问路助手。第四在 AI 回答中引用校园公告或建筑开放时间数据让助手能回答“图书馆几点关门”这类问题。不过扩展要建立在核心流程稳定运行的基础上。毕业设计最重要的是把一条链路做深做透而不是十个功能全部浅尝辄止。建议你把本文的核心代码先跑通一遍再逐步替换成自己的校园数据、自己的 Prompt 和自己的想法。等到你能清楚地解释每个模块为什么这样设计而不是照着源码背下来的时候这个项目才算真正变成你自己的东西。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门