Compare commits
45 Commits
Author | SHA1 | Date |
---|---|---|
v-lijf43 | f555c156c9 | 3 days ago |
mh | f5a1d1b698 | 1 week ago |
mh | 3fe22641d6 | 3 weeks ago |
mh | 6ccc5be414 | 3 months ago |
mh | 66c0b8f899 | 3 months ago |
mh | c95c8ebc21 | 3 months ago |
mh | b174d79fe5 | 3 months ago |
mh | 2b3b9fbdd5 | 3 months ago |
mh | 659913fd1d | 4 months ago |
mh | b298be7fd9 | 4 months ago |
mh | d93f91037c | 4 months ago |
mh | 6fa9ab3f7e | 4 months ago |
mh | 0023e82d89 | 4 months ago |
mh | 8d77490a9f | 4 months ago |
mh | 6e23904902 | 4 months ago |
mh | f0719ee78d | 5 months ago |
mh | 7fc0d63d6f | 5 months ago |
mh | 9b92196e9c | 6 months ago |
mh | dd2a9e984d | 6 months ago |
mh | 7af983ebad | 6 months ago |
mh | b819375d55 | 6 months ago |
mh | 0127b2122f | 6 months ago |
mh | fc890b53e0 | 6 months ago |
mh | 11fae3d85c | 6 months ago |
mh | c331d15b35 | 6 months ago |
mh | 0efc951fa7 | 6 months ago |
mh | 3adb86d86f | 6 months ago |
mh | c2fdcf763d | 7 months ago |
mh | f436d1690b | 7 months ago |
mh | d8abc75341 | 7 months ago |
mh | c795ac7737 | 7 months ago |
mh | 75aeaa8a12 | 8 months ago |
mh | 6aa5718d6a | 8 months ago |
mh | 19248479eb | 8 months ago |
mh | d3c672b64d | 9 months ago |
mh | 4f478a504d | 9 months ago |
mh | 6657e8ffeb | 9 months ago |
mh | b80e47e541 | 9 months ago |
mh | d3d970768a | 10 months ago |
mh | faa17b1a93 | 10 months ago |
mh | 5d6b9c58b2 | 10 months ago |
mh | b2e336d43f | 11 months ago |
mh | db2f64cd54 | 11 months ago |
mh | 40f7577927 | 11 months ago |
mh | 19dbbb5c81 | 11 months ago |
158 changed files with 12366 additions and 6622 deletions
@ -0,0 +1,199 @@ |
|||||||
|
-- 2024-05-07 维修表缺少字段 |
||||||
|
ALTER TABLE maintain_info |
||||||
|
ADD cost numeric(2, 0) NULL; |
||||||
|
EXEC sys.sp_addextendedproperty 'MS_Description', N'材料费用', 'schema', N'dbo', 'table', N'maintain_info', 'column', N'cost'; |
||||||
|
ALTER TABLE maintain_info |
||||||
|
ADD contents varchar(100) NULL; |
||||||
|
EXEC sys.sp_addextendedproperty 'MS_Description', N'维保内容', 'schema', N'dbo', 'table', N'maintain_info', 'column', N'contents'; |
||||||
|
ALTER TABLE maintain_info |
||||||
|
ADD evaluate varchar(10) NULL; |
||||||
|
EXEC sys.sp_addextendedproperty 'MS_Description', N'评价内容', 'schema', N'dbo', 'table', N'maintain_info', 'column', N'evaluate'; |
||||||
|
|
||||||
|
-- 训练集合: |
||||||
|
begin tran |
||||||
|
insert into history_data_pre(cur_date,building_id,water_value,elect_value,water_level,env_min_temp,env_max_temp) |
||||||
|
select eds.cur_date, |
||||||
|
eds.building_id, |
||||||
|
isnull(eds.water_value, |
||||||
|
0) as water_value, |
||||||
|
isnull(eds.elect_value, |
||||||
|
0) as elect_value, |
||||||
|
isnull(convert(numeric (24, 2), t1.water_level), |
||||||
|
0) as water_level, |
||||||
|
th.tempmin, |
||||||
|
th.tempmax |
||||||
|
from energy_day_sum eds |
||||||
|
left join (select convert(date, |
||||||
|
cur_date) as cur_date, |
||||||
|
building_id, |
||||||
|
avg(isnull(convert(numeric (24, 2), water_level), 0)) as water_level |
||||||
|
from history_data |
||||||
|
group by convert(date, |
||||||
|
cur_date), |
||||||
|
building_id) t1 on |
||||||
|
eds.cur_date = t1.cur_date and eds.building_id = t1.building_id |
||||||
|
left join temp_history th |
||||||
|
on eds.cur_date = th.cur_date |
||||||
|
where eds.building_id != '所有' |
||||||
|
order by |
||||||
|
eds.building_id, |
||||||
|
eds.cur_date |
||||||
|
rollback |
||||||
|
|
||||||
|
-- 2024-05-09 创建历史预测表 |
||||||
|
-- 历史水电用量以及预测值 |
||||||
|
CREATE TABLE history_data_pre |
||||||
|
( |
||||||
|
cur_date date NULL, |
||||||
|
building_id varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
env_min_temp numeric(24, 2) NULL, |
||||||
|
env_max_temp numeric(24, 2) NULL, |
||||||
|
water_value numeric(24, 2) NULL, |
||||||
|
elect_value numeric(24, 2) NULL, |
||||||
|
water_level numeric(24, 2) NULL, |
||||||
|
id bigint IDENTITY(1,1) NOT NULL, |
||||||
|
water_value_pre numeric(24, 2) NULL, |
||||||
|
elect_value_pre numeric(24, 2) NULL, |
||||||
|
water_level_pre numeric(24, 2) NULL, |
||||||
|
remark varchar(200) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
CONSTRAINT PK_history_data_pre PRIMARY KEY (id) |
||||||
|
); |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'历史水电用量以及预测值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'日期', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'cur_date'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'楼栋编号', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'building_id'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'环境最低温度', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'env_min_temp'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'环境最高温度', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'env_max_temp'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'实际用水量', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'water_value'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'实际用电量', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'elect_value'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'平均水位', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'water_level'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'id', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'id'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'用水量预测值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'water_value_pre'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'用电量预测值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'elect_value_pre'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'平均水位预测值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'water_level_pre'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'history_data_pre', @level2type=N'Column', @level2name=N'remark'; |
||||||
|
|
||||||
|
create index history_data_pre_building_id on history_data_pre (building_id); |
||||||
|
create index history_data_pre_cur_date on history_data_pre (cur_date); |
||||||
|
|
||||||
|
-- 2024-05-09 系统参数表增加天气区域 |
||||||
|
ALTER TABLE SysParam |
||||||
|
ADD proArea varchar(100) NULL; |
||||||
|
EXEC sp_addextendedproperty 'MS_Description', N'天气区域', 'schema', N'dbo', 'table', N'SysParam', 'column', N'proArea'; |
||||||
|
|
||||||
|
-- 2024-05-15 热泵使用时间表(月表) |
||||||
|
CREATE TABLE analysis_runtime_month ( |
||||||
|
id bigint IDENTITY(1,1) NOT NULL, |
||||||
|
cur_date varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
item_type varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day01 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day02 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day03 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day04 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day05 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day06 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day07 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day08 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day09 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day10 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day11 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day12 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day13 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day14 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day15 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day16 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day17 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day18 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day19 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day20 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day21 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day22 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day23 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day24 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day25 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day26 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day27 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day28 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day29 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day30 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
day31 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
total_value varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
building_id varchar(50) COLLATE Chinese_PRC_CI_AS NULL |
||||||
|
); |
||||||
|
-- 使用时间年表 |
||||||
|
CREATE TABLE analysis_runtime_year ( |
||||||
|
id bigint IDENTITY(1,1) NOT NULL, |
||||||
|
cur_date varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
item_type varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month01 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month02 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month03 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month04 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month05 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month06 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month07 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month08 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month09 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month10 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month11 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
month12 varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
total_value varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
building_id varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
building_name varchar(50) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
CONSTRAINT analysis_runtime_year_id PRIMARY KEY (id) |
||||||
|
); |
||||||
|
|
||||||
|
-- Extended properties |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'序号', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'id'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'日期', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'cur_date'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'类型', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'item_type'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'1月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month01'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'2月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month02'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'3月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month03'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'4月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month04'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'5月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month05'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'6月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month06'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'7月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month07'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'8月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month08'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'9月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month09'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'10月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month10'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'11月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month11'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'12月用量或比值', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'month12'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'合计用量', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'total_value'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'楼栋编号', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'building_id'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'楼栋名称', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'analysis_runtime_year', @level2type=N'Column', @level2name=N'building_name'; |
||||||
|
|
||||||
|
|
||||||
|
-- 2024-06-24 添加楼栋人数 |
||||||
|
alter table history_data_pre add people_num numeric(24,2) not null default 0; |
||||||
|
exec sp_addextendedproperty N'MS_Description', N'每栋楼人数', N'schema', N'dbo',N'table', N'history_data_pre', N'column', N'people_num'; |
||||||
|
|
||||||
|
-- 2024-06-26 添加知识库 |
||||||
|
CREATE TABLE knowledge_data |
||||||
|
( |
||||||
|
id bigint IDENTITY(1,1) NOT NULL, |
||||||
|
title varchar(100) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
description varchar(200) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
content varchar(2000) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
create_time datetime NULL, |
||||||
|
status int NULL, |
||||||
|
remark varchar(200) COLLATE Chinese_PRC_CI_AS NULL, |
||||||
|
CONSTRAINT pk_knowledge_data PRIMARY KEY (id) |
||||||
|
); |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'知识库数据', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'knowledge_data'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'id', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'knowledge_data', @level2type=N'Column', @level2name=N'id'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'标题', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'knowledge_data', @level2type=N'Column', @level2name=N'title'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'描述', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'knowledge_data', @level2type=N'Column', @level2name=N'description'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'内容', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'knowledge_data', @level2type=N'Column', @level2name=N'content'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'knowledge_data', @level2type=N'Column', @level2name=N'create_time'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'状态', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'knowledge_data', @level2type=N'Column', @level2name=N'status'; |
||||||
|
EXEC sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'Schema', @level0name=N'dbo', @level1type=N'Table', @level1name=N'knowledge_data', @level2type=N'Column', @level2name=N'remark'; |
||||||
|
|
||||||
|
create index knowledge_data_create_time on history_data_pre (create_time); |
||||||
|
|
||||||
|
-- 2024-07-01 水位变换添加 |
||||||
|
ALTER TABLE chws_gsh.dbo.waterLevel ADD level14 varchar(50) NULL; |
||||||
|
EXEC chws_gsh.sys.sp_addextendedproperty 'MS_Description', N'14点水位', 'schema', N'dbo', 'table', N'waterLevel', 'column', N'level14'; |
||||||
|
|
||||||
|
ALTER TABLE chws_gsh.dbo.building ADD low_tank_height numeric(24,2) NULL; |
||||||
|
EXEC chws_gsh.sys.sp_addextendedproperty 'MS_Description', N'低区域水箱高度', 'schema', N'dbo', 'table', N'building', 'column', N'low_tank_height'; |
||||||
|
|
@ -0,0 +1,135 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<parent> |
||||||
|
<groupId>com.mh</groupId> |
||||||
|
<artifactId>chws</artifactId> |
||||||
|
<version>1.0-SNAPSHOT</version> |
||||||
|
</parent> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<groupId>com.mh</groupId> |
||||||
|
<artifactId>algorithm</artifactId> |
||||||
|
<version>1.0.0</version> |
||||||
|
<packaging>jar</packaging> |
||||||
|
|
||||||
|
<properties> |
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||||
|
<encoding>UTF-8</encoding> |
||||||
|
<java.version>1.8</java.version> |
||||||
|
<maven.compiler.source>1.8</maven.compiler.source> |
||||||
|
<maven.compiler.target>1.8</maven.compiler.target> |
||||||
|
</properties> |
||||||
|
<dependencies> |
||||||
|
<!-- https://mvnrepository.com/artifact/net.sourceforge.javacsv/javacsv --> |
||||||
|
<dependency> |
||||||
|
<groupId>net.sourceforge.javacsv</groupId> |
||||||
|
<artifactId>javacsv</artifactId> |
||||||
|
<version>2.0</version> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>gov.nist.math</groupId> |
||||||
|
<artifactId>jama</artifactId> |
||||||
|
<version>1.0.3</version> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>junit</groupId> |
||||||
|
<artifactId>junit</artifactId> |
||||||
|
<version>RELEASE</version> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<plugins> |
||||||
|
<plugin> |
||||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||||
|
<version>3.9.3</version> |
||||||
|
<configuration> |
||||||
|
<source>1.8</source> |
||||||
|
<target>1.8</target> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
</plugins> |
||||||
|
</build> |
||||||
|
|
||||||
|
<profiles> |
||||||
|
<profile> |
||||||
|
<id>default</id> |
||||||
|
<activation> |
||||||
|
<activeByDefault>true</activeByDefault> |
||||||
|
</activation> |
||||||
|
<build> |
||||||
|
<plugins> |
||||||
|
<!-- java版本 --> |
||||||
|
<plugin> |
||||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||||
|
<version>3.8.0</version> |
||||||
|
<configuration> |
||||||
|
<source>1.8</source> |
||||||
|
<target>1.8</target> |
||||||
|
<encoding>UTF-8</encoding> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
<!-- 这是javadoc打包插件 --> |
||||||
|
<plugin> |
||||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||||
|
<artifactId>maven-javadoc-plugin</artifactId> |
||||||
|
<version>2.9.1</version> |
||||||
|
<executions> |
||||||
|
<execution> |
||||||
|
<id>attach-javadocs</id> |
||||||
|
<goals> |
||||||
|
<goal>jar</goal> |
||||||
|
</goals> |
||||||
|
<!-- 该处屏蔽jdk1.8后javadoc的严格校验 --> |
||||||
|
<configuration> |
||||||
|
<additionalparam>-Xdoclint:none</additionalparam> |
||||||
|
</configuration> |
||||||
|
</execution> |
||||||
|
</executions> |
||||||
|
</plugin> |
||||||
|
<!-- 打包源码插件 --> |
||||||
|
<plugin> |
||||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||||
|
<artifactId>maven-source-plugin</artifactId> |
||||||
|
<version>2.3</version> |
||||||
|
<executions> |
||||||
|
<execution> |
||||||
|
<id>attach-sources</id> |
||||||
|
<goals> |
||||||
|
<goal>jar</goal> |
||||||
|
</goals> |
||||||
|
</execution> |
||||||
|
</executions> |
||||||
|
</plugin> |
||||||
|
<!--签名插件--> |
||||||
|
<!-- <plugin>--> |
||||||
|
<!-- <groupId>org.apache.maven.plugins</groupId>--> |
||||||
|
<!-- <artifactId>maven-gpg-plugin</artifactId>--> |
||||||
|
<!-- <version>1.4</version>--> |
||||||
|
<!-- <executions>--> |
||||||
|
<!-- <execution>--> |
||||||
|
<!-- <id>sign-artifacts</id>--> |
||||||
|
<!-- <phase>verify</phase>--> |
||||||
|
<!-- <goals>--> |
||||||
|
<!-- <goal>sign</goal>--> |
||||||
|
<!-- </goals>--> |
||||||
|
<!-- </execution>--> |
||||||
|
<!-- </executions>--> |
||||||
|
<!-- </plugin>--> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-jar-plugin</artifactId> |
||||||
|
<version>2.3.1</version> |
||||||
|
<configuration> |
||||||
|
<classesDirectory>target/classes</classesDirectory> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
</plugins> |
||||||
|
</build> |
||||||
|
</profile> |
||||||
|
</profiles> |
||||||
|
</project> |
@ -0,0 +1,8 @@ |
|||||||
|
package com.mh.algorithm.bpnn; |
||||||
|
|
||||||
|
public interface ActivationFunction { |
||||||
|
//计算值
|
||||||
|
double computeValue(double val); |
||||||
|
//计算导数
|
||||||
|
double computeDerivative(double val); |
||||||
|
} |
@ -0,0 +1,111 @@ |
|||||||
|
package com.mh.algorithm.bpnn; |
||||||
|
|
||||||
|
import com.mh.algorithm.matrix.Matrix; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
public class BPModel implements Serializable { |
||||||
|
//BP神经网络权值与阈值
|
||||||
|
private Matrix weightIJ; |
||||||
|
private Matrix b1; |
||||||
|
private Matrix weightJP; |
||||||
|
private Matrix b2; |
||||||
|
/*用于反归一化*/ |
||||||
|
private Matrix inputMax; |
||||||
|
private Matrix inputMin; |
||||||
|
private Matrix outputMax; |
||||||
|
private Matrix outputMin; |
||||||
|
/*BP神经网络训练参数*/ |
||||||
|
private BPParameter bpParameter; |
||||||
|
/*BP神经网络训练情况*/ |
||||||
|
private double error; |
||||||
|
private int times; |
||||||
|
|
||||||
|
public Matrix getWeightIJ() { |
||||||
|
return weightIJ; |
||||||
|
} |
||||||
|
|
||||||
|
public void setWeightIJ(Matrix weightIJ) { |
||||||
|
this.weightIJ = weightIJ; |
||||||
|
} |
||||||
|
|
||||||
|
public Matrix getB1() { |
||||||
|
return b1; |
||||||
|
} |
||||||
|
|
||||||
|
public void setB1(Matrix b1) { |
||||||
|
this.b1 = b1; |
||||||
|
} |
||||||
|
|
||||||
|
public Matrix getWeightJP() { |
||||||
|
return weightJP; |
||||||
|
} |
||||||
|
|
||||||
|
public void setWeightJP(Matrix weightJP) { |
||||||
|
this.weightJP = weightJP; |
||||||
|
} |
||||||
|
|
||||||
|
public Matrix getB2() { |
||||||
|
return b2; |
||||||
|
} |
||||||
|
|
||||||
|
public void setB2(Matrix b2) { |
||||||
|
this.b2 = b2; |
||||||
|
} |
||||||
|
|
||||||
|
public Matrix getInputMax() { |
||||||
|
return inputMax; |
||||||
|
} |
||||||
|
|
||||||
|
public void setInputMax(Matrix inputMax) { |
||||||
|
this.inputMax = inputMax; |
||||||
|
} |
||||||
|
|
||||||
|
public Matrix getInputMin() { |
||||||
|
return inputMin; |
||||||
|
} |
||||||
|
|
||||||
|
public void setInputMin(Matrix inputMin) { |
||||||
|
this.inputMin = inputMin; |
||||||
|
} |
||||||
|
|
||||||
|
public Matrix getOutputMax() { |
||||||
|
return outputMax; |
||||||
|
} |
||||||
|
|
||||||
|
public void setOutputMax(Matrix outputMax) { |
||||||
|
this.outputMax = outputMax; |
||||||
|
} |
||||||
|
|
||||||
|
public Matrix getOutputMin() { |
||||||
|
return outputMin; |
||||||
|
} |
||||||
|
|
||||||
|
public void setOutputMin(Matrix outputMin) { |
||||||
|
this.outputMin = outputMin; |
||||||
|
} |
||||||
|
|
||||||
|
public BPParameter getBpParameter() { |
||||||
|
return bpParameter; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBpParameter(BPParameter bpParameter) { |
||||||
|
this.bpParameter = bpParameter; |
||||||
|
} |
||||||
|
|
||||||
|
public double getError() { |
||||||
|
return error; |
||||||
|
} |
||||||
|
|
||||||
|
public void setError(double error) { |
||||||
|
this.error = error; |
||||||
|
} |
||||||
|
|
||||||
|
public int getTimes() { |
||||||
|
return times; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTimes(int times) { |
||||||
|
this.times = times; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,262 @@ |
|||||||
|
package com.mh.algorithm.bpnn; |
||||||
|
|
||||||
|
import com.mh.algorithm.matrix.Matrix; |
||||||
|
import com.mh.algorithm.utils.MatrixUtil; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
public class BPNeuralNetworkFactory { |
||||||
|
/** |
||||||
|
* 训练BP神经网络模型 |
||||||
|
* @param bpParameter |
||||||
|
* @param inputAndOutput |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public BPModel trainBP(BPParameter bpParameter, Matrix inputAndOutput) throws Exception { |
||||||
|
|
||||||
|
ActivationFunction activationFunction = bpParameter.getActivationFunction(); |
||||||
|
int inputCount = bpParameter.getInputLayerNeuronCount(); |
||||||
|
int hiddenCount = bpParameter.getHiddenLayerNeuronCount(); |
||||||
|
int outputCount = bpParameter.getOutputLayerNeuronCount(); |
||||||
|
double normalizationMin = bpParameter.getNormalizationMin(); |
||||||
|
double normalizationMax = bpParameter.getNormalizationMax(); |
||||||
|
double step = bpParameter.getStep(); |
||||||
|
double momentumFactor = bpParameter.getMomentumFactor(); |
||||||
|
double precision = bpParameter.getPrecision(); |
||||||
|
int maxTimes = bpParameter.getMaxTimes(); |
||||||
|
|
||||||
|
if(inputAndOutput.getMatrixColCount() != inputCount + outputCount){ |
||||||
|
throw new Exception("神经元个数不符,请修改"); |
||||||
|
} |
||||||
|
// 初始化权值
|
||||||
|
Matrix weightIJ = initWeight(inputCount, hiddenCount); |
||||||
|
Matrix weightJP = initWeight(hiddenCount, outputCount); |
||||||
|
|
||||||
|
// 初始化阈值
|
||||||
|
Matrix b1 = initThreshold(hiddenCount); |
||||||
|
Matrix b2 = initThreshold(outputCount); |
||||||
|
|
||||||
|
// 动量项
|
||||||
|
Matrix deltaWeightIJ0 = new Matrix(inputCount, hiddenCount); |
||||||
|
Matrix deltaWeightJP0 = new Matrix(hiddenCount, outputCount); |
||||||
|
Matrix deltaB10 = new Matrix(1, hiddenCount); |
||||||
|
Matrix deltaB20 = new Matrix(1, outputCount); |
||||||
|
|
||||||
|
// 截取输入矩阵和输出矩阵
|
||||||
|
Matrix input = inputAndOutput.subMatrix(0,inputAndOutput.getMatrixRowCount(),0,inputCount); |
||||||
|
Matrix output = inputAndOutput.subMatrix(0,inputAndOutput.getMatrixRowCount(),inputCount,outputCount); |
||||||
|
|
||||||
|
// 归一化
|
||||||
|
Map<String,Object> inputAfterNormalize = MatrixUtil.normalize(input, normalizationMin, normalizationMax); |
||||||
|
input = (Matrix) inputAfterNormalize.get("res"); |
||||||
|
|
||||||
|
Map<String,Object> outputAfterNormalize = MatrixUtil.normalize(output, normalizationMin, normalizationMax); |
||||||
|
output = (Matrix) outputAfterNormalize.get("res"); |
||||||
|
|
||||||
|
int times = 1; |
||||||
|
double E = 0;//误差
|
||||||
|
while (times < maxTimes) { |
||||||
|
/*-----------------正向传播---------------------*/ |
||||||
|
// 隐含层输入
|
||||||
|
Matrix jIn = input.multiple(weightIJ); |
||||||
|
// 扩充阈值
|
||||||
|
Matrix b1Copy = b1.extend(2,jIn.getMatrixRowCount()); |
||||||
|
// 加上阈值
|
||||||
|
jIn = jIn.plus(b1Copy); |
||||||
|
// 隐含层输出
|
||||||
|
Matrix jOut = computeValue(jIn,activationFunction); |
||||||
|
// 输出层输入
|
||||||
|
Matrix pIn = jOut.multiple(weightJP); |
||||||
|
// 扩充阈值
|
||||||
|
Matrix b2Copy = b2.extend(2, pIn.getMatrixRowCount()); |
||||||
|
// 加上阈值
|
||||||
|
pIn = pIn.plus(b2Copy); |
||||||
|
// 输出层输出
|
||||||
|
Matrix pOut = computeValue(pIn,activationFunction); |
||||||
|
// 计算误差
|
||||||
|
Matrix e = output.subtract(pOut); |
||||||
|
E = computeE(e);//误差
|
||||||
|
// 判断是否符合精度
|
||||||
|
if (Math.abs(E) <= precision) { |
||||||
|
System.out.println("满足精度"); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
/*-----------------反向传播---------------------*/ |
||||||
|
// J与P之间权值修正量
|
||||||
|
Matrix deltaWeightJP = e.multiple(step); |
||||||
|
deltaWeightJP = deltaWeightJP.pointMultiple(computeDerivative(pIn,activationFunction)); |
||||||
|
deltaWeightJP = deltaWeightJP.transpose().multiple(jOut); |
||||||
|
deltaWeightJP = deltaWeightJP.transpose(); |
||||||
|
// P层神经元阈值修正量
|
||||||
|
Matrix deltaThresholdP = e.multiple(step); |
||||||
|
deltaThresholdP = deltaThresholdP.transpose().multiple(computeDerivative(pIn, activationFunction)); |
||||||
|
|
||||||
|
// I与J之间的权值修正量
|
||||||
|
Matrix deltaO = e.pointMultiple(computeDerivative(pIn,activationFunction)); |
||||||
|
Matrix tmp = weightJP.multiple(deltaO.transpose()).transpose(); |
||||||
|
Matrix deltaWeightIJ = tmp.pointMultiple(computeDerivative(jIn, activationFunction)); |
||||||
|
deltaWeightIJ = input.transpose().multiple(deltaWeightIJ); |
||||||
|
deltaWeightIJ = deltaWeightIJ.multiple(step); |
||||||
|
|
||||||
|
// J层神经元阈值修正量
|
||||||
|
Matrix deltaThresholdJ = tmp.transpose().multiple(computeDerivative(jIn, activationFunction)); |
||||||
|
deltaThresholdJ = deltaThresholdJ.multiple(-step); |
||||||
|
|
||||||
|
if (times == 1) { |
||||||
|
// 更新权值与阈值
|
||||||
|
weightIJ = weightIJ.plus(deltaWeightIJ); |
||||||
|
weightJP = weightJP.plus(deltaWeightJP); |
||||||
|
b1 = b1.plus(deltaThresholdJ); |
||||||
|
b2 = b2.plus(deltaThresholdP); |
||||||
|
}else{ |
||||||
|
// 加动量项
|
||||||
|
weightIJ = weightIJ.plus(deltaWeightIJ).plus(deltaWeightIJ0.multiple(momentumFactor)); |
||||||
|
weightJP = weightJP.plus(deltaWeightJP).plus(deltaWeightJP0.multiple(momentumFactor)); |
||||||
|
b1 = b1.plus(deltaThresholdJ).plus(deltaB10.multiple(momentumFactor)); |
||||||
|
b2 = b2.plus(deltaThresholdP).plus(deltaB20.multiple(momentumFactor)); |
||||||
|
} |
||||||
|
|
||||||
|
deltaWeightIJ0 = deltaWeightIJ; |
||||||
|
deltaWeightJP0 = deltaWeightJP; |
||||||
|
deltaB10 = deltaThresholdJ; |
||||||
|
deltaB20 = deltaThresholdP; |
||||||
|
|
||||||
|
times++; |
||||||
|
} |
||||||
|
|
||||||
|
// BP神经网络的输出
|
||||||
|
BPModel result = new BPModel(); |
||||||
|
result.setInputMax((Matrix) inputAfterNormalize.get("max")); |
||||||
|
result.setInputMin((Matrix) inputAfterNormalize.get("min")); |
||||||
|
result.setOutputMax((Matrix) outputAfterNormalize.get("max")); |
||||||
|
result.setOutputMin((Matrix) outputAfterNormalize.get("min")); |
||||||
|
result.setWeightIJ(weightIJ); |
||||||
|
result.setWeightJP(weightJP); |
||||||
|
result.setB1(b1); |
||||||
|
result.setB2(b2); |
||||||
|
result.setError(E); |
||||||
|
result.setTimes(times); |
||||||
|
result.setBpParameter(bpParameter); |
||||||
|
System.out.println("循环次数:" + times + ",误差:" + E); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 计算BP神经网络的值 |
||||||
|
* @param bpModel |
||||||
|
* @param input |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix computeBP(BPModel bpModel,Matrix input) throws Exception { |
||||||
|
if (input.getMatrixColCount() != bpModel.getBpParameter().getInputLayerNeuronCount()) { |
||||||
|
throw new Exception("输入矩阵纬度有误"); |
||||||
|
} |
||||||
|
ActivationFunction activationFunction = bpModel.getBpParameter().getActivationFunction(); |
||||||
|
Matrix weightIJ = bpModel.getWeightIJ(); |
||||||
|
Matrix weightJP = bpModel.getWeightJP(); |
||||||
|
Matrix b1 = bpModel.getB1(); |
||||||
|
Matrix b2 = bpModel.getB2(); |
||||||
|
double[][] normalizedInput = new double[input.getMatrixRowCount()][input.getMatrixColCount()]; |
||||||
|
for (int i = 0; i < input.getMatrixRowCount(); i++) { |
||||||
|
for (int j = 0; j < input.getMatrixColCount(); j++) { |
||||||
|
if ((input.getValOfIdx(i,j) - bpModel.getInputMin().getValOfIdx(0,j)) == 0 |
||||||
|
|| (bpModel.getInputMax().getValOfIdx(0,j) - bpModel.getInputMin().getValOfIdx(0,j)) == 0) { |
||||||
|
normalizedInput[i][j] = bpModel.getBpParameter().getNormalizationMin(); |
||||||
|
continue; |
||||||
|
} |
||||||
|
normalizedInput[i][j] = bpModel.getBpParameter().getNormalizationMin() |
||||||
|
+ (input.getValOfIdx(i,j) - bpModel.getInputMin().getValOfIdx(0,j)) |
||||||
|
/ (bpModel.getInputMax().getValOfIdx(0,j) - bpModel.getInputMin().getValOfIdx(0,j)) |
||||||
|
* (bpModel.getBpParameter().getNormalizationMax() - bpModel.getBpParameter().getNormalizationMin()); |
||||||
|
} |
||||||
|
} |
||||||
|
Matrix normalizedInputMatrix = new Matrix(normalizedInput); |
||||||
|
Matrix jIn = normalizedInputMatrix.multiple(weightIJ); |
||||||
|
// 扩充阈值
|
||||||
|
Matrix b1Copy = b1.extend(2,jIn.getMatrixRowCount()); |
||||||
|
// 加上阈值
|
||||||
|
jIn = jIn.plus(b1Copy); |
||||||
|
// 隐含层输出
|
||||||
|
Matrix jOut = computeValue(jIn,activationFunction); |
||||||
|
// 输出层输入
|
||||||
|
Matrix pIn = jOut.multiple(weightJP); |
||||||
|
// 扩充阈值
|
||||||
|
Matrix b2Copy = b2.extend(2,pIn.getMatrixRowCount()); |
||||||
|
// 加上阈值
|
||||||
|
pIn = pIn.plus(b2Copy); |
||||||
|
// 输出层输出
|
||||||
|
Matrix pOut = computeValue(pIn,activationFunction); |
||||||
|
// 反归一化
|
||||||
|
return MatrixUtil.inverseNormalize(pOut, bpModel.getBpParameter().getNormalizationMax(), bpModel.getBpParameter().getNormalizationMin(), bpModel.getOutputMax(), bpModel.getOutputMin()); |
||||||
|
} |
||||||
|
|
||||||
|
// 初始化权值
|
||||||
|
private Matrix initWeight(int x,int y){ |
||||||
|
Random random=new Random(); |
||||||
|
double[][] weight = new double[x][y]; |
||||||
|
for (int i = 0; i < x; i++) { |
||||||
|
for (int j = 0; j < y; j++) { |
||||||
|
weight[i][j] = 2*random.nextDouble()-1; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(weight); |
||||||
|
} |
||||||
|
// 初始化阈值
|
||||||
|
private Matrix initThreshold(int x){ |
||||||
|
Random random = new Random(); |
||||||
|
double[][] result = new double[1][x]; |
||||||
|
for (int i = 0; i < x; i++) { |
||||||
|
result[0][i] = 2*random.nextDouble()-1; |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 计算激活函数的值 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private Matrix computeValue(Matrix a, ActivationFunction activationFunction) throws Exception { |
||||||
|
if (a.getMatrix() == null) { |
||||||
|
throw new Exception("参数值为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[a.getMatrixRowCount()][a.getMatrixColCount()]; |
||||||
|
for (int i = 0; i < a.getMatrixRowCount(); i++) { |
||||||
|
for (int j = 0; j < a.getMatrixColCount(); j++) { |
||||||
|
result[i][j] = activationFunction.computeValue(a.getValOfIdx(i,j)); |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 激活函数导数的值 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private Matrix computeDerivative(Matrix a , ActivationFunction activationFunction) throws Exception { |
||||||
|
if (a.getMatrix() == null) { |
||||||
|
throw new Exception("参数值为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[a.getMatrixRowCount()][a.getMatrixColCount()]; |
||||||
|
for (int i = 0; i < a.getMatrixRowCount(); i++) { |
||||||
|
for (int j = 0; j < a.getMatrixColCount(); j++) { |
||||||
|
result[i][j] = activationFunction.computeDerivative(a.getValOfIdx(i,j)); |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 计算误差 |
||||||
|
* @param e |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private double computeE(Matrix e){ |
||||||
|
e = e.square(); |
||||||
|
return 0.5*e.sumAll(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,106 @@ |
|||||||
|
package com.mh.algorithm.bpnn; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
public class BPParameter implements Serializable { |
||||||
|
|
||||||
|
//输入层神经元个数
|
||||||
|
private int inputLayerNeuronCount = 3; |
||||||
|
//隐含层神经元个数
|
||||||
|
private int hiddenLayerNeuronCount = 3; |
||||||
|
//输出层神经元个数
|
||||||
|
private int outputLayerNeuronCount = 1; |
||||||
|
//归一化区间
|
||||||
|
private double normalizationMin = 0.2; |
||||||
|
private double normalizationMax = 0.8; |
||||||
|
//学习步长
|
||||||
|
private double step = 0.05; |
||||||
|
//动量因子
|
||||||
|
private double momentumFactor = 0.2; |
||||||
|
//激活函数
|
||||||
|
private ActivationFunction activationFunction = new Sigmoid(); |
||||||
|
//精度
|
||||||
|
private double precision = 0.000001; |
||||||
|
//最大循环次数
|
||||||
|
private int maxTimes = 1000000; |
||||||
|
|
||||||
|
public double getMomentumFactor() { |
||||||
|
return momentumFactor; |
||||||
|
} |
||||||
|
|
||||||
|
public void setMomentumFactor(double momentumFactor) { |
||||||
|
this.momentumFactor = momentumFactor; |
||||||
|
} |
||||||
|
|
||||||
|
public double getStep() { |
||||||
|
return step; |
||||||
|
} |
||||||
|
|
||||||
|
public void setStep(double step) { |
||||||
|
this.step = step; |
||||||
|
} |
||||||
|
|
||||||
|
public double getNormalizationMin() { |
||||||
|
return normalizationMin; |
||||||
|
} |
||||||
|
|
||||||
|
public void setNormalizationMin(double normalizationMin) { |
||||||
|
this.normalizationMin = normalizationMin; |
||||||
|
} |
||||||
|
|
||||||
|
public double getNormalizationMax() { |
||||||
|
return normalizationMax; |
||||||
|
} |
||||||
|
|
||||||
|
public void setNormalizationMax(double normalizationMax) { |
||||||
|
this.normalizationMax = normalizationMax; |
||||||
|
} |
||||||
|
|
||||||
|
public int getInputLayerNeuronCount() { |
||||||
|
return inputLayerNeuronCount; |
||||||
|
} |
||||||
|
|
||||||
|
public void setInputLayerNeuronCount(int inputLayerNeuronCount) { |
||||||
|
this.inputLayerNeuronCount = inputLayerNeuronCount; |
||||||
|
} |
||||||
|
|
||||||
|
public int getHiddenLayerNeuronCount() { |
||||||
|
return hiddenLayerNeuronCount; |
||||||
|
} |
||||||
|
|
||||||
|
public void setHiddenLayerNeuronCount(int hiddenLayerNeuronCount) { |
||||||
|
this.hiddenLayerNeuronCount = hiddenLayerNeuronCount; |
||||||
|
} |
||||||
|
|
||||||
|
public int getOutputLayerNeuronCount() { |
||||||
|
return outputLayerNeuronCount; |
||||||
|
} |
||||||
|
|
||||||
|
public void setOutputLayerNeuronCount(int outputLayerNeuronCount) { |
||||||
|
this.outputLayerNeuronCount = outputLayerNeuronCount; |
||||||
|
} |
||||||
|
|
||||||
|
public ActivationFunction getActivationFunction() { |
||||||
|
return activationFunction; |
||||||
|
} |
||||||
|
|
||||||
|
public void setActivationFunction(ActivationFunction activationFunction) { |
||||||
|
this.activationFunction = activationFunction; |
||||||
|
} |
||||||
|
|
||||||
|
public double getPrecision() { |
||||||
|
return precision; |
||||||
|
} |
||||||
|
|
||||||
|
public void setPrecision(double precision) { |
||||||
|
this.precision = precision; |
||||||
|
} |
||||||
|
|
||||||
|
public int getMaxTimes() { |
||||||
|
return maxTimes; |
||||||
|
} |
||||||
|
|
||||||
|
public void setMaxTimes(int maxTimes) { |
||||||
|
this.maxTimes = maxTimes; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
package com.mh.algorithm.bpnn; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
public class Sigmoid implements ActivationFunction, Serializable { |
||||||
|
@Override |
||||||
|
public double computeValue(double val) { |
||||||
|
return 1 / (1 + Math.exp(-val)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public double computeDerivative(double val) { |
||||||
|
return computeValue(val) * (1 - computeValue(val)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
package com.mh.algorithm.constants; |
||||||
|
|
||||||
|
/** |
||||||
|
* 排序枚举类 |
||||||
|
*/ |
||||||
|
public enum OrderEnum { |
||||||
|
|
||||||
|
ASC(1,"升序"), |
||||||
|
|
||||||
|
DESC(2,"降序"); |
||||||
|
|
||||||
|
OrderEnum(int flag, String name) { |
||||||
|
|
||||||
|
this.flag = flag; |
||||||
|
|
||||||
|
this.name = name; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private int flag; |
||||||
|
|
||||||
|
private String name; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
package com.mh.algorithm.knn; |
||||||
|
|
||||||
|
import com.mh.algorithm.constants.OrderEnum; |
||||||
|
import com.mh.algorithm.matrix.Matrix; |
||||||
|
import com.mh.algorithm.utils.MatrixUtil; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @program: top-algorithm-set |
||||||
|
* @description: KNN k-临近算法进行分类 |
||||||
|
* @author: Mr.Zhao |
||||||
|
* @create: 2020-10-13 22:03 |
||||||
|
**/ |
||||||
|
public class KNN { |
||||||
|
public static Matrix classify(Matrix input, Matrix dataSet, Matrix labels, int k) throws Exception { |
||||||
|
if (dataSet.getMatrixRowCount() != labels.getMatrixRowCount()) { |
||||||
|
throw new IllegalArgumentException("矩阵训练集与标签维度不一致"); |
||||||
|
} |
||||||
|
if (input.getMatrixColCount() != dataSet.getMatrixColCount()) { |
||||||
|
throw new IllegalArgumentException("待分类矩阵列数与训练集列数不一致"); |
||||||
|
} |
||||||
|
if (dataSet.getMatrixRowCount() < k) { |
||||||
|
throw new IllegalArgumentException("训练集样本数小于k"); |
||||||
|
} |
||||||
|
// 归一化
|
||||||
|
int trainCount = dataSet.getMatrixRowCount(); |
||||||
|
int testCount = input.getMatrixRowCount(); |
||||||
|
Matrix trainAndTest = dataSet.splice(2, input); |
||||||
|
Map<String, Object> normalize = MatrixUtil.normalize(trainAndTest, 0, 1); |
||||||
|
trainAndTest = (Matrix) normalize.get("res"); |
||||||
|
dataSet = trainAndTest.subMatrix(0, trainCount, 0, trainAndTest.getMatrixColCount()); |
||||||
|
input = trainAndTest.subMatrix(0, testCount, 0, trainAndTest.getMatrixColCount()); |
||||||
|
|
||||||
|
// 获取标签信息
|
||||||
|
List<Double> labelList = new ArrayList<>(); |
||||||
|
for (int i = 0; i < labels.getMatrixRowCount(); i++) { |
||||||
|
if (!labelList.contains(labels.getValOfIdx(i, 0))) { |
||||||
|
labelList.add(labels.getValOfIdx(i, 0)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Matrix result = new Matrix(new double[input.getMatrixRowCount()][1]); |
||||||
|
for (int i = 0; i < input.getMatrixRowCount(); i++) { |
||||||
|
// 计算向量间的欧式距离
|
||||||
|
// 将labels矩阵扩展
|
||||||
|
Matrix labelMatrixCopied = input.getRowOfIdx(i).extend(2, dataSet.getMatrixRowCount()); |
||||||
|
// 前面是计算欧氏距离,splice(1,labels)是将距离矩阵与labels矩阵合并
|
||||||
|
Matrix distanceMatrix = dataSet.subtract(labelMatrixCopied).square().sumRow().pow(0.5).splice(1, labels); |
||||||
|
// 将计算出的距离矩阵按照距离升序排序
|
||||||
|
distanceMatrix.sort(0, OrderEnum.ASC); |
||||||
|
// 遍历最近的k个变量
|
||||||
|
Map<Double, Integer> map = new HashMap<>(); |
||||||
|
for (int j = 0; j < k; j++) { |
||||||
|
// 遍历标签种类数
|
||||||
|
for (Double label : labelList) { |
||||||
|
if (distanceMatrix.getValOfIdx(j, 1) == label) { |
||||||
|
map.put(label, map.getOrDefault(label, 0) + 1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
result.setValue(i, 0, getKeyOfMaxValue(map)); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 取map中值最大的key |
||||||
|
* |
||||||
|
* @param map |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private static Double getKeyOfMaxValue(Map<Double, Integer> map) { |
||||||
|
if (map == null) |
||||||
|
return null; |
||||||
|
Double keyOfMaxValue = 0.0; |
||||||
|
Integer maxValue = 0; |
||||||
|
for (Double key : map.keySet()) { |
||||||
|
if (map.get(key) > maxValue) { |
||||||
|
keyOfMaxValue = key; |
||||||
|
maxValue = map.get(key); |
||||||
|
} |
||||||
|
} |
||||||
|
return keyOfMaxValue; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,646 @@ |
|||||||
|
package com.mh.algorithm.matrix; |
||||||
|
|
||||||
|
import com.mh.algorithm.constants.OrderEnum; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
public class Matrix implements Serializable { |
||||||
|
private double[][] matrix; |
||||||
|
//矩阵列数
|
||||||
|
private int matrixColCount; |
||||||
|
//矩阵行数
|
||||||
|
private int matrixRowCount; |
||||||
|
|
||||||
|
/** |
||||||
|
* 构造一个空矩阵 |
||||||
|
*/ |
||||||
|
public Matrix() { |
||||||
|
this.matrix = null; |
||||||
|
this.matrixColCount = 0; |
||||||
|
this.matrixRowCount = 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 构造一个matrix矩阵 |
||||||
|
* @param matrix |
||||||
|
*/ |
||||||
|
public Matrix(double[][] matrix) { |
||||||
|
this.matrix = matrix; |
||||||
|
this.matrixRowCount = matrix.length; |
||||||
|
this.matrixColCount = matrix[0].length; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 构造一个rowCount行colCount列值为0的矩阵 |
||||||
|
* @param rowCount |
||||||
|
* @param colCount |
||||||
|
*/ |
||||||
|
public Matrix(int rowCount,int colCount) { |
||||||
|
double[][] matrix = new double[rowCount][colCount]; |
||||||
|
for (int i = 0; i < rowCount; i++) { |
||||||
|
for (int j = 0; j < colCount; j++) { |
||||||
|
matrix[i][j] = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
this.matrix = matrix; |
||||||
|
this.matrixRowCount = rowCount; |
||||||
|
this.matrixColCount = colCount; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 构造一个rowCount行colCount列值为val的矩阵 |
||||||
|
* @param val |
||||||
|
* @param rowCount |
||||||
|
* @param colCount |
||||||
|
*/ |
||||||
|
public Matrix(double val,int rowCount,int colCount) { |
||||||
|
double[][] matrix = new double[rowCount][colCount]; |
||||||
|
for (int i = 0; i < rowCount; i++) { |
||||||
|
for (int j = 0; j < colCount; j++) { |
||||||
|
matrix[i][j] = val; |
||||||
|
} |
||||||
|
} |
||||||
|
this.matrix = matrix; |
||||||
|
this.matrixRowCount = rowCount; |
||||||
|
this.matrixColCount = colCount; |
||||||
|
} |
||||||
|
|
||||||
|
public double[][] getMatrix() { |
||||||
|
return matrix; |
||||||
|
} |
||||||
|
|
||||||
|
public void setMatrix(double[][] matrix) { |
||||||
|
this.matrix = matrix; |
||||||
|
this.matrixRowCount = matrix.length; |
||||||
|
this.matrixColCount = matrix[0].length; |
||||||
|
} |
||||||
|
|
||||||
|
public int getMatrixColCount() { |
||||||
|
return matrixColCount; |
||||||
|
} |
||||||
|
|
||||||
|
public int getMatrixRowCount() { |
||||||
|
return matrixRowCount; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取矩阵指定位置的值 |
||||||
|
* |
||||||
|
* @param x |
||||||
|
* @param y |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public double getValOfIdx(int x, int y) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
if (x > matrixRowCount - 1) { |
||||||
|
throw new IllegalArgumentException("索引x越界"); |
||||||
|
} |
||||||
|
if (y > matrixColCount - 1) { |
||||||
|
throw new IllegalArgumentException("索引y越界"); |
||||||
|
} |
||||||
|
return matrix[x][y]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取矩阵指定行 |
||||||
|
* |
||||||
|
* @param x |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix getRowOfIdx(int x) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
if (x > matrixRowCount - 1) { |
||||||
|
throw new IllegalArgumentException("索引x越界"); |
||||||
|
} |
||||||
|
double[][] result = new double[1][matrixColCount]; |
||||||
|
result[0] = matrix[x]; |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取矩阵指定列 |
||||||
|
* |
||||||
|
* @param y |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix getColOfIdx(int y) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
if (y > matrixColCount - 1) { |
||||||
|
throw new IllegalArgumentException("索引y越界"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][1]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
result[i][0] = matrix[i][y]; |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 设置矩阵中x,y位置元素的值 |
||||||
|
* @param x |
||||||
|
* @param y |
||||||
|
* @param val |
||||||
|
*/ |
||||||
|
public void setValue(int x, int y, double val) { |
||||||
|
if (x > this.matrixRowCount - 1) { |
||||||
|
throw new IllegalArgumentException("行索引越界"); |
||||||
|
} |
||||||
|
if (y > this.matrixColCount - 1) { |
||||||
|
throw new IllegalArgumentException("列索引越界"); |
||||||
|
} |
||||||
|
this.matrix[x][y] = val; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵乘矩阵 |
||||||
|
* |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws IllegalArgumentException |
||||||
|
*/ |
||||||
|
public Matrix multiple(Matrix a) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
if (a.getMatrix() == null || a.getMatrixRowCount() == 0 || a.getMatrixColCount() == 0) { |
||||||
|
throw new IllegalArgumentException("参数矩阵为空"); |
||||||
|
} |
||||||
|
if (matrixColCount != a.getMatrixRowCount()) { |
||||||
|
throw new IllegalArgumentException("矩阵纬度不同,不可计算"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][a.getMatrixColCount()]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < a.getMatrixColCount(); j++) { |
||||||
|
for (int k = 0; k < matrixColCount; k++) { |
||||||
|
result[i][j] = result[i][j] + matrix[i][k] * a.getMatrix()[k][j]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵乘一个数字 |
||||||
|
* |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix multiple(double a) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[i][j] = matrix[i][j] * a; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵点乘 |
||||||
|
* |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix pointMultiple(Matrix a) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
if (a.getMatrix() == null || a.getMatrixRowCount() == 0 || a.getMatrixColCount() == 0) { |
||||||
|
throw new IllegalArgumentException("参数矩阵为空"); |
||||||
|
} |
||||||
|
if (matrixRowCount != a.getMatrixRowCount() && matrixColCount != a.getMatrixColCount()) { |
||||||
|
throw new IllegalArgumentException("矩阵纬度不同,不可计算"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[i][j] = matrix[i][j] * a.getMatrix()[i][j]; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵除一个数字 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws IllegalArgumentException |
||||||
|
*/ |
||||||
|
public Matrix divide(double a) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[i][j] = matrix[i][j] / a; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵加法 |
||||||
|
* |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix plus(Matrix a) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
if (a.getMatrix() == null || a.getMatrixRowCount() == 0 || a.getMatrixColCount() == 0) { |
||||||
|
throw new IllegalArgumentException("参数矩阵为空"); |
||||||
|
} |
||||||
|
if (matrixRowCount != a.getMatrixRowCount() && matrixColCount != a.getMatrixColCount()) { |
||||||
|
throw new IllegalArgumentException("矩阵纬度不同,不可计算"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[i][j] = matrix[i][j] + a.getMatrix()[i][j]; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵加一个数字 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws IllegalArgumentException |
||||||
|
*/ |
||||||
|
public Matrix plus(double a) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[i][j] = matrix[i][j] + a; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵减法 |
||||||
|
* |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix subtract(Matrix a) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
if (a.getMatrix() == null || a.getMatrixRowCount() == 0 || a.getMatrixColCount() == 0) { |
||||||
|
throw new IllegalArgumentException("参数矩阵为空"); |
||||||
|
} |
||||||
|
if (matrixRowCount != a.getMatrixRowCount() && matrixColCount != a.getMatrixColCount()) { |
||||||
|
throw new IllegalArgumentException("矩阵纬度不同,不可计算"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[i][j] = matrix[i][j] - a.getMatrix()[i][j]; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵减一个数字 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws IllegalArgumentException |
||||||
|
*/ |
||||||
|
public Matrix subtract(double a) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[i][j] = matrix[i][j] - a; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵行求和 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix sumRow() throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][1]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[i][0] += matrix[i][j]; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵列求和 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix sumCol() throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[1][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[0][j] += matrix[i][j]; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵所有元素求和 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public double sumAll() throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
double result = 0; |
||||||
|
for (double[] doubles : matrix) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result += doubles[j]; |
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵所有元素求平方 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix square() throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[i][j] = matrix[i][j] * matrix[i][j]; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵所有元素求N次方 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix pow(double n) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[i][j] = Math.pow(matrix[i][j],n); |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵转置 |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Matrix transpose() throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixColCount][matrixRowCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
result[j][i] = matrix[i][j]; |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 截取矩阵 |
||||||
|
* @param startRowIndex 开始行索引 |
||||||
|
* @param rowCount 截取行数 |
||||||
|
* @param startColIndex 开始列索引 |
||||||
|
* @param colCount 截取列数 |
||||||
|
* @return |
||||||
|
* @throws IllegalArgumentException |
||||||
|
*/ |
||||||
|
public Matrix subMatrix(int startRowIndex,int rowCount,int startColIndex,int colCount) throws IllegalArgumentException { |
||||||
|
if (startRowIndex + rowCount > matrixRowCount) { |
||||||
|
throw new IllegalArgumentException("行索引越界"); |
||||||
|
} |
||||||
|
if (startColIndex + colCount> matrixColCount) { |
||||||
|
throw new IllegalArgumentException("列索引越界"); |
||||||
|
} |
||||||
|
double[][] result = new double[rowCount][colCount]; |
||||||
|
for (int i = startRowIndex; i < startRowIndex + rowCount; i++) { |
||||||
|
if (startColIndex + colCount - startColIndex >= 0) |
||||||
|
System.arraycopy(matrix[i], startColIndex, result[i - startRowIndex], 0, colCount); |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵合并 |
||||||
|
* @param direction 合并方向,1为横向,2为竖向 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws IllegalArgumentException |
||||||
|
*/ |
||||||
|
public Matrix splice(int direction, Matrix a) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
if (a.getMatrix() == null || a.getMatrixRowCount() == 0 || a.getMatrixColCount() == 0) { |
||||||
|
throw new IllegalArgumentException("参数矩阵为空"); |
||||||
|
} |
||||||
|
if(direction == 1){ |
||||||
|
//横向拼接
|
||||||
|
if (matrixRowCount != a.getMatrixRowCount()) { |
||||||
|
throw new IllegalArgumentException("矩阵行数不一致,无法拼接"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount + a.getMatrixColCount()]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
System.arraycopy(matrix[i],0,result[i],0,matrixColCount); |
||||||
|
System.arraycopy(a.getMatrix()[i],0,result[i],matrixColCount,a.getMatrixColCount()); |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
}else if(direction == 2){ |
||||||
|
//纵向拼接
|
||||||
|
if (matrixColCount != a.getMatrixColCount()) { |
||||||
|
throw new IllegalArgumentException("矩阵列数不一致,无法拼接"); |
||||||
|
} |
||||||
|
double[][] result = new double[matrixRowCount + a.getMatrixRowCount()][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
result[i] = matrix[i]; |
||||||
|
} |
||||||
|
for (int i = 0; i < a.getMatrixRowCount(); i++) { |
||||||
|
result[matrixRowCount + i] = a.getMatrix()[i]; |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
}else{ |
||||||
|
throw new IllegalArgumentException("方向参数有误"); |
||||||
|
} |
||||||
|
} |
||||||
|
/** |
||||||
|
* 扩展矩阵 |
||||||
|
* @param direction 扩展方向,1为横向,2为竖向 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws IllegalArgumentException |
||||||
|
*/ |
||||||
|
public Matrix extend(int direction , int a) throws IllegalArgumentException { |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
if(direction == 1){ |
||||||
|
//横向复制
|
||||||
|
double[][] result = new double[matrixRowCount][matrixColCount*a]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < a; j++) { |
||||||
|
System.arraycopy(matrix[i],0,result[i],j*matrixColCount,matrixColCount); |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
}else if(direction == 2){ |
||||||
|
//纵向复制
|
||||||
|
double[][] result = new double[matrixRowCount*a][matrixColCount]; |
||||||
|
for (int i = 0; i < matrixRowCount*a; i++) { |
||||||
|
result[i] = matrix[i%matrixRowCount]; |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
}else{ |
||||||
|
throw new IllegalArgumentException("方向参数有误"); |
||||||
|
} |
||||||
|
} |
||||||
|
/** |
||||||
|
* 获取每列的平均值 |
||||||
|
* @return |
||||||
|
* @throws IllegalArgumentException |
||||||
|
*/ |
||||||
|
public Matrix getColAvg() throws IllegalArgumentException { |
||||||
|
Matrix tmp = this.sumCol(); |
||||||
|
return tmp.divide(matrixRowCount); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵行排序 |
||||||
|
* @param index 根据第几列的数进行行排序 |
||||||
|
* @param order 排序顺序,升序或降序 |
||||||
|
* @return |
||||||
|
* @throws IllegalArgumentException |
||||||
|
*/ |
||||||
|
public void sort(int index, OrderEnum order) throws IllegalArgumentException{ |
||||||
|
if (matrix == null || matrixRowCount == 0 || matrixColCount == 0) { |
||||||
|
throw new IllegalArgumentException("矩阵为空"); |
||||||
|
} |
||||||
|
if(index >= matrixColCount){ |
||||||
|
throw new IllegalArgumentException("排序索引index越界"); |
||||||
|
} |
||||||
|
sort(index,order,0,this.matrixRowCount - 1); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 判断是否是方阵 |
||||||
|
* 行列数相等,并且不等于0 |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public boolean isSquareMatrix(){ |
||||||
|
return matrixColCount == matrixRowCount && matrixColCount != 0; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
StringBuilder stringBuilder = new StringBuilder(); |
||||||
|
stringBuilder.append("\r\n"); |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
stringBuilder.append("# "); |
||||||
|
for (int j = 0; j < matrixColCount; j++) { |
||||||
|
stringBuilder.append(matrix[i][j]).append("\t "); |
||||||
|
} |
||||||
|
stringBuilder.append("#\r\n"); |
||||||
|
} |
||||||
|
stringBuilder.append("\r\n"); |
||||||
|
return stringBuilder.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
private void sort(int index,OrderEnum order,int start,int end){ |
||||||
|
if(start >= end){ |
||||||
|
return; |
||||||
|
} |
||||||
|
int tmp = partition(index,order,start,end); |
||||||
|
sort(index,order, start, tmp - 1); |
||||||
|
sort(index,order, tmp + 1, end); |
||||||
|
} |
||||||
|
|
||||||
|
private int partition(int index,OrderEnum order,int start,int end){ |
||||||
|
int l = start + 1,r = end; |
||||||
|
double v = matrix[start][index]; |
||||||
|
switch (order){ |
||||||
|
case ASC: |
||||||
|
while(true){ |
||||||
|
while(matrix[r][index] >= v && r > start){ |
||||||
|
r--; |
||||||
|
} |
||||||
|
while(matrix[l][index] <= v && l < end){ |
||||||
|
l++; |
||||||
|
} |
||||||
|
if(l >= r){ |
||||||
|
break; |
||||||
|
} |
||||||
|
double[] tmp = matrix[r]; |
||||||
|
matrix[r] = matrix[l]; |
||||||
|
matrix[l] = tmp; |
||||||
|
} |
||||||
|
break; |
||||||
|
case DESC: |
||||||
|
while(true){ |
||||||
|
while(matrix[r][index] <= v && r > start){ |
||||||
|
r--; |
||||||
|
} |
||||||
|
while(matrix[l][index] >= v && l < end){ |
||||||
|
l++; |
||||||
|
} |
||||||
|
if(l >= r){ |
||||||
|
break; |
||||||
|
} |
||||||
|
double[] tmp = matrix[r]; |
||||||
|
matrix[r] = matrix[l]; |
||||||
|
matrix[l] = tmp; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
double[] tmp = matrix[r]; |
||||||
|
matrix[r] = matrix[start]; |
||||||
|
matrix[start] = tmp; |
||||||
|
return r; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
package com.mh.algorithm.utils; |
||||||
|
|
||||||
|
import com.mh.algorithm.matrix.Matrix; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
|
||||||
|
public class CsvInfo { |
||||||
|
private String[] header; |
||||||
|
private int csvRowCount; |
||||||
|
private int csvColCount; |
||||||
|
private ArrayList<String[]> csvFileList; |
||||||
|
|
||||||
|
public String[] getHeader() { |
||||||
|
return header; |
||||||
|
} |
||||||
|
|
||||||
|
public void setHeader(String[] header) { |
||||||
|
this.header = header; |
||||||
|
} |
||||||
|
|
||||||
|
public int getCsvRowCount() { |
||||||
|
return csvRowCount; |
||||||
|
} |
||||||
|
|
||||||
|
public int getCsvColCount() { |
||||||
|
return csvColCount; |
||||||
|
} |
||||||
|
|
||||||
|
public ArrayList<String[]> getCsvFileList() { |
||||||
|
return csvFileList; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCsvFileList(ArrayList<String[]> csvFileList) { |
||||||
|
this.csvFileList = csvFileList; |
||||||
|
this.csvColCount = csvFileList.get(0) != null?csvFileList.get(0).length:0; |
||||||
|
this.csvRowCount = csvFileList.size(); |
||||||
|
} |
||||||
|
|
||||||
|
public Matrix toMatrix() throws Exception { |
||||||
|
double[][] arr = new double[csvFileList.size()][csvFileList.get(0).length]; |
||||||
|
for (int i = 0; i < csvFileList.size(); i++) { |
||||||
|
for (int j = 0; j < csvFileList.get(0).length; j++) { |
||||||
|
try { |
||||||
|
arr[i][j] = Double.parseDouble(csvFileList.get(i)[j]); |
||||||
|
}catch (NumberFormatException e){ |
||||||
|
throw new Exception("Csv中含有非数字字符,无法转换成Matrix对象"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(arr); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
package com.mh.algorithm.utils; |
||||||
|
|
||||||
|
import com.csvreader.CsvReader; |
||||||
|
import com.csvreader.CsvWriter; |
||||||
|
import com.mh.algorithm.matrix.Matrix; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.ArrayList; |
||||||
|
|
||||||
|
public class CsvUtil { |
||||||
|
/** |
||||||
|
* 获取CSV中的信息 |
||||||
|
* @param hasHeader 是否含有表头 |
||||||
|
* @param path CSV文件的路径 |
||||||
|
* @return |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public static CsvInfo getCsvInfo(boolean hasHeader , String path) throws IOException { |
||||||
|
//创建csv对象,存储csv中的信息
|
||||||
|
CsvInfo csvInfo = new CsvInfo(); |
||||||
|
//获取CsvReader流
|
||||||
|
CsvReader csvReader = new CsvReader(path, ',', StandardCharsets.UTF_8); |
||||||
|
if(hasHeader){ |
||||||
|
csvReader.readHeaders(); |
||||||
|
} |
||||||
|
//获取Csv中的所有记录
|
||||||
|
ArrayList<String[]> csvFileList = new ArrayList<String[]>(); |
||||||
|
while (csvReader.readRecord()) { |
||||||
|
csvFileList.add(csvReader.getValues()); |
||||||
|
} |
||||||
|
//赋值
|
||||||
|
csvInfo.setHeader(csvReader.getHeaders()); |
||||||
|
csvInfo.setCsvFileList(csvFileList); |
||||||
|
//关闭流
|
||||||
|
csvReader.close(); |
||||||
|
return csvInfo; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 将矩阵写入到csv文件中 |
||||||
|
* @param header 表头 |
||||||
|
* @param data 以矩阵形式存放的数据 |
||||||
|
* @param path 写入的文件地址 |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public static void createCsvFile(String[] header,Matrix data,String path) throws Exception { |
||||||
|
|
||||||
|
if (header!=null && header.length != data.getMatrixColCount()) { |
||||||
|
throw new Exception("表头列数与数据列数不符"); |
||||||
|
} |
||||||
|
CsvWriter csvWriter = new CsvWriter(path, ',', StandardCharsets.UTF_8); |
||||||
|
|
||||||
|
if (header != null) { |
||||||
|
csvWriter.writeRecord(header); |
||||||
|
} |
||||||
|
for (int i = 0; i < data.getMatrixRowCount(); i++) { |
||||||
|
String[] record = new String[data.getMatrixColCount()]; |
||||||
|
for (int j = 0; j < data.getMatrixColCount(); j++) { |
||||||
|
record[j] = data.getValOfIdx(i, j)+""; |
||||||
|
} |
||||||
|
csvWriter.writeRecord(record); |
||||||
|
} |
||||||
|
csvWriter.close(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package com.mh.algorithm.utils; |
||||||
|
|
||||||
|
/** |
||||||
|
* @program: top-algorithm-set |
||||||
|
* @description: DoubleTool |
||||||
|
* @author: Mr.Zhao |
||||||
|
* @create: 2020-11-12 21:54 |
||||||
|
**/ |
||||||
|
public class DoubleUtil { |
||||||
|
|
||||||
|
private static final Double MAX_ERROR = 0.0001; |
||||||
|
|
||||||
|
public static boolean equals(Double a, Double b) { |
||||||
|
return Math.abs(a - b)< MAX_ERROR; |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean equals(Double a, Double b,Double maxError) { |
||||||
|
return Math.abs(a - b)< maxError; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,297 @@ |
|||||||
|
package com.mh.algorithm.utils; |
||||||
|
|
||||||
|
import Jama.EigenvalueDecomposition; |
||||||
|
import com.mh.algorithm.matrix.Matrix; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
public class MatrixUtil { |
||||||
|
/** |
||||||
|
* 创建一个单位矩阵 |
||||||
|
* @param matrixRowCount 单位矩阵的纬度 |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static Matrix eye(int matrixRowCount){ |
||||||
|
double[][] result = new double[matrixRowCount][matrixRowCount]; |
||||||
|
for (int i = 0; i < matrixRowCount; i++) { |
||||||
|
for (int j = 0; j < matrixRowCount; j++) { |
||||||
|
if(i == j){ |
||||||
|
result[i][j] = 1; |
||||||
|
}else{ |
||||||
|
result[i][j] = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 求矩阵的逆 |
||||||
|
* 原理:AE=EA^-1 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public static Matrix inv(Matrix a) throws Exception { |
||||||
|
if (!invable(a)) { |
||||||
|
throw new Exception("矩阵不可逆"); |
||||||
|
} |
||||||
|
// [a|E]
|
||||||
|
Matrix b = a.splice(1, eye(a.getMatrixRowCount())); |
||||||
|
double[][] data = b.getMatrix(); |
||||||
|
int rowCount = b.getMatrixRowCount(); |
||||||
|
int colCount = b.getMatrixColCount(); |
||||||
|
//此处应用a的列数,为简化,直接用b的行数
|
||||||
|
for (int j = 0; j < rowCount; j++) { |
||||||
|
//若遇到0则交换两行
|
||||||
|
int notZeroRow = -2; |
||||||
|
if(data[j][j] == 0){ |
||||||
|
notZeroRow = -1; |
||||||
|
for (int l = j; l < rowCount; l++) { |
||||||
|
if (data[l][j] != 0) { |
||||||
|
notZeroRow = l; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (notZeroRow == -1) { |
||||||
|
throw new Exception("矩阵不可逆"); |
||||||
|
}else if(notZeroRow != -2){ |
||||||
|
//交换j与notZeroRow两行
|
||||||
|
double[] tmp = data[j]; |
||||||
|
data[j] = data[notZeroRow]; |
||||||
|
data[notZeroRow] = tmp; |
||||||
|
} |
||||||
|
//将第data[j][j]化为1
|
||||||
|
if (data[j][j] != 1) { |
||||||
|
double multiple = data[j][j]; |
||||||
|
for (int colIdx = j; colIdx < colCount; colIdx++) { |
||||||
|
data[j][colIdx] /= multiple; |
||||||
|
} |
||||||
|
} |
||||||
|
//行与行相减
|
||||||
|
for (int i = 0; i < rowCount; i++) { |
||||||
|
if (i != j) { |
||||||
|
double multiple = data[i][j] / data[j][j]; |
||||||
|
//遍历行中的列
|
||||||
|
for (int k = j; k < colCount; k++) { |
||||||
|
data[i][k] = data[i][k] - multiple * data[j][k]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
Matrix result = new Matrix(data); |
||||||
|
return result.subMatrix(0, rowCount, rowCount, rowCount); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 求矩阵的伴随矩阵 |
||||||
|
* 原理:A*=|A|A^-1 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public static Matrix adj(Matrix a) throws Exception { |
||||||
|
return inv(a).multiple(det(a)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 矩阵转成上三角矩阵 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public static Matrix getTopTriangle(Matrix a) throws Exception { |
||||||
|
if (!a.isSquareMatrix()) { |
||||||
|
throw new Exception("不是方阵无法进行计算"); |
||||||
|
} |
||||||
|
int matrixHeight = a.getMatrixRowCount(); |
||||||
|
double[][] result = a.getMatrix(); |
||||||
|
//遍历列
|
||||||
|
for (int j = 0; j < matrixHeight; j++) { |
||||||
|
//遍历行
|
||||||
|
for (int i = j+1; i < matrixHeight; i++) { |
||||||
|
//若遇到0则交换两行
|
||||||
|
int notZeroRow = -2; |
||||||
|
if(result[j][j] == 0){ |
||||||
|
notZeroRow = -1; |
||||||
|
for (int l = i; l < matrixHeight; l++) { |
||||||
|
if (result[l][j] != 0) { |
||||||
|
notZeroRow = l; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (notZeroRow == -1) { |
||||||
|
throw new Exception("矩阵不可逆"); |
||||||
|
}else if(notZeroRow != -2){ |
||||||
|
//交换j与notZeroRow两行
|
||||||
|
double[] tmp = result[j]; |
||||||
|
result[j] = result[notZeroRow]; |
||||||
|
result[notZeroRow] = tmp; |
||||||
|
} |
||||||
|
|
||||||
|
double multiple = result[i][j]/result[j][j]; |
||||||
|
//遍历行中的列
|
||||||
|
for (int k = j; k < matrixHeight; k++) { |
||||||
|
result[i][k] = result[i][k] - multiple * result[j][k]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 计算矩阵的行列式 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public static double det(Matrix a) throws Exception { |
||||||
|
//将矩阵转成上三角矩阵
|
||||||
|
Matrix b = MatrixUtil.getTopTriangle(a); |
||||||
|
double result = 1; |
||||||
|
//计算矩阵行列式
|
||||||
|
for (int i = 0; i < b.getMatrixRowCount(); i++) { |
||||||
|
result *= b.getValOfIdx(i, i); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
/** |
||||||
|
* 获取协方差矩阵 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public static Matrix cov(Matrix a) throws Exception { |
||||||
|
if (a.getMatrix() == null) { |
||||||
|
throw new Exception("矩阵为空"); |
||||||
|
} |
||||||
|
Matrix avg = a.getColAvg().extend(2, a.getMatrixRowCount()); |
||||||
|
Matrix tmp = a.subtract(avg); |
||||||
|
return tmp.transpose().multiple(tmp).multiple(1/((double) a.getMatrixRowCount() -1)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 判断矩阵是否可逆 |
||||||
|
* 如果可转为上三角矩阵则可逆 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static boolean invable(Matrix a) { |
||||||
|
try { |
||||||
|
getTopTriangle(a); |
||||||
|
return true; |
||||||
|
} catch (Exception e) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取矩阵的特征值矩阵,调用Jama中的getV方法 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static Matrix getV(Matrix a) { |
||||||
|
EigenvalueDecomposition eig = new EigenvalueDecomposition(new Jama.Matrix(a.getMatrix())); |
||||||
|
return new Matrix(eig.getV().getArray()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 取特征值实部 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public double[] getRealEigenvalues(Matrix a){ |
||||||
|
EigenvalueDecomposition eig = new EigenvalueDecomposition(new Jama.Matrix(a.getMatrix())); |
||||||
|
return eig.getRealEigenvalues(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 取特征值虚部 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public double[] getImagEigenvalues(Matrix a){ |
||||||
|
EigenvalueDecomposition eig = new EigenvalueDecomposition(new Jama.Matrix(a.getMatrix())); |
||||||
|
return eig.getImagEigenvalues(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 取块对角特征值矩阵 |
||||||
|
* @param a |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static Matrix getD(Matrix a) { |
||||||
|
EigenvalueDecomposition eig = new EigenvalueDecomposition(new Jama.Matrix(a.getMatrix())); |
||||||
|
return new Matrix(eig.getD().getArray()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 数据归一化 |
||||||
|
* @param a 要归一化的数据 |
||||||
|
* @param normalizationMin 要归一化的区间下限 |
||||||
|
* @param normalizationMax 要归一化的区间上限 |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static Map<String, Object> normalize(Matrix a, double normalizationMin, double normalizationMax) throws Exception { |
||||||
|
HashMap<String, Object> result = new HashMap<>(); |
||||||
|
double[][] maxArr = new double[1][a.getMatrixColCount()]; |
||||||
|
double[][] minArr = new double[1][a.getMatrixColCount()]; |
||||||
|
double[][] res = new double[a.getMatrixRowCount()][a.getMatrixColCount()]; |
||||||
|
for (int i = 0; i < a.getMatrixColCount(); i++) { |
||||||
|
List tmp = new ArrayList(); |
||||||
|
for (int j = 0; j < a.getMatrixRowCount(); j++) { |
||||||
|
tmp.add(a.getValOfIdx(j,i)); |
||||||
|
} |
||||||
|
double max = (double) Collections.max(tmp); |
||||||
|
double min = (double) Collections.min(tmp); |
||||||
|
//数据归一化(注:若max与min均为0则不需要归一化)
|
||||||
|
if (max != 0 || min != 0) { |
||||||
|
for (int j = 0; j < a.getMatrixRowCount(); j++) { |
||||||
|
try { |
||||||
|
if ((a.getValOfIdx(j,i) - min) == 0 || (max - min) == 0) { |
||||||
|
res[j][i] = normalizationMin; |
||||||
|
continue; |
||||||
|
} |
||||||
|
res[j][i] = normalizationMin + (a.getValOfIdx(j,i) - min) / (max - min) * (normalizationMax - normalizationMin); |
||||||
|
} catch (IllegalArgumentException e) { |
||||||
|
res[j][i] = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
maxArr[0][i] = max; |
||||||
|
minArr[0][i] = min; |
||||||
|
} |
||||||
|
result.put("max", new Matrix(maxArr)); |
||||||
|
result.put("min", new Matrix(minArr)); |
||||||
|
result.put("res", new Matrix(res)); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 反归一化 |
||||||
|
* @param a 要反归一化的数据 |
||||||
|
* @param normalizationMin 要反归一化的区间下限 |
||||||
|
* @param normalizationMax 要反归一化的区间上限 |
||||||
|
* @param dataMax 数据最大值 |
||||||
|
* @param dataMin 数据最小值 |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static Matrix inverseNormalize(Matrix a, double normalizationMax, double normalizationMin , Matrix dataMax,Matrix dataMin){ |
||||||
|
double[][] res = new double[a.getMatrixRowCount()][a.getMatrixColCount()]; |
||||||
|
for (int i = 0; i < a.getMatrixColCount(); i++) { |
||||||
|
//数据反归一化
|
||||||
|
if (dataMin.getValOfIdx(0,i) != 0 || dataMax.getValOfIdx(0,i) != 0) { |
||||||
|
for (int j = 0; j < a.getMatrixRowCount(); j++) { |
||||||
|
if ((a.getValOfIdx(j,i) - normalizationMin) == 0 || (normalizationMax - normalizationMin) == 0) { |
||||||
|
res[j][i] = dataMin.getValOfIdx(0,i); |
||||||
|
continue; |
||||||
|
} |
||||||
|
res[j][i] = dataMin.getValOfIdx(0,i) + (dataMax.getValOfIdx(0,i) - dataMin.getValOfIdx(0,i)) * (a.getValOfIdx(j,i) - normalizationMin) / (normalizationMax - normalizationMin); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return new Matrix(res); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
package com.mh.algorithm.utils; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
|
||||||
|
public class SerializationUtil { |
||||||
|
/** |
||||||
|
* 对象序列化到本地 |
||||||
|
* @param object |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
public static void serialize(Object object, String path) throws IOException { |
||||||
|
File file = new File(path); |
||||||
|
System.out.println(file.getAbsolutePath()); |
||||||
|
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file)); |
||||||
|
out.writeObject(object); |
||||||
|
out.close(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 对象反序列化 |
||||||
|
* @return |
||||||
|
* @throws IOException |
||||||
|
* @throws ClassNotFoundException |
||||||
|
*/ |
||||||
|
public static Object deSerialization(String path) throws IOException, ClassNotFoundException { |
||||||
|
File file = new File(path); |
||||||
|
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file)); |
||||||
|
Object object = oin.readObject(); |
||||||
|
oin.close(); |
||||||
|
return object; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,71 @@ |
|||||||
|
package com.mh.algorithm.bpnn; |
||||||
|
|
||||||
|
import com.mh.algorithm.matrix.Matrix; |
||||||
|
import com.mh.algorithm.utils.CsvInfo; |
||||||
|
import com.mh.algorithm.utils.CsvUtil; |
||||||
|
import com.mh.algorithm.utils.SerializationUtil; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
public class bpnnTest { |
||||||
|
@Test |
||||||
|
public void test() throws Exception { |
||||||
|
// 创建训练集矩阵
|
||||||
|
CsvInfo csvInfo = CsvUtil.getCsvInfo(true, "D:\\ljf\\my_pro\\top-algorithm-set-dev\\src\\trainDataElec.csv"); |
||||||
|
Matrix trainSet = csvInfo.toMatrix(); |
||||||
|
// 创建BPNN工厂对象
|
||||||
|
BPNeuralNetworkFactory factory = new BPNeuralNetworkFactory(); |
||||||
|
// 创建BP参数对象
|
||||||
|
BPParameter bpParameter = new BPParameter(); |
||||||
|
bpParameter.setInputLayerNeuronCount(2); |
||||||
|
bpParameter.setHiddenLayerNeuronCount(2); |
||||||
|
bpParameter.setOutputLayerNeuronCount(2); |
||||||
|
bpParameter.setPrecision(0.01); |
||||||
|
bpParameter.setMaxTimes(10000); |
||||||
|
|
||||||
|
// 训练BP神经网络
|
||||||
|
System.out.println(new Date()); |
||||||
|
BPModel bpModel = factory.trainBP(bpParameter, trainSet); |
||||||
|
System.out.println(new Date()); |
||||||
|
|
||||||
|
// 将BPModel序列化到本地
|
||||||
|
SerializationUtil.serialize(bpModel, "elec"); |
||||||
|
|
||||||
|
CsvInfo csvInfo2 = CsvUtil.getCsvInfo(true, "D:\\ljf\\my_pro\\top-algorithm-set-dev\\src\\testDataElec.csv"); |
||||||
|
Matrix testSet = csvInfo2.toMatrix(); |
||||||
|
|
||||||
|
Matrix testData1 = testSet.subMatrix(0, testSet.getMatrixRowCount(), 0, testSet.getMatrixColCount() - 2); |
||||||
|
Matrix testLabel = testSet.subMatrix(0, testSet.getMatrixRowCount(), testSet.getMatrixColCount() - 2, 1); |
||||||
|
// 将BPModel反序列化
|
||||||
|
BPModel bpModel1 = (BPModel) SerializationUtil.deSerialization("elec"); |
||||||
|
Matrix result = factory.computeBP(bpModel1, testData1); |
||||||
|
|
||||||
|
int total = result.getMatrixRowCount(); |
||||||
|
int correct = 0; |
||||||
|
for (int i = 0; i < result.getMatrixRowCount(); i++) { |
||||||
|
if(Math.round(result.getValOfIdx(i,0)) == testLabel.getValOfIdx(i,0)){ |
||||||
|
correct++; |
||||||
|
} |
||||||
|
} |
||||||
|
double correctRate = Double.valueOf(correct) / Double.valueOf(total); |
||||||
|
System.out.println(correctRate); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 使用示例 |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void bpnnUsing() throws Exception{ |
||||||
|
CsvInfo csvInfo = CsvUtil.getCsvInfo(false, "D:\\ljf\\my_pro\\top-algorithm-set-dev\\src\\dataElec.csv"); |
||||||
|
Matrix data = csvInfo.toMatrix(); |
||||||
|
// 将BPModel反序列化
|
||||||
|
BPModel bpModel1 = (BPModel) SerializationUtil.deSerialization("elec"); |
||||||
|
// 创建工厂
|
||||||
|
BPNeuralNetworkFactory factory = new BPNeuralNetworkFactory(); |
||||||
|
Matrix result = factory.computeBP(bpModel1, data); |
||||||
|
CsvUtil.createCsvFile(null,result,"D:\\ljf\\my_pro\\top-algorithm-set-dev\\src\\computeResult.csv"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
//package com.mh.algorithm.knn;
|
||||||
|
//
|
||||||
|
//import com.mh.algorithm.matrix.Matrix;
|
||||||
|
//import com.mh.algorithm.utils.CsvInfo;
|
||||||
|
//import com.mh.algorithm.utils.CsvUtil;
|
||||||
|
//import com.mh.algorithm.utils.DoubleUtil;
|
||||||
|
//import org.junit.Test;
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * @program: top-algorithm-set
|
||||||
|
// * @description:
|
||||||
|
// * @author: Mr.Zhao
|
||||||
|
// * @create: 2020-10-26 22:04
|
||||||
|
// **/
|
||||||
|
//public class knnTest {
|
||||||
|
// @Test
|
||||||
|
// public void test() throws Exception {
|
||||||
|
// // 训练集
|
||||||
|
// CsvInfo csvInfo = CsvUtil.getCsvInfo(false, "E:\\jarTest\\trainData.csv");
|
||||||
|
// Matrix trainSet = csvInfo.toMatrix();
|
||||||
|
// Matrix trainSetLabels = trainSet.getColOfIdx(trainSet.getMatrixColCount() - 1);
|
||||||
|
// Matrix trainSetData = trainSet.subMatrix(0, trainSet.getMatrixRowCount(), 0, trainSet.getMatrixColCount() - 1);
|
||||||
|
//
|
||||||
|
// CsvInfo csvInfo1 = CsvUtil.getCsvInfo(false, "E:\\jarTest\\testData.csv");
|
||||||
|
// Matrix testSet = csvInfo1.toMatrix();
|
||||||
|
// Matrix testSetData = trainSet.subMatrix(0, testSet.getMatrixRowCount(), 0, testSet.getMatrixColCount() - 1);
|
||||||
|
// Matrix testSetLabels = trainSet.getColOfIdx(testSet.getMatrixColCount() - 1);
|
||||||
|
//
|
||||||
|
// // 分类
|
||||||
|
// long startTime = System.currentTimeMillis();
|
||||||
|
// Matrix result = KNN.classify(testSetData, trainSetData, trainSetLabels, 5);
|
||||||
|
// long endTime = System.currentTimeMillis();
|
||||||
|
// System.out.println("run time:" + (endTime - startTime));
|
||||||
|
// // 正确率
|
||||||
|
// Matrix error = result.subtract(testSetLabels);
|
||||||
|
// int total = error.getMatrixRowCount();
|
||||||
|
// int correct = 0;
|
||||||
|
// for (int i = 0; i < error.getMatrixRowCount(); i++) {
|
||||||
|
// if (DoubleUtil.equals(error.getValOfIdx(i, 0), 0.0)) {
|
||||||
|
// correct++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// double correctRate = Double.valueOf(correct) / Double.valueOf(total);
|
||||||
|
// System.out.println("correctRate:"+ correctRate);
|
||||||
|
// }
|
||||||
|
//}
|
@ -1,13 +1,13 @@ |
|||||||
package com.mh.common.annotation; |
//package com.mh.common.annotation;
|
||||||
|
//
|
||||||
import java.lang.annotation.*; |
//import java.lang.annotation.*;
|
||||||
|
//
|
||||||
/** |
///**
|
||||||
* Created by fangzhipeng on 2017/7/12. |
// * Created by fangzhipeng on 2017/7/12.
|
||||||
*/ |
// */
|
||||||
@Target(ElementType.METHOD) |
//@Target(ElementType.METHOD)
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
//@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented |
//@Documented
|
||||||
public @interface SysLogger { |
//public @interface SysLogger {
|
||||||
String value() default ""; |
// String value() default "";
|
||||||
} |
//}
|
||||||
|
@ -1,42 +1,42 @@ |
|||||||
package com.mh.common.utils; |
//package com.mh.common.utils;
|
||||||
|
//
|
||||||
import javax.servlet.http.HttpServletResponse; |
//import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.BufferedInputStream; |
//import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream; |
//import java.io.BufferedOutputStream;
|
||||||
import java.io.File; |
//import java.io.File;
|
||||||
import java.io.FileInputStream; |
//import java.io.FileInputStream;
|
||||||
import java.io.InputStream; |
//import java.io.InputStream;
|
||||||
|
//
|
||||||
/** |
///**
|
||||||
* 文件相关操作 |
// * 文件相关操作
|
||||||
* @author Louis |
// * @author Louis
|
||||||
* @date Jan 14, 2019 |
// * @date Jan 14, 2019
|
||||||
*/ |
// */
|
||||||
public class FileUtils { |
//public class FileUtils {
|
||||||
|
//
|
||||||
/** |
// /**
|
||||||
* 下载文件 |
// * 下载文件
|
||||||
* @param response |
// * @param response
|
||||||
* @param file |
// * @param file
|
||||||
* @param newFileName |
// * @param newFileName
|
||||||
*/ |
// */
|
||||||
public static void downloadFile(HttpServletResponse response, File file, String newFileName) { |
// public static void downloadFile(HttpServletResponse response, File file, String newFileName) {
|
||||||
try { |
// try {
|
||||||
response.setHeader("Content-Disposition", "attachment; filename=" + new String(newFileName.getBytes("ISO-8859-1"), "UTF-8")); |
// response.setHeader("Content-Disposition", "attachment; filename=" + new String(newFileName.getBytes("ISO-8859-1"), "UTF-8"));
|
||||||
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream()); |
// BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
|
||||||
InputStream is = new FileInputStream(file.getAbsolutePath()); |
// InputStream is = new FileInputStream(file.getAbsolutePath());
|
||||||
BufferedInputStream bis = new BufferedInputStream(is); |
// BufferedInputStream bis = new BufferedInputStream(is);
|
||||||
int length = 0; |
// int length = 0;
|
||||||
byte[] temp = new byte[1 * 1024 * 10]; |
// byte[] temp = new byte[1 * 1024 * 10];
|
||||||
while ((length = bis.read(temp)) != -1) { |
// while ((length = bis.read(temp)) != -1) {
|
||||||
bos.write(temp, 0, length); |
// bos.write(temp, 0, length);
|
||||||
} |
// }
|
||||||
bos.flush(); |
// bos.flush();
|
||||||
bis.close(); |
// bis.close();
|
||||||
bos.close(); |
// bos.close();
|
||||||
is.close(); |
// is.close();
|
||||||
} catch (Exception e) { |
// } catch (Exception e) {
|
||||||
e.printStackTrace(); |
// e.printStackTrace();
|
||||||
} |
// }
|
||||||
} |
// }
|
||||||
} |
//}
|
||||||
|
@ -1,91 +1,91 @@ |
|||||||
package com.mh.user.aspect; |
//package com.mh.user.aspect;
|
||||||
|
//
|
||||||
import java.util.Date; |
//import java.util.Date;
|
||||||
|
//
|
||||||
import javax.servlet.http.HttpServletRequest; |
//import javax.servlet.http.HttpServletRequest;
|
||||||
|
//
|
||||||
import com.mh.common.utils.StringUtils; |
//import com.mh.common.utils.StringUtils;
|
||||||
import com.mh.user.utils.SecurityUtils; |
//import com.mh.user.utils.SecurityUtils;
|
||||||
import org.apache.commons.beanutils.BeanUtils; |
//import org.apache.commons.beanutils.BeanUtils;
|
||||||
import org.aspectj.lang.ProceedingJoinPoint; |
//import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.Around; |
//import org.aspectj.lang.annotation.Around;
|
||||||
import org.aspectj.lang.annotation.Aspect; |
//import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.Pointcut; |
//import org.aspectj.lang.annotation.Pointcut;
|
||||||
import org.springframework.context.annotation.Configuration; |
//import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.stereotype.Component; |
//import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.context.request.RequestContextHolder; |
//import org.springframework.web.context.request.RequestContextHolder;
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes; |
//import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
//
|
||||||
/** |
///**
|
||||||
* DAO切面,插入创建人,创建时间,修改人,修改时间 |
// * DAO切面,插入创建人,创建时间,修改人,修改时间
|
||||||
* @author Louis |
// * @author Louis
|
||||||
* @date Oct 29, 2018 |
// * @date Oct 29, 2018
|
||||||
*/ |
// */
|
||||||
@Aspect |
//@Aspect
|
||||||
@Component |
//@Component
|
||||||
@Configuration |
//@Configuration
|
||||||
public class DaoAspect { |
//public class DaoAspect {
|
||||||
private static final String createBy = "createBy"; |
// private static final String createBy = "createBy";
|
||||||
private static final String createTime = "createTime"; |
// private static final String createTime = "createTime";
|
||||||
private static final String lastUpdateBy = "lastUpdateBy"; |
// private static final String lastUpdateBy = "lastUpdateBy";
|
||||||
private static final String lastUpdateTime = "lastUpdateTime"; |
// private static final String lastUpdateTime = "lastUpdateTime";
|
||||||
|
//
|
||||||
@Pointcut("execution(* com.mh.*.mapper.*.update*(..))") |
// @Pointcut("execution(* com.mh.*.mapper.*.update*(..))")
|
||||||
public void daoUpdate() { |
// public void daoUpdate() {
|
||||||
} |
// }
|
||||||
|
//
|
||||||
@Pointcut("execution(* com.mh.*.mapper.*.insert*(..))") |
// @Pointcut("execution(* com.mh.*.mapper.*.insert*(..))")
|
||||||
public void daoCreate() { |
// public void daoCreate() {
|
||||||
} |
// }
|
||||||
|
//
|
||||||
@Around("daoUpdate()") |
// @Around("daoUpdate()")
|
||||||
public Object doAroundUpdate(ProceedingJoinPoint pjp) throws Throwable { |
// public Object doAroundUpdate(ProceedingJoinPoint pjp) throws Throwable {
|
||||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); |
// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
if (attributes == null) { |
// if (attributes == null) {
|
||||||
return pjp.proceed(); |
// return pjp.proceed();
|
||||||
} |
// }
|
||||||
HttpServletRequest request = attributes.getRequest(); |
// HttpServletRequest request = attributes.getRequest();
|
||||||
String token = request.getHeader("token"); |
// String token = request.getHeader("token");
|
||||||
String username = getUserName(); |
// String username = getUserName();
|
||||||
if (token != null && username != null) { |
// if (token != null && username != null) {
|
||||||
Object[] objects = pjp.getArgs(); |
// Object[] objects = pjp.getArgs();
|
||||||
if (objects != null && objects.length > 0) { |
// if (objects != null && objects.length > 0) {
|
||||||
for (Object arg : objects) { |
// for (Object arg : objects) {
|
||||||
BeanUtils.setProperty(arg, lastUpdateBy, username); |
// BeanUtils.setProperty(arg, lastUpdateBy, username);
|
||||||
BeanUtils.setProperty(arg, lastUpdateTime, new Date()); |
// BeanUtils.setProperty(arg, lastUpdateTime, new Date());
|
||||||
} |
// }
|
||||||
} |
// }
|
||||||
} |
// }
|
||||||
Object object = pjp.proceed(); |
// Object object = pjp.proceed();
|
||||||
return object; |
// return object;
|
||||||
|
//
|
||||||
} |
// }
|
||||||
|
//
|
||||||
@Around("daoCreate()") |
// @Around("daoCreate()")
|
||||||
public Object doAroundCreate(ProceedingJoinPoint pjp) throws Throwable { |
// public Object doAroundCreate(ProceedingJoinPoint pjp) throws Throwable {
|
||||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); |
// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
if (attributes == null) { |
// if (attributes == null) {
|
||||||
return pjp.proceed(); |
// return pjp.proceed();
|
||||||
} |
// }
|
||||||
Object[] objects = pjp.getArgs(); |
// Object[] objects = pjp.getArgs();
|
||||||
if (objects != null && objects.length > 0) { |
// if (objects != null && objects.length > 0) {
|
||||||
for (Object arg : objects) { |
// for (Object arg : objects) {
|
||||||
String username = getUserName(); |
// String username = getUserName();
|
||||||
if (username != null) { |
// if (username != null) {
|
||||||
if (StringUtils.isBlank(BeanUtils.getProperty(arg, createBy))) { |
// if (StringUtils.isBlank(BeanUtils.getProperty(arg, createBy))) {
|
||||||
BeanUtils.setProperty(arg, createBy, username); |
// BeanUtils.setProperty(arg, createBy, username);
|
||||||
} |
// }
|
||||||
if (StringUtils.isBlank(BeanUtils.getProperty(arg, createTime))) { |
// if (StringUtils.isBlank(BeanUtils.getProperty(arg, createTime))) {
|
||||||
BeanUtils.setProperty(arg, createTime, new Date()); |
// BeanUtils.setProperty(arg, createTime, new Date());
|
||||||
} |
// }
|
||||||
} |
// }
|
||||||
} |
// }
|
||||||
} |
// }
|
||||||
Object object = pjp.proceed(); |
// Object object = pjp.proceed();
|
||||||
return object; |
// return object;
|
||||||
} |
// }
|
||||||
|
//
|
||||||
private String getUserName() { |
// private String getUserName() {
|
||||||
return SecurityUtils.getUsername(); |
// return SecurityUtils.getUsername();
|
||||||
} |
// }
|
||||||
} |
//}
|
||||||
|
@ -0,0 +1,59 @@ |
|||||||
|
package com.mh.user.config; |
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.*; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @title : |
||||||
|
* @description 使用caffeine缓存技术 |
||||||
|
* @updateTime 2020-12-15 |
||||||
|
* @throws : |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class CaffeineCacheConfig { |
||||||
|
|
||||||
|
// 软引用: 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。
|
||||||
|
// 弱引用: 弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,
|
||||||
|
// 不管当前内存空间足够与否,都会回收它的内存
|
||||||
|
@Bean(name = "caffeineCache") |
||||||
|
public Cache<String, Object> caffeineCache() { |
||||||
|
return Caffeine.newBuilder() |
||||||
|
// 软引用
|
||||||
|
.softValues() |
||||||
|
// 弱引用
|
||||||
|
// .weakValues()
|
||||||
|
// 设置最后一次写入或访问后经过固定时间过期
|
||||||
|
.expireAfterWrite(8*60*60, TimeUnit.SECONDS) |
||||||
|
// 初始的缓存空间大小
|
||||||
|
.initialCapacity(100) |
||||||
|
// 缓存的最大条数
|
||||||
|
.maximumSize(1000) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
|
||||||
|
//定义缓存,可直接使用
|
||||||
|
@Bean |
||||||
|
public LoadingCache expiryCache(){ |
||||||
|
LoadingCache<String, Object> loadingCache = Caffeine.newBuilder() |
||||||
|
.initialCapacity(100) |
||||||
|
.maximumSize(1000) |
||||||
|
//缓存写入/删除监控
|
||||||
|
.writer(new CacheWriter<Object, Object>() { |
||||||
|
@Override |
||||||
|
public void write(Object key, Object value) { //此方法是同步阻塞的
|
||||||
|
System.out.println("--缓存写入--:key=" + key + ", value=" + value); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void delete(Object key, Object value, RemovalCause cause) { System.out.println("--缓存删除--:key=" + key); } |
||||||
|
}) |
||||||
|
.expireAfterAccess(6, TimeUnit.HOURS) //过期时间
|
||||||
|
.build((String key)->"刷新的数据"); //cacheload实现类,刷新时候调用
|
||||||
|
// loadingCache.put("name","侯征");
|
||||||
|
return loadingCache; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,14 +1,22 @@ |
|||||||
package com.mh.user.config; |
package com.mh.user.config; |
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
import org.springframework.context.annotation.Configuration; |
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.web.client.RestTemplate; |
||||||
|
|
||||||
/** |
/** |
||||||
* @author ljf |
* @author LJF |
||||||
* @title : |
* @title : |
||||||
* @description : redis配置 |
* @description 请求数据 |
||||||
* @updateTime 2020-08-20 |
* @updateTime 2020-08-20 |
||||||
* @throws : |
* @throws : |
||||||
*/ |
*/ |
||||||
@Configuration |
@Configuration |
||||||
public class RestTemplateConfig { |
public class RestTemplateConfig { |
||||||
|
|
||||||
|
@Bean |
||||||
|
public RestTemplate restTemplate() { |
||||||
|
return new RestTemplate(); |
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
@ -0,0 +1,59 @@ |
|||||||
|
package com.mh.user.constants; |
||||||
|
|
||||||
|
import com.mh.user.factory.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 设备枚举类 |
||||||
|
* @date 2024-03-19 10:06:29 |
||||||
|
*/ |
||||||
|
public enum DeviceEnum { |
||||||
|
|
||||||
|
WtMeterEnum("水表", WtMeter.getInstance()), |
||||||
|
EleMeterEnum("电表", EleMeter.getInstance()), |
||||||
|
PressureTransEnum("压变", PressureTrans.getInstance()), |
||||||
|
HeatPumpEnum("热泵", HeatPump.getInstance()), |
||||||
|
TempControlEnum("温控", TempControl.getInstance()), |
||||||
|
TimeControlEnum("时控", TimeControl.getInstance()), |
||||||
|
WaterLevelSwitchEnum("水位开关", WaterLevelSwitch.getInstance()), |
||||||
|
StatusCheckEnum("状态检测", StatusCheck.getInstance()), |
||||||
|
TempTransEnum("温度变送器", TempTrans.getInstance()), |
||||||
|
HeatPumpStatusEnum("热泵状态", HeatPumpStatus.getInstance()); |
||||||
|
|
||||||
|
private String deviceType; |
||||||
|
|
||||||
|
private Device device; |
||||||
|
|
||||||
|
private |
||||||
|
DeviceEnum(String deviceType, Device device) { |
||||||
|
this.deviceType = deviceType; |
||||||
|
this.device = device; |
||||||
|
} |
||||||
|
|
||||||
|
public String getDeviceType() { |
||||||
|
return deviceType; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDeviceType(String deviceType) { |
||||||
|
this.deviceType = deviceType; |
||||||
|
} |
||||||
|
|
||||||
|
public Device getDevice() { |
||||||
|
return device; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDevice(Device device) { |
||||||
|
this.device = device; |
||||||
|
} |
||||||
|
|
||||||
|
public static Device getDevice(String deviceType) { |
||||||
|
for (DeviceEnum deviceEnum : DeviceEnum.values()) { |
||||||
|
if (deviceEnum.getDeviceType().equals(deviceType)) { |
||||||
|
return deviceEnum.getDevice(); |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
package com.mh.user.constants; |
||||||
|
|
||||||
|
import com.mh.user.factory.*; |
||||||
|
import com.mh.user.strategy.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 设备枚举类 |
||||||
|
* @date 2024-03-19 10:06:29 |
||||||
|
*/ |
||||||
|
public enum DeviceStrategyEnum { |
||||||
|
|
||||||
|
WtMeterEnum("水表", WtMeterStrategy.getInstance()), |
||||||
|
EleMeterEnum("电表", EleMeterStrategy.getInstance()), |
||||||
|
PressureTransEnum("压变", PressureTransStrategy.getInstance()), |
||||||
|
HeatPumpEnum("热泵", HeatPumpStrategy.getInstance()), |
||||||
|
TempControlEnum("温控", TempControlStrategy.getInstance()), |
||||||
|
TimeControlEnum("时控", TimeControlStrategy.getInstance()), |
||||||
|
WaterLevelSwitchEnum("水位开关", WaterLevelSwitchStrategy.getInstance()), |
||||||
|
StatusCheckEnum("状态检测", StatusCheckStrategy.getInstance()), |
||||||
|
TempTransEnum("温度变送器", TempTransStrategy.getInstance()), |
||||||
|
HeatPumpStatusEnum("热泵状态", HeatPumpStatusStrategy.getInstance()); |
||||||
|
|
||||||
|
private String deviceType; |
||||||
|
|
||||||
|
private DeviceStrategy deviceStrategy; |
||||||
|
|
||||||
|
private DeviceStrategyEnum(String deviceType, DeviceStrategy deviceStrategy) { |
||||||
|
this.deviceType = deviceType; |
||||||
|
this.deviceStrategy = deviceStrategy; |
||||||
|
} |
||||||
|
|
||||||
|
public String getDeviceType() { |
||||||
|
return deviceType; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDeviceType(String deviceType) { |
||||||
|
this.deviceType = deviceType; |
||||||
|
} |
||||||
|
|
||||||
|
public DeviceStrategy getDeviceStrategy() { |
||||||
|
return deviceStrategy; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDeviceStrategy(DeviceStrategy deviceStrategy) { |
||||||
|
this.deviceStrategy = deviceStrategy; |
||||||
|
} |
||||||
|
|
||||||
|
public static DeviceStrategy getDeviceStrategy(String deviceType) { |
||||||
|
for (DeviceStrategyEnum deviceEnum : DeviceStrategyEnum.values()) { |
||||||
|
if (deviceEnum.getDeviceType().equals(deviceType)) { |
||||||
|
return deviceEnum.getDeviceStrategy(); |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,94 @@ |
|||||||
|
package com.mh.user.controller; |
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject; |
||||||
|
import com.mh.common.http.HttpResult; |
||||||
|
import com.mh.common.utils.StringUtils; |
||||||
|
import com.mh.user.annotation.SysLogger; |
||||||
|
import com.mh.user.constants.Constant; |
||||||
|
import com.mh.user.entity.ControlSetEntity; |
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.entity.DeviceInstallEntity; |
||||||
|
import com.mh.user.entity.PumpSetEntity; |
||||||
|
import com.mh.user.model.DeviceModel; |
||||||
|
import com.mh.user.model.SerialPortModel; |
||||||
|
import com.mh.user.serialport.SerialPortSingle2; |
||||||
|
import com.mh.user.service.*; |
||||||
|
import com.mh.user.utils.ExchangeStringUtil; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.web.bind.annotation.*; |
||||||
|
|
||||||
|
import java.math.BigDecimal; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
@RestController |
||||||
|
@RequestMapping("serial") |
||||||
|
public class DeviceOperateController { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
DeviceInstallService deviceInstallService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
PumpSetService pumpSetService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ControlSetService controlSetService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
NowDataService nowDataService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private DeviceControlService deviceControlService; |
||||||
|
|
||||||
|
|
||||||
|
//操作设备
|
||||||
|
@SysLogger(title = "控制管理", optDesc = "设置设备参数值") |
||||||
|
@PostMapping(value = "/operate") |
||||||
|
public HttpResult operateDevice(@RequestBody List<SerialPortModel> params) { |
||||||
|
try { |
||||||
|
Constant.WEB_FLAG = true; //单抄,暂时停止采集
|
||||||
|
Thread.sleep(1000); |
||||||
|
String returnStr = deviceControlService.readOrWriteDevice(params, Constant.WRITE); |
||||||
|
if (!StringUtils.isBlank(returnStr) && "fail".equals(returnStr)) { |
||||||
|
return HttpResult.error(500, "fail"); |
||||||
|
} |
||||||
|
Constant.WEB_FLAG = false; //单抄,恢复采集
|
||||||
|
return HttpResult.ok(); |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("前端发送控制异常==>", e); |
||||||
|
Constant.WEB_FLAG = false; //单抄,恢复采集
|
||||||
|
return HttpResult.error(500, "fail"); |
||||||
|
} finally { |
||||||
|
Constant.WEB_FLAG = false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//读数据
|
||||||
|
@SysLogger(title = "控制管理", optDesc = "读设备数据") |
||||||
|
@PostMapping(value = "/read") |
||||||
|
public HttpResult readData(@RequestBody List<SerialPortModel> params) { |
||||||
|
try { |
||||||
|
Constant.WEB_FLAG = true; //单抄,暂时停止采集
|
||||||
|
Thread.sleep(1000); |
||||||
|
String rtData = deviceControlService.readOrWriteDevice(params, Constant.READ); |
||||||
|
if (ExchangeStringUtil.getJSONType(rtData)) { |
||||||
|
Map map = JSONObject.parseObject(rtData); |
||||||
|
return HttpResult.ok("success", map); |
||||||
|
} else { |
||||||
|
if (rtData.equals("fail")) { |
||||||
|
return HttpResult.error(500, "fail"); |
||||||
|
} else { |
||||||
|
return HttpResult.ok(rtData, rtData); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
Constant.WEB_FLAG = false; //单抄,恢复采集
|
||||||
|
return HttpResult.error(500, "fail"); |
||||||
|
} finally { |
||||||
|
Constant.WEB_FLAG = false; //单抄,恢复采集
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
package com.mh.user.controller; |
||||||
|
|
||||||
|
import com.mh.common.http.HttpResult; |
||||||
|
import com.mh.user.dto.EnergyPreDTO; |
||||||
|
import com.mh.user.service.HistoryDataPreService; |
||||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import javax.annotation.Resource; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 用能预测controller |
||||||
|
* @date 2024-05-09 17:24:48 |
||||||
|
*/ |
||||||
|
@RestController |
||||||
|
@RequestMapping("/energyPre") |
||||||
|
public class EnergyPreController { |
||||||
|
|
||||||
|
@Resource |
||||||
|
private HistoryDataPreService historyDataPreService; |
||||||
|
|
||||||
|
@PostMapping("/topData") |
||||||
|
public HttpResult getTopData(String buildingId, String type) { |
||||||
|
return HttpResult.ok(historyDataPreService.getTopData(buildingId, type)); |
||||||
|
} |
||||||
|
|
||||||
|
@PostMapping("/echartData") |
||||||
|
public HttpResult getEnergyPre(String buildingId, String beginDate, String endDate, String type) { |
||||||
|
return HttpResult.ok(historyDataPreService.getEnergyPre(buildingId, beginDate, endDate, type)); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
package com.mh.user.controller; |
||||||
|
|
||||||
|
import com.mh.common.http.HttpResult; |
||||||
|
import com.mh.common.page.PageRequest; |
||||||
|
import com.mh.common.page.PageResult; |
||||||
|
import com.mh.user.entity.KnowledgeDataEntity; |
||||||
|
import com.mh.user.service.KnowledgeDataService; |
||||||
|
import io.jsonwebtoken.lang.Assert; |
||||||
|
import org.springframework.validation.annotation.Validated; |
||||||
|
import org.springframework.web.bind.annotation.*; |
||||||
|
|
||||||
|
import javax.annotation.Resource; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 知识库管理 |
||||||
|
* @date 2024-06-26 14:39:24 |
||||||
|
*/ |
||||||
|
@RestController |
||||||
|
@RequestMapping("/knowledge") |
||||||
|
public class KnowledgeDataController { |
||||||
|
|
||||||
|
@Resource |
||||||
|
private KnowledgeDataService knowledgeDataService; |
||||||
|
|
||||||
|
@GetMapping("/query") |
||||||
|
public HttpResult queryKnowledgeData(@RequestParam("pageNum") int pageNum, @RequestParam("pageSize") int pageSize) { |
||||||
|
PageRequest pageRequest = new PageRequest(); |
||||||
|
pageRequest.setPageNum(pageNum); |
||||||
|
pageRequest.setPageSize(pageSize); |
||||||
|
return HttpResult.ok(knowledgeDataService.queryKnowledgeData(pageRequest)); |
||||||
|
} |
||||||
|
|
||||||
|
@GetMapping("/{id}") |
||||||
|
public HttpResult detail(@PathVariable(name = "id") Long id) { |
||||||
|
KnowledgeDataEntity knowledgeData = knowledgeDataService.getById(id); |
||||||
|
Assert.notNull(knowledgeData, "该文章已被删除"); |
||||||
|
return HttpResult.ok(knowledgeData); |
||||||
|
} |
||||||
|
|
||||||
|
@PostMapping("/update") |
||||||
|
public HttpResult updateData(@Validated @RequestBody KnowledgeDataEntity knowledgeData) { |
||||||
|
try { |
||||||
|
knowledgeDataService.updateData(knowledgeData); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
return HttpResult.ok(); |
||||||
|
} |
||||||
|
|
||||||
|
@PostMapping("/insert") |
||||||
|
public HttpResult insertKnowledgeData(@Validated @RequestBody KnowledgeDataEntity knowledgeData) { |
||||||
|
try { |
||||||
|
knowledgeDataService.insertKnowledgeData(knowledgeData); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
return HttpResult.ok(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.mh.user.dto; |
||||||
|
|
||||||
|
import lombok.Getter; |
||||||
|
import lombok.Setter; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 用能预测前端类 |
||||||
|
* @date 2024-05-09 17:31:27 |
||||||
|
*/ |
||||||
|
@Setter |
||||||
|
@Getter |
||||||
|
public class EnergyPreDTO { |
||||||
|
|
||||||
|
/** |
||||||
|
* 顶部数据 |
||||||
|
*/ |
||||||
|
private EnergyPreTopDataDTO topData; |
||||||
|
|
||||||
|
/** |
||||||
|
* 折线图数据 |
||||||
|
*/ |
||||||
|
private EnergyPreEchartDataDTO echartData; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
package com.mh.user.dto; |
||||||
|
|
||||||
|
import lombok.Getter; |
||||||
|
import lombok.Setter; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 用能预测前端类 |
||||||
|
* @date 2024-05-09 17:31:27 |
||||||
|
*/ |
||||||
|
@Setter |
||||||
|
@Getter |
||||||
|
public class EnergyPreEchartDataDTO { |
||||||
|
|
||||||
|
/** |
||||||
|
* 时间 |
||||||
|
*/ |
||||||
|
private String curDate; |
||||||
|
|
||||||
|
/** |
||||||
|
* 实际值 |
||||||
|
*/ |
||||||
|
private String curData; |
||||||
|
|
||||||
|
/** |
||||||
|
* 预测值 |
||||||
|
*/ |
||||||
|
private String preData; |
||||||
|
|
||||||
|
/** |
||||||
|
* 误差值 |
||||||
|
*/ |
||||||
|
private String errorData; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
package com.mh.user.dto; |
||||||
|
|
||||||
|
import lombok.Getter; |
||||||
|
import lombok.Setter; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 用能预测前端类 |
||||||
|
* @date 2024-05-09 17:31:27 |
||||||
|
*/ |
||||||
|
@Setter |
||||||
|
@Getter |
||||||
|
public class EnergyPreTopDataDTO { |
||||||
|
|
||||||
|
/** |
||||||
|
* 昨日实际值 |
||||||
|
*/ |
||||||
|
private String yesData; |
||||||
|
|
||||||
|
/** |
||||||
|
* 昨日预测值 |
||||||
|
*/ |
||||||
|
private String preYesData; |
||||||
|
|
||||||
|
/** |
||||||
|
* 今日预测值 |
||||||
|
*/ |
||||||
|
private String curYesData; |
||||||
|
|
||||||
|
/** |
||||||
|
* 误差值 |
||||||
|
*/ |
||||||
|
private String errorData; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,168 @@ |
|||||||
|
package com.mh.user.entity; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||||
|
|
||||||
|
import java.math.BigDecimal; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 历史预测数据表 |
||||||
|
* @date 2024-05-09 09:55:09 |
||||||
|
*/ |
||||||
|
public class HistoryDataPre { |
||||||
|
|
||||||
|
private Long id; |
||||||
|
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
||||||
|
private Date curDate; |
||||||
|
|
||||||
|
private String buildingId; |
||||||
|
|
||||||
|
private BigDecimal envMinTemp; |
||||||
|
|
||||||
|
private BigDecimal envMaxTemp; |
||||||
|
|
||||||
|
private BigDecimal waterValue; |
||||||
|
|
||||||
|
private BigDecimal electValue; |
||||||
|
|
||||||
|
private BigDecimal waterLevel; |
||||||
|
|
||||||
|
/** |
||||||
|
* 每栋楼人数 |
||||||
|
*/ |
||||||
|
private BigDecimal peopleNum; |
||||||
|
|
||||||
|
private BigDecimal waterValuePre; |
||||||
|
|
||||||
|
private BigDecimal electValuePre; |
||||||
|
|
||||||
|
private BigDecimal waterLevelPre; |
||||||
|
|
||||||
|
private String remark; |
||||||
|
|
||||||
|
public BigDecimal getPeopleNum() { |
||||||
|
return peopleNum; |
||||||
|
} |
||||||
|
|
||||||
|
public void setPeopleNum(BigDecimal peopleNum) { |
||||||
|
this.peopleNum = peopleNum; |
||||||
|
} |
||||||
|
|
||||||
|
public Long getId() { |
||||||
|
return id; |
||||||
|
} |
||||||
|
|
||||||
|
public void setId(Long id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
public Date getCurDate() { |
||||||
|
return curDate; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCurDate(Date curDate) { |
||||||
|
this.curDate = curDate; |
||||||
|
} |
||||||
|
|
||||||
|
public String getBuildingId() { |
||||||
|
return buildingId; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBuildingId(String buildingId) { |
||||||
|
this.buildingId = buildingId; |
||||||
|
} |
||||||
|
|
||||||
|
public BigDecimal getEnvMinTemp() { |
||||||
|
return envMinTemp; |
||||||
|
} |
||||||
|
|
||||||
|
public void setEnvMinTemp(BigDecimal envMinTemp) { |
||||||
|
this.envMinTemp = envMinTemp; |
||||||
|
} |
||||||
|
|
||||||
|
public BigDecimal getEnvMaxTemp() { |
||||||
|
return envMaxTemp; |
||||||
|
} |
||||||
|
|
||||||
|
public void setEnvMaxTemp(BigDecimal envMaxTemp) { |
||||||
|
this.envMaxTemp = envMaxTemp; |
||||||
|
} |
||||||
|
|
||||||
|
public BigDecimal getWaterValue() { |
||||||
|
return waterValue; |
||||||
|
} |
||||||
|
|
||||||
|
public void setWaterValue(BigDecimal waterValue) { |
||||||
|
this.waterValue = waterValue; |
||||||
|
} |
||||||
|
|
||||||
|
public BigDecimal getElectValue() { |
||||||
|
return electValue; |
||||||
|
} |
||||||
|
|
||||||
|
public void setElectValue(BigDecimal electValue) { |
||||||
|
this.electValue = electValue; |
||||||
|
} |
||||||
|
|
||||||
|
public BigDecimal getWaterLevel() { |
||||||
|
return waterLevel; |
||||||
|
} |
||||||
|
|
||||||
|
public void setWaterLevel(BigDecimal waterLevel) { |
||||||
|
this.waterLevel = waterLevel; |
||||||
|
} |
||||||
|
|
||||||
|
public BigDecimal getWaterValuePre() { |
||||||
|
return waterValuePre; |
||||||
|
} |
||||||
|
|
||||||
|
public void setWaterValuePre(BigDecimal waterValuePre) { |
||||||
|
this.waterValuePre = waterValuePre; |
||||||
|
} |
||||||
|
|
||||||
|
public BigDecimal getElectValuePre() { |
||||||
|
return electValuePre; |
||||||
|
} |
||||||
|
|
||||||
|
public void setElectValuePre(BigDecimal electValuePre) { |
||||||
|
this.electValuePre = electValuePre; |
||||||
|
} |
||||||
|
|
||||||
|
public BigDecimal getWaterLevelPre() { |
||||||
|
return waterLevelPre; |
||||||
|
} |
||||||
|
|
||||||
|
public void setWaterLevelPre(BigDecimal waterLevelPre) { |
||||||
|
this.waterLevelPre = waterLevelPre; |
||||||
|
} |
||||||
|
|
||||||
|
public String getRemark() { |
||||||
|
return remark; |
||||||
|
} |
||||||
|
|
||||||
|
public void setRemark(String remark) { |
||||||
|
this.remark = remark; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "HistoryDataPre{" + |
||||||
|
"id=" + id + |
||||||
|
", curDate=" + curDate + |
||||||
|
", buildingId='" + buildingId + '\'' + |
||||||
|
", envMinTemp=" + envMinTemp + |
||||||
|
", envMaxTemp=" + envMaxTemp + |
||||||
|
", waterValue=" + waterValue + |
||||||
|
", electValue=" + electValue + |
||||||
|
", waterLevel=" + waterLevel + |
||||||
|
", waterValuePre=" + waterValuePre + |
||||||
|
", electValuePre=" + electValuePre + |
||||||
|
", waterLevelPre=" + waterLevelPre + |
||||||
|
", remark='" + remark + '\'' + |
||||||
|
'}'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
package com.mh.user.entity; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank; |
||||||
|
import java.io.Serializable; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 知识库管理 |
||||||
|
* @date 2024-06-26 14:18:28 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class KnowledgeDataEntity implements Serializable { |
||||||
|
|
||||||
|
private Long id; |
||||||
|
|
||||||
|
@NotBlank(message = "标题不能为空") |
||||||
|
private String title; |
||||||
|
|
||||||
|
@NotBlank(message = "摘要不能为空") |
||||||
|
private String description; |
||||||
|
|
||||||
|
@NotBlank(message = "内容不能为空") |
||||||
|
private String content; |
||||||
|
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||||
|
private Date createTime; |
||||||
|
|
||||||
|
private Integer status; |
||||||
|
|
||||||
|
private String remark; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 设备接口 |
||||||
|
* @date 2024-03-15 16:48:26 |
||||||
|
*/ |
||||||
|
public interface Device { |
||||||
|
|
||||||
|
void setStrategy(DeviceStrategy strategy); |
||||||
|
|
||||||
|
String createOrders(DeviceCodeParamEntity deviceCodeParamEntity); |
||||||
|
|
||||||
|
String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr); |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.constants.DeviceEnum; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 设备工厂类 |
||||||
|
* @date 2024-03-15 17:09:49 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class DeviceFactory { |
||||||
|
|
||||||
|
public static Device createDevice(String deviceType) { |
||||||
|
return DeviceEnum.getDevice(deviceType); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 电表设备 |
||||||
|
* @date 2024-03-15 16:52:39 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class EleMeter implements Device { |
||||||
|
|
||||||
|
private DeviceStrategy eleMeterStrategy; |
||||||
|
|
||||||
|
private static class SingletonHolder { |
||||||
|
private static final EleMeter INSTANCE = new EleMeter(); |
||||||
|
} |
||||||
|
|
||||||
|
private EleMeter() { |
||||||
|
// 防止外部直接实例化
|
||||||
|
} |
||||||
|
|
||||||
|
public static EleMeter getInstance() { |
||||||
|
return EleMeter.SingletonHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStrategy(DeviceStrategy strategy) { |
||||||
|
this.eleMeterStrategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String createOrders(DeviceCodeParamEntity deviceCodeParamEntity) { |
||||||
|
log.info("电表设备创建报文"); |
||||||
|
return eleMeterStrategy.createOrders(deviceCodeParamEntity); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr) { |
||||||
|
return eleMeterStrategy.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 热泵 |
||||||
|
* @date 2024-03-18 16:53:35 |
||||||
|
*/ |
||||||
|
public class HeatPump implements Device { |
||||||
|
|
||||||
|
private DeviceStrategy strategy; |
||||||
|
|
||||||
|
private static class SingletonHolder { |
||||||
|
private static final HeatPump INSTANCE = new HeatPump(); |
||||||
|
} |
||||||
|
|
||||||
|
private HeatPump() { |
||||||
|
// 防止外部直接实例化
|
||||||
|
} |
||||||
|
|
||||||
|
public static HeatPump getInstance() { |
||||||
|
return HeatPump.SingletonHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStrategy(DeviceStrategy strategy) { |
||||||
|
this.strategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String createOrders(DeviceCodeParamEntity deviceCodeParamEntity) { |
||||||
|
return strategy.createOrders(deviceCodeParamEntity); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr) { |
||||||
|
return strategy.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 热泵状态 |
||||||
|
* @date 2024-03-18 16:53:35 |
||||||
|
*/ |
||||||
|
public class HeatPumpStatus implements Device { |
||||||
|
|
||||||
|
private DeviceStrategy strategy; |
||||||
|
|
||||||
|
private static class SingletonHolder { |
||||||
|
private static final HeatPumpStatus INSTANCE = new HeatPumpStatus(); |
||||||
|
} |
||||||
|
|
||||||
|
private HeatPumpStatus() { |
||||||
|
// 防止外部直接实例化
|
||||||
|
} |
||||||
|
|
||||||
|
public static HeatPumpStatus getInstance() { |
||||||
|
return HeatPumpStatus.SingletonHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStrategy(DeviceStrategy strategy) { |
||||||
|
this.strategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String createOrders(DeviceCodeParamEntity deviceCodeParamEntity) { |
||||||
|
return strategy.createOrders(deviceCodeParamEntity); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr) { |
||||||
|
return strategy.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 压力变送器 |
||||||
|
* @date 2024-03-18 16:53:35 |
||||||
|
*/ |
||||||
|
public class PressureTrans implements Device { |
||||||
|
|
||||||
|
private DeviceStrategy strategy; |
||||||
|
|
||||||
|
private static class SingletonHolder { |
||||||
|
private static final PressureTrans INSTANCE = new PressureTrans(); |
||||||
|
} |
||||||
|
|
||||||
|
private PressureTrans() { |
||||||
|
// 防止外部直接实例化
|
||||||
|
} |
||||||
|
|
||||||
|
public static PressureTrans getInstance() { |
||||||
|
return PressureTrans.SingletonHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStrategy(DeviceStrategy strategy) { |
||||||
|
this.strategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String createOrders(DeviceCodeParamEntity deviceCodeParamEntity) { |
||||||
|
return strategy.createOrders(deviceCodeParamEntity); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr) { |
||||||
|
return strategy.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 状态检测 |
||||||
|
* @date 2024-03-15 17:07:54 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class StatusCheck implements Device { |
||||||
|
|
||||||
|
private DeviceStrategy wtMeterStrategy; |
||||||
|
|
||||||
|
private static class SingletonHolder { |
||||||
|
private static final StatusCheck INSTANCE = new StatusCheck(); |
||||||
|
} |
||||||
|
|
||||||
|
private StatusCheck() { |
||||||
|
// 防止外部直接实例化
|
||||||
|
} |
||||||
|
|
||||||
|
public static StatusCheck getInstance() { |
||||||
|
return SingletonHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStrategy(DeviceStrategy strategy) { |
||||||
|
this.wtMeterStrategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String createOrders(DeviceCodeParamEntity deviceCodeParamEntity) { |
||||||
|
log.info("水表设备创建报文"); |
||||||
|
return wtMeterStrategy.createOrders(deviceCodeParamEntity); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr) { |
||||||
|
return wtMeterStrategy.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 温度控制器 |
||||||
|
* @date 2024-03-18 16:53:35 |
||||||
|
*/ |
||||||
|
public class TempControl implements Device { |
||||||
|
|
||||||
|
private DeviceStrategy strategy; |
||||||
|
|
||||||
|
private static class SingletonHolder { |
||||||
|
private static final TempControl INSTANCE = new TempControl(); |
||||||
|
} |
||||||
|
|
||||||
|
private TempControl() { |
||||||
|
// 防止外部直接实例化
|
||||||
|
} |
||||||
|
|
||||||
|
public static TempControl getInstance() { |
||||||
|
return TempControl.SingletonHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStrategy(DeviceStrategy strategy) { |
||||||
|
this.strategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String createOrders(DeviceCodeParamEntity deviceCodeParamEntity) { |
||||||
|
return strategy.createOrders(deviceCodeParamEntity); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr) { |
||||||
|
return strategy.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 压力变送器 |
||||||
|
* @date 2024-03-18 16:53:35 |
||||||
|
*/ |
||||||
|
public class TempTrans implements Device { |
||||||
|
|
||||||
|
private DeviceStrategy strategy; |
||||||
|
|
||||||
|
private static class SingletonHolder { |
||||||
|
private static final TempTrans INSTANCE = new TempTrans(); |
||||||
|
} |
||||||
|
|
||||||
|
private TempTrans() { |
||||||
|
// 防止外部直接实例化
|
||||||
|
} |
||||||
|
|
||||||
|
public static TempTrans getInstance() { |
||||||
|
return TempTrans.SingletonHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStrategy(DeviceStrategy strategy) { |
||||||
|
this.strategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String createOrders(DeviceCodeParamEntity deviceCodeParamEntity) { |
||||||
|
return strategy.createOrders(deviceCodeParamEntity); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr) { |
||||||
|
return strategy.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 时间控制器 |
||||||
|
* @date 2024-03-18 16:53:35 |
||||||
|
*/ |
||||||
|
public class TimeControl implements Device { |
||||||
|
|
||||||
|
private DeviceStrategy strategy; |
||||||
|
|
||||||
|
private static class SingletonHolder { |
||||||
|
private static final TimeControl INSTANCE = new TimeControl(); |
||||||
|
} |
||||||
|
|
||||||
|
private TimeControl() { |
||||||
|
// 防止外部直接实例化
|
||||||
|
} |
||||||
|
|
||||||
|
public static TimeControl getInstance() { |
||||||
|
return TimeControl.SingletonHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStrategy(DeviceStrategy strategy) { |
||||||
|
this.strategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String createOrders(DeviceCodeParamEntity deviceCodeParamEntity) { |
||||||
|
return strategy.createOrders(deviceCodeParamEntity); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr) { |
||||||
|
return strategy.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 水位开关控制 |
||||||
|
* @date 2024-03-18 16:53:35 |
||||||
|
*/ |
||||||
|
public class WaterLevelSwitch implements Device { |
||||||
|
|
||||||
|
private DeviceStrategy strategy; |
||||||
|
|
||||||
|
private static class SingletonHolder { |
||||||
|
private static final WaterLevelSwitch INSTANCE = new WaterLevelSwitch(); |
||||||
|
} |
||||||
|
|
||||||
|
private WaterLevelSwitch() { |
||||||
|
// 防止外部直接实例化
|
||||||
|
} |
||||||
|
|
||||||
|
public static WaterLevelSwitch getInstance() { |
||||||
|
return WaterLevelSwitch.SingletonHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStrategy(DeviceStrategy strategy) { |
||||||
|
this.strategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String createOrders(DeviceCodeParamEntity deviceCodeParamEntity) { |
||||||
|
return strategy.createOrders(deviceCodeParamEntity); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr) { |
||||||
|
return strategy.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
package com.mh.user.factory; |
||||||
|
|
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 水表设备 |
||||||
|
* @date 2024-03-15 17:07:54 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class WtMeter implements Device { |
||||||
|
|
||||||
|
private DeviceStrategy wtMeterStrategy; |
||||||
|
|
||||||
|
private static class SingletonHolder { |
||||||
|
private static final WtMeter INSTANCE = new WtMeter(); |
||||||
|
} |
||||||
|
|
||||||
|
private WtMeter() { |
||||||
|
// 防止外部直接实例化
|
||||||
|
} |
||||||
|
|
||||||
|
public static WtMeter getInstance() { |
||||||
|
return SingletonHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStrategy(DeviceStrategy strategy) { |
||||||
|
this.wtMeterStrategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String createOrders(DeviceCodeParamEntity deviceCodeParamEntity) { |
||||||
|
log.info("水表设备创建报文"); |
||||||
|
return wtMeterStrategy.createOrders(deviceCodeParamEntity); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String analysisReceiveData(String dateStr, String deviceType, String registerAddr, String brand, String buildingId, String buildingName, String dataStr) { |
||||||
|
return wtMeterStrategy.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
package com.mh.user.job; |
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON; |
||||||
|
import com.alibaba.fastjson2.JSONObject; |
||||||
|
import com.github.benmanes.caffeine.cache.Cache; |
||||||
|
import com.mh.common.utils.StringUtils; |
||||||
|
import com.mh.user.entity.SysParamEntity; |
||||||
|
import com.mh.user.service.SysParamService; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Qualifier; |
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
import org.springframework.web.client.RestTemplate; |
||||||
|
|
||||||
|
import javax.annotation.Resource; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project NewZhujiang_Server |
||||||
|
* @description 定期获取时间 |
||||||
|
* @date 2023-12-05 14:12:56 |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
@Slf4j |
||||||
|
public class GetWeatherInfoJob { |
||||||
|
|
||||||
|
@Resource |
||||||
|
private SysParamService sysParamService; |
||||||
|
|
||||||
|
@Resource |
||||||
|
private RestTemplate restTemplate; |
||||||
|
|
||||||
|
@Resource |
||||||
|
@Qualifier("caffeineCache") |
||||||
|
private Cache caffeineCache; |
||||||
|
|
||||||
|
@Value("${amap.key}") |
||||||
|
String amapKey; |
||||||
|
|
||||||
|
/** |
||||||
|
* 定时获取每天天气 |
||||||
|
*/ |
||||||
|
@Scheduled(cron = "0 0 0 0/1 * ? ") |
||||||
|
public void getWeatherInfo() { |
||||||
|
// 从系统参数中获取对应的项目区域
|
||||||
|
SysParamEntity sysParam = sysParamService.selectSysParam(); |
||||||
|
if (null != sysParam) { |
||||||
|
String url = "https://restapi.amap.com/v3/weather/weatherInfo?extensions=all&key="+amapKey+"&city="+sysParam.getProArea(); |
||||||
|
String returnResult = restTemplate.getForObject(url, String.class); |
||||||
|
if (!StringUtils.isBlank(returnResult)) { |
||||||
|
JSONObject jsonObject = JSON.parseObject(returnResult); |
||||||
|
if ("1".equals(jsonObject.get("status"))) { |
||||||
|
Object wetTemp = caffeineCache.getIfPresent(sysParam.getProArea()); |
||||||
|
if (wetTemp != null) { |
||||||
|
caffeineCache.invalidate(sysParam.getProArea()); |
||||||
|
} |
||||||
|
caffeineCache.put(sysParam.getProArea(), jsonObject.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,41 +0,0 @@ |
|||||||
package com.mh.user.job; |
|
||||||
|
|
||||||
import com.mh.user.netty.NettyClient; |
|
||||||
import com.mh.user.constants.SocketMessage; |
|
||||||
import lombok.SneakyThrows; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.quartz.DisallowConcurrentExecution; |
|
||||||
import org.quartz.Job; |
|
||||||
import org.quartz.JobExecutionContext; |
|
||||||
import org.quartz.JobExecutionException; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title : |
|
||||||
* @description : 定时采集冷量计任务 |
|
||||||
* @updateTime 2020-05-18 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
/** |
|
||||||
* :@DisallowConcurrentExecution : 此标记用在实现Job的类上面,意思是不允许并发执行. |
|
||||||
* :注意org.quartz.threadPool.threadCount线程池中线程的数量至少要多个,否则@DisallowConcurrentExecution不生效 |
|
||||||
* :假如Job的设置时间间隔为3秒,但Job执行时间是5秒,设置@DisallowConcurrentExecution以后程序会等任务执行完毕以后再去执行, |
|
||||||
* 否则会在3秒时再启用新的线程执行 |
|
||||||
*/ |
|
||||||
@DisallowConcurrentExecution |
|
||||||
@Slf4j |
|
||||||
public class JobCloud implements Job { |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private SocketMessage socketMessage; |
|
||||||
|
|
||||||
@SneakyThrows |
|
||||||
@Override |
|
||||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { |
|
||||||
// 定时采集冷量计
|
|
||||||
log.info("定时采集冷量计"); |
|
||||||
NettyClient nettyClient = new NettyClient(); |
|
||||||
nettyClient.connect(socketMessage.getPort(),socketMessage.getIP()); |
|
||||||
} |
|
||||||
} |
|
@ -1,39 +0,0 @@ |
|||||||
package com.mh.user.job; |
|
||||||
|
|
||||||
import com.mh.user.netty.NettyMeterClient; |
|
||||||
import com.mh.user.constants.SocketMessage; |
|
||||||
import lombok.SneakyThrows; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.quartz.DisallowConcurrentExecution; |
|
||||||
import org.quartz.Job; |
|
||||||
import org.quartz.JobExecutionContext; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title : |
|
||||||
* @description : 定时采集电表数据任务 |
|
||||||
* @updateTime 2020-05-18 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
/** |
|
||||||
* :@DisallowConcurrentExecution : 此标记用在实现Job的类上面,意思是不允许并发执行. |
|
||||||
* :注意org.quartz.threadPool.threadCount线程池中线程的数量至少要多个,否则@DisallowConcurrentExecution不生效 |
|
||||||
* :假如Job的设置时间间隔为3秒,但Job执行时间是5秒,设置@DisallowConcurrentExecution以后程序会等任务执行完毕以后再去执行, |
|
||||||
* 否则会在3秒时再启用新的线程执行 |
|
||||||
*/ |
|
||||||
@DisallowConcurrentExecution |
|
||||||
@Slf4j |
|
||||||
public class JobMeter implements Job { |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private SocketMessage socketMessage; |
|
||||||
|
|
||||||
@SneakyThrows |
|
||||||
@Override |
|
||||||
public void execute(JobExecutionContext jobExecutionContext) { |
|
||||||
log.info("定时采集电表数据任务开始"); |
|
||||||
NettyMeterClient nettyMeterClient = new NettyMeterClient(); |
|
||||||
nettyMeterClient.connect(socketMessage.getPort(), socketMessage.getIP()); |
|
||||||
} |
|
||||||
} |
|
@ -1,32 +0,0 @@ |
|||||||
package com.mh.user.job; |
|
||||||
|
|
||||||
import com.mh.user.constants.Constant; |
|
||||||
import lombok.SneakyThrows; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.quartz.DisallowConcurrentExecution; |
|
||||||
import org.quartz.Job; |
|
||||||
import org.quartz.JobExecutionContext; |
|
||||||
import org.quartz.JobExecutionException; |
|
||||||
|
|
||||||
/** |
|
||||||
* :@DisallowConcurrentExecution : 此标记用在实现Job的类上面,意思是不允许并发执行. |
|
||||||
* :注意org.quartz.threadPool.threadCount线程池中线程的数量至少要多个,否则@DisallowConcurrentExecution不生效 |
|
||||||
* :假如Job的设置时间间隔为3秒,但Job执行时间是5秒,设置@DisallowConcurrentExecution以后程序会等任务执行完毕以后再去执行, |
|
||||||
* 否则会在3秒时再启用新的线程执行 |
|
||||||
*/ |
|
||||||
@DisallowConcurrentExecution |
|
||||||
@Slf4j |
|
||||||
public class JobTest implements Job { |
|
||||||
@SneakyThrows |
|
||||||
@Override |
|
||||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { |
|
||||||
for (int i = 0; i < 30; i++) { |
|
||||||
if (Constant.FLAG) { |
|
||||||
break; |
|
||||||
} |
|
||||||
Thread.sleep(1000); |
|
||||||
log.info("第" + i + "个," +jobExecutionContext.getJobDetail()+"---------------------定时任务测试----------------------"); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
@ -1,32 +0,0 @@ |
|||||||
package com.mh.user.job; |
|
||||||
|
|
||||||
import com.mh.user.constants.Constant; |
|
||||||
import lombok.SneakyThrows; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.quartz.DisallowConcurrentExecution; |
|
||||||
import org.quartz.Job; |
|
||||||
import org.quartz.JobExecutionContext; |
|
||||||
import org.quartz.JobExecutionException; |
|
||||||
|
|
||||||
/** |
|
||||||
* :@DisallowConcurrentExecution : 此标记用在实现Job的类上面,意思是不允许并发执行. |
|
||||||
* :注意org.quartz.threadPool.threadCount线程池中线程的数量至少要多个,否则@DisallowConcurrentExecution不生效 |
|
||||||
* :假如Job的设置时间间隔为3秒,但Job执行时间是5秒,设置@DisallowConcurrentExecution以后程序会等任务执行完毕以后再去执行, |
|
||||||
* 否则会在3秒时再启用新的线程执行 |
|
||||||
*/ |
|
||||||
@DisallowConcurrentExecution |
|
||||||
@Slf4j |
|
||||||
public class JobTest1 implements Job { |
|
||||||
@SneakyThrows |
|
||||||
@Override |
|
||||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { |
|
||||||
for (int i = 0; i < 30; i++) { |
|
||||||
if (Constant.FLAG) { |
|
||||||
break; |
|
||||||
} |
|
||||||
Thread.sleep(1000); |
|
||||||
log.info("第" + i + "个," +jobExecutionContext.getJobDetail()+"---------------------定时任务测试----------------------"); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
@ -1,190 +0,0 @@ |
|||||||
package com.mh.user.job;//package com.mh.quartz.job;
|
|
||||||
//
|
|
||||||
//import com.mh.quartz.manage.SerialPortManager;
|
|
||||||
//import com.mh.quartz.utils.AnalysisReceiveOrder485;
|
|
||||||
//import com.mh.quartz.utils.ExchangeStringUtil;
|
|
||||||
//import com.mh.quartz.utils.GetReadOrder485;
|
|
||||||
//import gnu.io.PortInUseException;
|
|
||||||
//import gnu.io.SerialPort;
|
|
||||||
//import lombok.extern.slf4j.Slf4j;
|
|
||||||
//import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
//import org.springframework.stereotype.Component;
|
|
||||||
//
|
|
||||||
//import java.util.Date;
|
|
||||||
//import java.util.concurrent.BlockingQueue;
|
|
||||||
//import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * @author ljf
|
|
||||||
// * @title :
|
|
||||||
// * @description : 定时采集发送水电表数据
|
|
||||||
// * @updateTime 2020-04-22
|
|
||||||
// * @throws :
|
|
||||||
// */
|
|
||||||
//@Component
|
|
||||||
//@Slf4j
|
|
||||||
//public class SendMeterWaterJob {
|
|
||||||
//
|
|
||||||
// // 串口对象
|
|
||||||
// private SerialPort mSerialPort;
|
|
||||||
//
|
|
||||||
// AnalysisReceiveOrder485 analysisReceiveOrder485;
|
|
||||||
//
|
|
||||||
// // 测试
|
|
||||||
// @Scheduled(cron = "0,5 * * * * ? ")
|
|
||||||
// public void test() throws InterruptedException {
|
|
||||||
// Thread.sleep(10000);
|
|
||||||
// log.info("延迟10s");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Scheduled(cron = "0,20,40 * * * * ? ")
|
|
||||||
// public void task1() throws PortInUseException, InterruptedException {
|
|
||||||
//
|
|
||||||
// // 堵塞队列用来存放读到的数据
|
|
||||||
// BlockingQueue<String> msgQueue = new LinkedBlockingQueue<String>();
|
|
||||||
// log.info("每0、20、40秒执行一次!");
|
|
||||||
// if (mSerialPort == null){
|
|
||||||
// // 打开串口
|
|
||||||
// } else {
|
|
||||||
// // 关闭串口
|
|
||||||
// SerialPortManager.closePort(mSerialPort);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// mSerialPort = SerialPortManager.openPort("COM2",1200);
|
|
||||||
//
|
|
||||||
// // 发送数据(采集冷量计累计流量)
|
|
||||||
// String sendMeterOrderStr = "FEFEFE" + GetReadOrder485.createMeterOrder("080140001125","1");
|
|
||||||
// SerialPortManager.sendToPort(mSerialPort, ExchangeStringUtil.hexStrToBinaryStr(sendMeterOrderStr));
|
|
||||||
//
|
|
||||||
// // 添加串口监听
|
|
||||||
// SerialPort finalMSerialPort = mSerialPort;
|
|
||||||
// SerialPortManager.addListener(mSerialPort, () -> {
|
|
||||||
// byte[] data = null;
|
|
||||||
// try {
|
|
||||||
// // 读取串口数据
|
|
||||||
// data = SerialPortManager.readFromPort(finalMSerialPort);
|
|
||||||
// String needData = ExchangeStringUtil.printHexString(data);
|
|
||||||
// msgQueue.add(needData);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.info(e.getMessage());
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// // 创建线程解析队列信息
|
|
||||||
// Thread thread = new Thread(() -> {
|
|
||||||
// try {
|
|
||||||
// log.info("--------------任务处理线程运行了--------------");
|
|
||||||
// String vo = "";
|
|
||||||
// String vos[] = new String[0];
|
|
||||||
// while (true) {
|
|
||||||
// // 判断数组是否完整
|
|
||||||
// // 电表
|
|
||||||
// if (vos.length >= 22) {
|
|
||||||
// log.info("获取到数据长度: " + vos.length);
|
|
||||||
// log.info("电表: " + new Date() + " 完整收到的数据为:-----" + vo);
|
|
||||||
// // 解析接收到的报文
|
|
||||||
// analysisReceiveOrder485.analysisMeterOrder485(vo);
|
|
||||||
// vos = new String[0];
|
|
||||||
// vo = "";
|
|
||||||
//// sendOrder();
|
|
||||||
// } else {
|
|
||||||
// // 如果堵塞队列中存在数据就将其输出
|
|
||||||
// if (msgQueue.size() > 0) {
|
|
||||||
// if (vo == "") {
|
|
||||||
// vo = msgQueue.peek();
|
|
||||||
// } else {
|
|
||||||
// vo = vo + " " + msgQueue.peek();
|
|
||||||
// }
|
|
||||||
// vos = vo.split(" ", -1);
|
|
||||||
//// getData(vos);
|
|
||||||
// msgQueue.take();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// // TODO Auto-generated catch block
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// thread.start();
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Scheduled(cron = "10,30,50 * * * * ? ")
|
|
||||||
// public void task2() throws PortInUseException, InterruptedException {
|
|
||||||
// // 堵塞队列用来存放读到的数据
|
|
||||||
// BlockingQueue<String> msgQueue = new LinkedBlockingQueue<String>();
|
|
||||||
// log.info("每10、30、50秒执行一次!");
|
|
||||||
// if (mSerialPort == null){
|
|
||||||
// // 打开串口
|
|
||||||
// } else {
|
|
||||||
// // 关闭串口
|
|
||||||
// SerialPortManager.closePort(mSerialPort);
|
|
||||||
// }
|
|
||||||
// mSerialPort = SerialPortManager.openPort("COM3",9600);
|
|
||||||
//
|
|
||||||
// // 发送数据(采集冷量计累计流量)
|
|
||||||
// String sendOrderStr = GetReadOrder485.createCloudOrder("88","34");
|
|
||||||
// SerialPortManager.sendToPort(mSerialPort, ExchangeStringUtil.hexStrToBinaryStr(sendOrderStr));
|
|
||||||
//
|
|
||||||
// // 添加串口监听
|
|
||||||
// SerialPort finalMSerialPort = mSerialPort;
|
|
||||||
// SerialPortManager.addListener(mSerialPort, () -> {
|
|
||||||
// byte[] data = null;
|
|
||||||
// try {
|
|
||||||
// // 读取串口数据
|
|
||||||
// data = SerialPortManager.readFromPort(finalMSerialPort);
|
|
||||||
// String needData = ExchangeStringUtil.printHexString(data);
|
|
||||||
// msgQueue.add(needData);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.info(e.getMessage());
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// // 创建线程解析队列信息
|
|
||||||
// Thread thread = new Thread(() -> {
|
|
||||||
// try {
|
|
||||||
// log.info("--------------任务处理线程运行了--------------");
|
|
||||||
// String vo = "";
|
|
||||||
// String vos[] = new String[0];
|
|
||||||
// while (true) {
|
|
||||||
// // 判断数组是否完整
|
|
||||||
// // 冷量计
|
|
||||||
// if (vos.length >= 9) {
|
|
||||||
// if (vos.length == 9) {
|
|
||||||
// log.info("获取到数据长度: " + vos.length);
|
|
||||||
// log.info("冷量计: " + new Date() + " 完整收到的数据为:-----" + vo);
|
|
||||||
// // 解析接收到的报文
|
|
||||||
// analysisReceiveOrder485.analysisCloudOrder485(vo);
|
|
||||||
// }
|
|
||||||
// vos = new String[0];
|
|
||||||
// vo = "";
|
|
||||||
//// sendOrder();
|
|
||||||
// } else {
|
|
||||||
// // 如果堵塞队列中存在数据就将其输出
|
|
||||||
// if (msgQueue.size() > 0) {
|
|
||||||
// if (vo.equalsIgnoreCase("")){
|
|
||||||
// vo = msgQueue.peek();
|
|
||||||
// } else {
|
|
||||||
// vo = vo + " " + msgQueue.peek();
|
|
||||||
// }
|
|
||||||
// vos = vo.split(" ", -1);
|
|
||||||
//// getData(vos);
|
|
||||||
// msgQueue.take();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// // TODO Auto-generated catch block
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// thread.start();
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//}
|
|
@ -0,0 +1,227 @@ |
|||||||
|
package com.mh.user.mapper; |
||||||
|
|
||||||
|
import com.mh.user.dto.EnergyPreEchartDataDTO; |
||||||
|
import com.mh.user.dto.EnergyPreTopDataDTO; |
||||||
|
import com.mh.user.entity.HistoryDataPre; |
||||||
|
import org.apache.ibatis.annotations.*; |
||||||
|
import org.springframework.security.core.parameters.P; |
||||||
|
import tk.mybatis.mapper.common.BaseMapper; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 预测历史数据mapper |
||||||
|
* @date 2024-05-09 10:01:46 |
||||||
|
*/ |
||||||
|
@Mapper |
||||||
|
public interface HistoryDataPreMapper extends BaseMapper<HistoryDataPre> { |
||||||
|
|
||||||
|
@Results(id ="rs_train_data",value ={ |
||||||
|
@Result(column = "env_min_temp", property = "envMinTemp"), |
||||||
|
@Result(column = "env_max_temp", property = "envMaxTemp"), |
||||||
|
@Result(column = "water_value", property = "waterValue"), |
||||||
|
@Result(column = "elect_value", property = "electValue"), |
||||||
|
@Result(column = "water_level", property = "waterLevel"), |
||||||
|
@Result(column = "people_num", property = "peopleNum") |
||||||
|
}) |
||||||
|
@Select("select env_min_temp, env_max_temp, water_value, elect_value, water_level, people_num from history_data_pre where building_id = #{buildingId} order by cur_date ") |
||||||
|
List<HistoryDataPre> getTrainData(@Param("buildingId") String buildingId); |
||||||
|
|
||||||
|
@Results(id ="rs_recent_data",value ={ |
||||||
|
@Result(column = "id",property = "id" ), |
||||||
|
@Result(column = "building_id", property = "buildingId"), |
||||||
|
@Result(column = "cur_date", property = "curDate"), |
||||||
|
@Result(column = "env_min_temp", property = "envMinTemp"), |
||||||
|
@Result(column = "env_max_temp", property = "envMaxTemp"), |
||||||
|
@Result(column = "water_value", property = "waterValue"), |
||||||
|
@Result(column = "elect_value", property = "electValue"), |
||||||
|
@Result(column = "water_level", property = "waterLevel"), |
||||||
|
@Result(column = "water_value_pre", property = "waterValuePre"), |
||||||
|
@Result(column = "elect_value_pre", property = "electValuePre"), |
||||||
|
@Result(column = "water_level_pre", property = "waterLevelPre"), |
||||||
|
@Result(column = "remark", property = "remark") |
||||||
|
}) |
||||||
|
@Select("select * from history_date_pre where building_id = #{buildingId} and cur_date = #{curDate} order by cur_date ") |
||||||
|
List<HistoryDataPre> getRecentData(@Param("buildingId") String buildingId, |
||||||
|
@Param("curDate") String curDate); |
||||||
|
|
||||||
|
@Update("update history_data_pre set water_value_pre = #{waterValuePre},elect_value_pre = #{electValuePre},water_level_pre = #{waterLevelPre}," + |
||||||
|
" water_value = #{waterValue},elect_value = #{electValue},water_level = #{waterLevel} " + |
||||||
|
" where id = #{id} and building_id = #{buildingId}") |
||||||
|
void updateById(HistoryDataPre preHistoryData); |
||||||
|
|
||||||
|
@Select("select count(*) from history_data_pre where building_id = #{buildingId} and cur_date = #{curDate} and env_min_temp is not null ") |
||||||
|
int selectIsPre(@Param("buildingId") String buildingId, |
||||||
|
@Param("curDate") String curDate); |
||||||
|
|
||||||
|
@Results(id ="rs_cur_data",value ={ |
||||||
|
@Result(column = "id",property = "id" ), |
||||||
|
@Result(column = "building_id", property = "buildingId"), |
||||||
|
@Result(column = "cur_date", property = "curDate"), |
||||||
|
@Result(column = "env_min_temp", property = "envMinTemp"), |
||||||
|
@Result(column = "env_max_temp", property = "envMaxTemp"), |
||||||
|
@Result(column = "water_value", property = "waterValue"), |
||||||
|
@Result(column = "elect_value", property = "electValue"), |
||||||
|
@Result(column = "water_level", property = "waterLevel") |
||||||
|
}) |
||||||
|
@Select("select top 1 " + |
||||||
|
" convert(date,eds.cur_date) as cur_date, " + |
||||||
|
" eds.building_id, " + |
||||||
|
" isnull(eds.water_value, " + |
||||||
|
" 0) as water_value, " + |
||||||
|
" isnull(eds.elect_value, " + |
||||||
|
" 0) as elect_value, " + |
||||||
|
" isnull(convert(numeric(24, " + |
||||||
|
" 2), " + |
||||||
|
" t1.water_level), " + |
||||||
|
" 0) as water_level " + |
||||||
|
"from " + |
||||||
|
" energy_day_sum eds " + |
||||||
|
"left join ( " + |
||||||
|
" select " + |
||||||
|
" convert(date, " + |
||||||
|
" cur_date) as cur_date, " + |
||||||
|
" building_id, " + |
||||||
|
" avg(isnull(convert(numeric(24, 2), water_level), 0)) as water_level " + |
||||||
|
" from " + |
||||||
|
" history_data " + |
||||||
|
" where " + |
||||||
|
" building_id = #{buildingId} " + |
||||||
|
" and cur_date = #{curDate} " + |
||||||
|
" group by " + |
||||||
|
" convert(date, " + |
||||||
|
" cur_date), " + |
||||||
|
" building_id " + |
||||||
|
" ) t1 on " + |
||||||
|
" eds.cur_date = t1.cur_date " + |
||||||
|
" and eds.building_id = t1.building_id " + |
||||||
|
"where " + |
||||||
|
" eds.building_id != '所有' " + |
||||||
|
" and eds.building_id = #{buildingId} " + |
||||||
|
" and eds.cur_date = #{curDate} " + |
||||||
|
"order by " + |
||||||
|
" eds.building_id, " + |
||||||
|
" eds.cur_date ") |
||||||
|
HistoryDataPre selectCurData(@Param("buildingId") String buildingId, |
||||||
|
@Param("curDate") String curDate); |
||||||
|
|
||||||
|
@Insert("insert into history_data_pre(cur_date, building_id, env_min_temp, env_max_temp, water_value, elect_value, water_level) values(" + |
||||||
|
"convert(date,#{curDate}), #{buildingId}, #{envMinTemp}, #{envMaxTemp}, #{waterValue}, #{electValue}, #{waterLevel}" + |
||||||
|
")") |
||||||
|
void insertData(HistoryDataPre curHistoryData); |
||||||
|
|
||||||
|
@Results(id ="rs_one_data",value ={ |
||||||
|
@Result(column = "id",property = "id" ), |
||||||
|
@Result(column = "building_id", property = "buildingId"), |
||||||
|
@Result(column = "cur_date", property = "curDate"), |
||||||
|
@Result(column = "env_min_temp", property = "envMinTemp"), |
||||||
|
@Result(column = "env_max_temp", property = "envMaxTemp"), |
||||||
|
@Result(column = "people_num", property = "peopleNum") |
||||||
|
}) |
||||||
|
@Select("select top 1 id, building_id, cur_date, env_min_temp, env_max_temp, people_num from history_data_pre where building_id = #{buildingId} and cur_date = #{curDate} ") |
||||||
|
HistoryDataPre selectOneData(@Param("buildingId") String buildingId, |
||||||
|
@Param("curDate") String curDate); |
||||||
|
|
||||||
|
@Results({ |
||||||
|
@Result(column = "cur_yes_data",property = "curYesData" ), |
||||||
|
@Result(column = "yes_data", property = "yesData"), |
||||||
|
@Result(column = "pre_yes_data", property = "preYesData"), |
||||||
|
@Result(column = "error_data", property = "errorData") |
||||||
|
}) |
||||||
|
@Select("<script>" + |
||||||
|
"SELECT " + |
||||||
|
" <choose>" + |
||||||
|
" <when test='type == \"2\"'>" + |
||||||
|
" isnull(t.water_value_pre, 0) as cur_yes_data, " + |
||||||
|
" isnull(t1.water_value, 0) as yes_data, " + |
||||||
|
" isnull(t1.water_value_pre, 0) as pre_yes_data, " + |
||||||
|
" CASE WHEN t1.water_value_pre > 0 THEN CONVERT(decimal(18, 2), ABS(isnull(t1.water_value_pre, 0) - isnull(t1.water_value, 0)) / t1.water_value_pre * 100) ELSE '0' END as error_data" + |
||||||
|
" </when>" + |
||||||
|
" <when test='type == \"1\"'>" + |
||||||
|
" isnull(t.elect_value_pre, 0) as cur_yes_data, " + |
||||||
|
" isnull(t1.elect_value, 0) as yes_data, " + |
||||||
|
" isnull(t1.elect_value_pre, 0) as pre_yes_data, " + |
||||||
|
" CASE WHEN t1.elect_value_pre > 0 THEN CONVERT(decimal(18, 2), ABS(isnull(t1.elect_value_pre, 0) - isnull(t1.elect_value, 0)) / t1.elect_value_pre * 100) ELSE '0' END as error_data" + |
||||||
|
" </when>" + |
||||||
|
" <when test='type == \"3\"'>" + |
||||||
|
" isnull(t.water_level_pre, 0) as cur_yes_data, " + |
||||||
|
" isnull(t1.water_level, 0) as yes_data, " + |
||||||
|
" isnull(t1.water_level_pre, 0) as pre_yes_data, " + |
||||||
|
" CASE WHEN t1.water_level_pre > 0 THEN CONVERT(decimal(18, 2), ABS(isnull(t1.water_level_pre, 0) - isnull(t1.water_level, 0)) / t1.water_level_pre * 100) ELSE '0' END as error_data" + |
||||||
|
" </when>" + |
||||||
|
" <otherwise>null</otherwise>" + |
||||||
|
" </choose>" + |
||||||
|
"FROM (" + |
||||||
|
" SELECT " + |
||||||
|
" building_id, " + |
||||||
|
" water_value, " + |
||||||
|
" elect_value, " + |
||||||
|
" water_level, " + |
||||||
|
" water_value_pre, " + |
||||||
|
" elect_value_pre, " + |
||||||
|
" water_level_pre " + |
||||||
|
" FROM history_data_pre " + |
||||||
|
" WHERE cur_date = CONVERT(varchar(10), GETDATE(), 120) AND building_id = #{buildingId}" + |
||||||
|
") t " + |
||||||
|
"JOIN (" + |
||||||
|
" SELECT " + |
||||||
|
" building_id, " + |
||||||
|
" water_value, " + |
||||||
|
" elect_value, " + |
||||||
|
" water_level, " + |
||||||
|
" water_value_pre, " + |
||||||
|
" elect_value_pre, " + |
||||||
|
" water_level_pre " + |
||||||
|
" FROM history_data_pre " + |
||||||
|
" WHERE cur_date = CONVERT(varchar(10), DATEADD(day, -1, GETDATE()), 120) AND building_id = #{buildingId}" + |
||||||
|
") t1 ON t.building_id = t1.building_id " + |
||||||
|
"</script>") |
||||||
|
List<EnergyPreTopDataDTO> getTopData(@Param("buildingId") String buildingId, @Param("type") String type); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Results({ |
||||||
|
@Result(column = "cur_date",property = "curDate" ), |
||||||
|
@Result(column = "cur_data", property = "curData"), |
||||||
|
@Result(column = "pre_data", property = "preData"), |
||||||
|
@Result(column = "error_data", property = "errorData") |
||||||
|
}) |
||||||
|
@Select("<script>" + |
||||||
|
"SELECT " + |
||||||
|
" hdp.cur_date, " + |
||||||
|
" <choose>" + |
||||||
|
" <when test='type == \"2\"'>isnull(hdp.water_value, 0)</when>" + |
||||||
|
" <when test='type == \"1\"'>isnull(hdp.elect_value, 0)</when>" + |
||||||
|
" <when test='type == \"3\"'>isnull(hdp.water_level, 0)</when>" + |
||||||
|
" <otherwise>0</otherwise>" + |
||||||
|
" </choose> as cur_data, " + |
||||||
|
" <choose>" + |
||||||
|
" <when test='type == \"2\"'>isnull(hdp.water_value_pre, 0)</when>" + |
||||||
|
" <when test='type == \"1\"'>isnull(hdp.elect_value_pre, 0)</when>" + |
||||||
|
" <when test='type == \"3\"'>isnull(hdp.water_level_pre, 0)</when>" + |
||||||
|
" <otherwise>0</otherwise>" + |
||||||
|
" </choose> as pre_data, " + |
||||||
|
" CASE " + |
||||||
|
" <when test='type == \"2\"'>" + |
||||||
|
" WHEN hdp.water_value_pre > 0 THEN CONVERT(decimal(18, 2), ABS(isnull(hdp.water_value_pre, 0) - isnull(hdp.water_value, 0)) / hdp.water_value_pre * 100) else 0 " + |
||||||
|
" </when>" + |
||||||
|
" <when test='type == \"1\"'>" + |
||||||
|
" WHEN hdp.elect_value_pre > 0 THEN CONVERT(decimal(18, 2), ABS(isnull(hdp.elect_value_pre, 0) - isnull(hdp.elect_value, 0)) / hdp.elect_value_pre * 100) else 0 " + |
||||||
|
" </when>" + |
||||||
|
" <when test='type == \"3\"'>" + |
||||||
|
" WHEN hdp.water_level_pre > 0 THEN CONVERT(decimal(18, 2), ABS(isnull(hdp.water_level_pre, 0) - isnull(hdp.water_level, 0)) / hdp.water_level_pre * 100) else 0 " + |
||||||
|
" </when>" + |
||||||
|
" END as error_data " + |
||||||
|
"FROM history_data_pre hdp " + |
||||||
|
"WHERE hdp.building_id = #{buildingId} " + |
||||||
|
" AND cur_date BETWEEN #{beginDate} AND #{endDate} " + |
||||||
|
"ORDER BY cur_date" + |
||||||
|
"</script>") |
||||||
|
List<EnergyPreEchartDataDTO> getEnergyPre(@Param("buildingId") String buildingId, |
||||||
|
@Param("beginDate") String beginDate, |
||||||
|
@Param("endDate") String endDate, |
||||||
|
@Param("type") String type); |
||||||
|
} |
@ -0,0 +1,57 @@ |
|||||||
|
package com.mh.user.mapper; |
||||||
|
|
||||||
|
import com.mh.user.entity.KnowledgeDataEntity; |
||||||
|
import org.apache.ibatis.annotations.*; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 知识库管理 |
||||||
|
* @date 2024-06-26 14:21:47 |
||||||
|
*/ |
||||||
|
@Mapper |
||||||
|
public interface KnowledgeDataMapper { |
||||||
|
|
||||||
|
@Insert("insert into knowledge_data(title,description,content,create_time,status,remark) " + |
||||||
|
" values(#{title},#{description},#{content},getDate(),#{status},#{remark})") |
||||||
|
void insertKnowledgeData(KnowledgeDataEntity knowledgeData); |
||||||
|
|
||||||
|
@Results({ |
||||||
|
@Result(column = "id",property = "id" ), |
||||||
|
@Result(column = "title", property = "title"), |
||||||
|
@Result(column = "description", property = "description"), |
||||||
|
@Result(column = "content", property = "content"), |
||||||
|
@Result(column = "create_time", property = "createTime"), |
||||||
|
@Result(column = "status", property = "status"), |
||||||
|
@Result(column = "remark", property = "remark") |
||||||
|
}) |
||||||
|
@Select("select id,title,description,content,create_time,status,remark from knowledge_data order by create_time desc") |
||||||
|
List<KnowledgeDataEntity> findPage(); |
||||||
|
|
||||||
|
@Update("<script>" + |
||||||
|
" update knowledge_data set " + |
||||||
|
" <if test='title!=null'> title = #{title} </if>" + |
||||||
|
" <if test='description!=null'> , description = #{description} </if>" + |
||||||
|
" <if test='content!=null'> , content = #{content} </if>" + |
||||||
|
" <if test='createTime!=null'> , create_time = #{createTime} </if>" + |
||||||
|
" <if test='status!=null'> , status = #{status} </if>" + |
||||||
|
" <if test='remark!=null'> , remark = #{remark} </if>" + |
||||||
|
" where id = #{id} " + |
||||||
|
"</script>") |
||||||
|
void updateData(KnowledgeDataEntity knowledgeData); |
||||||
|
|
||||||
|
@Results({ |
||||||
|
@Result(column = "id",property = "id" ), |
||||||
|
@Result(column = "title", property = "title"), |
||||||
|
@Result(column = "description", property = "description"), |
||||||
|
@Result(column = "content", property = "content"), |
||||||
|
@Result(column = "create_time", property = "createTime"), |
||||||
|
@Result(column = "status", property = "status"), |
||||||
|
@Result(column = "remark", property = "remark") |
||||||
|
}) |
||||||
|
@Select("select id,title,description,content,create_time,status,remark from knowledge_data where id = #{id} order by create_time desc") |
||||||
|
KnowledgeDataEntity getById(@Param("id") Long id); |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package com.mh.user.mapper; |
||||||
|
|
||||||
|
import com.mh.user.entity.SysParamEntity; |
||||||
|
import org.apache.ibatis.annotations.Mapper; |
||||||
|
import org.apache.ibatis.annotations.Select; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 系统参数 |
||||||
|
* @date 2024-01-16 08:58:43 |
||||||
|
*/ |
||||||
|
@Mapper |
||||||
|
public interface SysParamMapper { |
||||||
|
|
||||||
|
@Select("select top 1 * from SysParam ") |
||||||
|
SysParamEntity selectSysParam(); |
||||||
|
|
||||||
|
} |
@ -1,98 +0,0 @@ |
|||||||
package com.mh.user.netty; |
|
||||||
|
|
||||||
import com.mh.user.entity.OrderMessageEntity; |
|
||||||
import io.netty.bootstrap.Bootstrap; |
|
||||||
import io.netty.channel.*; |
|
||||||
import io.netty.channel.nio.NioEventLoopGroup; |
|
||||||
import io.netty.channel.socket.SocketChannel; |
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel; |
|
||||||
import io.netty.handler.timeout.IdleStateHandler; |
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler; |
|
||||||
import lombok.Getter; |
|
||||||
import lombok.Setter; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
import java.util.concurrent.TimeUnit; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title : |
|
||||||
* @description : 控制冷水机组和其他设备 |
|
||||||
* @updateTime 2020-05-28 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
@Setter |
|
||||||
@Getter |
|
||||||
@Slf4j |
|
||||||
public class NettyChillerControlClient { |
|
||||||
|
|
||||||
// private int port;
|
|
||||||
// private String host;
|
|
||||||
// private List<OrderMessageEntity> orderMessageEntityList;
|
|
||||||
|
|
||||||
// 构造函数传递值 继承Thread时需要
|
|
||||||
// public NettyChillerControlClient(int port, String host) {
|
|
||||||
// this.port = port;
|
|
||||||
// this.host = host;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public void connect(int port, String host, List<OrderMessageEntity> orderMessageEntityList) throws InterruptedException { |
|
||||||
// 配置客户端NIO线程组
|
|
||||||
EventLoopGroup group = new NioEventLoopGroup(1); |
|
||||||
try { |
|
||||||
Bootstrap bootstrap = new Bootstrap(); |
|
||||||
bootstrap.group(group).channel(NioSocketChannel.class) |
|
||||||
.option(ChannelOption.TCP_NODELAY, true) |
|
||||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) |
|
||||||
.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(1024*1024)) |
|
||||||
.handler(new ChannelInitializer<SocketChannel>() { |
|
||||||
@Override |
|
||||||
protected void initChannel(SocketChannel socketChannel) { |
|
||||||
// 基于换行符号
|
|
||||||
// socketChannel.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,4,4,-8,0));
|
|
||||||
// // 解码转String,注意调整自己的编码格式GBK、UTF-8
|
|
||||||
// socketChannel.pipeline().addLast(new StringDecoder(StandardCharsets.UTF_8));
|
|
||||||
// // 解码转String,注意调整自己的编码格式GBK、UTF-8
|
|
||||||
// socketChannel.pipeline().addLast(new StringEncoder(StandardCharsets.UTF_8));
|
|
||||||
// socketChannel.pipeline().addLast(new LengthFieldPrepender(4));
|
|
||||||
// 超过10秒钟没有数据读取自动断开连接
|
|
||||||
// socketChannel.pipeline().addLast(new ReadTimeoutHandler(30));
|
|
||||||
// 超过10秒没有返回触发心跳机制 update by ljf on 2021-01-30
|
|
||||||
socketChannel.pipeline().addLast(new IdleStateHandler(10,10,6, TimeUnit.SECONDS)); |
|
||||||
// 在管道中添加我们自己的接收数据实现方法
|
|
||||||
socketChannel.pipeline().addLast(new NettyChillerControlHandler(orderMessageEntityList)); |
|
||||||
// socketChannel.pipeline().addLast(new NettyMeterClientHandler());
|
|
||||||
} |
|
||||||
}); |
|
||||||
// 发起异步连接操作
|
|
||||||
ChannelFuture channelFuture = bootstrap.connect(host, port).sync(); |
|
||||||
if (channelFuture.isSuccess()) { |
|
||||||
log.info("connect server 成功---------"); |
|
||||||
} else { |
|
||||||
log.info("连接失败!"); |
|
||||||
log.info("准备重连!"); |
|
||||||
// connect(port, host);
|
|
||||||
} |
|
||||||
|
|
||||||
// 等待客户端连接链路关闭future.channel().closeFuture().sync(); // 阻塞main线程
|
|
||||||
channelFuture.channel().closeFuture().sync(); |
|
||||||
} catch (Exception e) { |
|
||||||
log.error(e.getMessage()); |
|
||||||
} finally { |
|
||||||
group.shutdownGracefully(); |
|
||||||
// try {
|
|
||||||
// TimeUnit.SECONDS.sleep(5);
|
|
||||||
// connect(port, host); // 断线重连
|
|
||||||
// } catch (InterruptedException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// @SneakyThrows
|
|
||||||
// @Override
|
|
||||||
// public void run() {
|
|
||||||
// connect(port, host);
|
|
||||||
// }
|
|
||||||
} |
|
@ -1,311 +0,0 @@ |
|||||||
package com.mh.user.netty; |
|
||||||
|
|
||||||
import com.mh.user.entity.OrderMessageEntity; |
|
||||||
import com.mh.user.service.impl.DeviceDisplayServiceImpl; |
|
||||||
import com.mh.user.constants.Constant; |
|
||||||
import com.mh.user.utils.ExchangeStringUtil; |
|
||||||
import com.mh.user.utils.SpringBeanUtil; |
|
||||||
import io.netty.buffer.ByteBuf; |
|
||||||
import io.netty.channel.ChannelHandlerAdapter; |
|
||||||
import io.netty.channel.ChannelHandlerContext; |
|
||||||
import io.netty.handler.timeout.IdleState; |
|
||||||
import io.netty.handler.timeout.IdleStateEvent; |
|
||||||
import io.netty.util.ReferenceCountUtil; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.springframework.context.ApplicationContext; |
|
||||||
|
|
||||||
import java.text.SimpleDateFormat; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title : |
|
||||||
* @description :客户端异步消息处理机制 |
|
||||||
* @updateTime 2020-05-13 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
@Slf4j |
|
||||||
public class NettyChillerControlHandler extends ChannelHandlerAdapter { |
|
||||||
|
|
||||||
private int num = 0; |
|
||||||
private int size = 0; |
|
||||||
private String receiveStr = ""; |
|
||||||
private int sendNum = 0; |
|
||||||
private int idle_count = 1; |
|
||||||
|
|
||||||
List<OrderMessageEntity> orderMessageEntityList; |
|
||||||
|
|
||||||
// 调用service
|
|
||||||
ApplicationContext context = SpringBeanUtil.getApplicationContext(); |
|
||||||
DeviceDisplayServiceImpl.GatewayManageService gatewayManageService = context.getBean(DeviceDisplayServiceImpl.GatewayManageService.class); |
|
||||||
//OrderMessageService orderMessageService = context.getBean(OrderMessageService.class);
|
|
||||||
|
|
||||||
public NettyChillerControlHandler(List<OrderMessageEntity> orderMessageEntityList) { |
|
||||||
this.orderMessageEntityList = orderMessageEntityList; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { |
|
||||||
log.info("当前channel从EventLoop取消注册"); |
|
||||||
// Constant.SEND_STATUS = false;
|
|
||||||
// super.channelUnregistered(ctx);
|
|
||||||
ctx.close(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 超时处理 |
|
||||||
* 如果120秒没有接受客户端的心跳,就触发; |
|
||||||
* 如果超过3次,则直接关闭; |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { |
|
||||||
if (obj instanceof IdleStateEvent) { |
|
||||||
IdleStateEvent event = (IdleStateEvent) obj; |
|
||||||
if (IdleState.READER_IDLE.equals(event.state())) { //如果读通道处于空闲状态,说明没有接收到心跳命令
|
|
||||||
System.out.println("第" + idle_count + "已经10秒没有接收到服务器的信息了,发送第" + num + "条数据"); |
|
||||||
if (num > size - 1) { |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
Constant.SEND_STATUS = true; |
|
||||||
System.out.println("关闭这个不活跃的channel"); |
|
||||||
ctx.close(); |
|
||||||
} else if (idle_count > 3) { |
|
||||||
System.out.println("关闭这个不活跃的channel"); |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
Constant.SEND_STATUS = false; |
|
||||||
ctx.close(); |
|
||||||
} else { |
|
||||||
// 发送采集DDC指令
|
|
||||||
// 判断空值
|
|
||||||
if (orderMessageEntityList.get(num).getRegisterAddr() == null || |
|
||||||
orderMessageEntityList.get(num).getRegisterAddr().equalsIgnoreCase("")) { |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
Constant.SEND_STATUS = true; |
|
||||||
ctx.close(); |
|
||||||
} else { |
|
||||||
String sendStr = orderMessageEntityList.get(num).getOrderStr(); |
|
||||||
// // 获取采集参数个数
|
|
||||||
// size = orderMessageEntityList.size();
|
|
||||||
// 2.发送数据
|
|
||||||
ByteBuf buffer = getByteBuf(ctx, sendStr); |
|
||||||
ctx.channel().writeAndFlush(buffer); |
|
||||||
idle_count++; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} else { |
|
||||||
super.userEventTriggered(ctx, obj); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { |
|
||||||
// super.exceptionCaught(ctx, cause);
|
|
||||||
log.info("通信异常!!"); |
|
||||||
cause.printStackTrace(); |
|
||||||
// receiveStr = null;
|
|
||||||
// Channel incoming = ctx.channel();
|
|
||||||
// if (incoming.isActive()) {
|
|
||||||
// // 重新发送
|
|
||||||
// if (sendNum > 2) {
|
|
||||||
// // 通信异常,发送失败
|
|
||||||
// log.info("SimpleClient: " + incoming.remoteAddress() + "异常");
|
|
||||||
// cause.printStackTrace();
|
|
||||||
// Constant.SEND_STATUS = false;
|
|
||||||
// ctx.close();
|
|
||||||
// } else {
|
|
||||||
// // 发送采集DDC指令
|
|
||||||
// String sendStr = orderMessageEntityList.get(num).getOrderStr();
|
|
||||||
// // 获取采集参数个数
|
|
||||||
// size = orderMessageEntityList.size();
|
|
||||||
// // 2.发送数据
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx,sendStr);
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
// sendNum += 1;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // 判断发送的下标,如果不等于指令数组大小
|
|
||||||
// num = num + 1;
|
|
||||||
// if (num > size-1) {
|
|
||||||
// num = 0;
|
|
||||||
// // 关闭连接
|
|
||||||
// receiveStr = null;
|
|
||||||
// Constant.SEND_STATUS = true;
|
|
||||||
// ctx.close();
|
|
||||||
// }
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception { |
|
||||||
super.channelActive(ctx); |
|
||||||
SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-mm-dd HH:mm:ss"); |
|
||||||
Date date=new Date(); |
|
||||||
log.info(ctx.channel().remoteAddress() + " " + sdf1.format(date) + "链接服务端成功!"); |
|
||||||
// 截取IP地址
|
|
||||||
String IP = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress()+"","/", ":"); |
|
||||||
// 截取端口号
|
|
||||||
String port = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress()+"",":", ""); |
|
||||||
log.info("IP: " + IP + ",端口号: " + port); |
|
||||||
// 更新对应的网关在线情况
|
|
||||||
gatewayManageService.updateGatewayManage(IP, port); |
|
||||||
|
|
||||||
// 发送控制DDC指令
|
|
||||||
String sendStr = orderMessageEntityList.get(num).getOrderStr(); |
|
||||||
// 获取采集参数个数
|
|
||||||
size = orderMessageEntityList.size(); |
|
||||||
|
|
||||||
// 2.发送数据
|
|
||||||
ByteBuf buffer = getByteBuf(ctx,sendStr); |
|
||||||
ctx.channel().writeAndFlush(buffer); |
|
||||||
} |
|
||||||
|
|
||||||
private ByteBuf getByteBuf(ChannelHandlerContext ctx, String sendStr) { |
|
||||||
// 申请一个数据结构存储信息
|
|
||||||
ByteBuf buffer = ctx.alloc().buffer(); |
|
||||||
// 将信息放入数据结构中
|
|
||||||
buffer.writeBytes(ExchangeStringUtil.hexStrToBinaryStr(sendStr));//对接需要16进制
|
|
||||||
return buffer; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception { |
|
||||||
// Thread.sleep(100);
|
|
||||||
ctx.close(); |
|
||||||
log.info(ctx.channel().localAddress() + "退出链接!!"); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { |
|
||||||
// super.channelRead(ctx, msg);
|
|
||||||
// ByteBuf buf = (ByteBuf)msg;
|
|
||||||
// byte[] req = new byte[buf.readableBytes()];
|
|
||||||
// buf.readBytes(req);
|
|
||||||
// String body = new String(req, "UTF-8");
|
|
||||||
try { |
|
||||||
ByteBuf buf = (ByteBuf)msg; |
|
||||||
byte [] bytes = new byte[buf.readableBytes()]; |
|
||||||
buf.readBytes(bytes);//复制内容到字节数组bytes
|
|
||||||
buf.clear(); |
|
||||||
log.info("获取到的值: " + ExchangeStringUtil.bytesToHexString(bytes)); |
|
||||||
// if (bytes.length <= 24) {
|
|
||||||
if (bytes.length != 0) { |
|
||||||
// receiveStr = receiveStr.replace("null", "");
|
|
||||||
// receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
// log.info(ctx.channel().remoteAddress() + " " + ctx.channel().localAddress() + " 接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length());
|
|
||||||
receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
receiveStr = receiveStr.replace("null", ""); |
|
||||||
log.info("接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length()); |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} finally { |
|
||||||
ReferenceCountUtil.release(msg); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { |
|
||||||
log.info("数据读取接收完成: " + receiveStr); |
|
||||||
if (receiveStr.length() == 24) { |
|
||||||
if (receiveStr.equalsIgnoreCase(orderMessageEntityList.get(num).getOrderStr())) { |
|
||||||
// 解析采集回来的数据
|
|
||||||
log.info("采集完整的报文: " + receiveStr + ",指令下标: " + size); |
|
||||||
// 解析采集的报文
|
|
||||||
// 更新发送后的指令
|
|
||||||
OrderMessageEntity orderMessageEntity = new OrderMessageEntity(); |
|
||||||
orderMessageEntity.setRegisterAddr(orderMessageEntityList.get(num).getRegisterAddr()); |
|
||||||
orderMessageEntity.setCreateTime(orderMessageEntityList.get(num).getCreateTime()); |
|
||||||
orderMessageEntity.setGrade(1); |
|
||||||
orderMessageEntity.setSendNum(1); |
|
||||||
orderMessageEntity.setStatus(1); |
|
||||||
orderMessageEntity.setOrderStr(orderMessageEntityList.get(num).getOrderStr()); |
|
||||||
//orderMessageService.updateOrderMessage(orderMessageEntity);
|
|
||||||
|
|
||||||
// // 关闭连接
|
|
||||||
// receiveStr = null;
|
|
||||||
// Constant.SEND_STATUS = true;
|
|
||||||
// ctx.close();
|
|
||||||
|
|
||||||
// 清空receiveStr
|
|
||||||
receiveStr = ""; |
|
||||||
// 判断发送的下标,如果不等于指令数组大小
|
|
||||||
num = num + 1; |
|
||||||
if (num > size - 1) { |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
Constant.SEND_STATUS = true; |
|
||||||
ctx.close(); |
|
||||||
} else { |
|
||||||
Thread.sleep(4000); |
|
||||||
// 继续发送下一个采集DDC设备指令
|
|
||||||
String sendStr = orderMessageEntityList.get(num).getOrderStr(); |
|
||||||
ByteBuf buffer = getByteBuf(ctx, sendStr); |
|
||||||
// 2.发送数据
|
|
||||||
ctx.channel().writeAndFlush(buffer); |
|
||||||
log.info("客户端再次往服务端发送数据" + num + ",报文: " + sendStr); |
|
||||||
} |
|
||||||
} |
|
||||||
} else if ((receiveStr.length() > 24) && (num == 0)) { |
|
||||||
// 发送采集DDC指令
|
|
||||||
String sendStr = orderMessageEntityList.get(num).getOrderStr(); |
|
||||||
// 获取采集参数个数
|
|
||||||
size = orderMessageEntityList.size(); |
|
||||||
// 2.发送数据
|
|
||||||
ByteBuf buffer = getByteBuf(ctx,sendStr); |
|
||||||
ctx.channel().writeAndFlush(buffer); |
|
||||||
// 清空receiveStr
|
|
||||||
receiveStr = ""; |
|
||||||
sendNum += 1; |
|
||||||
} else if (sendNum > 2){ |
|
||||||
// 更新发送后的指令
|
|
||||||
OrderMessageEntity orderMessageEntity = new OrderMessageEntity(); |
|
||||||
orderMessageEntity.setRegisterAddr(orderMessageEntityList.get(num).getRegisterAddr()); |
|
||||||
orderMessageEntity.setCreateTime(orderMessageEntityList.get(num).getCreateTime()); |
|
||||||
orderMessageEntity.setGrade(1); |
|
||||||
orderMessageEntity.setSendNum(sendNum); |
|
||||||
orderMessageEntity.setStatus(0); |
|
||||||
orderMessageEntity.setOrderStr(orderMessageEntityList.get(num).getOrderStr()); |
|
||||||
//orderMessageService.updateOrderMessage(orderMessageEntity);
|
|
||||||
Constant.SEND_STATUS = false; |
|
||||||
ctx.close(); |
|
||||||
} else if ((receiveStr.length() > 24)) { |
|
||||||
// 接收采集DDC的数据
|
|
||||||
// 解析采集的报文
|
|
||||||
// AnalysisReceiveOrder485 analysisReceiveOrder485 = new AnalysisReceiveOrder485();
|
|
||||||
// analysisReceiveOrder485.analysisChillersDDC(receiveStr);
|
|
||||||
|
|
||||||
// 清空receiveStr
|
|
||||||
receiveStr = ""; |
|
||||||
// 更新发送后的指令
|
|
||||||
OrderMessageEntity orderMessageEntity = new OrderMessageEntity(); |
|
||||||
orderMessageEntity.setRegisterAddr(orderMessageEntityList.get(num).getRegisterAddr()); |
|
||||||
orderMessageEntity.setCreateTime(orderMessageEntityList.get(num).getCreateTime()); |
|
||||||
orderMessageEntity.setGrade(1); |
|
||||||
orderMessageEntity.setSendNum(1); |
|
||||||
orderMessageEntity.setStatus(1); |
|
||||||
orderMessageEntity.setOrderStr(orderMessageEntityList.get(num).getOrderStr()); |
|
||||||
//orderMessageService.updateOrderMessage(orderMessageEntity);
|
|
||||||
|
|
||||||
// 判断发送的下标,如果不等于指令数组大小
|
|
||||||
num = num + 1; |
|
||||||
// Thread.sleep(500);
|
|
||||||
if (num > size-1) { |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
Constant.SEND_STATUS = true; |
|
||||||
ctx.close(); |
|
||||||
} |
|
||||||
} |
|
||||||
ctx.flush(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,90 +0,0 @@ |
|||||||
package com.mh.user.netty; |
|
||||||
|
|
||||||
import io.netty.bootstrap.Bootstrap; |
|
||||||
import io.netty.channel.*; |
|
||||||
import io.netty.channel.nio.NioEventLoopGroup; |
|
||||||
import io.netty.channel.socket.SocketChannel; |
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel; |
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler; |
|
||||||
import lombok.Getter; |
|
||||||
import lombok.Setter; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title : |
|
||||||
* @description :Netty客户端,采集冷量计 |
|
||||||
* @updateTime 2020-05-13 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
@Slf4j |
|
||||||
@Setter |
|
||||||
@Getter |
|
||||||
public class NettyClient { |
|
||||||
|
|
||||||
private int port; |
|
||||||
private String host; |
|
||||||
|
|
||||||
// 构造函数传递值 继承Thread时需要
|
|
||||||
// public NettyClient(int port, String host) {
|
|
||||||
// this.port = port;
|
|
||||||
// this.host = host;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public void connect(int port, String host) throws InterruptedException { |
|
||||||
// 配置客户端NIO线程组
|
|
||||||
EventLoopGroup group = new NioEventLoopGroup(1); |
|
||||||
try { |
|
||||||
Bootstrap bootstrap = new Bootstrap(); |
|
||||||
bootstrap.group(group).channel(NioSocketChannel.class) |
|
||||||
.option(ChannelOption.TCP_NODELAY, true) |
|
||||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) |
|
||||||
.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(1024*1024)) |
|
||||||
.handler(new ChannelInitializer<SocketChannel>() { |
|
||||||
@Override |
|
||||||
protected void initChannel(SocketChannel socketChannel) { |
|
||||||
// 基于换行符号
|
|
||||||
// socketChannel.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,4,4,-8,0));
|
|
||||||
// // 解码转String,注意调整自己的编码格式GBK、UTF-8
|
|
||||||
// socketChannel.pipeline().addLast(new StringDecoder(StandardCharsets.UTF_8));
|
|
||||||
// // 解码转String,注意调整自己的编码格式GBK、UTF-8
|
|
||||||
// socketChannel.pipeline().addLast(new StringEncoder(StandardCharsets.UTF_8));
|
|
||||||
// socketChannel.pipeline().addLast(new LengthFieldPrepender(4));
|
|
||||||
// 超过10秒钟没有数据读取自动断开连接
|
|
||||||
socketChannel.pipeline().addLast(new ReadTimeoutHandler(10)); |
|
||||||
// 在管道中添加我们自己的接收数据实现方法
|
|
||||||
socketChannel.pipeline().addLast(new NettyClientHandler()); |
|
||||||
// socketChannel.pipeline().addLast(new NettyMeterClientHandler());
|
|
||||||
} |
|
||||||
}); |
|
||||||
// 发起异步连接操作
|
|
||||||
ChannelFuture channelFuture = bootstrap.connect(host, port).sync(); |
|
||||||
if (channelFuture.isSuccess()) { |
|
||||||
log.info("connect server 成功---------"); |
|
||||||
} else { |
|
||||||
log.info("连接失败!"); |
|
||||||
log.info("准备重连!"); |
|
||||||
// connect(port, host);
|
|
||||||
} |
|
||||||
|
|
||||||
// 等待客户端连接链路关闭future.channel().closeFuture().sync(); // 阻塞main线程
|
|
||||||
channelFuture.channel().closeFuture().sync(); |
|
||||||
} catch (Exception e) { |
|
||||||
log.error(e.getMessage()); |
|
||||||
} finally { |
|
||||||
group.shutdownGracefully(); |
|
||||||
// try {
|
|
||||||
// TimeUnit.SECONDS.sleep(5);
|
|
||||||
// connect(port, host); // 断线重连
|
|
||||||
// } catch (InterruptedException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// @SneakyThrows
|
|
||||||
// @Override
|
|
||||||
// public void run() {
|
|
||||||
// connect(port, host);
|
|
||||||
// }
|
|
||||||
} |
|
@ -1,295 +0,0 @@ |
|||||||
package com.mh.user.netty; |
|
||||||
|
|
||||||
import com.mh.user.constants.Constant; |
|
||||||
import com.mh.user.entity.DeviceManageEntity; |
|
||||||
import com.mh.user.service.DeviceManageService; |
|
||||||
import com.mh.user.utils.*; |
|
||||||
import io.netty.buffer.ByteBuf; |
|
||||||
import io.netty.channel.Channel; |
|
||||||
import io.netty.channel.ChannelHandlerAdapter; |
|
||||||
import io.netty.channel.ChannelHandlerContext; |
|
||||||
import io.netty.util.ReferenceCountUtil; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.springframework.context.ApplicationContext; |
|
||||||
|
|
||||||
import java.text.SimpleDateFormat; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title : |
|
||||||
* @description :客户端异步消息处理机制 |
|
||||||
* @updateTime 2020-05-13 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
@Slf4j |
|
||||||
public class NettyClientHandler extends ChannelHandlerAdapter { |
|
||||||
|
|
||||||
private int num = 0; |
|
||||||
private int size = 0; |
|
||||||
private String receiveStr = null; |
|
||||||
private String IP = null; |
|
||||||
private String port = null; |
|
||||||
List<DeviceManageEntity> deviceManageEntityList; |
|
||||||
|
|
||||||
// 调用service
|
|
||||||
ApplicationContext context = SpringBeanUtil.getApplicationContext(); |
|
||||||
DeviceManageService deviceManageService = context.getBean(DeviceManageService.class); |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { |
|
||||||
log.info("当前channel从EventLoop取消注册"); |
|
||||||
super.channelUnregistered(ctx); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { |
|
||||||
// super.exceptionCaught(ctx, cause);
|
|
||||||
log.info("通信异常!!"); |
|
||||||
receiveStr = null; |
|
||||||
Channel incoming = ctx.channel(); |
|
||||||
if (incoming.isActive()){ |
|
||||||
log.info("SimpleClient: " + incoming.remoteAddress() + "异常"); |
|
||||||
cause.printStackTrace(); |
|
||||||
ctx.close(); |
|
||||||
// receiveStr = null;
|
|
||||||
// try {
|
|
||||||
// TimeUnit.SECONDS.sleep(5);
|
|
||||||
// SocketAddress remoteAddress = ctx.channel().remoteAddress();
|
|
||||||
// String port = ExchangeStringUtil.endData(remoteAddress.toString(),":");
|
|
||||||
// String host = ExchangeStringUtil.splitData(remoteAddress.toString(),"/",":");
|
|
||||||
// NettyClient nettyClient = new NettyClient();
|
|
||||||
// nettyClient.connect(Integer.parseInt(port), host); // 断线重连
|
|
||||||
// } catch (InterruptedException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelActive(ChannelHandlerContext ctx) { |
|
||||||
// 添加一个状态值,判断是否继续发送指令 update by ljf on 2020-08-07
|
|
||||||
if (Constant.WEB_FLAG) { |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
ctx.close(); |
|
||||||
} else { |
|
||||||
ctx.channel().read(); |
|
||||||
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss"); |
|
||||||
Date date = new Date(); |
|
||||||
log.info(ctx.channel().remoteAddress() + " " + sdf1.format(date) + "链接服务端成功!"); |
|
||||||
// 截取IP地址
|
|
||||||
IP = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress() + "", "/", ":"); |
|
||||||
// 截取端口号
|
|
||||||
port = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress() + "", ":", ""); |
|
||||||
log.info("IP: " + IP + ",端口号: " + port); |
|
||||||
// 生成对应采集冷量计的命令
|
|
||||||
// 生成对应的采集指令
|
|
||||||
deviceManageEntityList = deviceManageService.queryDevicesByType("3"); |
|
||||||
size = deviceManageEntityList.size(); |
|
||||||
|
|
||||||
// 封装工具类进行采集,update by ljf on 2021-01-26
|
|
||||||
SendOrderUtils.sendCloudOrder(deviceManageEntityList.get(0),0,IP,port,ctx); |
|
||||||
// // 1.创建将要写出的数据
|
|
||||||
// String collectionNum = deviceManageEntityList.get(0).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createCloudOrder(IP, port,
|
|
||||||
// deviceManageEntityList.get(0).getDataCom(),
|
|
||||||
// collectionNum, "34");
|
|
||||||
//// String sendStr = "5803004900021914";
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx, sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
} |
|
||||||
|
|
||||||
// String sendStr = "5803004900021914"; // 冷量计
|
|
||||||
// // 申请一个数据结构存储信息
|
|
||||||
// ByteBuf buffer = ctx.alloc().buffer();
|
|
||||||
// // 将信息放入数据结构中
|
|
||||||
// buffer.writeBytes(ExchangeStringUtil.hexStrToBinaryStr(sendStr));//对接需要16进制
|
|
||||||
// ctx.writeAndFlush(buffer, ctx.newProgressivePromise());
|
|
||||||
} |
|
||||||
|
|
||||||
private ByteBuf getByteBuf(ChannelHandlerContext ctx, String sendStr) { |
|
||||||
// byte类型的数据
|
|
||||||
// byte[] bytes = "这里是将要写往服务端的数据".getBytes(Charset.forName("utf-8"));
|
|
||||||
// String sendStr = "5803004900021914"; // 冷量计
|
|
||||||
// 申请一个数据结构存储信息
|
|
||||||
ByteBuf buffer = ctx.alloc().buffer(); |
|
||||||
// 将信息放入数据结构中
|
|
||||||
buffer.writeBytes(ExchangeStringUtil.hexStrToBinaryStr(sendStr));//对接需要16进制
|
|
||||||
return buffer; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception { |
|
||||||
Thread.sleep(100); |
|
||||||
ctx.close(); |
|
||||||
log.info(ctx.channel().localAddress() + "退出链接!!"); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { |
|
||||||
try { |
|
||||||
ByteBuf buf = (ByteBuf)msg; |
|
||||||
byte [] bytes = new byte[buf.readableBytes()]; |
|
||||||
buf.readBytes(bytes);//复制内容到字节数组bytes
|
|
||||||
buf.clear(); |
|
||||||
log.info("获取到的值: " + ExchangeStringUtil.bytesToHexString(bytes)); |
|
||||||
if (bytes.length <= 36) { |
|
||||||
// receiveStr = receiveStr.replace("null", "");
|
|
||||||
// receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
// log.info(ctx.channel().remoteAddress() + " " + ctx.channel().localAddress() + " 接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length());
|
|
||||||
receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
receiveStr = receiveStr.replace("null", ""); |
|
||||||
log.info("接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length()); |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} finally { |
|
||||||
ReferenceCountUtil.release(msg); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { |
|
||||||
log.info("采集冷量计-数据读取接收完成: " + receiveStr); |
|
||||||
// A9 FE C2 C7 1F 90 01 58 03 04 4A 30 00 53 65 1C C4 06
|
|
||||||
if (receiveStr.length() == 36) { |
|
||||||
// 接收到的报文
|
|
||||||
log.info("接收完整报文: " + receiveStr); |
|
||||||
// 解析报文
|
|
||||||
// AnalysisReceiveOrder485 analysisReceiveOrder485 = new AnalysisReceiveOrder485();
|
|
||||||
// analysisReceiveOrder485.analysisCloudOrder485(receiveStr); // 解析冷量计
|
|
||||||
receiveStr = ""; |
|
||||||
// 1.创建将要写出的数据
|
|
||||||
// String sendStr = "5803004900021914";
|
|
||||||
num = num + 1; |
|
||||||
Thread.sleep(500); |
|
||||||
if (num > size-1) { |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
ctx.close(); |
|
||||||
// 保持长连接
|
|
||||||
// // 封装工具类进行采集,update by ljf on 2021-01-26
|
|
||||||
// SendOrderUtils.sendCloudOrder(deviceManageEntityList.get(num),num,IP,port,ctx);
|
|
||||||
} else { |
|
||||||
// 添加一个状态值,判断是否继续发送指令 update by ljf on 2020-08-07
|
|
||||||
if (Constant.WEB_FLAG) { |
|
||||||
log.info("有指令下发退出定时采集DDC参数"); |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
ctx.close(); |
|
||||||
} else { |
|
||||||
// 封装工具类进行采集,update by ljf on 2021-01-26
|
|
||||||
SendOrderUtils.sendCloudOrder(deviceManageEntityList.get(num),num,IP,port,ctx); |
|
||||||
// // 1.创建将要写出的数据
|
|
||||||
// String collectionNum = deviceManageEntityList.get(num).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createCloudOrder(IP, port,
|
|
||||||
// deviceManageEntityList.get(num).getDataCom(),
|
|
||||||
// collectionNum, "34");
|
|
||||||
//// String sendStr = "5803004900021914";
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx, sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
// log.info("客户端再次往服务端发送数据" + sendStr);
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} else { |
|
||||||
log.info(receiveStr); |
|
||||||
receiveStr = null; |
|
||||||
ctx.flush(); |
|
||||||
ctx.close(); |
|
||||||
} |
|
||||||
|
|
||||||
// if (receiveStr.contains("c0a801fc")) { // 冷量计
|
|
||||||
//
|
|
||||||
// // 生成对应的采集指令
|
|
||||||
// deviceManageEntityList = deviceManageService.queryDevicesByType("3");
|
|
||||||
// size = deviceManageEntityList.size();
|
|
||||||
//
|
|
||||||
// log.info("初始连接报文: " + receiveStr);
|
|
||||||
// IP = receiveStr;
|
|
||||||
// receiveStr = "";
|
|
||||||
// // 1.创建将要写出的数据
|
|
||||||
// String collectionNum = deviceManageEntityList.get(0).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createCloudOrder(collectionNum,"34");
|
|
||||||
//// String sendStr = "5803004900021914";
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx,sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
// } else if (receiveStr.contains("c0a801f0")) { // 电表
|
|
||||||
//
|
|
||||||
// // 生成对应的采集指令
|
|
||||||
// deviceManageEntityList = deviceManageService.queryDevicesByType("1");
|
|
||||||
// size = deviceManageEntityList.size();
|
|
||||||
//
|
|
||||||
// log.info("初始连接报文: " + receiveStr);
|
|
||||||
// IP = receiveStr;
|
|
||||||
// receiveStr = "";
|
|
||||||
// // 1.创建将要写出的数据
|
|
||||||
//// String sendStr = "6830043080000068110432326536C816"; // 网络单相电表
|
|
||||||
//// String sendStr = "FEFEFEFE6880025007000068010243C3B216"; // 广仪三相电表
|
|
||||||
// String collectionNum = deviceManageEntityList.get(0).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createMeterOrder(collectionNum,"1");
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx,sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
// } else if ((receiveStr.length() == 18) && (IP.contains("c0a801fc"))) {
|
|
||||||
// analysisReceiveOrder485.analysisCloudOrder485(receiveStr); // 解析冷量计
|
|
||||||
// receiveStr = "";
|
|
||||||
// // 1.创建将要写出的数据
|
|
||||||
//// String sendStr = "5803004900021914";
|
|
||||||
// num = num + 1;
|
|
||||||
// Thread.sleep(1000);
|
|
||||||
// if (num >= size-1) {
|
|
||||||
// num = 0;
|
|
||||||
// // 关闭连接
|
|
||||||
// receiveStr = null;
|
|
||||||
// ctx.close();
|
|
||||||
// } else {
|
|
||||||
// String collectionNum = deviceManageEntityList.get(num).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createCloudOrder(collectionNum, "34");
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx, sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
// log.info("客户端再次往服务端发送数据" + num);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// } else if ((receiveStr.length() == 44) && (IP.contains("c0a801f0"))) {
|
|
||||||
// analysisReceiveOrder485.analysisMeterOrder485(receiveStr); // 解析电表
|
|
||||||
// receiveStr = "";
|
|
||||||
// num = num + 1;
|
|
||||||
// Thread.sleep(1000);
|
|
||||||
// if (num >= size-1) {
|
|
||||||
// num = 0;
|
|
||||||
// receiveStr = null;
|
|
||||||
// // 关闭连接
|
|
||||||
// ctx.close();
|
|
||||||
// } else {
|
|
||||||
// // 1.创建将要写出的数据
|
|
||||||
// // fe fe fe fe 68 80 02 50 07 00 00 68 81 06 43 c3 8c 34 33 33 5c 16
|
|
||||||
//// String sendStr = "FEFEFE6880025007000068010243C3B216";
|
|
||||||
// String collectionNum = deviceManageEntityList.get(num).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createMeterOrder(collectionNum, "1");
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx, sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
// log.info("客户端再次往服务端发送数据" + num);
|
|
||||||
// }
|
|
||||||
// } else if ((receiveStr.length() > 44)) {
|
|
||||||
// log.info(receiveStr);
|
|
||||||
// receiveStr = null;
|
|
||||||
// ctx.flush();
|
|
||||||
// ctx.close();
|
|
||||||
// }
|
|
||||||
ctx.flush(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,179 +0,0 @@ |
|||||||
package com.mh.user.netty; |
|
||||||
|
|
||||||
import com.mh.user.utils.ExchangeStringUtil; |
|
||||||
import io.netty.bootstrap.ServerBootstrap; |
|
||||||
import io.netty.buffer.ByteBuf; |
|
||||||
import io.netty.buffer.Unpooled; |
|
||||||
import io.netty.channel.*; |
|
||||||
import io.netty.channel.nio.NioEventLoopGroup; |
|
||||||
import io.netty.channel.socket.SocketChannel; |
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel; |
|
||||||
import io.netty.handler.logging.LogLevel; |
|
||||||
import io.netty.handler.logging.LoggingHandler; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.springframework.util.StringUtils; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.net.InetSocketAddress; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title :Netty |
|
||||||
* @description :netty 使用 |
|
||||||
* @updateTime 2020-04-21 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
@Slf4j |
|
||||||
public class NettyEchoServer { |
|
||||||
|
|
||||||
public void bind(int port) throws Exception { |
|
||||||
// accept线程组,用来接收连接
|
|
||||||
EventLoopGroup bossGroup = new NioEventLoopGroup(1); |
|
||||||
// IO 线程组,用来处理业务逻辑
|
|
||||||
EventLoopGroup workerGroup = new NioEventLoopGroup(1); |
|
||||||
|
|
||||||
try { |
|
||||||
// 服务端启动引导
|
|
||||||
ServerBootstrap serverBootstrap = new ServerBootstrap(); |
|
||||||
serverBootstrap.group(bossGroup,workerGroup) // 绑定两个线程
|
|
||||||
.channel(NioServerSocketChannel.class) // 指定通道类型
|
|
||||||
.option(ChannelOption.SO_BACKLOG, 1024) // 设置TCP连接的缓冲区
|
|
||||||
.handler(new LoggingHandler(LogLevel.INFO)) // 设置日志级别
|
|
||||||
.childHandler(new ChannelInitializer<SocketChannel>() { |
|
||||||
@Override |
|
||||||
protected void initChannel(SocketChannel socketChannel) throws Exception { |
|
||||||
ChannelPipeline pipeline = socketChannel.pipeline(); // 获取处理器链
|
|
||||||
pipeline.addLast(new EchoServerHandler()); // 添加新的事件处理器
|
|
||||||
} |
|
||||||
}); |
|
||||||
// 通过bind启动服务
|
|
||||||
ChannelFuture f = serverBootstrap.bind(port).sync(); |
|
||||||
// 阻塞主线程,知道网络服务被关闭
|
|
||||||
f.channel().closeFuture().sync(); |
|
||||||
} catch (Exception e){ |
|
||||||
e.printStackTrace(); |
|
||||||
} finally { |
|
||||||
workerGroup.shutdownGracefully(); |
|
||||||
bossGroup.shutdownGracefully(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static class EchoServerHandler extends ChannelHandlerAdapter { |
|
||||||
|
|
||||||
// 每当从客户端收到新的数据时,这个方法会在收到消息时被调用
|
|
||||||
@Override |
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { |
|
||||||
try { |
|
||||||
ByteBuf buf = (ByteBuf)msg; |
|
||||||
byte [] bytes = new byte[buf.readableBytes()]; |
|
||||||
buf.readBytes(bytes);//复制内容到字节数组bytes
|
|
||||||
String receiveStr = ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
log.info("接收到的数据: "+ receiveStr); |
|
||||||
//返回16进制到客户端
|
|
||||||
writeToClient(receiveStr,ctx,"测试"); |
|
||||||
} catch (Exception e) { |
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
// ctx.write(Unpooled.wrappedBuffer("Server message".getBytes()));
|
|
||||||
// ctx.fireChannelRead(msg);
|
|
||||||
} |
|
||||||
|
|
||||||
// 数据读取完后被调用
|
|
||||||
@Override |
|
||||||
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { |
|
||||||
ctx.flush(); |
|
||||||
} |
|
||||||
|
|
||||||
// 当Netty由于IO错误或者处理器在处理事件时抛出的异常时被调用
|
|
||||||
@Override |
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { |
|
||||||
cause.printStackTrace(); |
|
||||||
ctx.close(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 客户端与服务端第一次建立连接时 执行 |
|
||||||
* |
|
||||||
* @param ctx |
|
||||||
* @throws Exception |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception, IOException |
|
||||||
{ |
|
||||||
super.channelActive(ctx); |
|
||||||
ctx.channel().read(); |
|
||||||
InetSocketAddress ifsock = (InetSocketAddress) ctx.channel().remoteAddress(); |
|
||||||
String clientIp = ifsock.getAddress().getHostAddress(); |
|
||||||
//此处不能使用ctx.close(),否则客户端始终无法与服务端建立连接
|
|
||||||
log.info("channelActive: "+clientIp + ctx.name()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 客户端与服务端 断连时 执行 |
|
||||||
* |
|
||||||
* @param ctx |
|
||||||
* @throws Exception |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception, IOException |
|
||||||
{ |
|
||||||
super.channelInactive(ctx); |
|
||||||
InetSocketAddress ifsock = (InetSocketAddress) ctx.channel().remoteAddress(); |
|
||||||
String clientIp = ifsock.getAddress().getHostAddress(); |
|
||||||
ctx.close(); //断开连接时,必须关闭,否则造成资源浪费,并发量很大情况下可能造成宕机
|
|
||||||
System.out.println("channelInactive:"+clientIp); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 服务端当read超时, 会调用这个方法 |
|
||||||
* |
|
||||||
* @param ctx |
|
||||||
* @param evt |
|
||||||
* @throws Exception |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception, IOException |
|
||||||
{ |
|
||||||
super.userEventTriggered(ctx, evt); |
|
||||||
InetSocketAddress ifsock = (InetSocketAddress) ctx.channel().remoteAddress(); |
|
||||||
String clientIp = ifsock.getAddress().getHostAddress(); |
|
||||||
ctx.close();//超时时断开连接
|
|
||||||
System.out.println("userEventTriggered:"+clientIp); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 公用回写数据到客户端的方法 |
|
||||||
* @param channel |
|
||||||
* @param mark 用于打印/log的输出 |
|
||||||
* <br>//channel.writeAndFlush(msg);//不行
|
|
||||||
* <br>//channel.writeAndFlush(receiveStr.getBytes());//不行
|
|
||||||
* <br>在netty里,进出的都是ByteBuf,楼主应确定服务端是否有对应的编码器,将字符串转化为ByteBuf |
|
||||||
*/ |
|
||||||
private void writeToClient(final String receiveStr, ChannelHandlerContext channel, final String mark) { |
|
||||||
try { |
|
||||||
ByteBuf buff = Unpooled.buffer();//netty需要用ByteBuf传输
|
|
||||||
buff.writeBytes(ExchangeStringUtil.hexStrToBinaryStr(receiveStr));//对接需要16进制
|
|
||||||
channel.writeAndFlush(buff).addListener((ChannelFutureListener) future -> { |
|
||||||
StringBuilder sb = new StringBuilder(""); |
|
||||||
if(!StringUtils.isEmpty(mark)){ |
|
||||||
sb.append("【").append(mark).append("】"); |
|
||||||
} |
|
||||||
if (future.isSuccess()) { |
|
||||||
System.out.println(sb.toString()+"回写成功"+receiveStr); |
|
||||||
log.info(sb.toString()+"回写成功"+receiveStr); |
|
||||||
} else { |
|
||||||
System.out.println(sb.toString()+"回写失败"+receiveStr); |
|
||||||
log.error(sb.toString()+"回写失败"+receiveStr); |
|
||||||
} |
|
||||||
}); |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
System.out.println("调用通用writeToClient()异常"+e.getMessage()); |
|
||||||
log.error("调用通用writeToClient()异常:",e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,97 +0,0 @@ |
|||||||
package com.mh.user.netty; |
|
||||||
|
|
||||||
import io.netty.bootstrap.Bootstrap; |
|
||||||
import io.netty.channel.*; |
|
||||||
import io.netty.channel.nio.NioEventLoopGroup; |
|
||||||
import io.netty.channel.socket.SocketChannel; |
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel; |
|
||||||
import io.netty.handler.timeout.IdleStateHandler; |
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler; |
|
||||||
import lombok.Getter; |
|
||||||
import lombok.Setter; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title : |
|
||||||
* @description :Netty客户端,采集电表 |
|
||||||
* @updateTime 2020-05-13 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
@Slf4j |
|
||||||
@Setter |
|
||||||
@Getter |
|
||||||
public class NettyMeterAndCloudClient { |
|
||||||
// implements Runnable {
|
|
||||||
|
|
||||||
private int port; |
|
||||||
private String host; |
|
||||||
|
|
||||||
// 构造函数传递值 继承Thread时需要
|
|
||||||
public NettyMeterAndCloudClient(int port, String host) { |
|
||||||
this.port = port; |
|
||||||
this.host = host; |
|
||||||
} |
|
||||||
|
|
||||||
public NettyMeterAndCloudClient() { |
|
||||||
super(); |
|
||||||
} |
|
||||||
|
|
||||||
public void connect(int port, String host) throws InterruptedException { |
|
||||||
// 配置客户端NIO线程组
|
|
||||||
EventLoopGroup group = new NioEventLoopGroup(1); |
|
||||||
try { |
|
||||||
Bootstrap bootstrap = new Bootstrap(); |
|
||||||
bootstrap.group(group).channel(NioSocketChannel.class) |
|
||||||
.option(ChannelOption.TCP_NODELAY, true) |
|
||||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) |
|
||||||
.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(1024*1024)) |
|
||||||
.handler(new ChannelInitializer<SocketChannel>() { |
|
||||||
@Override |
|
||||||
protected void initChannel(SocketChannel socketChannel) { |
|
||||||
// 基于换行符号
|
|
||||||
// socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
|
|
||||||
// // 解码转String,注意调整自己的编码格式GBK、UTF-8
|
|
||||||
// socketChannel.pipeline().addLast(new StringDecoder(StandardCharsets.UTF_8));
|
|
||||||
// // 解码转String,注意调整自己的编码格式GBK、UTF-8
|
|
||||||
// socketChannel.pipeline().addLast(new StringEncoder(StandardCharsets.UTF_8));
|
|
||||||
// 超过10秒钟没有数据读取自动断开连接
|
|
||||||
socketChannel.pipeline().addLast(new IdleStateHandler(10,10,10, TimeUnit.SECONDS)); |
|
||||||
// 在管道中添加我们自己的接收数据实现方法
|
|
||||||
// socketChannel.pipeline().addLast(new NettyClientHandler());
|
|
||||||
socketChannel.pipeline().addLast(new NettyMeterAndCloudClientHandler()); |
|
||||||
} |
|
||||||
}); |
|
||||||
// 发起异步连接操作
|
|
||||||
ChannelFuture channelFuture = bootstrap.connect(host, port).sync(); |
|
||||||
if (channelFuture.isSuccess()) { |
|
||||||
log.info("connect server 成功---------"); |
|
||||||
} else { |
|
||||||
log.info("连接失败!"); |
|
||||||
log.info("准备重连!"); |
|
||||||
// connect(port, host);
|
|
||||||
} |
|
||||||
|
|
||||||
// 等待客户端连接链路关闭future.channel().closeFuture().sync(); // 阻塞main线程
|
|
||||||
channelFuture.channel().closeFuture().sync(); |
|
||||||
} catch (Exception e) { |
|
||||||
log.error(e.getMessage()); |
|
||||||
} finally { |
|
||||||
group.shutdownGracefully(); |
|
||||||
// try {
|
|
||||||
// TimeUnit.SECONDS.sleep(5);
|
|
||||||
// connect(port, host); // 断线重连
|
|
||||||
// } catch (InterruptedException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
} |
|
||||||
} |
|
||||||
//
|
|
||||||
// @SneakyThrows
|
|
||||||
// @Override
|
|
||||||
// public void run() {
|
|
||||||
// connect(port, host);
|
|
||||||
// }
|
|
||||||
} |
|
@ -1,193 +0,0 @@ |
|||||||
package com.mh.user.netty; |
|
||||||
|
|
||||||
import com.mh.user.constants.Constant; |
|
||||||
import com.mh.user.entity.DeviceManageEntity; |
|
||||||
import com.mh.user.service.DeviceManageService; |
|
||||||
import com.mh.user.utils.*; |
|
||||||
import io.netty.buffer.ByteBuf; |
|
||||||
import io.netty.channel.Channel; |
|
||||||
import io.netty.channel.ChannelHandlerAdapter; |
|
||||||
import io.netty.channel.ChannelHandlerContext; |
|
||||||
import io.netty.handler.timeout.IdleState; |
|
||||||
import io.netty.handler.timeout.IdleStateEvent; |
|
||||||
import io.netty.util.ReferenceCountUtil; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.springframework.context.ApplicationContext; |
|
||||||
|
|
||||||
import java.text.SimpleDateFormat; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title : |
|
||||||
* @description :客户端异步消息处理机制 |
|
||||||
* @updateTime 2020-05-13 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
@Slf4j |
|
||||||
public class NettyMeterAndCloudClientHandler extends ChannelHandlerAdapter { |
|
||||||
|
|
||||||
|
|
||||||
private int num = 0; |
|
||||||
private int size = 0; |
|
||||||
private String receiveStr = null; |
|
||||||
private int idle_count = 0; |
|
||||||
private String IP = ""; |
|
||||||
private String port = ""; |
|
||||||
|
|
||||||
List<DeviceManageEntity> deviceManageEntityList; |
|
||||||
|
|
||||||
// 调用service
|
|
||||||
ApplicationContext context = SpringBeanUtil.getApplicationContext(); |
|
||||||
DeviceManageService deviceManageService = context.getBean(DeviceManageService.class); |
|
||||||
|
|
||||||
AnalysisReceiveOrder485 analysisReceiveOrder485 = new AnalysisReceiveOrder485(); |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { |
|
||||||
log.info("当前channel从EventLoop取消注册"); |
|
||||||
super.channelUnregistered(ctx); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 超时处理 |
|
||||||
* 如果120秒没有接受客户端的心跳,就触发; |
|
||||||
* 如果超过3次,则直接关闭; |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { |
|
||||||
if (obj instanceof IdleStateEvent) { |
|
||||||
IdleStateEvent event = (IdleStateEvent) obj; |
|
||||||
if (IdleState.READER_IDLE.equals(event.state())) { //如果读通道处于空闲状态,说明没有接收到心跳命令
|
|
||||||
System.out.println("第" + idle_count + "已经20秒没有接收到服务器的信息了,发送的第" + num + "条数据"); |
|
||||||
if (deviceManageEntityList.get(num) == null) { |
|
||||||
ctx.channel().close(); |
|
||||||
} else { |
|
||||||
if (idle_count > 3 || num > size - 1) { |
|
||||||
System.out.println("关闭这个不活跃的channel"); |
|
||||||
ctx.channel().close(); |
|
||||||
} |
|
||||||
|
|
||||||
SendOrderUtils.sendMeterOrCloud(deviceManageEntityList.get(num), num, IP, port, ctx); |
|
||||||
idle_count++; |
|
||||||
} |
|
||||||
} |
|
||||||
} else { |
|
||||||
super.userEventTriggered(ctx, obj); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { |
|
||||||
log.info("通信异常!!"); |
|
||||||
Channel incoming = ctx.channel(); |
|
||||||
if (incoming.isActive()) { |
|
||||||
log.info("SimpleClient: " + incoming.remoteAddress() + "异常"); |
|
||||||
receiveStr = null; |
|
||||||
cause.printStackTrace(); |
|
||||||
ctx.close(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception { |
|
||||||
// super.channelActive(ctx);
|
|
||||||
// 添加一个状态值,判断是否继续发送指令 update by ljf on 2020-08-07
|
|
||||||
if (Constant.WEB_FLAG) { |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
ctx.close(); |
|
||||||
} else { |
|
||||||
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss"); |
|
||||||
Date date = new Date(); |
|
||||||
log.info(ctx.channel().remoteAddress() + " " + sdf1.format(date) + "链接服务端成功!"); |
|
||||||
|
|
||||||
// 截取IP地址
|
|
||||||
IP = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress() + "", "/", ":"); |
|
||||||
// 截取端口号
|
|
||||||
port = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress() + "", ":", ""); |
|
||||||
log.info("IP: " + IP + ",端口号: " + port); |
|
||||||
|
|
||||||
// 生成对应的采集指令
|
|
||||||
deviceManageEntityList = deviceManageService.queryDevicesByType(null); |
|
||||||
size = deviceManageEntityList.size(); |
|
||||||
|
|
||||||
log.info("初始连接报文: " + receiveStr); |
|
||||||
receiveStr = ""; |
|
||||||
// 保持长连接,封装发送电表工具方法 update by ljf on 2021-01-26
|
|
||||||
SendOrderUtils.sendMeterOrCloud(deviceManageEntityList.get(0), 0, IP, port, ctx); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception { |
|
||||||
Thread.sleep(500); |
|
||||||
receiveStr = null; |
|
||||||
ctx.close(); |
|
||||||
log.info(ctx.channel().localAddress() + "退出链接!!"); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { |
|
||||||
try { |
|
||||||
ByteBuf buf = (ByteBuf) msg; |
|
||||||
byte[] bytes = new byte[buf.readableBytes()]; |
|
||||||
buf.readBytes(bytes);//复制内容到字节数组bytes
|
|
||||||
buf.clear(); |
|
||||||
log.info("获取到的值: " + ExchangeStringUtil.bytesToHexString(bytes)); |
|
||||||
if (bytes.length <= 62) { |
|
||||||
// if (bytes.length <= 142) {
|
|
||||||
// receiveStr = receiveStr.replace("null", "");
|
|
||||||
// receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
// log.info(ctx.channel().remoteAddress() + " " + ctx.channel().localAddress() + " 接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length());
|
|
||||||
receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
receiveStr = receiveStr.replace("null", ""); |
|
||||||
log.info("接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length()); |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} finally { |
|
||||||
ReferenceCountUtil.release(msg); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { |
|
||||||
log.info("采集电表或者冷量计-数据读取接收完成: " + receiveStr); |
|
||||||
if ((receiveStr.length() == 36) && (deviceManageEntityList.get(num).getParamId() == 3)) { |
|
||||||
// analysisReceiveOrder485.analysisCloudOrder485(receiveStr); // 解析冷量计
|
|
||||||
} else if ((receiveStr.length() == 62) && (deviceManageEntityList.get(num).getParamId() == 1)) { |
|
||||||
// 把receiveStr的"null"值去掉
|
|
||||||
// a9fec2c71f9002fefefefe6839025007000068810643c3bb446c338d16c2b8
|
|
||||||
// A9 FE C2 C7 1F 90 02 FE FE FE FE 68 39 02 50 07 00 00 68 81 06 43 C3 5B 38 6C 33 21 16 F8 12
|
|
||||||
analysisReceiveOrder485.analysisMeterOrder485(receiveStr,"","",""); // 解析电表
|
|
||||||
} |
|
||||||
receiveStr = ""; |
|
||||||
num = num + 1; |
|
||||||
Thread.sleep(600); |
|
||||||
if (num > size - 1) { |
|
||||||
num = 0; |
|
||||||
receiveStr = null; |
|
||||||
// 关闭连接
|
|
||||||
ctx.close(); |
|
||||||
// // 保持长连接,封装发送电表工具方法 update by ljf on 2021-01-26
|
|
||||||
// SendOrderUtils.sendMeterOrder(deviceManageEntityList.get(num),num,IP,port,ctx);
|
|
||||||
} else { |
|
||||||
// 添加一个状态值,判断是否继续发送指令 update by ljf on 2020-08-07
|
|
||||||
if (Constant.WEB_FLAG) { |
|
||||||
log.info("有指令下发退出定时采集DDC参数"); |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
ctx.close(); |
|
||||||
} else { |
|
||||||
// 封装发送电表工具方法 update by ljf on 2021-01-26
|
|
||||||
SendOrderUtils.sendMeterOrCloud(deviceManageEntityList.get(num), num, IP, port, ctx); |
|
||||||
} |
|
||||||
} |
|
||||||
ctx.flush(); |
|
||||||
} |
|
||||||
} |
|
@ -1,96 +0,0 @@ |
|||||||
package com.mh.user.netty; |
|
||||||
|
|
||||||
import io.netty.bootstrap.Bootstrap; |
|
||||||
import io.netty.channel.*; |
|
||||||
import io.netty.channel.nio.NioEventLoopGroup; |
|
||||||
import io.netty.channel.socket.SocketChannel; |
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel; |
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler; |
|
||||||
import lombok.Getter; |
|
||||||
import lombok.Setter; |
|
||||||
import lombok.SneakyThrows; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title : |
|
||||||
* @description :Netty客户端,采集电表 |
|
||||||
* @updateTime 2020-05-13 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
@Slf4j |
|
||||||
@Setter |
|
||||||
@Getter |
|
||||||
public class NettyMeterClient { |
|
||||||
// implements Runnable {
|
|
||||||
|
|
||||||
private int port; |
|
||||||
private String host; |
|
||||||
|
|
||||||
// 构造函数传递值 继承Thread时需要
|
|
||||||
public NettyMeterClient(int port, String host) { |
|
||||||
this.port = port; |
|
||||||
this.host = host; |
|
||||||
} |
|
||||||
|
|
||||||
public NettyMeterClient() { |
|
||||||
super(); |
|
||||||
} |
|
||||||
|
|
||||||
public void connect(int port, String host) throws InterruptedException { |
|
||||||
// 配置客户端NIO线程组
|
|
||||||
// 配置客户端NIO线程组
|
|
||||||
EventLoopGroup group = new NioEventLoopGroup(1); |
|
||||||
try { |
|
||||||
Bootstrap bootstrap = new Bootstrap(); |
|
||||||
bootstrap.group(group).channel(NioSocketChannel.class) |
|
||||||
.option(ChannelOption.TCP_NODELAY, true) |
|
||||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) |
|
||||||
.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(1024*1024)) |
|
||||||
.handler(new ChannelInitializer<SocketChannel>() { |
|
||||||
@Override |
|
||||||
protected void initChannel(SocketChannel socketChannel) { |
|
||||||
// 基于换行符号
|
|
||||||
// socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
|
|
||||||
// // 解码转String,注意调整自己的编码格式GBK、UTF-8
|
|
||||||
// socketChannel.pipeline().addLast(new StringDecoder(StandardCharsets.UTF_8));
|
|
||||||
// // 解码转String,注意调整自己的编码格式GBK、UTF-8
|
|
||||||
// socketChannel.pipeline().addLast(new StringEncoder(StandardCharsets.UTF_8));
|
|
||||||
// 超过10秒钟没有数据读取自动断开连接
|
|
||||||
socketChannel.pipeline().addLast(new ReadTimeoutHandler(20)); |
|
||||||
// 在管道中添加我们自己的接收数据实现方法
|
|
||||||
// socketChannel.pipeline().addLast(new NettyClientHandler());
|
|
||||||
socketChannel.pipeline().addLast(new NettyMeterClientHandler1()); |
|
||||||
} |
|
||||||
}); |
|
||||||
// 发起异步连接操作
|
|
||||||
ChannelFuture channelFuture = bootstrap.connect(host, port).sync(); |
|
||||||
if (channelFuture.isSuccess()) { |
|
||||||
log.info("connect server 成功---------"); |
|
||||||
} else { |
|
||||||
log.info("连接失败!"); |
|
||||||
log.info("准备重连!"); |
|
||||||
// connect(port, host);
|
|
||||||
} |
|
||||||
|
|
||||||
// 等待客户端连接链路关闭future.channel().closeFuture().sync(); // 阻塞main线程
|
|
||||||
channelFuture.channel().closeFuture().sync(); |
|
||||||
} catch (Exception e) { |
|
||||||
log.error(e.getMessage()); |
|
||||||
} finally { |
|
||||||
group.shutdownGracefully(); |
|
||||||
// try {
|
|
||||||
// TimeUnit.SECONDS.sleep(5);
|
|
||||||
// connect(port, host); // 断线重连
|
|
||||||
// } catch (InterruptedException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
} |
|
||||||
} |
|
||||||
//
|
|
||||||
// @SneakyThrows
|
|
||||||
// @Override
|
|
||||||
// public void run() {
|
|
||||||
// connect(port, host);
|
|
||||||
// }
|
|
||||||
} |
|
@ -1,143 +0,0 @@ |
|||||||
//package com.mh.user.netty;
|
|
||||||
//
|
|
||||||
//import com.mh.user.entity.DeviceManageEntity;
|
|
||||||
//import com.mh.user.service.DeviceManageService;
|
|
||||||
//import com.mh.user.utils.AnalysisReceiveOrder485;
|
|
||||||
//import com.mh.user.utils.ExchangeStringUtil;
|
|
||||||
//import com.mh.user.utils.GetReadOrder485;
|
|
||||||
//import com.mh.user.utils.SpringBeanUtil;
|
|
||||||
//import io.netty.buffer.ByteBuf;
|
|
||||||
//import io.netty.channel.Channel;
|
|
||||||
//import io.netty.channel.ChannelHandlerAdapter;
|
|
||||||
//import io.netty.channel.ChannelHandlerContext;
|
|
||||||
//import lombok.extern.slf4j.Slf4j;
|
|
||||||
//import org.springframework.context.ApplicationContext;
|
|
||||||
//
|
|
||||||
//import java.text.SimpleDateFormat;
|
|
||||||
//import java.util.Date;
|
|
||||||
//import java.util.List;
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * @author ljf
|
|
||||||
// * @title :
|
|
||||||
// * @description :客户端异步消息处理机制
|
|
||||||
// * @updateTime 2020-05-13
|
|
||||||
// * @throws :
|
|
||||||
// */
|
|
||||||
//@Slf4j
|
|
||||||
//public class NettyMeterClientHandler extends ChannelHandlerAdapter {
|
|
||||||
//
|
|
||||||
// private static int num = 0;
|
|
||||||
// private static int size = 0;
|
|
||||||
// private static String receiveStr = "";
|
|
||||||
// private static String IP = "";
|
|
||||||
// List<DeviceManageEntity> deviceManageEntityList;
|
|
||||||
//
|
|
||||||
// // 调用service
|
|
||||||
// ApplicationContext context = SpringBeanUtil.getApplicationContext();
|
|
||||||
// DeviceManageService deviceManageService = context.getBean(DeviceManageService.class);
|
|
||||||
//
|
|
||||||
// AnalysisReceiveOrder485 analysisReceiveOrder485;
|
|
||||||
//
|
|
||||||
// // 到处理IO事件,异常抛出时调用,已丢弃
|
|
||||||
// @Override
|
|
||||||
// public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
|
||||||
// Channel incoming = ctx.channel();
|
|
||||||
// if (!incoming.isActive()){
|
|
||||||
// log.info("通信异常!!");
|
|
||||||
// receiveStr = "";
|
|
||||||
// log.info("SimpleClient: " + incoming.remoteAddress() + "异常");
|
|
||||||
// cause.printStackTrace();
|
|
||||||
// ctx.close();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
|
||||||
// SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
|
|
||||||
// Date date=new Date();
|
|
||||||
// log.info(sdf1.format(date) + "链接服务端成功!");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private ByteBuf getByteBuf(ChannelHandlerContext ctx, String sendStr) {
|
|
||||||
// // byte类型的数据
|
|
||||||
//// byte[] bytes = "这里是将要写往服务端的数据".getBytes(Charset.forName("utf-8"));
|
|
||||||
//// String sendStr = "5803004900021914"; // 冷量计
|
|
||||||
// // 申请一个数据结构存储信息
|
|
||||||
// ByteBuf buffer = ctx.alloc().buffer();
|
|
||||||
// // 将信息放入数据结构中
|
|
||||||
// buffer.writeBytes(ExchangeStringUtil.hexStrToBinaryStr(sendStr));//对接需要16进制
|
|
||||||
// return buffer;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
|
||||||
// Thread.sleep(500);
|
|
||||||
// ctx.close();
|
|
||||||
// log.info("退出链接!!");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
|
||||||
//// ByteBuf buf = (ByteBuf)msg;
|
|
||||||
//// byte[] req = new byte[buf.readableBytes()];
|
|
||||||
//// buf.readBytes(req);
|
|
||||||
//// String body = new String(req, "UTF-8");
|
|
||||||
// ByteBuf buf = (ByteBuf)msg;
|
|
||||||
// byte [] bytes = new byte[buf.readableBytes()];
|
|
||||||
// buf.readBytes(bytes);//复制内容到字节数组bytes
|
|
||||||
// receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
// log.info("接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
|
|
||||||
// log.info("数据读取接收完成");
|
|
||||||
// if (receiveStr.contains("c0a801f0")) { // 电表
|
|
||||||
//
|
|
||||||
// // 生成对应的采集指令
|
|
||||||
// deviceManageEntityList = deviceManageService.queryDevicesByType("1");
|
|
||||||
// size = deviceManageEntityList.size();
|
|
||||||
//
|
|
||||||
// log.info("初始连接报文: " + receiveStr);
|
|
||||||
// IP = receiveStr;
|
|
||||||
// receiveStr = "";
|
|
||||||
// num = 0;
|
|
||||||
// // 1.创建将要写出的数据
|
|
||||||
//// String sendStr = "6830043080000068110432326536C816"; // 网络单相电表
|
|
||||||
//// String sendStr = "FEFEFEFE6880025007000068010243C3B216"; // 广仪三相电表
|
|
||||||
// String collectionNum = deviceManageEntityList.get(num).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createMeterOrder(collectionNum,"1");
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx,sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
// } else if ((receiveStr.length() == 44) && (IP.contains("c0a801f0"))) {
|
|
||||||
// analysisReceiveOrder485.analysisMeterOrder485(receiveStr); // 解析电表
|
|
||||||
// receiveStr = "";
|
|
||||||
// num = num + 1;
|
|
||||||
// Thread.sleep(1000);
|
|
||||||
// if (num >= size-1) {
|
|
||||||
// num = 0;
|
|
||||||
// // 关闭连接
|
|
||||||
// ctx.close();
|
|
||||||
// } else {
|
|
||||||
// // 1.创建将要写出的数据
|
|
||||||
// // fe fe fe fe 68 80 02 50 07 00 00 68 81 06 43 c3 8c 34 33 33 5c 16
|
|
||||||
//// String sendStr = "FEFEFE6880025007000068010243C3B216";
|
|
||||||
// String collectionNum = deviceManageEntityList.get(num).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createMeterOrder(collectionNum, "1");
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx, sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
// log.info("客户端再次往服务端发送数据" + num);
|
|
||||||
// }
|
|
||||||
// } else if ((receiveStr.length() > 44)) {
|
|
||||||
// log.info(receiveStr);
|
|
||||||
// receiveStr = "";
|
|
||||||
// ctx.flush();
|
|
||||||
// ctx.close();
|
|
||||||
// }
|
|
||||||
// ctx.flush();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//}
|
|
@ -1,259 +0,0 @@ |
|||||||
package com.mh.user.netty; |
|
||||||
|
|
||||||
import com.mh.user.constants.Constant; |
|
||||||
import com.mh.user.entity.DeviceManageEntity; |
|
||||||
import com.mh.user.service.DeviceManageService; |
|
||||||
import com.mh.user.utils.*; |
|
||||||
import io.netty.buffer.ByteBuf; |
|
||||||
import io.netty.channel.Channel; |
|
||||||
import io.netty.channel.ChannelHandlerAdapter; |
|
||||||
import io.netty.channel.ChannelHandlerContext; |
|
||||||
import io.netty.util.ReferenceCountUtil; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.springframework.context.ApplicationContext; |
|
||||||
|
|
||||||
import java.text.SimpleDateFormat; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ljf |
|
||||||
* @title : |
|
||||||
* @description :客户端异步消息处理机制 |
|
||||||
* @updateTime 2020-05-13 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
@Slf4j |
|
||||||
public class NettyMeterClientHandler1 extends ChannelHandlerAdapter { |
|
||||||
|
|
||||||
|
|
||||||
private int num = 0; |
|
||||||
private int size = 0; |
|
||||||
private String receiveStr = null; |
|
||||||
private String IP = ""; |
|
||||||
private String port = ""; |
|
||||||
List<DeviceManageEntity> deviceManageEntityList; |
|
||||||
|
|
||||||
// 调用service
|
|
||||||
ApplicationContext context = SpringBeanUtil.getApplicationContext(); |
|
||||||
DeviceManageService deviceManageService = context.getBean(DeviceManageService.class); |
|
||||||
|
|
||||||
AnalysisReceiveOrder485 analysisReceiveOrder485 = new AnalysisReceiveOrder485(); |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { |
|
||||||
log.info("当前channel从EventLoop取消注册"); |
|
||||||
super.channelUnregistered(ctx); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { |
|
||||||
// super.exceptionCaught(ctx, cause);
|
|
||||||
log.info("通信异常!!"); |
|
||||||
// receiveStr = null;
|
|
||||||
Channel incoming = ctx.channel(); |
|
||||||
if (incoming.isActive()) { |
|
||||||
log.info("SimpleClient: " + incoming.remoteAddress() + "异常"); |
|
||||||
receiveStr = null; |
|
||||||
cause.printStackTrace(); |
|
||||||
ctx.close(); |
|
||||||
// receiveStr = null;
|
|
||||||
// try {
|
|
||||||
// TimeUnit.SECONDS.sleep(5);
|
|
||||||
// SocketAddress remoteAddress = ctx.channel().remoteAddress();
|
|
||||||
// String port = ExchangeStringUtil.endData(remoteAddress.toString(),":");
|
|
||||||
// String host = ExchangeStringUtil.splitData(remoteAddress.toString(),"/",":");
|
|
||||||
// NettyClient nettyClient = new NettyClient();
|
|
||||||
// nettyClient.connect(Integer.parseInt(port), host); // 断线重连
|
|
||||||
// } catch (InterruptedException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception { |
|
||||||
// super.channelActive(ctx);
|
|
||||||
// 添加一个状态值,判断是否继续发送指令 update by ljf on 2020-08-07
|
|
||||||
if (Constant.WEB_FLAG) { |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
ctx.close(); |
|
||||||
} else { |
|
||||||
ctx.channel().read(); |
|
||||||
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss"); |
|
||||||
Date date = new Date(); |
|
||||||
log.info(ctx.channel().remoteAddress() + " " + sdf1.format(date) + "链接服务端成功!"); |
|
||||||
|
|
||||||
// 截取IP地址
|
|
||||||
IP = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress() + "", "/", ":"); |
|
||||||
// 截取端口号
|
|
||||||
port = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress() + "", ":", ""); |
|
||||||
log.info("IP: " + IP + ",端口号: " + port); |
|
||||||
|
|
||||||
// 生成对应的采集指令
|
|
||||||
// 修改生成指令(冷量计和电量一起采集) update by ljf on 2021-01-27
|
|
||||||
deviceManageEntityList = deviceManageService.queryDevicesByType(null); |
|
||||||
size = deviceManageEntityList.size(); |
|
||||||
|
|
||||||
log.info("初始连接报文: " + receiveStr); |
|
||||||
receiveStr = ""; |
|
||||||
// 保持长连接,封装发送电表工具方法 update by ljf on 2021-01-26
|
|
||||||
SendOrderUtils.sendMeterOrder(deviceManageEntityList.get(0), 0, IP, port, ctx); |
|
||||||
// 1.创建将要写出的数据
|
|
||||||
// String sendStr = "6830043080000068110432326536C816"; // 网络单相电表
|
|
||||||
// String sendStr = "FEFEFEFE6880025007000068010243C3B216"; // 广仪三相电表
|
|
||||||
// String collectionNum = deviceManageEntityList.get(0).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createMeterOrder(IP, port,
|
|
||||||
// deviceManageEntityList.get(0).getDataCom(), collectionNum, "1");
|
|
||||||
//// FileUtils.createFileAndWrite(sendStr, 0);
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx, sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private ByteBuf getByteBuf(ChannelHandlerContext ctx, String sendStr) { |
|
||||||
// byte类型的数据
|
|
||||||
// byte[] bytes = "这里是将要写往服务端的数据".getBytes(Charset.forName("utf-8"));
|
|
||||||
// String sendStr = "5803004900021914"; // 冷量计
|
|
||||||
// 申请一个数据结构存储信息
|
|
||||||
ByteBuf buffer = ctx.alloc().buffer(); |
|
||||||
// 将信息放入数据结构中
|
|
||||||
buffer.writeBytes(ExchangeStringUtil.hexStrToBinaryStr(sendStr));//对接需要16进制
|
|
||||||
return buffer; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception { |
|
||||||
Thread.sleep(500); |
|
||||||
receiveStr = null; |
|
||||||
ctx.close(); |
|
||||||
log.info(ctx.channel().localAddress() + "退出链接!!"); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { |
|
||||||
try { |
|
||||||
ByteBuf buf = (ByteBuf) msg; |
|
||||||
byte[] bytes = new byte[buf.readableBytes()]; |
|
||||||
buf.readBytes(bytes);//复制内容到字节数组bytes
|
|
||||||
buf.clear(); |
|
||||||
log.info("获取到的值: " + ExchangeStringUtil.bytesToHexString(bytes)); |
|
||||||
if (bytes.length <= 62) { |
|
||||||
// if (bytes.length <= 142) {
|
|
||||||
// receiveStr = receiveStr.replace("null", "");
|
|
||||||
// receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
// log.info(ctx.channel().remoteAddress() + " " + ctx.channel().localAddress() + " 接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length());
|
|
||||||
receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
receiveStr = receiveStr.replace("null", ""); |
|
||||||
log.info("接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length()); |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} finally { |
|
||||||
ReferenceCountUtil.release(msg); |
|
||||||
} |
|
||||||
// super.channelRead(ctx, msg);
|
|
||||||
// ByteBuf buf = (ByteBuf)msg;
|
|
||||||
// byte[] req = new byte[buf.readableBytes()];
|
|
||||||
// buf.readBytes(req);
|
|
||||||
// String body = new String(req, "UTF-8");
|
|
||||||
// ByteBuf buf = (ByteBuf)msg;
|
|
||||||
// byte [] bytes = new byte[buf.readableBytes()];
|
|
||||||
// buf.readBytes(bytes);//复制内容到字节数组bytes
|
|
||||||
// log.info("获取到的值: " + ExchangeStringUtil.bytesToHexString(bytes));
|
|
||||||
// if (bytes.length != 0) {
|
|
||||||
//// receiveStr = receiveStr.replace("null", "");
|
|
||||||
//// receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
//// log.info(ctx.channel().remoteAddress() + " " + ctx.channel().localAddress() + " 接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length());
|
|
||||||
// receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
|
||||||
// receiveStr = receiveStr.replace("null", "");
|
|
||||||
// log.info("接受服务器数据:" + receiveStr + ",大小: " + receiveStr.length());
|
|
||||||
// }
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { |
|
||||||
log.info("采集电表-数据读取接收完成: " + receiveStr); |
|
||||||
// 把receiveStr的"null"值去掉
|
|
||||||
// a9fec2c71f9002fefefefe6839025007000068810643c3bb446c338d16c2b8
|
|
||||||
// A9 FE C2 C7 1F 90 02 FE FE FE FE 68 39 02 50 07 00 00 68 81 06 43 C3 5B 38 6C 33 21 16 F8 12
|
|
||||||
if ((receiveStr.length() == 62)) { |
|
||||||
// log.info(receiveStr);
|
|
||||||
analysisReceiveOrder485.analysisMeterOrder485(receiveStr,"","",""); // 解析电表
|
|
||||||
receiveStr = ""; |
|
||||||
num = num + 1; |
|
||||||
Thread.sleep(600); |
|
||||||
if (num > size - 1) { |
|
||||||
num = 0; |
|
||||||
receiveStr = null; |
|
||||||
// 关闭连接
|
|
||||||
ctx.close(); |
|
||||||
// // 保持长连接,封装发送电表工具方法 update by ljf on 2021-01-26
|
|
||||||
// SendOrderUtils.sendMeterOrder(deviceManageEntityList.get(num),num,IP,port,ctx);
|
|
||||||
} else { |
|
||||||
// 添加一个状态值,判断是否继续发送指令 update by ljf on 2020-08-07
|
|
||||||
if (Constant.WEB_FLAG) { |
|
||||||
log.info("有指令下发退出定时采集DDC参数"); |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
ctx.close(); |
|
||||||
} else { |
|
||||||
// 封装发送电表工具方法 update by ljf on 2021-01-26
|
|
||||||
SendOrderUtils.sendMeterOrder(deviceManageEntityList.get(num), num, IP, port, ctx); |
|
||||||
// 1.创建将要写出的数据
|
|
||||||
// fe fe fe fe 68 80 02 50 07 00 00 68 81 06 43 c3 8c 34 33 33 5c 16
|
|
||||||
// String sendStr = "FEFEFE6880025007000068010243C3B216";
|
|
||||||
// String collectionNum = deviceManageEntityList.get(num).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createMeterOrder(IP, port,
|
|
||||||
// deviceManageEntityList.get(num).getDataCom(), collectionNum, "1");
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx, sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
// log.info("客户端再次往服务端发送数据" + num);
|
|
||||||
} |
|
||||||
} |
|
||||||
} else if ((receiveStr.length() > 62)) { |
|
||||||
receiveStr = null; |
|
||||||
num = num + 1; |
|
||||||
Thread.sleep(500); |
|
||||||
if (num > size - 1) { |
|
||||||
num = 0; |
|
||||||
receiveStr = null; |
|
||||||
// 关闭连接
|
|
||||||
ctx.close(); |
|
||||||
// // 保持长连接,封装发送电表工具方法 update by ljf on 2021-01-26
|
|
||||||
// SendOrderUtils.sendMeterOrder(deviceManageEntityList.get(num),num,IP,port,ctx);
|
|
||||||
} else { |
|
||||||
// 添加一个状态值,判断是否继续发送指令 update by ljf on 2020-08-07
|
|
||||||
if (Constant.WEB_FLAG) { |
|
||||||
log.info("有指令下发退出定时采集DDC参数"); |
|
||||||
num = 0; |
|
||||||
// 关闭连接
|
|
||||||
receiveStr = null; |
|
||||||
ctx.close(); |
|
||||||
} else { |
|
||||||
// 封装发送电表工具方法 update by ljf on 2021-01-26
|
|
||||||
SendOrderUtils.sendMeterOrder(deviceManageEntityList.get(num), num, IP, port, ctx); |
|
||||||
// 1.创建将要写出的数据
|
|
||||||
// fe fe fe fe 68 80 02 50 07 00 00 68 81 06 43 c3 8c 34 33 33 5c 16
|
|
||||||
// String sendStr = "FEFEFE6880025007000068010243C3B216";
|
|
||||||
// String collectionNum = deviceManageEntityList.get(num).getCollectionNum();
|
|
||||||
// String sendStr = GetReadOrder485.createMeterOrder(IP, port,
|
|
||||||
// deviceManageEntityList.get(num).getDataCom(), collectionNum, "1");
|
|
||||||
// ByteBuf buffer = getByteBuf(ctx, sendStr);
|
|
||||||
// // 2.发送数据
|
|
||||||
// ctx.channel().writeAndFlush(buffer);
|
|
||||||
// log.info("客户端再次往服务端发送数据" + num);
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
ctx.flush(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,215 @@ |
|||||||
|
package com.mh.user.serialport; |
||||||
|
|
||||||
|
import com.mh.common.utils.StringUtils; |
||||||
|
import com.mh.user.constants.Constant; |
||||||
|
import com.mh.user.entity.DeviceCodeParamEntity; |
||||||
|
import com.mh.user.factory.Device; |
||||||
|
import com.mh.user.factory.DeviceFactory; |
||||||
|
import com.mh.user.service.BuildingService; |
||||||
|
import com.mh.user.service.DeviceInstallService; |
||||||
|
import com.mh.user.service.NowDataService; |
||||||
|
import com.mh.user.service.SysParamService; |
||||||
|
import com.mh.user.strategy.DeviceStrategy; |
||||||
|
import com.mh.user.strategy.DeviceStrategyFactory; |
||||||
|
import com.mh.user.utils.*; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.context.ApplicationContext; |
||||||
|
import purejavacomm.SerialPort; |
||||||
|
|
||||||
|
import java.util.Comparator; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.List; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author LJF |
||||||
|
* @version 1.0 |
||||||
|
* @project CHWS |
||||||
|
* @description 通过串口发送和接收数据 |
||||||
|
* @date 2024-03-18 14:56:32 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class SendAndReceiveByCom { |
||||||
|
|
||||||
|
List<DeviceCodeParamEntity> deviceManageEntityList; |
||||||
|
|
||||||
|
ApplicationContext context = SpringBeanUtil.getApplicationContext(); |
||||||
|
DeviceInstallService deviceInstallService = context.getBean(DeviceInstallService.class); |
||||||
|
NowDataService nowDataService = context.getBean(NowDataService.class); |
||||||
|
BuildingService buildingService = context.getBean(BuildingService.class); |
||||||
|
|
||||||
|
public void sendAndReceive(String sort, String thread) { |
||||||
|
SerialPort serialPort = null; |
||||||
|
CacheUtil cacheUtil = CacheUtil.getInstance(); |
||||||
|
try { |
||||||
|
//生成对应的采集指令
|
||||||
|
List<DeviceCodeParamEntity> deviceParamsByType = cacheUtil.getDeviceParamsByType(sort); |
||||||
|
deviceManageEntityList = deviceParamsByType |
||||||
|
.parallelStream() |
||||||
|
.filter(value -> value.getThread().equals(thread)) |
||||||
|
.sorted(Comparator.comparing(DeviceCodeParamEntity::getDataCom)) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
int size = deviceManageEntityList.size(); |
||||||
|
for (int i = 0; i < size; i++) { |
||||||
|
//判断网页端是否有操作设备的
|
||||||
|
if (Constant.WEB_FLAG) { |
||||||
|
if (serialPort != null) { |
||||||
|
SerialTool.closePort(serialPort); |
||||||
|
} |
||||||
|
log.info("有指令下发退出定时采集"); |
||||||
|
break; |
||||||
|
} |
||||||
|
String comName = deviceManageEntityList.get(i).getDataCom(); |
||||||
|
if (StringUtils.isBlank(comName)) { |
||||||
|
log.info("-------------串口:" + comName + "不存在!-------------"); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
//获取设备实际波特率
|
||||||
|
int baudrate = deviceManageEntityList.get(i).getBaudrate(); |
||||||
|
//获取设备实际校验位
|
||||||
|
String parity = deviceManageEntityList.get(i).getParity(); |
||||||
|
String deviceAddr = deviceManageEntityList.get(i).getDeviceAddr(); |
||||||
|
String deviceType = deviceManageEntityList.get(i).getDeviceType(); |
||||||
|
String registerAddr = deviceManageEntityList.get(i).getRegisterAddr(); |
||||||
|
String brand = deviceManageEntityList.get(i).getBrand();//品牌
|
||||||
|
String buildingId = deviceManageEntityList.get(i).getBuildingId(); |
||||||
|
String buildingName = buildingService.queryBuildingName(buildingId); //查询楼栋名称
|
||||||
|
// 创建设备报文
|
||||||
|
Device device = DeviceFactory.createDevice(deviceType); |
||||||
|
DeviceStrategy strategy = DeviceStrategyFactory.createStrategy(deviceType); |
||||||
|
if (null == strategy) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
device.setStrategy(strategy); |
||||||
|
String sendStr = device.createOrders(deviceManageEntityList.get(i)); |
||||||
|
|
||||||
|
try { |
||||||
|
//传入对应的串口参数并打开串口
|
||||||
|
if (StringUtils.isBlank(parity) || parity.equalsIgnoreCase("none")) { |
||||||
|
serialPort = SerialTool.openPort(comName, baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); |
||||||
|
} else { |
||||||
|
serialPort = SerialTool.openPort(comName, baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_EVEN); |
||||||
|
} |
||||||
|
if (null == serialPort) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
//向串口发送指令
|
||||||
|
if (StringUtils.isBlank(sendStr)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
SerialTool.sendToPort(SerialTool.HexString2Bytes(sendStr), serialPort, sendStr, deviceType); |
||||||
|
if (deviceType.equals("热泵")) { |
||||||
|
for (int j = 0; j < 4; j++) { |
||||||
|
Thread.sleep(1000); |
||||||
|
// 判断网页端是否有操作设备的
|
||||||
|
if (Constant.WEB_FLAG) { |
||||||
|
SerialTool.closePort(serialPort); |
||||||
|
log.info("有指令下发退出定时采集"); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
Thread.sleep(2000); |
||||||
|
} |
||||||
|
|
||||||
|
//从串口读取数据
|
||||||
|
byte[] bytes = SerialTool.readFromPort(serialPort); |
||||||
|
Date date1 = new Date(); |
||||||
|
String dateStr = DateUtil.dateToString(date1, "yyyy-MM-dd HH:mm:ss"); |
||||||
|
if (bytes == null) { |
||||||
|
SerialTool.closePort(serialPort); |
||||||
|
log.info("串口" + serialPort.getName() + "没有数据返回!" + i); |
||||||
|
log.info("----------------" + deviceType + "离线,设备号:" + deviceAddr + ",所属楼栋:" + buildingName + "----------------"); |
||||||
|
String time1 = deviceInstallService.selectLastDate(deviceType, deviceAddr, buildingId); |
||||||
|
if (time1 == null) { |
||||||
|
time1 = dateStr; |
||||||
|
} |
||||||
|
int d = ExchangeStringUtil.compareCopyTime(time1, dateStr); |
||||||
|
if (d == 1) { |
||||||
|
deviceInstallService.updateNotOnline(deviceAddr, deviceType, buildingId, "离线"); //所有设备离线
|
||||||
|
if (deviceType.equals("热泵")) { |
||||||
|
nowDataService.updateRunState(buildingId, deviceAddr, "离线", buildingName); //监控界面状态表热泵在线状态
|
||||||
|
} |
||||||
|
} |
||||||
|
continue; |
||||||
|
} |
||||||
|
// 处理返回来的数据报文
|
||||||
|
dealReceiveData(dateStr, serialPort, i, deviceAddr, deviceType, registerAddr, brand, buildingId, buildingName, bytes, device); |
||||||
|
|
||||||
|
} catch (Exception e) { |
||||||
|
if (null != serialPort) { |
||||||
|
SerialTool.closePort(serialPort); |
||||||
|
log.error("发送窗口数据异常==>", e); |
||||||
|
} |
||||||
|
} finally { |
||||||
|
if (null != serialPort) { |
||||||
|
SerialTool.closePort(serialPort); |
||||||
|
log.info("关闭串口==" + serialPort.getName()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("-------------串口采集异常!----------->>", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 处理返回来的数据 |
||||||
|
* |
||||||
|
* @param dateStr |
||||||
|
* @param serialPort |
||||||
|
* @param i |
||||||
|
* @param deviceAddr |
||||||
|
* @param deviceType |
||||||
|
* @param registerAddr |
||||||
|
* @param brand |
||||||
|
* @param buildingId |
||||||
|
* @param buildingName |
||||||
|
* @param bytes |
||||||
|
* @throws InterruptedException |
||||||
|
*/ |
||||||
|
private void dealReceiveData(String dateStr, |
||||||
|
SerialPort serialPort, |
||||||
|
int i, |
||||||
|
String deviceAddr, |
||||||
|
String deviceType, |
||||||
|
String registerAddr, |
||||||
|
String brand, |
||||||
|
String buildingId, |
||||||
|
String buildingName, byte[] bytes, Device device) { |
||||||
|
try { |
||||||
|
String receiveStr = ""; |
||||||
|
receiveStr = ExchangeStringUtil.parseByte2HexStr(bytes); |
||||||
|
//去掉空格和null
|
||||||
|
receiveStr = receiveStr.replace("null", ""); |
||||||
|
receiveStr = receiveStr.replace(" ", ""); |
||||||
|
log.info("串口:" + serialPort.getName() + ",接受第" + i + "数据:" + receiveStr + ",大小: " + receiveStr.length()); |
||||||
|
//返回值全部变成大写
|
||||||
|
String receiveData = receiveStr.toUpperCase(); |
||||||
|
//截取去掉FE
|
||||||
|
String dataStr; |
||||||
|
if (receiveData.length() > 8) { |
||||||
|
String str1 = receiveData.substring(0, 8); |
||||||
|
String str2 = receiveData.substring(8); |
||||||
|
dataStr = str1.replace("FE", "") + str2; |
||||||
|
} else { |
||||||
|
dataStr = receiveData.replace("FE", ""); |
||||||
|
} |
||||||
|
deviceInstallService.updateOnline(deviceAddr, deviceType, buildingId, "在线"); //设备在线
|
||||||
|
log.info("----------------" + deviceType + "在线,设备号:" + deviceAddr + ",所属楼栋:" + buildingName + "----------------"); |
||||||
|
if (deviceType.equals("热泵")) { |
||||||
|
String strState = nowDataService.selectState(buildingId, deviceAddr); |
||||||
|
if (strState != null && strState.equals("离线")) { //采集到数据
|
||||||
|
nowDataService.updateRunState(buildingId, deviceAddr, "不运行", buildingName); //监控界面状态表热泵在线状态
|
||||||
|
} |
||||||
|
} |
||||||
|
// 解析返回来的数据
|
||||||
|
device.analysisReceiveData(dateStr, deviceType, registerAddr, brand, buildingId, buildingName, dataStr); |
||||||
|
|
||||||
|
} catch (Exception e) { |
||||||
|
log.error("楼栋:" + buildingName + "设备类型:" + deviceType + "保存数据库失败!" + i, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,306 +0,0 @@ |
|||||||
package com.mh.user.serialport; |
|
||||||
|
|
||||||
import com.mh.user.constants.Constant; |
|
||||||
import com.mh.user.entity.DeviceCodeParamEntity; |
|
||||||
import com.mh.user.service.BuildingService; |
|
||||||
import com.mh.user.service.DeviceCodeParamService; |
|
||||||
import com.mh.user.service.DeviceInstallService; |
|
||||||
import com.mh.user.service.NowDataService; |
|
||||||
import com.mh.user.utils.*; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.springframework.context.ApplicationContext; |
|
||||||
import gnu.io.SerialPort; |
|
||||||
import java.nio.ByteBuffer; |
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
import java.text.SimpleDateFormat; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author nxr |
|
||||||
* @title : |
|
||||||
* @description : 串口发送和接收处理,采集类 |
|
||||||
* @updateTime 2022-08-10 |
|
||||||
* @throws : |
|
||||||
*/ |
|
||||||
@Slf4j |
|
||||||
public class SerialPortSendReceive { |
|
||||||
|
|
||||||
private String receiveStr = null; |
|
||||||
public SerialPort serialPort = null; |
|
||||||
private int size = 0; |
|
||||||
private int baudrate=9600; |
|
||||||
private String parity=null; |
|
||||||
List<DeviceCodeParamEntity> deviceManageEntityList; |
|
||||||
// 调用service
|
|
||||||
ApplicationContext context = SpringBeanUtil.getApplicationContext(); |
|
||||||
DeviceCodeParamService deviceCodeParamService = context.getBean(DeviceCodeParamService.class); |
|
||||||
DeviceInstallService deviceInstallService = context.getBean(DeviceInstallService.class); |
|
||||||
NowDataService nowDataService = context.getBean(NowDataService.class); |
|
||||||
BuildingService buildingService = context.getBean(BuildingService.class); |
|
||||||
AnalysisReceiveOrder485 analysisReceiveOrder485 = new AnalysisReceiveOrder485(); |
|
||||||
|
|
||||||
public void serialPortSend(String sort,String thread) { |
|
||||||
//查看所有串口
|
|
||||||
SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil(); |
|
||||||
ArrayList<String> port = serialPortUtil.findPort(); |
|
||||||
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|
||||||
Date date = new Date(); |
|
||||||
String dateStr = df.format(date); |
|
||||||
|
|
||||||
// SerialTool serialPortUtil = SerialTool.getSerialPortUtil();
|
|
||||||
// ArrayList<String> port = serialPortUtil.findPort();
|
|
||||||
// comName=comName.toUpperCase(); //转为大写
|
|
||||||
// if (port.contains(comName)){
|
|
||||||
try{ |
|
||||||
//生成对应的采集指令
|
|
||||||
if (sort.equals("1")){ //水温、水位
|
|
||||||
deviceManageEntityList = deviceCodeParamService.queryCodeParam3(thread); |
|
||||||
}else if (sort.equals("2")){ //采集水、电、运行状态!
|
|
||||||
deviceManageEntityList = deviceCodeParamService.queryCodeParam4(thread); |
|
||||||
}else if (sort.equals("3")){ //采集设定温度、设定水位、故障状态!
|
|
||||||
deviceManageEntityList = deviceCodeParamService.queryCodeParam5(thread); |
|
||||||
}else{ |
|
||||||
deviceManageEntityList = deviceCodeParamService.queryCodeParam3(thread); |
|
||||||
} |
|
||||||
size = deviceManageEntityList.size(); |
|
||||||
for (int i=0;i<size;i++){ |
|
||||||
//判断网页端是否有操作设备的
|
|
||||||
if (Constant.WEB_FLAG) { |
|
||||||
Constant.FLAG=false; |
|
||||||
serialPortUtil.closePort(serialPort); |
|
||||||
// Thread.sleep(2000);
|
|
||||||
log.info("有指令下发退出定时采集"); |
|
||||||
break; |
|
||||||
} |
|
||||||
//获取设备实际波特率
|
|
||||||
baudrate=deviceManageEntityList.get(i).getBaudrate(); |
|
||||||
//获取设备实际校验位
|
|
||||||
parity=deviceManageEntityList.get(i).getParity(); |
|
||||||
String comName=deviceManageEntityList.get(i).getDataCom(); |
|
||||||
comName=comName.toUpperCase(); //转为大写
|
|
||||||
if (port.contains(comName)){ |
|
||||||
String deviceAddr=deviceManageEntityList.get(i).getDeviceAddr(); |
|
||||||
String deviceType=deviceManageEntityList.get(i).getDeviceType(); |
|
||||||
String registerAddr=deviceManageEntityList.get(i).getRegisterAddr(); |
|
||||||
String brand=deviceManageEntityList.get(i).getBrand();//品牌
|
|
||||||
String buildingId=deviceManageEntityList.get(i).getBuildingId(); |
|
||||||
String buildingName=buildingService.queryBuildingName(buildingId); //查询楼栋名称
|
|
||||||
try{ |
|
||||||
//传入对应的串口参数并打开串口
|
|
||||||
if (parity==null || parity.equals("") || parity.equalsIgnoreCase("none")){ |
|
||||||
serialPort = serialPortUtil.openPort(comName, baudrate, SerialPort.DATABITS_8, SerialPort.PARITY_NONE, SerialPort.PARITY_ODD); |
|
||||||
}else{ |
|
||||||
serialPort = serialPortUtil.openPort(comName, baudrate, SerialPort.DATABITS_8, SerialPort.PARITY_EVEN, SerialPort.PARITY_ODD); |
|
||||||
} |
|
||||||
//向串口发送指令
|
|
||||||
if (serialPort != null) { |
|
||||||
// log.info("---------波特率:"+baudrate+",校验位:"+parity+" -----------");
|
|
||||||
SendOrderUtils.sendSerialPort(deviceManageEntityList.get(i), serialPort); |
|
||||||
if (deviceType.equals("热泵")){ |
|
||||||
Thread.sleep(4000); |
|
||||||
}else{ |
|
||||||
Thread.sleep(2000); |
|
||||||
} |
|
||||||
}else{ |
|
||||||
continue; //continue时,跳出本次循环,继续执行下次循环。Break时,跳出循环(结束循环),执行下面的语句。
|
|
||||||
} |
|
||||||
}catch (Exception e){ |
|
||||||
// e.printStackTrace();
|
|
||||||
Constant.WEB_FLAG=false;//可以采集的状态
|
|
||||||
if(i==size-1){ |
|
||||||
Constant.FLAG=false; |
|
||||||
} |
|
||||||
} |
|
||||||
receiveStr=""; |
|
||||||
//从串口读取数据
|
|
||||||
byte[] bytes= serialPortUtil.readFromPort(serialPort); |
|
||||||
try { |
|
||||||
String byteStr = new String(bytes, 0, bytes.length).trim(); |
|
||||||
} catch (NullPointerException e) { |
|
||||||
serialPortUtil.closePort(serialPort); |
|
||||||
Thread.sleep(2000); |
|
||||||
log.info("串口"+serialPort+"没有数据返回!"+i); |
|
||||||
log.info("----------------"+deviceType+"离线,设备号:"+deviceAddr+",所属楼栋:"+buildingName+"----------------"); |
|
||||||
Constant.WEB_FLAG=false;//可以采集的状态
|
|
||||||
if(i==size-1){ |
|
||||||
Constant.FLAG=false; |
|
||||||
} |
|
||||||
String time1=deviceInstallService.selectLastDate(deviceType,deviceAddr,buildingId); |
|
||||||
Date date1=new Date(); |
|
||||||
String time2=df.format(date1); |
|
||||||
if (time1==null){ |
|
||||||
time1=df.format(date1); |
|
||||||
} |
|
||||||
int d= ExchangeStringUtil.compareCopyTime(time1,time2); |
|
||||||
if (d==1){ |
|
||||||
deviceInstallService.updateNotOnline(deviceAddr,deviceType,buildingId,"离线"); //所有设备离线
|
|
||||||
if (deviceType.equals("热泵")){ |
|
||||||
nowDataService.updateRunState(buildingId,deviceAddr,"离线"); //监控界面状态表热泵在线状态
|
|
||||||
} |
|
||||||
} |
|
||||||
continue; |
|
||||||
} |
|
||||||
receiveStr = receiveStr + printHexString(bytes); |
|
||||||
//去掉空格和null
|
|
||||||
receiveStr = receiveStr.replace("null", ""); |
|
||||||
receiveStr = receiveStr.replace(" ", ""); |
|
||||||
log.info("串口"+serialPort+"接受第"+i+"数据:" + receiveStr + ",大小: " + receiveStr.length()); |
|
||||||
try{ |
|
||||||
serialPortUtil.closePort(serialPort); |
|
||||||
log.info("关闭"+serialPort); |
|
||||||
}catch (Exception e){ |
|
||||||
// e.printStackTrace();
|
|
||||||
Constant.WEB_FLAG=false;//可以采集的状态
|
|
||||||
if(i==size-1){ |
|
||||||
Constant.FLAG=false; |
|
||||||
} |
|
||||||
log.error("关闭"+serialPort+"失败!"); |
|
||||||
} |
|
||||||
//返回值全部变成大写
|
|
||||||
String receiveData = receiveStr.toUpperCase(); |
|
||||||
//截取去掉FE
|
|
||||||
String dataStr; |
|
||||||
if (receiveData.length()>8){ |
|
||||||
String str1=receiveData.substring(0,8); |
|
||||||
String str2=receiveData.substring(8); |
|
||||||
dataStr=str1.replace("FE", "")+str2; |
|
||||||
}else{ |
|
||||||
dataStr = receiveData.replace("FE", ""); |
|
||||||
} |
|
||||||
deviceInstallService.updateOnline(deviceAddr,deviceType,buildingId,"在线"); //设备在线
|
|
||||||
log.info("----------------"+deviceType+"在线,设备号:"+deviceAddr+",所属楼栋:"+buildingName+"----------------"); |
|
||||||
if (deviceType.equals("热泵")){ |
|
||||||
String strState=nowDataService.selectState(buildingId,deviceAddr); |
|
||||||
if (strState!=null && strState.equals("离线")){ //采集到数据
|
|
||||||
nowDataService.updateRunState(buildingId,deviceAddr,"不运行"); //监控界面状态表热泵在线状态
|
|
||||||
} |
|
||||||
} |
|
||||||
try{ |
|
||||||
if ((dataStr.length() == 36 || dataStr.length() == 44 || dataStr.length()==40 || dataStr.length()==50) && deviceType.equals("电表")) { |
|
||||||
analysisReceiveOrder485.analysisMeterOrder485(dataStr,registerAddr,brand,buildingId); |
|
||||||
nowDataService.proWaterLevel(dateStr,buildingId); //保存时间点楼栋水位
|
|
||||||
}else if ((dataStr.length() == 18 || dataStr.length() == 70 || dataStr.length() == 44) && deviceType.equals("水表")) { |
|
||||||
analysisReceiveOrder485.analysisWtMeterOrder485(dataStr,registerAddr,brand,buildingId); |
|
||||||
}else if (deviceType.equals("压变")) { |
|
||||||
analysisReceiveOrder485.analysisPressureOrder485(dataStr,registerAddr,brand,buildingId); |
|
||||||
}else if (deviceType.equals("热泵")) { |
|
||||||
analysisReceiveOrder485.analysisPumpOrder485(dataStr,registerAddr,brand,buildingId); |
|
||||||
}else if (deviceType.equals("温控")) { |
|
||||||
analysisReceiveOrder485.analysisTempOrder485(dataStr,registerAddr,brand,buildingId); |
|
||||||
}else if (deviceType.equals("时控")) { |
|
||||||
analysisReceiveOrder485.analysisTimeSetOrder485(dataStr,registerAddr,brand,buildingId); |
|
||||||
}else if (deviceType.equals("水位开关") && (registerAddr.equals("0018") || registerAddr.equals("0017"))){ |
|
||||||
analysisReceiveOrder485.analysisRelayOrder485(dataStr,registerAddr,brand,buildingId); |
|
||||||
}else if (dataStr.length() == 30 && deviceType.equals("状态检测")) {//五路状态读取,兼容旧版系统
|
|
||||||
analysisReceiveOrder485.analysisStateOrder485(dataStr,registerAddr,brand,buildingId); |
|
||||||
}else if (deviceType.equals("水位开关") && registerAddr.equals("0010")){ |
|
||||||
analysisReceiveOrder485.analysisPumpStateOrder(dataStr,registerAddr,brand,buildingId); //创新,热泵状态与水位共用一个8路设备
|
|
||||||
// analysisReceiveOrder485.analysisRelayOrder485(dataStr,registerAddr,brand,buildingId); //华厦
|
|
||||||
nowDataService.proWaterLevel(dateStr,buildingId); //保存时间点楼栋水位
|
|
||||||
}else if (deviceType.equals("温度变送器")){ |
|
||||||
analysisReceiveOrder485.analysisMulTempOrder485(dataStr,registerAddr,brand,buildingId); |
|
||||||
}else if (deviceType.equals("热泵状态")){ |
|
||||||
analysisReceiveOrder485.analysisPumpStateOrder(dataStr,registerAddr,brand,buildingId); |
|
||||||
} |
|
||||||
}catch (Exception e){ |
|
||||||
// e.printStackTrace();
|
|
||||||
Constant.WEB_FLAG=false;//可以采集的状态
|
|
||||||
if(i==size-1){ |
|
||||||
Constant.FLAG=false; |
|
||||||
} |
|
||||||
log.error(deviceManageEntityList.get(i).getDeviceType()+"保存数据库失败!"+i); |
|
||||||
} |
|
||||||
Thread.sleep(1000); |
|
||||||
}else{ |
|
||||||
Constant.WEB_FLAG=false;//可以采集的状态
|
|
||||||
if(i==size-1){ |
|
||||||
Constant.FLAG=false; |
|
||||||
} |
|
||||||
log.info("-------------串口:"+comName+"不存在!-------------"); |
|
||||||
} |
|
||||||
if(i==size-1){ |
|
||||||
Constant.FLAG=false; |
|
||||||
log.info("-------------一轮采集完,采集标志Constant.Flag="+Constant.FLAG+"-------------"); |
|
||||||
} |
|
||||||
} |
|
||||||
}catch (Exception e){ |
|
||||||
e.printStackTrace(); |
|
||||||
Constant.WEB_FLAG=false;//可以采集的状态
|
|
||||||
Constant.FLAG=false; |
|
||||||
log.error("-------------串口采集异常!-------------"); |
|
||||||
} |
|
||||||
// }else {
|
|
||||||
// log.info("串口:"+comName+"不存在!");
|
|
||||||
// }
|
|
||||||
} |
|
||||||
/** |
|
||||||
* 字节数组转16进制字符串 |
|
||||||
* @param b 字节数组 |
|
||||||
* @return 16进制字符串 |
|
||||||
*/ |
|
||||||
public static String printHexString(byte[] b) { |
|
||||||
StringBuilder sbf = new StringBuilder(); |
|
||||||
for (byte value : b) { |
|
||||||
String hex = Integer.toHexString(value & 0xFF); |
|
||||||
if (hex.length() == 1) { |
|
||||||
hex = '0' + hex; |
|
||||||
} |
|
||||||
sbf.append(hex.toUpperCase()).append(" "); |
|
||||||
} |
|
||||||
return sbf.toString().trim(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 十六进制字符串转byte[] |
|
||||||
* @param hex 十六进制字符串 |
|
||||||
* @return byte[] |
|
||||||
*/ |
|
||||||
public static byte[] hexStr2Byte(String hex) { |
|
||||||
if (hex == null) { |
|
||||||
return new byte[] {}; |
|
||||||
} |
|
||||||
|
|
||||||
// 奇数位补0
|
|
||||||
if (hex.length() % 2 != 0) { |
|
||||||
hex = "0" + hex; |
|
||||||
} |
|
||||||
|
|
||||||
int length = hex.length(); |
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(length / 2); |
|
||||||
for (int i = 0; i < length; i++) { |
|
||||||
String hexStr = hex.charAt(i) + ""; |
|
||||||
i++; |
|
||||||
hexStr += hex.charAt(i); |
|
||||||
byte b = (byte) Integer.parseInt(hexStr, 16); |
|
||||||
buffer.put(b); |
|
||||||
} |
|
||||||
return buffer.array(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 16进制转换成为string类型字符串 |
|
||||||
* @param s 待转换字符串 |
|
||||||
*/ |
|
||||||
public static String hexStringToString(String s) { |
|
||||||
if (s == null || "".equals(s)) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
s = s.replace(" ", ""); |
|
||||||
byte[] baKeyword = new byte[s.length() / 2]; |
|
||||||
for (int i = 0; i < baKeyword.length; i++) { |
|
||||||
try { |
|
||||||
baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16)); |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
try { |
|
||||||
s = new String(baKeyword, StandardCharsets.UTF_8); |
|
||||||
} catch (Exception e1) { |
|
||||||
e1.printStackTrace(); |
|
||||||
} |
|
||||||
return s; |
|
||||||
} |
|
||||||
} |
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue