尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Java+MVC天气预报穿衣搭配APP毕业设计:架构、算法与避坑指南

发布时间:2026/9/26 4:30:42

资讯中心
01
ARTICLE

Java+MVC天气预报穿衣搭配APP毕业设计:架构、算法与避坑指南

Java+MVC天气预报穿衣搭配APP毕业设计:架构、算法与避坑指南
简介这是一套面向高校计算机相关专业毕业设计的完整项目源码基于Java与MVC三层架构开发同时包含PC端与安卓Android手机客户端适合需要完成天气类或生活服务类毕设的学生参考与二次开发。项目以天气预报为核心管理员可在服务器端发布各地区天气与穿衣搭配公告用户查询所在地区气温变化并获取搭配建议客户端还支持虚拟人物风格展示。压缩包共424个文件约2.73MB其中93个java源文件承载业务逻辑86个xml与31个jsp构成界面与配置另有gif、png、jpg等图片素材及sql数据库脚本、class编译文件结构完整便于导入MyEclipse、Eclipse、Idea或Android Studio运行。目前已有265人学习下载读者可获得从数据库设计、实体建模到客户端通信的完整赛题方案并借助分层代码理解MVC思想与XML、JSON数据交互方式快速搭建可演示的毕设系统。1. 从一份毕业设计说起JavaMVC 的天气预报穿衣搭配 APP 到底在做什么每年毕业季计算机专业的选题里总有一类特别受欢迎——既有真实数据来源又能做出看得见的界面还能把 Java 后端、Android 客户端、数据库设计串成一条完整链路。天气预报穿衣搭配 APP 就是这类选题的典型代表。它的核心逻辑并不复杂拉取天气数据根据温度、湿度、风力、天气状况等参数结合一套穿衣建议规则给用户推荐今天穿什么。但真正动手做的时候你会发现从天气 API 选型、MVC 三层架构拆分、PC 端和 Android 端的数据同步到 Android Studio 里的网络请求适配每一步都有具体的坑。这个方案适合正在准备毕业设计的学生也适合想用 Java 技术栈练手一个完整前后端项目的开发者。PC 端可以用 Java Swing 或 JavaFX 做桌面应用Android 端用原生 Android SDK 配合 Retrofit 或 OkHttp 请求后端接口后端用 Spring MVC 或 ServletJSP 搭建 RESTful 服务数据库用 MySQL 存储用户信息和穿衣规则。整套技术栈都是 Java 生态里最成熟、资料最多的组合遇到问题容易搜到答案。下面我会按实际开发顺序把架构设计、天气数据接入、穿衣推荐算法、Android 端实现和调试排错逐一讲清楚。2. 架构选型与 MVC 三层拆分为什么不用 Spring Boot 一把梭2.1 毕业设计场景下的技术栈取舍很多同学一上来就想用 Spring Boot Vue 微服务结果光环境配置就耗掉两周核心功能反而没时间做。毕业设计的评判标准是功能完整、代码规范、架构清晰不是技术栈有多新。JavaMVC 这个组合的好处是Servlet 容器Tomcat直接跑不需要额外学 Spring Boot 的自动配置原理MVC 三层架构Model-View-Controller是教科书级别的设计模式答辩时老师一听就懂PC 端和 Android 端共用同一套后端接口工作量可控。具体选型建议层次技术选择理由后端框架Spring MVC 或 ServletJSP轻量配置透明适合展示 MVC 理解数据库MySQL 5.7/8.0免费资料多JDBC 连接稳定数据访问JDBC DAO 模式 或 MyBatisJDBC 更能体现底层理解MyBatis 更省代码PC 端Java Swing / JavaFX纯 Java无需额外前端技术栈Android 端原生 Android SDK OkHttp直接调 REST API逻辑清晰天气数据和风天气 / 高德天气 API免费额度够用返回 JSON 格式规范JSON 解析Gson / FastJsonGson 与 Android 兼容性最好如果你的学校要求必须用 SSHStrutsSpringHibernate那就按学校要求来但核心的 MVC 分层思想是一样的。我一般会建议学生先用 ServletJSP 把流程跑通再决定要不要换成 Spring MVC这样至少有一个能跑的版本保底。2.2 MVC 三层在项目里的具体落地MVC 不是三个文件夹那么简单关键是职责边界要清晰。以「查询某城市今天天气并返回穿衣建议」这个功能为例Model模型层封装 Weather 实体类城市、温度、湿度、风力、天气状况和 ClothingAdvice 实体类上衣建议、下装建议、外套建议、 accessories。同时包含 DAO 类负责从 MySQL 读取穿衣规则表以及从天气 API 获取数据后的解析逻辑。View视图层PC 端是 Swing 的 JFrame 面板Android 端是 Activity 的 XML 布局。视图层只负责展示数据不包含任何业务判断。Controller控制层接收前端请求调用 Service 层获取天气数据和穿衣建议再把结果返回给 View。Controller 里不写 SQL也不写穿衣规则的具体判断。后端目录结构可以这样组织src/ ├── com.weather.model/ # 实体类 │ ├── Weather.java │ └── ClothingAdvice.java ├── com.weather.dao/ # 数据访问 │ ├── WeatherDao.java │ └── ClothingRuleDao.java ├── com.weather.service/ # 业务逻辑 │ ├── WeatherService.java │ └── ClothingService.java ├── com.weather.controller/ # 控制层 │ └── WeatherServlet.java └── com.weather.util/ # 工具类 ├── DBUtil.java └── HttpUtil.javaAndroid 端的目录结构对应为app/src/main/java/com/weather/app/ ├── model/ # 与后端对应的实体类 ├── network/ # OkHttp 请求封装 ├── ui/ # Activity 和 Adapter └── util/ # 工具类注意实体类在 PC 端、Android 端、后端三处都要有一份字段名保持一致否则 JSON 解析时会丢字段。建议用 Gson 的 SerializedName 注解做映射避免因为命名风格不一致导致解析失败。2.3 数据库表设计的最小可用集毕业设计不需要几十张表三张核心表就能撑起整个系统-- 用户表 CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, default_city VARCHAR(50) DEFAULT 北京, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 穿衣规则表 CREATE TABLE clothing_rule ( id INT PRIMARY KEY AUTO_INCREMENT, min_temp INT NOT NULL, max_temp INT NOT NULL, weather_condition VARCHAR(50), tops_advice VARCHAR(200), bottoms_advice VARCHAR(200), outerwear_advice VARCHAR(200), accessories_advice VARCHAR(200) ); -- 查询历史表 CREATE TABLE query_history ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT, city VARCHAR(50), query_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, weather_json TEXT, FOREIGN KEY (user_id) REFERENCES user(id) );穿衣规则表的数据可以预先插入十几条覆盖常见温度区间比如 28°C 以上推荐短袖短裤15-27°C 推荐长袖薄外套5-14°C 推荐毛衣加风衣5°C 以下推荐羽绒服加保暖内衣。weather_condition 字段用来处理特殊情况比如下雨天要加雨具建议下雪天要加防滑提醒。3. 天气数据接入与穿衣推荐算法从 API 返回到可读建议3.1 天气 API 的选型与请求封装国内可用的免费天气 API 里和风天气和高德天气是毕业设计最常用的两个。和风天气的免费版每天有 1000 次调用额度返回字段包括温度、体感温度、湿度、风向、风力、天气状况码等足够支撑穿衣推荐。高德天气的优势是定位和城市搜索接口更完善但天气字段相对少一些。以和风天气为例请求 URL 格式如下https://devapi.qweather.com/v7/weather/now?location101010100key你的KEY其中 location 是城市 ID需要先通过城市查询接口获取。返回的 JSON 结构里now 对象包含 temp温度、feelsLike体感温度、humidity湿度、windScale风力等级、text天气状况文字等字段。后端封装 HTTP 请求的工具类public class HttpUtil { public static String doGet(String url) throws IOException { OkHttpClient client new OkHttpClient(); Request request new Request.Builder() .url(url) .build(); try (Response response client.newCall(request).execute()) { if (response.body() ! null) { return response.body().string(); } return ; } } }这段代码用 OkHttp 发起同步 GET 请求返回响应体字符串。参数说明url 是完整的请求地址包含 API Key 和城市 ID。实际使用时建议把 API Key 放在配置文件里不要硬编码在 Java 源码中否则提交代码时会泄露。Android 端同样可以用 OkHttp但要注意网络请求必须放在子线程否则会抛 NetworkOnMainThreadException。3.2 穿衣推荐算法的规则引擎设计穿衣推荐的核心是一个基于温度区间和天气状况的规则匹配。最简单的实现方式是查表法根据当前温度落在哪个区间从 clothing_rule 表里查对应的建议。但实际体验要好还需要叠加几个修正因子体感温度优先如果体感温度和实际温度差超过 3°C以体感温度为准。比如夏天湿度高时体感温度会明显高于实际温度。风力修正风力达到 4 级以上时建议增加防风外套。天气状况修正下雨天增加雨具提醒下雪天增加防滑鞋建议雾霾天增加口罩提醒。时段修正早晚温差大的季节建议采用洋葱式穿法方便增减。后端 Service 层的核心逻辑public ClothingAdvice getAdvice(Weather weather) { // 优先使用体感温度 int temp weather.getFeelsLike() ! 0 ? weather.getFeelsLike() : weather.getTemp(); // 查询基础规则 ClothingRule rule clothingRuleDao.findByTemp(temp); if (rule null) { return new ClothingAdvice(暂无建议, 暂无建议, 暂无建议, ); } String outerwear rule.getOuterwearAdvice(); String accessories rule.getAccessoriesAdvice(); // 风力修正 if (weather.getWindScale() 4) { outerwear 建议加一件防风外套; } // 天气状况修正 String condition weather.getText(); if (condition.contains(雨)) { accessories 记得带伞; } else if (condition.contains(雪)) { accessories 注意穿防滑鞋; } else if (condition.contains(雾) || condition.contains(霾)) { accessories 建议戴口罩; } return new ClothingAdvice( rule.getTopsAdvice(), rule.getBottomsAdvice(), outerwear, accessories ); }这段代码的逻辑是先取体感温度如果没有则用实际温度然后从数据库查基础规则再根据风力和天气状况做二次修正。参数说明weather 对象由天气 API 解析而来clothingRuleDao 是 DAO 层实例。注意 findByTemp 方法的 SQL 要处理边界情况比如温度正好等于区间端点时应该归入较暖的那个区间避免出现“无匹配规则”的情况。3.3 后端接口设计与 JSON 返回格式PC 端和 Android 端共用同一套接口所以返回格式要统一。建议用如下 JSON 结构{ code: 200, message: success, data: { city: 北京, temp: 22, feelsLike: 24, humidity: 45, windScale: 3, condition: 晴, advice: { tops: 长袖T恤或薄衬衫, bottoms: 牛仔裤或休闲裤, outerwear: 薄外套, accessories: 无需特殊配件 } } }Controller 层用 Servlet 实现时注意设置响应头和编码WebServlet(/api/weather) public class WeatherServlet extends HttpServlet { private WeatherService weatherService new WeatherService(); Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType(application/json;charsetUTF-8); String city req.getParameter(city); if (city null || city.isEmpty()) { city 北京; } Weather weather weatherService.getWeather(city); ClothingAdvice advice weatherService.getAdvice(weather); MapString, Object result new HashMap(); result.put(code, 200); result.put(message, success); MapString, Object data new HashMap(); data.put(city, city); data.put(temp, weather.getTemp()); data.put(feelsLike, weather.getFeelsLike()); data.put(humidity, weather.getHumidity()); data.put(windScale, weather.getWindScale()); data.put(condition, weather.getText()); data.put(advice, advice); result.put(data, data); resp.getWriter().write(new Gson().toJson(result)); } }这段 Servlet 代码处理 GET 请求接收 city 参数调用 Service 层获取天气和穿衣建议最后用 Gson 序列化为 JSON 返回。参数说明city 为空时默认北京实际项目中应该从用户表读取默认城市。注意 Gson 序列化 Map 时如果 value 是自定义对象需要确保该对象的字段有 getter 方法否则会序列化为空对象。4. Android 端与 PC 端的实现差异网络、线程与界面适配4.1 Android 端网络请求与权限配置Android 端和 PC 端最大的差异在于网络请求必须处理线程切换和权限声明。在 AndroidManifest.xml 中需要添加uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE /如果 targetSdkVersion 在 28 以上还需要在 application 标签中设置android:usesCleartextTraffictrue否则 HTTP 请求会被系统拦截。虽然现在推荐用 HTTPS但毕业设计阶段如果后端部署在本地 Tomcat 上可能只有 HTTP这个配置能省去很多调试时间。Android 端用 OkHttp 请求后端接口的封装public class WeatherApi { private static final String BASE_URL http://你的服务器IP:8080/weather/api/weather; private final OkHttpClient client new OkHttpClient(); public void getWeather(String city, Callback callback) { HttpUrl url HttpUrl.parse(BASE_URL) .newBuilder() .addQueryParameter(city, city) .build(); Request request new Request.Builder() .url(url) .build(); client.newCall(request).enqueue(new okhttp3.Callback() { Override public void onFailure(Call call, IOException e) { callback.onFailure(e.getMessage()); } Override public void onResponse(Call call, Response response) throws IOException { if (response.body() ! null) { String json response.body().string(); // 在主线程更新 UI new Handler(Looper.getMainLooper()).post(() - { callback.onSuccess(json); }); } } }); } public interface Callback { void onSuccess(String json); void onFailure(String error); } }这段代码用 OkHttp 的 enqueue 方法发起异步请求避免阻塞主线程。参数说明BASE_URL 需要替换成实际服务器地址如果是本地测试Android 模拟器访问宿主机要用 10.0.2.2 而不是 localhost。onResponse 回调在子线程执行更新 UI 必须通过 Handler 切回主线程否则会崩溃。4.2 PC 端 Swing 界面的数据绑定PC 端用 Swing 做界面时网络请求可以放在 SwingWorker 里执行避免界面卡死。核心代码结构public class WeatherPanel extends JPanel { private JLabel cityLabel, tempLabel, adviceLabel; private JButton queryButton; private JTextField cityField; public WeatherPanel() { setLayout(new BorderLayout()); JPanel topPanel new JPanel(); cityField new JTextField(10); queryButton new JButton(查询); topPanel.add(new JLabel(城市)); topPanel.add(cityField); topPanel.add(queryButton); JPanel centerPanel new JPanel(new GridLayout(3, 1)); cityLabel new JLabel(城市--); tempLabel new JLabel(温度--); adviceLabel new JLabel(建议--); centerPanel.add(cityLabel); centerPanel.add(tempLabel); centerPanel.add(adviceLabel); add(topPanel, BorderLayout.NORTH); add(centerPanel, BorderLayout.CENTER); queryButton.addActionListener(e - queryWeather()); } private void queryWeather() { String city cityField.getText().trim(); if (city.isEmpty()) { JOptionPane.showMessageDialog(this, 请输入城市名); return; } new SwingWorkerString, Void() { Override protected String doInBackground() throws Exception { return HttpUtil.doGet(http://localhost:8080/weather/api/weather?city city); } Override protected void done() { try { String json get(); // 解析 JSON 并更新界面 updateUI(json); } catch (Exception ex) { JOptionPane.showMessageDialog(WeatherPanel.this, 查询失败 ex.getMessage()); } } }.execute(); } }这段代码用 SwingWorker 把网络请求放到后台线程done 方法在主线程执行可以安全更新界面。参数说明cityField 接收用户输入的城市名queryButton 绑定查询事件。注意 PC 端访问本机 Tomcat 用 localhost 即可但如果 Tomcat 和 PC 端不在同一台机器需要改成实际 IP。4.3 两端数据同步与缓存策略PC 端和 Android 端共用后端接口数据一致性由后端保证。但移动端网络不稳定建议加一层本地缓存用 SharedPreferences 存储最近一次查询结果下次打开 APP 时先展示缓存数据再发起网络请求更新。这样即使网络不好用户也能看到上次的穿衣建议。缓存逻辑可以这样实现// 保存缓存 SharedPreferences sp getSharedPreferences(weather_cache, MODE_PRIVATE); sp.edit().putString(last_weather, json).apply(); // 读取缓存 String cached sp.getString(last_weather, ); if (!cached.isEmpty()) { updateUI(cached); // 先展示缓存 } // 再发起网络请求 api.getWeather(city, callback);注意缓存不要设置太长的过期时间天气数据变化快建议缓存有效期设为 30 分钟。可以在保存时同时存一个时间戳读取时判断是否过期。5. 避坑与排查那些让毕业设计卡壳的典型问题5.1 中文乱码从 Tomcat 到 Android 的全链路排查现象PC 端查询返回的 JSON 里中文显示为问号或乱码Android 端同样。原因Tomcat 默认编码、Servlet 响应编码、JDBC 连接编码、Android 端解析编码四个环节任何一个不一致都会导致乱码。解决Tomcat 的 server.xml 中 Connector 标签加 URIEncodingUTF-8Servlet 里 resp.setContentType(application/json;charsetUTF-8)JDBC URL 加 useUnicodetruecharacterEncodingUTF-8Android 端 OkHttp 读取响应时用 response.body().string() 默认按 UTF-8 解析一般不需要额外设置。四个地方都确认一遍基本能解决。5.2 Android 9.0 以上 HTTP 请求被拦截现象Android 模拟器或真机上请求后端接口直接走 onFailure报错 Cleartext HTTP traffic not permitted。原因Android 9.0API 28开始默认禁止明文 HTTP 请求。解决在 AndroidManifest.xml 的 application 标签加 android:usesCleartextTraffictrue。如果后端已经上了 HTTPS则不需要这个配置。毕业设计阶段后端通常部署在本地加这个配置最快。5.3 天气 API 返回城市 ID 不匹配现象请求天气接口返回 404 或 city not found。原因和风天气的城市 ID 是固定的数字编码不是城市名。直接传“北京”会失败需要先调城市查询接口获取 location ID。解决先请求https://geoapi.qweather.com/v2/city/lookup?location北京key你的KEY从返回结果里取 id 字段再用这个 id 请求天气接口。建议把常用城市的 ID 缓存在本地数据库或配置文件里减少 API 调用次数。5.4 穿衣规则表温度区间不连续现象某些温度下查询不到穿衣建议返回“暂无建议”。原因clothing_rule 表的 min_temp 和 max_temp 区间没有覆盖所有温度比如 14°C 到 15°C 之间有空隙。解决设计规则时确保区间连续后一个区间的 min_temp 等于前一个区间的 max_temp。查询 SQL 用WHERE min_temp ? AND max_temp ?注意边界用 而不是 避免端点重复匹配。插入数据后手动检查一遍所有区间是否无缝衔接。5.5 PC 端打包后连接不上数据库现象在 IDE 里运行正常打成 JAR 包后双击运行报数据库连接失败。原因IDE 里 MySQL 驱动 JAR 在 classpath 中打包时没有把驱动打进去或者数据库连接 URL 写的是 localhost 但目标机器上没有 MySQL。解决用 Maven 的 assembly 插件或 shade 插件把依赖一起打包数据库连接信息写到外部配置文件里打包后可以修改。如果答辩时是在自己电脑上演示确保 MySQL 服务已启动并且用户名密码正确。6. 让穿衣建议更准一步体感温度加权与用户反馈微调基础版的穿衣推荐只用了温度区间查表实际体验中会发现同一个温度下不同湿度、不同风力给人的感觉差别很大。我在做这类项目时习惯加一层体感温度加权计算让建议更贴近真实感受。体感温度的计算可以参考澳大利亚体感温度公式AT它同时考虑温度和湿度public static double calculateApparentTemp(double temp, double humidity) { // 简化版体感温度公式适用于温度 20-50°C 的场景 double e (humidity / 100.0) * 6.105 * Math.exp(17.27 * temp / (237.7 temp)); return temp 0.348 * e - 0.70 * (windSpeed) - 4.25; }参数说明temp 是实际温度摄氏度humidity 是相对湿度百分比windSpeed 是风速米/秒。这个公式在高温高湿场景下会算出比实际温度更高的体感温度此时穿衣建议应该更偏向清凉。低温场景下可以用风寒指数公式替代。实际使用时可以把计算结果和 API 返回的 feelsLike 字段做对比取两者中更极端的一个作为推荐依据。另一个提升准确度的方式是加用户反馈。在 Android 端加一个简单的“建议是否合适”按钮用户点击“偏冷”或“偏热”后把当前温度、湿度和反馈结果存到数据库。积累几十条数据后可以在规则表里对特定温度区间做微调比如把 20-24°C 区间的外套建议从“薄外套”改成“可选外套”。这个功能不需要机器学习纯 SQL 统计就能做但能让答辩时的演示效果提升一个档次。验证方法也很直接找五个同学让他们在早上出门前用你的 APP 查一次建议晚上回来反馈当天穿着是否合适。收集一周数据统计“合适”的比例。如果低于 70%就检查是温度区间划分太粗还是修正因子权重不对。我自己的经验是把温度区间从 10°C 一档细化到 5°C 一档合适率能提升 15% 左右。希望这些经验能帮到你少走一些我当年踩过的弯路。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。