ARTICLE DETAIL

资讯详情

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

基于SSM+MySQL的作物生长监控系统开发实战与日志排查

基于SSM+MySQL的作物生长监控系统开发实战与日志排查 简介基于JavaSSM与MySQL开发的Web作物生长监控系统面向计算机相关专业课程设计与毕业设计人群可用于理解SSM框架整合、数据采集与Web端可视化展示的完整流程。系统在调研基础上构建包含硬件温湿度采集配合软件侧实现实时推送、站点地图、农业新闻爬取、数据查询、温湿度分析、角色权限管理及站点创建等模块。资源包大小86.02MB共564个文件涵盖Java源码及class编译文件、JSP/HTML/CSS/JS前端页面、Spring/MyBatis相关XML配置、SQL脚本、JAR依赖库、日志与war部署包等便于对照源码、数据库脚本和部署文件进行本地复现与二次开发。压缩包内还包含多份日志文件与项目说明文档可辅助排查运行环境问题。已有127人学习对需要快速搭建作物监控类项目并完成SSM实践的同学具有较高参考价值。1. 作物生长监控系统一套把 SSM 全家桶串起来的课程设计收到一套“基于 Java(SSM)MySQL 的 Web 作物生长监控系统”的项目资源压缩包里除了源码之外还有一串 log.log 和 error.log 的日志文件以及一个编译好的 DataAnalysisServiceImpl.class。这套资源本质上是某个毕业设计的完整工程硬件部分使用现成的多点温湿度采集设备软件部分用 SpringMVC Spring MyBatis 整合 MySQL实现了从数据采集、实时展示到农业新闻抓取和权限管理的完整闭环。对正在做 Java Web 课程设计、或者想在一周内拼出一套能演示的 SSM 项目的同学来说这个资源的价值在于功能模块齐全、前端页面齐整、日志规范值得抄。我的切入点是把它当作一个“可复现课设”来拆——不讨论硬件怎么接线只讲拿到工程之后怎么把环境跑起来、核心模块的代码逻辑落在哪里、改哪些参数能让演示效果更好以及最常见的五个翻车点怎么排查。2. 先把 SSM 工程立起来Maven 结构、数据库脚本与三层分包怎么对得上2.1 工程目录与配置文件的位置拿到源码后第一件事不是看代码而是看工程结构。这个资源用的是 SSM 标准布局源码根目录下应该能看到 pom.xml 或者 lib 目录src/main/java 下面是 com 开头的包名resources 目录里有 spring 配置文件、mybatis 配置和 log4j 日志配置。如果你之前只做过 Servlet 或 Spring Boot 项目这里要适应一件事情SSM 没有自动配置每个 bean 都要在 XML 里声明或通过注解扫描注册。我习惯先把 resources 下的三个核心文件找全一个是 Spring 的 applicationContext.xml管 Service、Mapper、数据源一个是 spring-mvc.xml管 Controller、视图解析器、静态资源放行还有一个是 mybatis-config.xml管别名、驼峰映射。这三个文件只要有一个路径配错Tomcat 启动时要么直接报 ClassNotFoundException要么启动成功后访问页面 404 一片白。!-- applicationContext.xml 关键片段 -- context:component-scan base-packagecom.crop.system.service / bean iddataSource classcom.alibaba.druid.pool.DruidDataSource property namedriverClassName valuecom.mysql.jdbc.Driver / property nameurl valuejdbc:mysql://localhost:3306/crop_monitor?useUnicodetrueamp;characterEncodingutf8 / property nameusername valueroot / property namepassword valueroot / /bean bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource / property namemapperLocations valueclasspath:mapper/*.xml / /bean bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.crop.system.dao / /bean这段配置里数据源用的是 Druid本资源没有强制指定连接池但 SSM 课设里 Druid 是主流选择因为它自带监控页面出问题时可以看到 SQL 执行数和慢查询记录。url 里的 characterEncodingutf8 必须带上否则后面所有中文查询都会乱码。mapperLocations 指向 classpath:mapper/*.xml也就是说你的 MyBatis 映射文件要放在 resources/mapper 目录下而不是和 dao 接口混在 java 包里。2.2 数据库初始化与表结构设计初始化脚本一般放在 sql 目录或者源码根的 db 文件夹里如果有 .sql 文件直接用 Navicat 导入即可。核心表大概会有这么几张sys_user用户表、crop_site站点表记录大棚或田块位置、crop_data温湿度采集记录表、crop_news农业新闻表、sys_role角色表。站点与采集数据之间是一对多关系用户与角色之间是多对多关系通过中间表关联。CREATE TABLE crop_data ( id INT(11) NOT NULL AUTO_INCREMENT, site_id INT(11) NOT NULL COMMENT 站点编号, temperature DECIMAL(5,2) DEFAULT NULL COMMENT 温度, humidity DECIMAL(5,2) DEFAULT NULL COMMENT 湿度, collect_time DATETIME DEFAULT NULL COMMENT 采集时间, PRIMARY KEY (id), KEY idx_site_time (site_id, collect_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT温湿度采集记录表;注意 collect_time 这个字段的索引设计——后面做数据分析和曲线图展示时所有 SQL 都会按 site_id collect_time 来查如果没有这个联合索引数据量过万之后前端页面的响应速度会明显变慢。如果你拿到的脚本里没建这个索引建议自己补上。主键用 AUTO_INCREMENT 而不是雪花 ID因为这是课设没有必要把简单问题复杂化。2.3 三层分包与代码运行顺序SSM 项目的分包是有规律的你可以照着这个规律快速定位资源里每个类的职责。controller 包是入口接收前端请求返回 ModelAndView 或 JSONservice 包写业务逻辑dao 包里放 MyBatis 的 Mapper 接口对应的 XML 在 resources/mapper 下。实体类放在 pojo 或 entity 包本质上就是数据库表映射的 Java 对象。启动顺序上也有一条固定的路先启动 MySQL 并导入脚本再改 Spring 配置文件里的数据库账号密码然后用 Tomcat 7 或 8 启动项目这里不建议用 Tomcat 10因为 Jakarta 命名空间和 javax 不兼容课设项目基本全是 javax.servlet。启动成功后先访问登录页再进主页看温湿度数据是否有值。如果你的环境是 JDK 8 Tomcat 8 MySQL 5.7按这个顺序走一遍大多数情况能直接跑通。3. 核心业务落地的三条线站点与数据、查询与权限的数据库到底怎么串3.1 站点管理模块ly 创建与地图展示的数据来源站点管理是本系统硬件和软件的连接点。每一个温室大棚对应一个 site 记录site 里除了名称和位置描述还有经纬度字段这个字段是给地图展示模块用的。站点创建删除的前端页面背后就是一张 crop_site 表的增删改查算上分页和表单校验。RequestMapping(/site/add) ResponseBody public Result addSite(CropSite site) { if (site.getSiteName() null || site.getSiteName().trim().isEmpty()) { return Result.error(站点名称不能为空); } if (site.getLongitude() null || site.getLatitude() null) { return Result.error(经纬度不能为空请先在地图上选点); } siteService.addSite(site); return Result.success(); }前端地图选点之后把经纬度回填到隐藏域提交到 /site/add。ResponseBody 注解在这里很关键——如果不加SpringMVC 会把返回值当成视图名去解析结果就是返回 JSON 变成 404。Result 是统一的返回包装类包含 code、msg、data 三个字段课设里这样写在答辩时很讨喜因为评委能一眼看出你对前后端分离有概念。数据库层面有一个经常被忽略的细节站点表尽量加一个 deleted 字段做逻辑删除而不是物理 DELETE。因为这个资源里 crop_data 表有外键关系物理删站点会把历史数据也带走演示时你反悔了都找不回来。3.2 温湿度查询与数据分析DataAnalysisServiceImpl 到底做了什么资源的项目正文里出现了 DataAnalysisServiceImpl.class这是温湿度数据分析模块的编译产物也是整个系统里技术含量最高的一处。它的职责是按站点、按时间范围天/周/月对 crop_data 表做聚合统计计算平均温湿度、最高最低值并输出给前端绘制折线图。SELECT DATE_FORMAT(collect_time, %Y-%m-%d) AS day, ROUND(AVG(temperature), 2) AS avg_temp, ROUND(AVG(humidity), 2) AS avg_hum, MAX(temperature) AS max_temp, MIN(temperature) AS min_temp FROM crop_data WHERE site_id #{siteId} AND collect_time BETWEEN #{startTime} AND #{endTime} GROUP BY DATE_FORMAT(collect_time, %Y-%m-%d) ORDER BY day聚合功能的实现方式通常是 MyBatis 的 XML 文件里写动态 SQLservice 层调用 mapper 接口拿到 List 再封装成图表数据。这里的难点在于时间格式化的粒度——如果前端展示的是 24 小时曲线SQL 里就得用 DATE_FORMAT 按小时分组如果按周聚合就要用 YEARWEEK(collect_time, 1)。不同粒度对应不同 SQL不要试图用一个接口同时满足全部需求最稳的做法是在 Service 层通过参数 switch 判断粒度再分别调用不同 SQL 或拼接条件。3.3 角色权限控制拦截器与 Session 的用户状态管理权限模块在 SSM 里最常见的是用 SpringMVC 拦截器实现。定义一个 HandlerInterceptor在 preHandle 方法里检查 Session 中是否有已登录用户再进行角色判断admin 角色可以访问站点管理接口普通用户只能看数据页面。public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); SysUser user (SysUser) session.getAttribute(loginUser); if (user null) { response.sendRedirect(request.getContextPath() /login); return false; } // 角色校验admin 角色才允许写操作 if (!admin.equals(user.getRole().getRoleCode())) { response.sendRedirect(request.getContextPath() /unauthorized); return false; } return true; } }拦截器要在 spring-mvc.xml 里注册并且要把登录接口本身 exclude 掉否则会造成死循环。这里有一个非常经典的课设坑只拦截了 Controller 层 URL但静态资源 css、js 也被拦截了导致登录页样式全丢。所以拦截路径里一定要排除 /static/** 和 /login/**。4. 实时推送与新闻爬虫SSM 里不写 WebSocket用轮询也能做出实时感4.1 实时温湿度数据推送的前端轮询方案作物监控这类系统页面上几乎都会有一块区域展示“当前温度 25.3℃湿度 68%”这种实时数据。很多第一次做课设的人会直接上 WebSocket但 SSM 项目里配置 WebSocket 拦截器、握手处理器、消息代理要写一坨代码弊大于利。实际这个资源最可能采用的方案是前端定时轮询——每隔 3 秒发一次 Ajax 请求后端查最新一条采集记录返回 JSON。function fetchLatestData() { $.ajax({ url: /data/latest, method: GET, data: { siteId: 1 }, dataType: json, success: function (res) { if (res.code 200) { $(#temp).text(res.data.temperature ℃); $(#hum).text(res.data.humidity %); } } }); } setInterval(fetchLatestData, 3000);从浏览器向 /data/latest 发请求后端只需一条 SQL 就能返回性能压力很小。轮询间隔没有固定标准我一般在演示环境用 3 秒生产用 10 秒避免把后端接口打崩。前端定时器注意一个问题setInterval 不会考虑请求耗时如果请求因网络慢超过 3 秒浏览器会堆积并发请求。常见改进是 setTimeout 嵌套请求完成后再启动下一次定时。4.2 HTTP 协议爬取农业新闻的实现与编码处理新闻爬虫模块用的是 HttpClient 发出 GET 请求拿到 HTML 后由 Jsoup 解析提取标题、发布时间、摘要和原文链接再存入 crop_news 表。这段代码比较适合作为答辩亮点因为它涉及第三方库的使用和数据清洗。String url https://www.example-agri.com/news; CloseableHttpClient client HttpClients.createDefault(); HttpGet get new HttpGet(url); get.setHeader(User-Agent, Mozilla/5.0 (Windows NT 10.0; Win64; x64)); CloseableHttpResponse response client.execute(get); String html EntityUtils.toString(response.getEntity(), utf-8); Document doc Jsoup.parse(html); Elements items doc.select(div.news-item h2 a); for (Element item : items) { String title item.text(); String link item.attr(abs:href); // 去重逻辑按 link 或 title 判断是否已存在 newsService.saveIfNotExist(title, link); }编码处理是爬虫模块最大的坑。很多农业新闻网站都是 GBK 编码EntityUtils.toString 时如果写死 utf-8轻则标题乱码重则 Jsoup 解析直接按乱码文本处理。我一般会先取响应头的 Content-Type 判断charset拿不到就用 Jsoup 的 doc.charset() 读取 HTML 里 meta 标签声明的编码。另外一个细节是设置 Connection timeout不然某次爬取目标站响应超时整个 request 处理会卡死十几秒。4.3 日志文件在项目里的作用资源列表里那串 log.log.2019-04-17、error.log.2019-04-17 之类的文件是 Log4j 按日期滚动生成的日志。这绝对是加分项因为它说明作者在开发调试时技术栈里有日志规范意识。后面第六章我会专门讲怎么用这些日志定位问题这里先给一个判断标准log.log 记录的是业务操作和正常执行过程error.log 记录的是异常栈。你拿到别人的源码第一件事就应该翻 error.log——里面带着整个系统最真实的病历史。5. 温湿度统计的边界处理避坑与五个常见翻车现场5.1 数据统计常见错误一没有数据时前端图表崩掉现象数据库里没有任何温湿度记录页面加载后 ECharts 图表区域一片空白控制台报 “Cannot read property ‘push’ of undefined”。原因后端返回的 JSON 里 data 数组是 null前端直接对 data 做 forEach 或 push没有做空值判断。解决在 service 层查询结果上强制加一层判空返回空数组而不是 null前端再做一次 length 为 0 时显示“暂无可展示数据”文案。5.2 数据统计常见错误二时间范围查询查不到记录现象选择某一个日期图表显示无数据但翻数据库明明有记录。原因前端传入的时间格式是 “yyyy-MM-dd HH:mm:ss” 带横线的格式而后端 SQL 里用了 DATE_FORMAT 后与字符串比较MySQL 里 9 以下的月份日期不带前导零导致两边对不上。解决时间字符串统一用 Timestamp.valueOf() 转成 java.sql.Timestamp 传入 mapper不要在 SQL 里拼字符串时间让 MySQL 自己处理日期格式。5.3 数据统计常见错误三MyBatis 查询结果字段全是 null现象控制台打印 SQL 有数据但返回给前端 temperature 字段为 null。原因数据库列名 temperature 和驼峰属性名 temperature 对不上——数据库列名可能是 temp或者 resultMap 没配MyBatis 默认自动映射是关闭的。解决在 mybatis-config.xml 里开启 mapUnderscoreToCamelCase 设为 true或者手写 resultMap 把每列对应到实体字段。前者是省事方案后者是稳妥方案。5.4 数据统计常见错误四爬虫新闻存不进去报主键冲突现象日志里出现 Duplicate entry xxx for key PRIMARY。原因crop_news 表主键是自增但代码里 news.setId() 手动赋值了爬虫网站的原始 ID或者两次爬取抓到了同一条新闻表里没加唯一约束。解决设计表时给 news_url 字段加 unique 索引插入前先按 url 查一次存在就跳过。5.5 数据统计常见错误五Druid 连接池报 connection refused现象Tomcat 启动后第一次访问页面报 CannotGetJdbcConnectionException后台看 Druid 的监控页面连接数一直是 0。原因部署在两台机器上时MySQL 配置文件里的 bind-address 是 127.0.0.1只允许本机连接或者防火墙没有放行 3306 端口。课设场景大概率是前者。解决修改 MySQL my.cnf 里 bind-address 为 0.0.0.0 或注释掉该行然后执行 flush privileges再在 ApplicationContext 中确认 url 写的是数据库所在机器的 IP 而不是 localhost。6. 日志是不花钱的调试入口把 error.log 当诊断依据的排查习惯这套资源的调试价值其实都藏在那几个日志文件里。拿到任何 SSM 课设项目我建议强制做一遍以下动作启动 Tomcat登录系统在站点管理里新增一个站点再查一次温湿度数据曲线然后去 logs 目录翻 log.log 和 error.log 的最新几行看日志记录和你的操作是否能对上。log4j.properties 里有用的配置片段长这样log4j.rootLoggerINFO, stdout, file log4j.appender.fileorg.apache.log4j.DailyRollingFileAppender log4j.appender.file.File${catalina.base}/logs/error.log log4j.appender.file.DatePattern.yyyy-MM-dd log4j.appender.file.layoutorg.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n几个判断日志的关键点INFO 级别记录的是业务节点比如“站点 3 新增成功”“爬虫抓取新闻 7 条”WARN 级别往往是查询慢或者空结果警告这条最容易被忽略但它能帮你发现漏配的索引ERROR 级别记录的是根本没有兜底的异常比如 SQL 语法错误、实体类找不到、NullPointerException这些通常就是答辩前要修复的对象。日志格式里的 %c{1}:%L 非常有用它把类名和行号打印出来StackOverflow 时可以直接定位是在哪一行的空指针。我一般拿到 error.log 第一反应不是看堆栈最后的 cause而是先 grep 一下最近一次时间戳找出最后一次 ERROR 前 5 行日志里业务走到哪一步再结合控制台反向推导是哪个 Bean 没注入成功。从那以后我每次接手 SSM 课设项目都强制在这个文件里跑一遍操作路径确认日志与功能点能对上才继续改代码。这大概是我从这套资源里带走的最值钱的东西希望帮到你。本文还有配套的精品资源点击获取
返回列表