diff --git a/.gitignore b/.gitignore index 8ec80db..a0166ac 100644 --- a/.gitignore +++ b/.gitignore @@ -98,3 +98,5 @@ code/java/天气灾害预警/target/ code/java/天气灾害预警/out/ *.jar *.iws +*.log +*.lck diff --git a/code/java/DisasterWarning/.gitignore b/code/java/DisasterWarning/.gitignore index 569855c..612c062 100644 --- a/code/java/DisasterWarning/.gitignore +++ b/code/java/DisasterWarning/.gitignore @@ -133,4 +133,7 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk -target/* \ No newline at end of file +target/* + +logs/* +logs \ No newline at end of file diff --git a/code/java/DisasterWarning/config.json b/code/java/DisasterWarning/config.json index 014224c..3795a43 100644 --- a/code/java/DisasterWarning/config.json +++ b/code/java/DisasterWarning/config.json @@ -3,6 +3,7 @@ "key": "fe9fa8eeeb6f4301a92541eed565dd15", "query_url": "https://devapi.qweather.com/v7/warning/now?", "wechat_officalaccount_url": "https://cxxmwx.cpic.com.cn/app/index.php?i=2&c=entry&do=send_group_tpl_api&m=ok_tplmessage", + "query_interval": 10, "cities": [ { "city_name": "厦门", diff --git a/code/java/DisasterWarning/db.json b/code/java/DisasterWarning/db.json index 7d27945..a8f5ddd 100644 --- a/code/java/DisasterWarning/db.json +++ b/code/java/DisasterWarning/db.json @@ -1,12 +1,14 @@ { "tns_name": "xmcx1", "ip_addr": "10.39.0.86", - "user_name": "", - "password": "", + "jdbc_url": "jdbc:oracle:thin:@10.39.0.86:1521:xmcx1", + "table_space": "wechat", + "user_name": "wechat", + "password": "@rn7Q+t5zeyKIZ~s", "tables": [ { - "table_name": "", - "table_description": "" + "table_name": "weather_disaster_notify", + "table_description": "天气预警消息表" } ] -} \ No newline at end of file +} diff --git a/code/java/DisasterWarning/logging.properties b/code/java/DisasterWarning/logging.properties new file mode 100644 index 0000000..f82b56f --- /dev/null +++ b/code/java/DisasterWarning/logging.properties @@ -0,0 +1,10 @@ + +handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler + +.level = INFO + +java.util.logging.FileHandler.pattern = ./logs/log_%u.log +java.util.logging.FileHandler.limit = 50000 +java.util.logging.FileHandler.count = 1 +java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter +java.util.logging.FileHandler.append = true; diff --git a/code/java/DisasterWarning/pom.xml b/code/java/DisasterWarning/pom.xml index f2ef2b1..bc67e03 100644 --- a/code/java/DisasterWarning/pom.xml +++ b/code/java/DisasterWarning/pom.xml @@ -5,6 +5,13 @@ disaster_warning 1.0-SNAPSHOT + + com.oracle + ojdbc8 + 1.0 + system + ${project.basedir}/lib/ojdbc8.jar + org.apache.httpcomponents httpclient @@ -16,7 +23,7 @@ 4.13.2 test - + com.fasterxml.jackson.core jackson-core @@ -72,6 +79,40 @@ compile + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M6 + + true + + + + org.apache.maven.plugins + maven-assembly-plugin + + + jar-with-dependencies + + + + AppMain + + + + + + make-assmenbly + package + + single + + + + + diff --git a/code/java/DisasterWarning/src/main/java/AppMain.java b/code/java/DisasterWarning/src/main/java/AppMain.java index 1b52676..9373c01 100644 --- a/code/java/DisasterWarning/src/main/java/AppMain.java +++ b/code/java/DisasterWarning/src/main/java/AppMain.java @@ -2,41 +2,62 @@ * @Author: Kane * @Date: 2022-04-22 10:53:49 * @LastEditors: Kane - * @LastEditTime: 2022-04-23 23:22:57 + * @LastEditTime: 2022-05-10 16:28:07 * @FilePath: \DisasterWarning\src\main\java\AppMain.java * @Description: 和风天气预警推送厦门太保公众号主程序! * * Copyright (c) ${2022} by Kane, All Rights Reserved. */ +import com.cpic.xim.config.AppConfigManager; import com.cpic.xim.config.City; import com.cpic.xim.notify.disaster.QWeatherDisasterWarning; import com.cpic.xim.notify.disaster.WeatherDisasterWarningGrabber; -import com.cpic.xim.config.WeatherDisasterNotifyConfig; import com.cpic.xim.wechat.officalAccount.sendMessage; - +import com.cpic.xim.config.WeatherDisasterNotifyConfig; +import java.io.FileInputStream; import java.io.IOException; +import java.sql.SQLException; import java.util.Vector; +import java.util.logging.*; + public class AppMain { - private static final String CONFIG_FILE_PATH = "./config.json"; + // private final static String LOG_FILE_PATH = "./logs/app%u.log"; public static void main( String[] args ) { String json; WeatherDisasterNotifyConfig config = null; QWeatherDisasterWarning warning = null; + Logger logger = null; + + // 配置logger + try + { + setRootLogger(); + + logger = Logger.getLogger( "com.cpicxim" ); + } + catch ( IOException error ) + { + System.out.println( "配置logger失败,原因:" + error.getMessage() ); + + return; + } // 读取配置 try { - config = WeatherDisasterNotifyConfig.load( CONFIG_FILE_PATH ); + config = AppConfigManager.getConfig(); } - catch (IOException error) + catch ( IOException error ) { System.out.println( "读取配置文件失败!" ); System.out.println( error.getMessage() ); + logger.log( Level.SEVERE, "读取配置文件失败:{0}", error.getMessage() ); + return; } @@ -45,30 +66,91 @@ public class AppMain String userKey = config.getKey(); // 遍历所有城市,查询是否有警报,有则推送。 - for ( City city : cities) + while (true) { + for ( City city : cities ) + { + try + { + json = WeatherDisasterWarningGrabber.getWeatherDisasterWarningJSON( queryURL, + userKey, city.getCityCode() ); + warning = WeatherDisasterWarningGrabber.convertWeatherDisasterWarning( json ); + + logger.log( Level.INFO, "查询{0}天气预警,结果:{1}。", new Object[] + { city.getCityName(), json} ); + + // 判断是否有警报 + if ( warning.getWarning().isEmpty() == true) + { + logger.log( Level.INFO, "查询{0}天气预警,无警报!。", new Object[] + { city.getCityName()} ); + continue; + } + + logger.log( Level.INFO, "查询{0}天气预警,发送日志。", new Object[] + { city.getCityName()} ); + + sendMessage.sendWeatherDisasterWarning( config.getWechatOfficalAccountURL(), + warning ); + + logger.log( Level.INFO, "{0}天气预警,日志发送成功。", new Object[] + { city.getCityName()} ); + + sendMessage.saveWeatherDisasterWarning( city.getCityName(), warning ); + } + catch ( IOException error ) + { + System.out.println( "查询" + city.getCityName() + "出现异常!" ); + System.out.println( error.getMessage() ); + + logger.log( Level.SEVERE, "查询 {0} 出现异常:{1}。", new Object[] + { city.getCityName(), error.getMessage()} ); + } + catch ( SQLException error ) + { + logger.log( Level.SEVERE, "查询 {0} 写入数据库失败:{1}。", new Object[] + { city.getCityName(), error.getMessage()} ); + } + catch ( ClassNotFoundException error ) + { + logger.log( Level.SEVERE, "查询 {0} 加载oracle驱动失败:{1}。", new Object[] + { city.getCityName(), error.getMessage()} ); + + } + catch ( Exception error ) + { + logger.log( Level.SEVERE, "查询 {0} 出现未知错误:{1}。", new Object[] + { city.getCityName(), error.getMessage()} ); + } + } + try { - json = WeatherDisasterWarningGrabber.getWeatherDisasterWarningJSON( queryURL, - userKey, city.getCityCode() ); - warning = WeatherDisasterWarningGrabber.convertWeatherDisasterWarning( json ); - - // 判断是否有警报 - if ( warning.getWarning().isEmpty() == true) - { - continue; - } - - sendMessage.sendWeatherDisasterWarning( config.getWechatOfficalAccountURL(), - warning ); + logger.log( Level.INFO, "查询结束,休眠{0}分钟。", config.getQueryInterval() ); + Thread.sleep( config.getQueryInterval() * 1000 * 60 ); } - catch (IOException error) + catch ( InterruptedException error ) { - System.out.println( "查询" + city.getCityName() + "出现异常!" ); - System.out.println( error.getMessage() ); - - continue; + logger.log( Level.SEVERE, "线程休眠异常,错误信息:{0}", new Object[] + { error.getMessage()} ); } } } + + /** + * 设置JUL的logger。 + */ + private static void setRootLogger() throws IOException + { + LogManager logManager = LogManager.getLogManager(); + // 使用外部的配置文件。 + FileInputStream configFile = new FileInputStream( "./logging.properties" ); + // 使用jar中的配置文件。 + // InputStream configFile = + // AppMain.class.getClassLoader().getResourceAsStream( "logging.properties" ); + + logManager.readConfiguration( configFile ); + + Logger.getLogger( "com.cpicxim" ); + } } diff --git a/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/AppConfigManager.java b/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/AppConfigManager.java new file mode 100644 index 0000000..69fcfa0 --- /dev/null +++ b/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/AppConfigManager.java @@ -0,0 +1,79 @@ +/* + * @Author: Kane + * @Date: 2022-05-10 16:06:14 + * @LastEditors: Kane + * @LastEditTime: 2022-05-10 16:09:07 + * @FilePath: \DisasterWarning\src\main\java\com\cpic\xim\config\AppConfigManager.java + * @Description: + * + * Copyright (c) ${2022} by Kane, All Rights Reserved. + */ + +package com.cpic.xim.config; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.FileInputStream; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; + +public class AppConfigManager +{ + private static final int BUFFER_SIZE = 1024; + private static final String CONFIG_FILE_CHARSET = "UTF-8"; + private static final String CONFIG_FILE_PATH = "./config.json"; + private static WeatherDisasterNotifyConfig appConfig = null; + + public static WeatherDisasterNotifyConfig getConfig() throws IOException + + { + if ( appConfig != null) + { + return appConfig; + } + + ObjectMapper mapper = new ObjectMapper(); + FileInputStream configFile = null; + InputStreamReader in = null; + StringBuffer json = null; + char[] buffer = new char[BUFFER_SIZE]; + + // 设置json属性 + mapper.setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE ); + + try + { + configFile = new FileInputStream( CONFIG_FILE_PATH ); + in = new InputStreamReader( configFile, CONFIG_FILE_CHARSET ); + json = new StringBuffer(); + + int length = in.read( buffer ); + + while (length != -1) + { + json.append( buffer ); + + length = in.read( buffer ); + } + + appConfig = mapper.readValue( json.toString(), WeatherDisasterNotifyConfig.class ); + } + finally + { + if ( configFile != null) + { + try + { + configFile.close(); + } + catch ( IOException e ) + { + e.printStackTrace(); + } + } + } + + return appConfig; + } +} diff --git a/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/WeatherDisasterNotifyConfig.java b/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/WeatherDisasterNotifyConfig.java index f3bdeaf..dd1892d 100644 --- a/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/WeatherDisasterNotifyConfig.java +++ b/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/WeatherDisasterNotifyConfig.java @@ -1,62 +1,22 @@ +/* + * @Author: Kane + * @Date: 2022-04-24 10:21:46 + * @LastEditors: Kane + * @LastEditTime: 2022-05-10 16:16:28 + * @FilePath: \DisasterWarning\src\main\java\com\cpic\xim\config\WeatherDisasterNotifyConfig.java + * @Description: + * + * Copyright (c) ${2022} by Kane, All Rights Reserved. + */ package com.cpic.xim.config; -import java.io.FileReader; -import java.io.IOException; import java.util.Vector; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; + public class WeatherDisasterNotifyConfig { - private static final int BUFFER_SIZE = 1024; - - public static WeatherDisasterNotifyConfig load( String filePath ) throws IOException - - { - WeatherDisasterNotifyConfig config = null; - ObjectMapper mapper = new ObjectMapper(); - FileReader configFile = null; - StringBuffer json = null; - char[] buffer = new char[BUFFER_SIZE]; - - // 设置json属性 - mapper.setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE ); - - try - { - configFile = new FileReader( filePath ); - json = new StringBuffer(); - - int length = configFile.read( buffer ); - - while (length != -1) - { - json.append( buffer ); - - length = configFile.read( buffer ); - } - - config = mapper.readValue( json.toString(), WeatherDisasterNotifyConfig.class ); - } - finally - { - if ( configFile != null) - { - try - { - configFile.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - } - - return config; - } public WeatherDisasterNotifyConfig() {}; @@ -96,6 +56,18 @@ public class WeatherDisasterNotifyConfig return cities; } + + public int getQueryInterval() + { + return queryInterval; + } + + public void setQueryInterval( int queryInterval ) + { + this.queryInterval = queryInterval; + } + + public void setCities( Vector cities ) { this.cities = cities; @@ -121,14 +93,24 @@ public class WeatherDisasterNotifyConfig this.wechatOfficalAccountURL = wechatOfficalAccountURL; } + @JsonProperty( "title") private String title; + + @JsonProperty( "key") private String key; + + @JsonProperty( "query_url") private String queryUrl; + @JsonProperty( "query_interval") + private int queryInterval; + @JsonProperty( "wechat_officalaccount_url") private String wechatOfficalAccountURL; + + @JsonProperty( "cities") private Vector cities; + + @JsonProperty( "notify_stuffs") private Vector notifyStuffs; - - } diff --git a/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/DBTable.java b/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/DBTable.java index 2c5a8e1..a41c6a8 100644 --- a/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/DBTable.java +++ b/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/DBTable.java @@ -2,7 +2,7 @@ * @Author: Kane * @Date: 2022-04-22 17:33:30 * @LastEditors: Kane - * @LastEditTime: 2022-04-23 23:50:20 + * @LastEditTime: 2022-04-27 16:53:13 * @FilePath: \DisasterWarning\src\main\java\com\cpic\xim\config\db\DBTable.java * @Description: * @@ -12,6 +12,8 @@ package com.cpic.xim.config.db; import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; + public class DBTable { public DBTable() @@ -59,6 +61,9 @@ public class DBTable return Objects.hash( tableName, tableDescription ); } + @JsonProperty( "table_name") private String tableName; + + @JsonProperty( "table_description") private String tableDescription; } diff --git a/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/OracleConfig.java b/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/OracleConfig.java index 4caaccd..ff6c3ca 100644 --- a/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/OracleConfig.java +++ b/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/OracleConfig.java @@ -2,7 +2,7 @@ * @Author: Kane * @Date: 2022-04-22 17:33:30 * @LastEditors: Kane - * @LastEditTime: 2022-04-23 23:51:46 + * @LastEditTime: 2022-04-25 21:33:07 * @FilePath: \DisasterWarning\src\main\java\com\cpic\xim\config\db\OracleConfig.java * @Description: * @@ -11,7 +11,11 @@ package com.cpic.xim.config.db; import java.util.Vector; +import com.fasterxml.jackson.annotation.JsonProperty; +/** + * @Description oracle数据库相关参数对象。 + */ public class OracleConfig { @@ -45,6 +49,17 @@ public class OracleConfig this.jdbcURL = jdbcURL; } + + public String getTableSpace() + { + return tableSpace; + } + + public void setTableSpace( String tableSpace ) + { + this.tableSpace = tableSpace; + } + public String getUserName() { return userName; @@ -75,10 +90,24 @@ public class OracleConfig this.tables = tables; } + @JsonProperty( "tns_name") private String tnsName; + + @JsonProperty( "ip_addr") private String ipAddr; + + @JsonProperty( "jdbc_url") private String jdbcURL; + + @JsonProperty( "table_space") + private String tableSpace; + + @JsonProperty( "user_name") private String userName; + + @JsonProperty( "password") private String password; + + @JsonProperty( "tables") private Vector tables; } diff --git a/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/OracleConfigManager.java b/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/OracleConfigManager.java new file mode 100644 index 0000000..3a32004 --- /dev/null +++ b/code/java/DisasterWarning/src/main/java/com/cpic/xim/config/db/OracleConfigManager.java @@ -0,0 +1,77 @@ +/* + * @Author: Kane + * @Date: 2022-04-25 21:45:12 + * @LastEditors: Kane + * @LastEditTime: 2022-05-03 22:34:37 + * @FilePath: \DisasterWarning\src\main\java\com\cpic\xim\config\db\OracleConfigManager.java + * @Description: oracle数据库配置文件加载类 + * + * Copyright (c) ${2022} by Kane, All Rights Reserved. + */ +package com.cpic.xim.config.db; + +import java.io.*; + +import com.fasterxml.jackson.databind.*; + +public class OracleConfigManager +{ + private static final String CONFIG_FILE_PATH = "./db.json"; + private static final String CONFIG_FILE_CHARSET = "UTF-8"; + private static final int BUFFER_SIZE = 1024; + private static OracleConfig dbConfig = null; + + private OracleConfigManager() + {} + + public static OracleConfig getOracleConfig() throws IOException + { + FileInputStream file = null; + InputStreamReader in = null; + StringBuffer json = null; + char[] buffer = new char[BUFFER_SIZE]; + + if ( dbConfig != null) + { + return dbConfig; + } + + try + { + file = new FileInputStream( CONFIG_FILE_PATH ); + in = new InputStreamReader( file, CONFIG_FILE_CHARSET ); + json = new StringBuffer(); + + int count = in.read( buffer ); + + while (count != -1) + { + json.append( buffer ); + + count = in.read( buffer ); + } + + ObjectMapper mapper = new ObjectMapper(); + + dbConfig = mapper.readValue( json.toString(), OracleConfig.class ); + } + catch ( IOException error ) + { + throw error; + } + finally + { + try + { + file.close(); + } + catch ( Exception error ) + { + error.printStackTrace(); + } + + } + + return dbConfig; + } +} diff --git a/code/java/DisasterWarning/src/main/java/com/cpic/xim/notify/disaster/QWeatherDisasterWarning.java b/code/java/DisasterWarning/src/main/java/com/cpic/xim/notify/disaster/QWeatherDisasterWarning.java index e527a88..ec911b6 100644 --- a/code/java/DisasterWarning/src/main/java/com/cpic/xim/notify/disaster/QWeatherDisasterWarning.java +++ b/code/java/DisasterWarning/src/main/java/com/cpic/xim/notify/disaster/QWeatherDisasterWarning.java @@ -1,23 +1,24 @@ +/* + * @Author: Kane + * @Date: 2022-04-24 10:21:46 + * @LastEditors: Kane + * @LastEditTime: 2022-04-24 11:28:58 + * @FilePath: \DisasterWarning\src\main\java\com\cpic\xim\notify\disaster\QWeatherDisasterWarning.java + * @Description: + * + * Copyright (c) ${2022} by Kane, All Rights Reserved. + */ package com.cpic.xim.notify.disaster; +import java.util.Date; import java.util.Vector; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; public class QWeatherDisasterWarning { - public QWeatherDisasterWarning( String code, - String updateTime, - String fxLink, - Vector warning, - QWeatherDisasterWarningRefer refer ) - { - this.code = code; - this.updateTime = updateTime; - this.fxLink = fxLink; - this.warning = warning; - this.refer = refer; - } - - public QWeatherDisasterWarning() {} + public QWeatherDisasterWarning() + {} public String getCode() { @@ -29,12 +30,12 @@ public class QWeatherDisasterWarning this.code = code; } - public String getUpdateTime() + public Date getUpdateTime() { return updateTime; } - public void setUpdateTime( String updateTime ) + public void setUpdateTime( Date updateTime ) { this.updateTime = updateTime; } @@ -69,9 +70,19 @@ public class QWeatherDisasterWarning this.refer = refer; } - private String code; - private String updateTime; - private String fxLink; + @JsonProperty( "code") + private String code; + + @JsonProperty( "updateTime") + @JsonFormat( pattern = "yyyy-MM-dd\'T\'HH:mmXXX") + private Date updateTime; + + @JsonProperty( "fxLink") + private String fxLink; + + @JsonProperty( "warning") private Vector warning; - private QWeatherDisasterWarningRefer refer; + + @JsonProperty( "refer") + private QWeatherDisasterWarningRefer refer; } diff --git a/code/java/DisasterWarning/src/main/java/com/cpic/xim/notify/disaster/QWeatherDisasterWarningItem.java b/code/java/DisasterWarning/src/main/java/com/cpic/xim/notify/disaster/QWeatherDisasterWarningItem.java index ad4ba37..53397ea 100644 --- a/code/java/DisasterWarning/src/main/java/com/cpic/xim/notify/disaster/QWeatherDisasterWarningItem.java +++ b/code/java/DisasterWarning/src/main/java/com/cpic/xim/notify/disaster/QWeatherDisasterWarningItem.java @@ -1,79 +1,61 @@ package com.cpic.xim.notify.disaster; +import java.util.Date; import java.util.Objects; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; //import com.fasterxml.jackson.annotation.JsonIgnore; public class QWeatherDisasterWarningItem { - public QWeatherDisasterWarningItem() {} - public QWeatherDisasterWarningItem( String id, - String sender, - String pubTime, - String title, - String status, - String level, - String type, - String typeName, - String text, - String related, - String urgency, String certainty ) + public QWeatherDisasterWarningItem() + {} + + public QWeatherDisasterWarningItem( String id, String sender, Date pubTime, String title, + String status, String level, String type, String typeName, String text, String related, + String urgency, String certainty) { - this.id = id; - this.sender = sender; - this.pubTime = pubTime; - this.title = title; - this.status = status; - this.level = level; - this.type = type; + this.id = id; + this.sender = sender; + this.pubTime = pubTime; + this.title = title; + this.status = status; + this.level = level; + this.type = type; this.typeName = typeName; - this.text = text; - this.related = related; - this.urgency = urgency; + this.text = text; + this.related = related; + this.urgency = urgency; this.certainty = certainty; } @Override public boolean equals( Object o ) { - if ( this == o ) + if ( this == o) { return true; } - if ( o == null || getClass() != o.getClass() ) + if ( o == null || getClass() != o.getClass()) { return false; } QWeatherDisasterWarningItem that = (QWeatherDisasterWarningItem) o; - return id.equals( that.id ) && Objects.equals( sender, that.sender ) && Objects.equals( pubTime, - that.pubTime ) && Objects.equals( - title, - that.title ) && Objects.equals( status, that.status ) && Objects.equals( level, - that.level ) && Objects.equals( - type, - that.type ) && Objects.equals( typeName, that.typeName ) && Objects.equals( text, - that.text ) && Objects.equals( - related, - that.related ) && Objects.equals( urgency, that.urgency ) && Objects.equals( certainty, - that.certainty ); + return id.equals( that.id ) && Objects.equals( sender, that.sender ) + && Objects.equals( pubTime, that.pubTime ) && Objects.equals( title, that.title ) + && Objects.equals( status, that.status ) && Objects.equals( level, that.level ) + && Objects.equals( type, that.type ) && Objects.equals( typeName, that.typeName ) + && Objects.equals( text, that.text ) && Objects.equals( related, that.related ) + && Objects.equals( urgency, that.urgency ) + && Objects.equals( certainty, that.certainty ); } @Override public int hashCode() { - return Objects.hash( id, - sender, - pubTime, - title, - status, - level, - type, - typeName, - text, - related, - urgency, - certainty ); + return Objects.hash( id, sender, pubTime, title, status, level, type, typeName, text, + related, urgency, certainty ); } public String getId() @@ -96,12 +78,12 @@ public class QWeatherDisasterWarningItem this.sender = sender; } - public String getPubTime() + public Date getPubTime() { return pubTime; } - public void setPubTime( String pubTime ) + public void setPubTime( Date pubTime ) { this.pubTime = pubTime; } @@ -198,8 +180,11 @@ public class QWeatherDisasterWarningItem private String id; private String sender; - @JsonFormat(pattern="yyyy-MM-dd'T'HH:mm") - private String pubTime; + + @JsonProperty( "pubTime") + @JsonFormat( shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd\'T\'HH:mmXXX") + private Date pubTime; + private String title; private String status; private String level; diff --git a/code/java/DisasterWarning/src/main/java/com/cpic/xim/wechat/officalAccount/sendMessage.java b/code/java/DisasterWarning/src/main/java/com/cpic/xim/wechat/officalAccount/sendMessage.java index 221f4ca..198e768 100644 --- a/code/java/DisasterWarning/src/main/java/com/cpic/xim/wechat/officalAccount/sendMessage.java +++ b/code/java/DisasterWarning/src/main/java/com/cpic/xim/wechat/officalAccount/sendMessage.java @@ -2,7 +2,7 @@ * @Author: Kane * @Date: 2022-04-22 10:53:49 * @LastEditors: Kane - * @LastEditTime: 2022-04-23 23:46:54 + * @LastEditTime: 2022-05-06 11:14:32 * @FilePath: \DisasterWarning\src\main\java\com\cpic\xim\wechat\officalAccount\sendMessage.java * @Description: 用来推送公众号消息的程序库。 * @@ -10,13 +10,20 @@ */ package com.cpic.xim.wechat.officalAccount; +import com.cpic.xim.config.db.OracleConfigManager; +import com.cpic.xim.config.db.OracleConfig; import com.fasterxml.jackson.annotation.JsonProperty; - +import java.io.IOException; import java.net.MalformedURLException; import java.util.HashMap; import java.util.Vector; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import com.cpic.xim.notify.disaster.*; import com.cpic.xim.httpUtil.HttpUtils; @@ -31,7 +38,7 @@ public class sendMessage /** * 推送天气灾害预警!接口文档参考 彭奕洁 编写《消息发送接口调用文档》 - * + * 使用 post 方式,请求体内容以最基础的 post 格式。 * @param officalAccountURL 产险厦门分公司公众号接口网址 * @param warning 灾害预警对象 */ @@ -49,7 +56,7 @@ public class sendMessage headers.put( "Content-Type", "application/x-www-form-urlencoded;charset=UTF-8" ); // 遍历消息,将消息推送出去。 - for ( QWeatherDisasterWarningItem item : warningItems) + for ( QWeatherDisasterWarningItem item : warningItems ) { // 拼接消息内容 String title = item.getTitle(); @@ -57,7 +64,6 @@ public class sendMessage String color = warningLevel.keySet().contains( item.getLevel() ) ? warningLevel.get( item.getLevel() ) : "#000000"; - requestBody = new StringBuilder(); requestBody.append( "tplid=57&groupid=1&first=尊敬的#realname#,您好!&" ); @@ -69,13 +75,188 @@ public class sendMessage { HttpUtils.postHttpRequest( officalAccountURL, headers, requestBody.toString() ); } - catch (MalformedURLException error) + catch ( MalformedURLException error ) { error.printStackTrace(); } } } + /** + * 检查预警是否已经推送过,通过 QWeatherDisasterWarningItem 对象的 id 属性。 + * 查询 oracle xmcx1 数据库 wechat 表空间下 weather_disaster_notify 表, + * 统计 warningID 的数量,如果不为0,说明该预警已经保存过,视为已经推送过。 + * @param warningID 预警的id + * @return 如果推送过,返回false,否则返回 true。 + */ + public static boolean checkWarningHasSended( String warningID ) + throws ClassNotFoundException, SQLException, IOException + { + boolean result = false; + + OracleConfig dbConfig = OracleConfigManager.getOracleConfig();; + + Connection conn = null; + PreparedStatement stmt = null; + ResultSet rs = null; + + String jdbcURL = dbConfig.getJdbcURL(); + String userName = dbConfig.getUserName(); + String password = dbConfig.getPassword(); + String sql = "select count(*) from weather_disaster_notify where notify_id = ?"; + + // Logger logger = Logger.getLogger( "com.cpicxim.wechat.officalAccount.sendMessage" ); + + try + { + Class.forName( "oracle.jdbc.driver.OracleDriver" ); + + conn = DriverManager.getConnection( jdbcURL, userName, password ); + stmt = conn.prepareStatement( sql ); + stmt.setString( 1, warningID ); + + rs = stmt.executeQuery(); + + if ( rs.next() && rs.getInt( 1 ) == 0) + { + result = true; + } + } + finally + { + try + { + if ( rs != null) + { + rs.close(); + } + } + catch ( Exception error ) + { + error.printStackTrace(); + } + + try + { + if ( stmt != null) + { + stmt.close(); + } + } + catch ( Exception error ) + { + error.printStackTrace(); + } + + try + { + if ( conn != null) + { + conn.close(); + } + } + catch ( Exception error ) + { + error.printStackTrace(); + } + } + + return result; + } + + /** + * 保存天气预警警报数据。 + * 保存至 oracle xmcx1 数据库 wechat 表空间下 weather_disaster_notify 表。 + * 保存的数据用来判断预警是否已经推送过,以防止反复推送数据。 + * @param city 城市名称 + * @param warning 预警数据,为 QWeatherDisasterWarningItem 对象。 + * @throws SQLException 执行sql时可能抛出的异常。出现sql异常,就回滚事务。 + * @throws IOException 读取数据库配置文件时可能抛出的异常。 + * @throws ClassNotFoundException 加载oracle jdbc驱动时可能抛出的异常。 + */ + public static void saveWeatherDisasterWarning( String city, QWeatherDisasterWarning warnings ) + throws SQLException, IOException, ClassNotFoundException + { + Connection conn = null; + PreparedStatement stmt = null; + + String sql = "insert into weather_disaster_notify(notify_id, sender, city," + + "warning_level, warning_type_code, warning_type_name, title," + + "text, pub_time) values( ?,?,?,?,?,?,?,?,?)"; + + OracleConfig dbConfig = OracleConfigManager.getOracleConfig(); + + String jdbcURL = dbConfig.getJdbcURL(); + String userName = dbConfig.getUserName(); + String password = dbConfig.getPassword(); + + try + { + Class.forName( "oracle.jdbc.driver.OracleDriver" ); + + conn = DriverManager.getConnection( jdbcURL, userName, password ); + stmt = conn.prepareStatement( sql ); + + for ( QWeatherDisasterWarningItem warning : warnings.getWarning() ) + { + java.sql.Timestamp pubTime = + new java.sql.Timestamp( warning.getPubTime().getTime() ); + + stmt.setString( 1, warning.getId() ); + stmt.setString( 2, warning.getSender() ); + stmt.setString( 3, city ); + stmt.setString( 4, warning.getLevel() ); + stmt.setString( 5, warning.getType() ); + stmt.setString( 6, warning.getTypeName() ); + stmt.setString( 7, warning.getTitle() ); + stmt.setString( 8, warning.getText() ); + stmt.setTimestamp( 9, pubTime ); + + stmt.execute(); + } + + // 没有问题就提交 + conn.commit(); + } + catch ( SQLException error ) + { + // 出现sql错误,就回滚! + if ( conn != null) + { + conn.rollback(); + } + + throw error; + } + finally + { + try + { + if ( stmt != null) + { + stmt.close(); + } + } + catch ( Exception error ) + { + error.printStackTrace(); + } + + try + { + if ( conn != null) + { + conn.close(); + } + } + catch ( Exception error ) + { + error.printStackTrace(); + } + } + } + + static { // 预警级别色彩 diff --git a/code/java/DisasterWarning/src/main/resources/assembly.xml b/code/java/DisasterWarning/src/main/resources/assembly.xml new file mode 100644 index 0000000..e69de29 diff --git a/code/java/DisasterWarning/src/main/resources/logging.properties b/code/java/DisasterWarning/src/main/resources/logging.properties new file mode 100644 index 0000000..707450e --- /dev/null +++ b/code/java/DisasterWarning/src/main/resources/logging.properties @@ -0,0 +1,10 @@ + +handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler + +.level = INFO + +java.util.logging.FileHandler.pattern = ./logs/log_%u.log +java.util.logging.FileHandler.limit = 50000 +java.util.logging.FileHandler.count = 10 +java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter +java.util.logging.FileHandler.append = true; diff --git a/code/java/DisasterWarning/src/test/java/com/cpic/xim/wechat/officalAccount/sendMessageTest.java b/code/java/DisasterWarning/src/test/java/com/cpic/xim/wechat/officalAccount/sendMessageTest.java index 2cda05e..90078f6 100644 --- a/code/java/DisasterWarning/src/test/java/com/cpic/xim/wechat/officalAccount/sendMessageTest.java +++ b/code/java/DisasterWarning/src/test/java/com/cpic/xim/wechat/officalAccount/sendMessageTest.java @@ -2,7 +2,7 @@ * @Author: Kane * @Date: 2022-04-22 10:53:49 * @LastEditors: Kane - * @LastEditTime: 2022-04-23 23:44:54 + * @LastEditTime: 2022-05-10 11:33:41 * @FilePath: \DisasterWarning\src\test\java\com\cpic\xim\wechat\officalAccount\sendMessageTest.java * @Description: * @@ -12,10 +12,10 @@ package com.cpic.xim.wechat.officalAccount; import com.cpic.xim.notify.disaster.QWeatherDisasterWarning; -import org.junit.Test; import static org.junit.Assert.*; import com.cpic.xim.httpUtil.*; import java.io.IOException; + import java.util.*; import com.fasterxml.jackson.databind.ObjectMapper; @@ -32,7 +32,7 @@ public class sendMessageTest { // sendMessage.postNotifyMessageJSON( url, "警报", "警报标题", "警报内容!" ); } - catch (Exception error) + catch ( Exception error ) { fail( "测试失败!" ); } @@ -54,13 +54,13 @@ public class sendMessageTest { HttpUtils.postHttpRequest( url, headers, param ); } - catch (Exception error) + catch ( Exception error ) { } } - @Test + // @Test public void testSendWeatherDisasterWarning() throws IOException { String warningJSON = @@ -72,11 +72,29 @@ public class sendMessageTest QWeatherDisasterWarning warning = mapper.readValue( warningJSON, QWeatherDisasterWarning.class ); - sendMessage.sendWeatherDisasterWarning( url, warning ); + String city = "东山县"; + + + sendMessage.saveWeatherDisasterWarning( city, warning ); } - catch (Exception error) + catch ( Exception error ) { fail( error.getMessage() ); } } + + // @Test + public void testCheckWarningHasSended() + { + String warningID = "10123060820220422061200476313081"; + + try + { + sendMessage.checkWarningHasSended( warningID ); + } + catch ( Exception error ) + { + error.printStackTrace(); + } + } } diff --git a/应用/1.0/config.json b/应用/1.0/config.json new file mode 100644 index 0000000..3795a43 --- /dev/null +++ b/应用/1.0/config.json @@ -0,0 +1,19 @@ +{ + "title": "天气灾害预警配置文件", + "key": "fe9fa8eeeb6f4301a92541eed565dd15", + "query_url": "https://devapi.qweather.com/v7/warning/now?", + "wechat_officalaccount_url": "https://cxxmwx.cpic.com.cn/app/index.php?i=2&c=entry&do=send_group_tpl_api&m=ok_tplmessage", + "query_interval": 10, + "cities": [ + { + "city_name": "厦门", + "city_code": "101230201" + } + ], + "notify_stuffs": [ + { + "stuff_name": "王炜", + "mobile_phone": "15959215339" + } + ] +} diff --git a/应用/1.0/db.json b/应用/1.0/db.json new file mode 100644 index 0000000..a8f5ddd --- /dev/null +++ b/应用/1.0/db.json @@ -0,0 +1,14 @@ +{ + "tns_name": "xmcx1", + "ip_addr": "10.39.0.86", + "jdbc_url": "jdbc:oracle:thin:@10.39.0.86:1521:xmcx1", + "table_space": "wechat", + "user_name": "wechat", + "password": "@rn7Q+t5zeyKIZ~s", + "tables": [ + { + "table_name": "weather_disaster_notify", + "table_description": "天气预警消息表" + } + ] +} diff --git a/应用/1.0/logging.properties b/应用/1.0/logging.properties new file mode 100644 index 0000000..f82b56f --- /dev/null +++ b/应用/1.0/logging.properties @@ -0,0 +1,10 @@ + +handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler + +.level = INFO + +java.util.logging.FileHandler.pattern = ./logs/log_%u.log +java.util.logging.FileHandler.limit = 50000 +java.util.logging.FileHandler.count = 1 +java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter +java.util.logging.FileHandler.append = true;