完整教程:【数据监测项目】Java基础、JDBC、Maven的简单项目

目录

一、项目背景与目标:

1、项目背景与目前行情:

2、项目的主要目标:

二、功能需求分析:

三、概要设计:

四、详细设计:

五、项目开发:

(一)相关接口与实体类的定义:

实体类Environment:封装对象

采集模块接口:需要完成从文件中将数据导出后处理并封装到对象中

客户端模块:将采集模块得到的集合传输给服务端

数据入库模块:将服务端得到的集合中的数据存到数据库中

服务端模块:接受客户端发来的数据并且调用数据入库方法存入数据库

(二)数据库建表与数据源的准备

(三)依赖的配置:

(四)接口的实现类:

采集接口实现类:

客户端接口实现类:

数据入库接口实现类:

服务端模块实现类:

六、项目测试:

(一)客户端测试类:

(二)服务端测试类:


这个项目我们只完成后端代码部分!!!(这里不是按照项目生命周期去写的,有很大出入,不要随便引用,注意注意)

一、项目背景与目标:

1、项目背景与目前行情:

        随着国家经济的快速发展,农业生产规模的不断提高,农产品在大棚中培育的品种越来越多,规模也越来越大。传统的农业大棚中的大部分操作都是在人工情况下进行的,对于数量较多或者面积较大的农业大棚就显现出很大的局限性,因此,实现农业大棚生产的自动化和信息化(智能化),能够方便有效地对农业大棚环境进行监控,提高资源利用率和农业生产水平,这是目前农业发展的趋势。

        智能化的监控系统成本较高,我国现代温室技术起步较晚,而国外所开发的大棚监控系统价格昂贵,难以适应我国农业生长环境监控的需求。传统的农业温室大棚监控系统中,大都采用有线设备来进行大棚环境数据的采集及数据的传输,较大的监控区域需要大量传感器和执行设备的使用导致监控系统的建设和维护产生很多问题,导致施工难度大,且维修不便。

2、项目的主要目标:

(1)农棚设备与农棚内的环境参数相关联,将获得的环境参数经由数据服务中心处理后,自动实现农棚设备的开关控制,如此在无人管理的情况下也能实现对大棚的智能监控,同时,减少人工的误操作。

(2)采用Zigbee技术来实现树莓派与开发板的无线通讯功能,Zigbee技术用于大量传感器组网及进行数据采集和传输,代替了传统农业温室大棚采用有线设备来进行大棚环境数据的采集及数据的传输,降低系统成本及施工和维护难度。

(3)采用了温度传感器实时监测温度情况,根据温度来控制顶棚,温度过高则打开顶棚用雨水给作物浇灌,湿度传感器数据过大则关上顶棚防止土壤被破坏。

二、功能需求分析:

  1. 环境监测功能:实时采集农棚内空气温湿度、土壤湿度、光照强度、二氧化碳浓度等农作物生长关键参数,通过实验箱模拟数据收集,重点处理上述四类参数7、23。

  2. 设备控制功能:支持自动与手动双模式控制,自动模式下根据环境参数关联控制农棚设备(如温度过高开顶棚、湿度过大关顶棚,控制湿帘风机、喷淋滴灌等);手动模式下管理员通过移动端或 Web 端操作设备开关

  3. 数据处理与管理功能:对采集数据进行预处理(十六进制转十进制,温湿度按特定公式计算),按采集日期 “日” 分表存储(31 张表 e_detail_1 至 e_detail_31),支持数据备份、日志记录(基于 log4j)与配置管理(基于 dom4j 解析 xml)

  4. 用户交互功能:移动端支持实时查数据、收异常报警、控设备;Web 端支持历史数据可视化(表格、折线图、柱形图)、收报警、手动控设备

这里我们实现的功能主要是数据处理与管理功能,再往下的部分我们就只描述这一功能,其他部分不做阐述!

三、概要设计:

采用 “客户端 - 服务器” 二级架构,聚焦数据采集、处理、传输与存储核心流程,适配农业大棚环境监测场景:

  1. 客户端:核心负责数据提取、处理与封装,包含采集模块(读取预处理文件数据)、数据处理模块(解析十六进制数据、按公式转换温湿度)、封装模块(将处理后数据封装为Environment实体类)、网络模块(将实体类数据传输至服务端),依赖配置模块(dom4j 解析 XML)与日志模块(log4j 记录运行日志)保障运行。

  2. 服务器端:核心负责数据接收与存储,包含网络模块(接收客户端传输的Environment实体类数据)、入库模块(按采集日期分表存储至对应数据库表)、备份模块(数据备份与历史备份读取),与客户端共用配置、日志模块,确保系统参数统一与问题可追溯

四、详细设计:

(一)客户端数据处理模块详细逻辑

  1. 数据读取逻辑

    • 采用文件流读取预处理数据文件,按行读取数据,每行作为一条独立数据记录;

    • 对读取的每行数据,使用 “|” 作为分隔符拆分,校验拆分后字段数量是否为 9 个,若不是则通过日志模块记录异常,跳过该条数据。

  2. 数据转换逻辑

    • 传感器地址判断:若为 16,取十六进制环境数据前 2 字节转十进制作为温度原始值,中间 2 字节转十进制作为湿度原始值,分别执行公式计算;若为 256/1280,取前 2 字节转十进制作为光照强度 / 二氧化碳值,无需额外计算;

    • 数值校验:对转换后的温湿度、光照强度、二氧化碳值进行合理性校验(如温度范围 - 40℃~60℃、湿度 0%~100%),异常值记录日志后跳过。

  3. 实体类封装逻辑

    • 新建Environment对象,按字段映射赋值:

      • srcId = 拆分后第 1 字段(发送端 id);

      • desId = 拆分后第 2 字段(树莓派系统 id);

      • devId = 拆分后第 3 字段(实验箱区域模块 id);

      • sensorAddress = 拆分后第 4 字段(传感器地址);

      • count = Integer.parseInt (拆分后第 5 字段)(传感器个数);

      • cmd = 拆分后第 6 字段(指令标号);

      • data = 转换计算后的环境值(float 类型);

      • status = Integer.parseInt (拆分后第 8 字段)(状态标识);

      • gatherDate = new Timestamp (Long.parseLong (拆分后第 9 字段))(采集时间,时间戳转 Timestamp);

      • name = 根据sensorAddress赋值(16 对应 “温度”/“湿度”、256 对应 “光照强度”、1280 对应 “二氧化碳”)。

(二)客户端网络传输模块详细逻辑

  1. 采用 TCP 协议与服务端建立稳定连接,连接前读取 XML 配置文件中的服务端 IP 与端口(通过 dom4j 解析配置文件);

  2. 若连接成功,将Environment实体类对象序列化为可传输数据格式,发送至服务端;

  3. 接收服务端的传输确认响应,若收到 “成功” 响应,记录日志;若超时或收到 “失败” 响应,重试传输(重试次数可通过配置文件设置,默认 3 次),仍失败则记录错误日志并终止该条数据传输。

(三)服务端入库模块简要逻辑

        服务端接收Environment实体类数据后,提取gatherDate中的 “日”(如 1-31),确定目标表为env_detail_日,通过 JDBC 执行 INSERT 语句,将实体类属性对应插入表中字段,完成数据存储

五、项目开发:

(一)相关接口与实体类的定义:

实体类Environment:封装对象

/**
* 环境存储实体类,包括环境种类(温度,湿度,二氧化碳,光照强度)
*/
public class Environment implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 环境种类名称
*/
private String name;
/**
* 发送端id
*/
private String srcId;
/**
* 树莓派系统id
*/
private String desId;
/**
* 实验箱区域模块id(1-8)
*/
private String devId;
/**
* 模块上传感器地址
*/
private String sensorAddress;
/**
* 传感器个数
*/
private int count;
/**
* 发送指令标号 3表示接收数据 16表示发送命令
*/
private String cmd;
/**
* 状态 默认1表示成功
*/
private int status;
/**
* 环境值
*/
private float data;
/**
* 采集时间
*/
private Timestamp gatherDate;
public Environment() {
}
public Environment(String name, String srcId, String desId, String devId,
String sensorAddress, int count, String cmd, int status,
float data, Timestamp gatherDate) {
this.name = name;
this.srcId = srcId;
this.desId = desId;
this.devId = devId;
this.sensorAddress = sensorAddress;
this.count = count;
this.cmd = cmd;
this.status = status;
this.data = data;
this.gatherDate = gatherDate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSrcId() {
return srcId;
}
public void setSrcId(String srcId) {
this.srcId = srcId;
}
public String getDesId() {
return desId;
}
public void setDesId(String desId) {
this.desId = desId;
}
public String getDevId() {
return devId;
}
public void setDevId(String devId) {
this.devId = devId;
}
public String getSensorAddress() {
return sensorAddress;
}
public void setSensorAddress(String sensorAddress) {
this.sensorAddress = sensorAddress;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getCmd() {
return cmd;
}
public void setCmd(String cmd) {
this.cmd = cmd;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public float getData() {
return data;
}
public void setData(float data) {
this.data = data;
}
public Timestamp getGatherDate() {
return gatherDate;
}
public void setGatherDate(Timestamp gatherDate) {
this.gatherDate = gatherDate;
}
@Override
public String toString() {
return "Environment{" +
"name='" + name + '\'' +
", srcId='" + srcId + '\'' +
", desId='" + desId + '\'' +
", devId='" + devId + '\'' +
", sensorAddress='" + sensorAddress + '\'' +
", count=" + count +
", cmd='" + cmd + '\'' +
", status=" + status +
", data=" + data +
", gatherDate=" + gatherDate +
'}';
}
}

采集模块接口:需要完成从文件中将数据导出后处理并封装到对象中

/**
* Gather接口是物联网数据中心项目采集模块的规范
* 该模块对物联网数据中心项目环境信息进行采集
* 将采集的数据封装成Collection集合
*/
public interface Gather {
/**
* 使用IO流读取数据文件中的一行行数据,对数据进行解析,封装成Environment类的对象
* 将所有Environment类的对象保存到集合中
*
* @return 存储了若干个Environment对象的集合,Environment对象是对采集数据的封装
*/
Collection gather() throws Exception;
}

客户端模块:将采集模块得到的集合传输给服务端

/**
* Client接口是物联网环境监测数据中心项目网络模块中客户端的规范
* Client的作用就是与服务器进行通信传递信息
*/
public interface Client {
/**
* 向网络模块服务端发送对象
*
* @param collection 集合对象
*/
void send(Collection collection) throws Exception;
}

数据入库模块:将服务端得到的集合中的数据存到数据库中

/**
* DBStore接口是物联网数据中心项目入库模块的规范
* 该模块负责对Environment集合进行持久化操作
*/
public interface DBStore {
/**
* 將集合对象 collection 中的一条条数据保存到数据库中
*
* @param collection 存储了Environment类的对象的集合
*/
void saveDB(Collection collection) throws Exception;
}

服务端模块:接受客户端发来的数据并且调用数据入库方法存入数据库

/**
* Server接口是物联网数据中心项目网络模块中服务端的规范
* 该模板负责与客户端进行通信接收信息
* 并且利用DBStore模块的功能将接收的数据进行持久化操作
*/
public interface Server {
/**
* 接收网络模块客户端的连接,要求一直接收连接,每当有一个客户端连接到服务端
* 后,服务端就创建一个线程来接收客户端发送过来的数据。接收完毕后调用入库模块
* 将接收的数据保存到数据库中
*/
void receive() throws Exception;
/**
* 关闭网络模块服务端,停止接收来自网络模块客户端的连接
*/
void shutdown() throws Exception;
}

以上就是主要功能需要的接口,日志模块,配置模块这些不做阐述

(二)数据库建表与数据源的准备

-- 定义
delimiter //
DROP PROCEDURE IF EXISTS `create_table_do`;
CREATE PROCEDURE create_table_do()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i < 32 DO
SET @STMT = CONCAT("DROP TABLE IF EXISTS `env_detail_",i,"`;");
PREPARE STMT FROM @STMT;
EXECUTE STMT;
SET @STMT = CONCAT("CREATE TABLE IF NOT EXISTS `env_detail_",i,
"`(`name` varchar(20) NOT NULL COMMENT '传感器名称',
`src_id` varchar(5) NOT NULL COMMENT '发送端id',
`des_id` varchar(5) NOT NULL COMMENT '树莓派系统id(1-8)',
`dev_id` varchar(5) NOT NULL COMMENT '实验箱区域模块id',
`sensor_address` varchar(7) NOT NULL COMMENT '模块上传感器地址',
`count` int(2) NOT NULL DEFAULT '1' COMMENT '传感器个数',
`cmd` varchar(5) NOT NULL DEFAULT '3' COMMENT '指令标号(3表示需要接受数据,16表示需要发送数据)',
`data` float(9,4) NOT NULL COMMENT '环境数据',
`status` int(2) NOT NULL DEFAULT '1' COMMENT '状态标示(默认为1,表示成功)',
`gather_date` timestamp NOT NULL COMMENT '采集时间')ENGINE=InnoDBDEFAULT CHARSET=utf8 COMMENT='数据详情日表';"
);
PREPARE STMT FROM @STMT;
EXECUTE STMT;
SET i = i + 1;
END WHILE;
END//
-- 执行
CALL create_table_do();

数据源的准备,存放在txt文件中即可:

100|101|2|16|1|3|5d606f7802|1|1516323596029
100|101|2|16|1|3|5d606f7802|1|1516323597007
100|101|2|16|1|3|5d646f7802|1|1516323598382
100|101|2|16|1|3|5d646f8802|1|1516323598936
100|101|2|16|1|3|5d686f8802|1|1516323599977
100|101|2|16|1|3|5d686f9802|1|1516323601007
100|101|2|16|1|3|5d6c6fac02|1|1516323601926
100|101|2|256|1|3|003703|1|1516415240975
100|101|2|256|1|3|003703|1|1516415241900
100|101|2|256|1|3|003703|1|1516415242923
100|101|2|256|1|3|003703|1|1516415243947
100|101|2|1280|1|3|027001|1|1516530459627
100|101|2|1280|1|3|026f01|1|1516530460642
100|101|2|1280|1|3|026f01|1|1516530461671
100|101|2|1280|1|3|026e01|1|1516530462694

这里实际上有21条数据,温度和湿度共同占用一条数据,但是我们需要都罗列出来。

(三)依赖的配置:

我这里第一个是一个外部引入的自定义依赖,里面存放了(一)中的接口与实体类,大家自定义就行

com.briup.smart
env-gather-base
1.0-SNAPSHOT
junit
junit
4.13.2
mysql
mysql-connector-java
8.0.27
com.alibaba
druid
1.2.16
junit
junit
RELEASE
compile
log4j
log4j
1.2.17
org.dom4j
dom4j
2.1.3

(四)接口的实现类:

采集接口实现类:

public class GatherImpl implements Gather {
@Override
public Collection gather(){
//        指出数据所在文件
File file = new File("D:\\JDBC_project\\JDBC_Demo\\src\\main\\resources\\data-file-simple");
//        创建存放环境对象的集合
List list = new ArrayList<>();
//        从文件中一行一行读取数据
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file));){
//           如果文件中还有数据
while (bufferedReader.ready()){
Environment environment = new Environment();
//                将这一行数据存放在字符串对象中
String line = bufferedReader.readLine();
//                按照"|"分隔字符串,得到字符串数组
String[] arr = line.split("\\|");
//                将分割出的各个部分赋给环境对象
environment.setSrcId(arr[0]);
environment.setDesId(arr[1]);
environment.setDevId(arr[2]);
environment.setSensorAddress(arr[3]);
environment.setCount(Integer.parseInt(arr[4]));
//3表示结束数据,16表示发送命令
environment.setCmd(arr[5]);
//环境数据表值,在下面的计算中
//environment.setData(Float.parseFloat(arr[6]));
environment.setStatus(Integer.parseInt(arr[7]));
environment.setGatherDate(new Timestamp(Long.parseLong(arr[8])));
//                对采集到的数据的处理,转换为可以理解的符合现实的数据
switch (arr[3]){
case "16":
String temp = arr[6].substring(0,4);
int temp_int = Integer.parseInt(temp,16);
float temp_real = (temp_int*(0.00268127F))-46.85F;
environment.setData(temp_real);
environment.setName("温度");
//一个对象完成,放在集合中
list.add(environment);
Environment environment2 = new Environment("湿度",environment.getSrcId(),environment.getDesId(),environment.getDevId(),environment.getSensorAddress(),environment.getCount(),environment.getCmd(),environment.getStatus(),0,environment.getGatherDate());
String humi = arr[6].substring(4,8);
int humi_int = Integer.parseInt(humi,16);
float humi_real = (humi_int*0.00190735F)-6;
environment2.setData(humi_real);
list.add(environment2);
break;
case "256":
String light = arr[6].substring(0,4);
int light_int = Integer.parseInt(light,16);
environment.setData(light_int);
environment.setName("光照强度");
list.add(environment);
break;
case "1280":
String co2 = arr[6].substring(0,4);
int co2_int = Integer.parseInt(co2,16);
environment.setData(co2_int);
environment.setName("二氧化碳浓度");
list.add(environment);
break;
default:
//                    System.out.println("数据格式有误,请排查");
}
}
}catch (Exception e){
e.printStackTrace();
}
System.out.println("采集到的对象的个数" + list.size());
return list;
}
}

客户端接口实现类:

public class ClientImpl implements Client {
@Override
public void send(Collection collection){
String ip = "127.0.0.1";
int port = 8030;
try(Socket socket = new Socket(ip,port);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());){
System.out.println("连接服务端成功!");
System.out.println("准备发送数据");
oos.writeObject(collection);
System.out.println("发送数据成功共" +collection.size() + "条!");
}catch (Exception e){
e.printStackTrace();
}
System.out.println("客户端网络模块成功关闭");
}
}

数据入库接口实现类:

public class DBStoreImpl implements DBStore {
@Override
public void saveDB(Collection collection) throws Exception {
String driverClass = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/你的数据库";
String username = "你的账户名";
String password = "你的密码";
Connection conn = null;
PreparedStatement pstmt = null;
try {
Class.forName(driverClass);
conn = DriverManager.getConnection(url, username, password);
conn.setAutoCommit(false);
String sql = "insert into e_detail_1(name,srcId,desId,devId,sersorAddress,count,cmd,status,data,gather_Date) values(?,?,?,?,?,?,?,?,?,?)";
pstmt = conn.prepareStatement(sql);
for (Environment e :
collection) {
pstmt.setString(1,e.getName());
pstmt.setString(2,e.getSrcId());
pstmt.setString(3,e.getDesId());
pstmt.setString(4,e.getDevId());
pstmt.setString(5,e.getSensorAddress());
pstmt.setInt(6,e.getCount());
pstmt.setString(7,e.getCmd());
pstmt.setInt(8,e.getStatus());
pstmt.setFloat(9,e.getData());
pstmt.setTimestamp(10,e.getGatherDate());
pstmt.addBatch();
pstmt.executeBatch();
conn.commit();
}
System.out.println("服务端成功将数据放入数据库中");
}catch (Exception e){
e.printStackTrace();
}finally {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

服务端模块实现类:

public class ServerImpl implements Server {
@Override
public void receive(){
try ( ServerSocket serverSocket = new ServerSocket(8030);
Socket socket = serverSocket.accept();
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());){
System.out.println("成功启动客户端");
Collection coll = new ArrayList<>();
coll = (Collection) ois.readObject();
System.out.println("接收数据成功共" +coll.size() + "条!");
//            for (Environment environment : coll) {
//                System.out.println(environment);
//            }
DBStoreImpl dbStore = new DBStoreImpl();
dbStore.saveDB(coll);;
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void shutdown() throws Exception {
}
}

六、项目测试:

(一)客户端测试类:

public class ClientMain {
public static void main(String[] args) {
GatherImpl gather = new GatherImpl();
Collection list = gather.gather();
ClientImpl client = new ClientImpl();
client.send(list);
// GatherBackupImpl gather = new GatherBackupImpl();
// Collection list = gather.gather();
// ClientImpl client = new ClientImpl();
// client.send(list);
for (Environment environment:
list){
System.out.println(environment);
}
System.out.println("采集到的对象的个数" + list.size());
}
}

(二)服务端测试类:

public class ServerMain {
public static void main(String[] args){
ServerImpl server = new ServerImpl();
server.receive();
}
}

先启动服务端,在启动客户端即可成功将数据传入数据库中

posted @ 2025-09-25 19:20  ycfenxi  阅读(11)  评论(0)    收藏  举报