diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..666c5aa
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/HELP.md b/HELP.md
new file mode 100644
index 0000000..8cf6373
--- /dev/null
+++ b/HELP.md
@@ -0,0 +1,10 @@
+# Getting Started
+
+### Reference Documentation
+
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.5.3/maven-plugin/reference/html/)
+* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.5.3/maven-plugin/reference/html/#build-image)
+
diff --git a/mqtt_java_maven.zip b/mqtt_java_maven.zip
new file mode 100644
index 0000000..b4426c3
Binary files /dev/null and b/mqtt_java_maven.zip differ
diff --git a/mqtt_java_maven/.gitignore b/mqtt_java_maven/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/mqtt_java_maven/.idea/compiler.xml b/mqtt_java_maven/.idea/compiler.xml
new file mode 100644
index 0000000..a31f1d1
--- /dev/null
+++ b/mqtt_java_maven/.idea/compiler.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/encodings.xml b/mqtt_java_maven/.idea/encodings.xml
new file mode 100644
index 0000000..63e9001
--- /dev/null
+++ b/mqtt_java_maven/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/inspectionProfiles/Project_Default.xml b/mqtt_java_maven/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..6560a98
--- /dev/null
+++ b/mqtt_java_maven/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/jarRepositories.xml b/mqtt_java_maven/.idea/jarRepositories.xml
new file mode 100644
index 0000000..2d9362f
--- /dev/null
+++ b/mqtt_java_maven/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_4.xml b/mqtt_java_maven/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_4.xml
new file mode 100644
index 0000000..4c5df29
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_4.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_4.xml b/mqtt_java_maven/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_4.xml
new file mode 100644
index 0000000..1e5c99e
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_4.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__com_github_kittinunf_fuel_fuel_2_3_1.xml b/mqtt_java_maven/.idea/libraries/Maven__com_github_kittinunf_fuel_fuel_2_3_1.xml
new file mode 100644
index 0000000..981b4bd
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__com_github_kittinunf_fuel_fuel_2_3_1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__com_github_kittinunf_fuel_fuel_gson_2_3_1.xml b/mqtt_java_maven/.idea/libraries/Maven__com_github_kittinunf_fuel_fuel_gson_2_3_1.xml
new file mode 100644
index 0000000..88881c4
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__com_github_kittinunf_fuel_fuel_gson_2_3_1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__com_github_kittinunf_result_result_3_1_0.xml b/mqtt_java_maven/.idea/libraries/Maven__com_github_kittinunf_result_result_3_1_0.xml
new file mode 100644
index 0000000..720d840
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__com_github_kittinunf_result_result_3_1_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__com_google_code_gson_gson_2_8_7.xml b/mqtt_java_maven/.idea/libraries/Maven__com_google_code_gson_gson_2_8_7.xml
new file mode 100644
index 0000000..12484a2
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__com_google_code_gson_gson_2_8_7.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_5_0.xml b/mqtt_java_maven/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_5_0.xml
new file mode 100644
index 0000000..b76ecb0
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_5_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml b/mqtt_java_maven/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml
new file mode 100644
index 0000000..b8581a6
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__commons_codec_commons_codec_1_15.xml b/mqtt_java_maven/.idea/libraries/Maven__commons_codec_commons_codec_1_15.xml
new file mode 100644
index 0000000..c88c2b7
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__commons_codec_commons_codec_1_15.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__commons_io_commons_io_2_7.xml b/mqtt_java_maven/.idea/libraries/Maven__commons_io_commons_io_2_7.xml
new file mode 100644
index 0000000..ded72c9
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__commons_io_commons_io_2_7.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml b/mqtt_java_maven/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml
new file mode 100644
index 0000000..be90656
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml b/mqtt_java_maven/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml
new file mode 100644
index 0000000..cba9dd2
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml b/mqtt_java_maven/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml
new file mode 100644
index 0000000..04213f7
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_10_22.xml b/mqtt_java_maven/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_10_22.xml
new file mode 100644
index 0000000..db4968e
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_10_22.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_10_22.xml b/mqtt_java_maven/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_10_22.xml
new file mode 100644
index 0000000..910ad03
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_10_22.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__net_minidev_accessors_smart_2_4_7.xml b/mqtt_java_maven/.idea/libraries/Maven__net_minidev_accessors_smart_2_4_7.xml
new file mode 100644
index 0000000..8157bb4
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__net_minidev_accessors_smart_2_4_7.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__net_minidev_json_smart_2_4_7.xml b/mqtt_java_maven/.idea/libraries/Maven__net_minidev_json_smart_2_4_7.xml
new file mode 100644
index 0000000..a17f648
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__net_minidev_json_smart_2_4_7.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_13.xml b/mqtt_java_maven/.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_13.xml
new file mode 100644
index 0000000..63bee0e
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_13.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_13.xml b/mqtt_java_maven/.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_13.xml
new file mode 100644
index 0000000..b475675
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_13.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_14_1.xml b/mqtt_java_maven/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_14_1.xml
new file mode 100644
index 0000000..700b41b
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_14_1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_14_1.xml b/mqtt_java_maven/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_14_1.xml
new file mode 100644
index 0000000..ae5c0b5
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_14_1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml b/mqtt_java_maven/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml
new file mode 100644
index 0000000..f854ab0
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_assertj_assertj_core_3_19_0.xml b/mqtt_java_maven/.idea/libraries/Maven__org_assertj_assertj_core_3_19_0.xml
new file mode 100644
index 0000000..94e438d
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_assertj_assertj_core_3_19_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_bouncycastle_bcpkix_jdk15on_1_47.xml b/mqtt_java_maven/.idea/libraries/Maven__org_bouncycastle_bcpkix_jdk15on_1_47.xml
new file mode 100644
index 0000000..cdf8bb1
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_bouncycastle_bcpkix_jdk15on_1_47.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_bouncycastle_bcprov_jdk15on_1_47.xml b/mqtt_java_maven/.idea/libraries/Maven__org_bouncycastle_bcprov_jdk15on_1_47.xml
new file mode 100644
index 0000000..13f7b2e
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_bouncycastle_bcprov_jdk15on_1_47.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_eclipse_paho_org_eclipse_paho_client_mqttv3_1_2_0.xml b/mqtt_java_maven/.idea/libraries/Maven__org_eclipse_paho_org_eclipse_paho_client_mqttv3_1_2_0.xml
new file mode 100644
index 0000000..4c81ce4
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_eclipse_paho_org_eclipse_paho_client_mqttv3_1_2_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml b/mqtt_java_maven/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml
new file mode 100644
index 0000000..6b5496f
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_jetbrains_annotations_13_0.xml b/mqtt_java_maven/.idea/libraries/Maven__org_jetbrains_annotations_13_0.xml
new file mode 100644
index 0000000..e2c8297
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_jetbrains_annotations_13_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_1_5_21.xml b/mqtt_java_maven/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_1_5_21.xml
new file mode 100644
index 0000000..7e1a185
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_1_5_21.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_common_1_5_21.xml b/mqtt_java_maven/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_common_1_5_21.xml
new file mode 100644
index 0000000..f9bf542
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_common_1_5_21.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_7_2.xml b/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_7_2.xml
new file mode 100644
index 0000000..a9a0266
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_7_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_7_2.xml b/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_7_2.xml
new file mode 100644
index 0000000..2b9b506
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_7_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_7_2.xml b/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_7_2.xml
new file mode 100644
index 0000000..636171a
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_7_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_7_2.xml b/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_7_2.xml
new file mode 100644
index 0000000..380c9dd
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_7_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_7_2.xml b/mqtt_java_maven/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_7_2.xml
new file mode 100644
index 0000000..66260e6
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_7_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_7_2.xml b/mqtt_java_maven/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_7_2.xml
new file mode 100644
index 0000000..af6fc85
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_7_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_mockito_mockito_core_3_9_0.xml b/mqtt_java_maven/.idea/libraries/Maven__org_mockito_mockito_core_3_9_0.xml
new file mode 100644
index 0000000..a46e355
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_mockito_mockito_core_3_9_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_3_9_0.xml b/mqtt_java_maven/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_3_9_0.xml
new file mode 100644
index 0000000..0fc879a
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_3_9_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_objenesis_objenesis_3_2.xml b/mqtt_java_maven/.idea/libraries/Maven__org_objenesis_objenesis_3_2.xml
new file mode 100644
index 0000000..6613def
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_objenesis_objenesis_3_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml b/mqtt_java_maven/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml
new file mode 100644
index 0000000..fbc1b16
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_ow2_asm_asm_9_1.xml b/mqtt_java_maven/.idea/libraries/Maven__org_ow2_asm_asm_9_1.xml
new file mode 100644
index 0000000..67127c2
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_ow2_asm_asm_9_1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_projectlombok_lombok_1_18_26.xml b/mqtt_java_maven/.idea/libraries/Maven__org_projectlombok_lombok_1_18_26.xml
new file mode 100644
index 0000000..76fa15b
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_projectlombok_lombok_1_18_26.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_0.xml b/mqtt_java_maven/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_0.xml
new file mode 100644
index 0000000..c4c54d6
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_32.xml b/mqtt_java_maven/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_32.xml
new file mode 100644
index 0000000..a758eac
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_32.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_32.xml b/mqtt_java_maven/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_32.xml
new file mode 100644
index 0000000..e5a84fb
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_32.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_5_3.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_5_3.xml
new file mode 100644
index 0000000..9692f2c
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_5_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_5_3.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_5_3.xml
new file mode 100644
index 0000000..2de3bc4
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_5_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_5_3.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_5_3.xml
new file mode 100644
index 0000000..b31fb3d
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_5_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_5_3.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_5_3.xml
new file mode 100644
index 0000000..c26578f
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_5_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_2_5_3.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_2_5_3.xml
new file mode 100644
index 0000000..039b0fc
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_2_5_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_2_5_3.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_2_5_3.xml
new file mode 100644
index 0000000..18a4a48
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_2_5_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_5_3.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_5_3.xml
new file mode 100644
index 0000000..a81ff33
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_5_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_aop_5_3_9.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_aop_5_3_9.xml
new file mode 100644
index 0000000..06b191b
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_aop_5_3_9.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_beans_5_3_9.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_beans_5_3_9.xml
new file mode 100644
index 0000000..c5bd2d3
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_beans_5_3_9.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_context_5_3_9.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_context_5_3_9.xml
new file mode 100644
index 0000000..4c2900a
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_context_5_3_9.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_core_5_3_9.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_core_5_3_9.xml
new file mode 100644
index 0000000..2529cbf
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_core_5_3_9.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_expression_5_3_9.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_expression_5_3_9.xml
new file mode 100644
index 0000000..dea9689
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_expression_5_3_9.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_jcl_5_3_9.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_jcl_5_3_9.xml
new file mode 100644
index 0000000..feea851
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_jcl_5_3_9.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_test_5_3_9.xml b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_test_5_3_9.xml
new file mode 100644
index 0000000..b90da2f
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_springframework_spring_test_5_3_9.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_8_2.xml b/mqtt_java_maven/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_8_2.xml
new file mode 100644
index 0000000..e6506e0
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_8_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/libraries/Maven__org_yaml_snakeyaml_1_28.xml b/mqtt_java_maven/.idea/libraries/Maven__org_yaml_snakeyaml_1_28.xml
new file mode 100644
index 0000000..1f853f7
--- /dev/null
+++ b/mqtt_java_maven/.idea/libraries/Maven__org_yaml_snakeyaml_1_28.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/misc.xml b/mqtt_java_maven/.idea/misc.xml
new file mode 100644
index 0000000..fa89799
--- /dev/null
+++ b/mqtt_java_maven/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/modules.xml b/mqtt_java_maven/.idea/modules.xml
new file mode 100644
index 0000000..8251c27
--- /dev/null
+++ b/mqtt_java_maven/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/mqtt_java_maven.iml b/mqtt_java_maven/.idea/mqtt_java_maven.iml
new file mode 100644
index 0000000..0870fa1
--- /dev/null
+++ b/mqtt_java_maven/.idea/mqtt_java_maven.iml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/vcs.xml b/mqtt_java_maven/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/mqtt_java_maven/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.idea/workspace.xml b/mqtt_java_maven/.idea/workspace.xml
new file mode 100644
index 0000000..772f840
--- /dev/null
+++ b/mqtt_java_maven/.idea/workspace.xml
@@ -0,0 +1,305 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1627608635806
+
+
+ 1627608635806
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/.mvn/wrapper/MavenWrapperDownloader.java b/mqtt_java_maven/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 0000000..a45eb6b
--- /dev/null
+++ b/mqtt_java_maven/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+ private static final String WRAPPER_VERSION = "0.5.6";
+ /**
+ * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+ */
+ private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+ /**
+ * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+ * use instead of the default one.
+ */
+ private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+ ".mvn/wrapper/maven-wrapper.properties";
+
+ /**
+ * Path where the maven-wrapper.jar will be saved to.
+ */
+ private static final String MAVEN_WRAPPER_JAR_PATH =
+ ".mvn/wrapper/maven-wrapper.jar";
+
+ /**
+ * Name of the property which should be used to override the default download url for the wrapper.
+ */
+ private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+ public static void main(String args[]) {
+ System.out.println("- Downloader started");
+ File baseDirectory = new File(args[0]);
+ System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+ // If the maven-wrapper.properties exists, read it and check if it contains a custom
+ // wrapperUrl parameter.
+ File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+ String url = DEFAULT_DOWNLOAD_URL;
+ if (mavenWrapperPropertyFile.exists()) {
+ FileInputStream mavenWrapperPropertyFileInputStream = null;
+ try {
+ mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+ Properties mavenWrapperProperties = new Properties();
+ mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+ url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+ } catch (IOException e) {
+ System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+ } finally {
+ try {
+ if (mavenWrapperPropertyFileInputStream != null) {
+ mavenWrapperPropertyFileInputStream.close();
+ }
+ } catch (IOException e) {
+ // Ignore ...
+ }
+ }
+ }
+ System.out.println("- Downloading from: " + url);
+
+ File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+ if (!outputFile.getParentFile().exists()) {
+ if (!outputFile.getParentFile().mkdirs()) {
+ System.out.println(
+ "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+ }
+ }
+ System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+ try {
+ downloadFileFromURL(url, outputFile);
+ System.out.println("Done");
+ System.exit(0);
+ } catch (Throwable e) {
+ System.out.println("- Error downloading");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+ if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+ String username = System.getenv("MVNW_USERNAME");
+ char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+ Authenticator.setDefault(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(username, password);
+ }
+ });
+ }
+ URL website = new URL(urlString);
+ ReadableByteChannel rbc;
+ rbc = Channels.newChannel(website.openStream());
+ FileOutputStream fos = new FileOutputStream(destination);
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ fos.close();
+ rbc.close();
+ }
+
+}
diff --git a/mqtt_java_maven/.mvn/wrapper/maven-wrapper.jar b/mqtt_java_maven/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000..2cc7d4a
Binary files /dev/null and b/mqtt_java_maven/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/mqtt_java_maven/.mvn/wrapper/maven-wrapper.properties b/mqtt_java_maven/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..ffdc10e
--- /dev/null
+++ b/mqtt_java_maven/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
diff --git a/README.md b/mqtt_java_maven/README.md
similarity index 100%
rename from README.md
rename to mqtt_java_maven/README.md
diff --git a/mqtt_java_maven/client.key b/mqtt_java_maven/client.key
new file mode 100644
index 0000000..fb54e44
--- /dev/null
+++ b/mqtt_java_maven/client.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAvur5N8+LcHizZWj7zXZuhUesy48hxhPo781iVM9XdL9ywa8p
+kEJ9yN6qBjk/RAnUu1SnRgPB5L2zmN3jQhZX/sW2BIOx7I5kDMnTPKsvbPtJOWOs
+nYVjUWnNHBAmPILe9wd2SdkmGvOGn4cqn308xfuzSGZbbbeR6nmZHthZgHBJf9DI
+xVYJj2wbE03WQ7PjA+3/CUI3O3ACNSZl5qtN51g3ZITuscghAsg6/OIZa4UYuK/G
+SOfSP0f/427rOVIobXptuMYnSSIQyXxr/AO7gGOCZfTcR81pzsMcRU/t1KcI1aAu
+JhvaSdWiKUjO89xv+CDvf9xKp/KlBWJjwvzOiQIDAQABAoIBAQCr52NTT3tcYDIY
+A7mGvTayp2D9QPnGIrNBCQubFb7HjoLDxvaDwHsF3Qf25qECoF999bFQJ530WqNV
+56TzIq9E5b0Iv5P7ThLkOO4M2I6xcGn0VL1ecHaHHd7jf98N6UDd6UgnInFfHxt+
+lPRZ+yg3lHVPoWp9lia6m5a14VRlgiUH8yeBXrh6+C1GJ8BfL7qVdyOK98fXJPQ2
+ldalM4EeYqcWwOeHLvtnJNHjGgnBEbPkBBha5eEtk0Gmbiiikb41plFLEgz0HNbU
+Z8pJTk2WXO6qnFRYU60eu+3naTnZBn70RT7bDJyITHM8RoIeEswyWF6mXAZNbKwW
+CK21WaohAoGBAPasBmJvQUdxuq10ebmVrEkR29b745ktteZhk7Zsb2B6yR3sg68t
+17/tq/FJoIYsYgEZu9Kafzyucd4nlFsR+JNOaKGJjvZpGx6XwDgoeEBmEcN6ug+k
+Zshavtezh1c8EZvjvAmkEwIyq1x+8C00ujSqBrK4NfBBcEnKv1f3yroNAoGBAMYj
+NK41xwslu7wdgD4kFx/lli6sA3nZ7MPOL0YE0rcBbDADTCACufUsHp4NrtNuN9Vn
+MqWJVTWUfv0ImSNAebVL49fAu2CRsB3FWrgRmLnbZSaPxDRzH/IXO/6Er5GHIj7D
+56bWGEFgNVG/peubatOkXJu5PnDHjTRATKEZRzNtAoGAa6lRcA0W9NPSono/1pxZ
+AdtllEOEZwroZZEZI3nYcsekmAbuwrrDe+WEMl/sTCN68vgEXjtIZXfOAyRLQCRr
+1f9W84pSd4IQcB3Tq68eLR1fi245XzJmGfRhb0vQOmbhWKThIWQXV9I9sLVGprRo
+wSukmMSF5kLpe4ueUAq61NECgYB6CDzt/xk0eG0EE3dkzn2fm5u/6xnI9ruobVkY
+Wugc5rdnauB75rH5ms7QscS3W+7vdLvw0IC2m1sLJTyMRa2wR6lwvLerZo9+Bos1
+S0ExVzsZYPqLA0ztofnFbJtlmkExPx9x1fLicQrl6o+aaQKGj3iqQJGAjKcfQ2ru
+3c7IkQKBgDZfEzNBLbH+lr73FKoSJpH5bu/gEqt8m72vWlZiY1ozOUmK3qnQI0MI
+DQ/M77DTJ+nw4uRePzoivuhR8ElWJbW4QEwUIkDFH2WHYkl6lWGFOBYAVxqCiXWB
+iDa3fKx25ggV3GkjKl7Ct3ToNzP94qxbxLsJTCjBLNUxuIOJZfQd
+-----END RSA PRIVATE KEY-----
diff --git a/mqtt_java_maven/client.pem b/mqtt_java_maven/client.pem
new file mode 100644
index 0000000..6f01d2a
--- /dev/null
+++ b/mqtt_java_maven/client.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDhTCCAm0CCQCGLmLZ4MiwvjANBgkqhkiG9w0BAQUFADCBtjELMAkGA1UEBhMC
+Q04xEjAQBgNVBAgMCUd1YW5nZG9uZzEPMA0GA1UEBwwGWmh1aGFpMSUwIwYDVQQK
+DBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQLDBREb21haW4g
+VmFsaWRhdGVkIFNTTDEdMBsGA1UEAwwUVHJ1c3RBc2lhIFRMUyBSU0EgQ0ExHTAb
+BgkqhkiG9w0BCQEWDmh3ZjQ1M0AxNjMuY29tMB4XDTIxMDgwNTEyMzY1NVoXDTMx
+MDgwMzEyMzY1NVowUjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzEP
+MA0GA1UEBwwGWmh1aGFpMQ0wCwYDVQQKDARFTVFYMQ8wDQYDVQQDDAZjbGllbnQw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+6vk3z4tweLNlaPvNdm6F
+R6zLjyHGE+jvzWJUz1d0v3LBrymQQn3I3qoGOT9ECdS7VKdGA8HkvbOY3eNCFlf+
+xbYEg7HsjmQMydM8qy9s+0k5Y6ydhWNRac0cECY8gt73B3ZJ2SYa84afhyqffTzF
++7NIZlttt5HqeZke2FmAcEl/0MjFVgmPbBsTTdZDs+MD7f8JQjc7cAI1JmXmq03n
+WDdkhO6xyCECyDr84hlrhRi4r8ZI59I/R//jbus5Uihtem24xidJIhDJfGv8A7uA
+Y4Jl9NxHzWnOwxxFT+3UpwjVoC4mG9pJ1aIpSM7z3G/4IO9/3Eqn8qUFYmPC/M6J
+AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBADI5aypoagVc74HMrQ19xvAYkhXqvDfg
+L+xwD7XdUz0smL41psyYVgd7tWOIUGarMuMIqvzIXw4nDdWeuskGSi4As9rO8Aha
+Ms2k3nayXd7Bl8Wc0fkPJPf3g+POWyFX1dTi+2lgB1vNqJlf0rnmuWaA+2kS9b2V
+yUf+fFOf4Oe7KsPsYF/PWpa2+9wE5zGktiEOgXq2CDgUVH9c7Z/6uGQs0YRP1ZmP
+ErRwxzYi18De8M7kt9hbjUngi7V4WenX++xEQdXio9ZauKZGnIDtvpvAQykf74h7
+JneS1tGeTWHZVs6kwM7pb3zl6VRlOI3Tno9RJQBIdGLbNPHe/hA/Tcw=
+-----END CERTIFICATE-----
diff --git a/mqtt_java_maven/emqx.crt b/mqtt_java_maven/emqx.crt
new file mode 100644
index 0000000..192dbef
Binary files /dev/null and b/mqtt_java_maven/emqx.crt differ
diff --git a/mqtt_java_maven/mqtt01.iml b/mqtt_java_maven/mqtt01.iml
new file mode 100644
index 0000000..cd8f2ba
--- /dev/null
+++ b/mqtt_java_maven/mqtt01.iml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mqtt_java_maven/mqtt_java_maven.zip b/mqtt_java_maven/mqtt_java_maven.zip
new file mode 100644
index 0000000..3550a0c
Binary files /dev/null and b/mqtt_java_maven/mqtt_java_maven.zip differ
diff --git a/mqtt_java_maven/mvnw b/mqtt_java_maven/mvnw
new file mode 100644
index 0000000..a16b543
--- /dev/null
+++ b/mqtt_java_maven/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/mqtt_java_maven/mvnw.cmd b/mqtt_java_maven/mvnw.cmd
new file mode 100644
index 0000000..c8d4337
--- /dev/null
+++ b/mqtt_java_maven/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/mqtt_java_maven/my_root_ca.pem b/mqtt_java_maven/my_root_ca.pem
new file mode 100644
index 0000000..52dfcbb
--- /dev/null
+++ b/mqtt_java_maven/my_root_ca.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID6jCCAtICCQDZhZupRjNreTANBgkqhkiG9w0BAQsFADCBtjELMAkGA1UEBhMC
+Q04xEjAQBgNVBAgMCUd1YW5nZG9uZzEPMA0GA1UEBwwGWmh1aGFpMSUwIwYDVQQK
+DBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQLDBREb21haW4g
+VmFsaWRhdGVkIFNTTDEdMBsGA1UEAwwUVHJ1c3RBc2lhIFRMUyBSU0EgQ0ExHTAb
+BgkqhkiG9w0BCQEWDmh3ZjQ1M0AxNjMuY29tMB4XDTIxMDgwNTEyMjk1MFoXDTMx
+MDgwMzEyMjk1MFowgbYxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ2Rvbmcx
+DzANBgNVBAcMBlpodWhhaTElMCMGA1UECgwcVHJ1c3RBc2lhIFRlY2hub2xvZ2ll
+cywgSW5jLjEdMBsGA1UECwwURG9tYWluIFZhbGlkYXRlZCBTU0wxHTAbBgNVBAMM
+FFRydXN0QXNpYSBUTFMgUlNBIENBMR0wGwYJKoZIhvcNAQkBFg5od2Y0NTNAMTYz
+LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqCs/p1Acvqdkhp
+zZGpr70bBU6w3VNURZQPFqtAmJwDz1sbhA4ek+aWUJz7aGqHv80EYsIaGmbZoaA1
+0/n5SfgQjaojD7syT7JRDaqBjCujvZ+4YRpeihcapRdAwnUf9iN87P27gh0GGaMS
+Q+aKMOdgChKBN8dBK+EZWx1CfFEyzOCuxajumN+jSNHLBJop55MB0jxQ2PldBV7Z
+mcKLtPpZTE1+PIsjowy8hhkaaLBtNn6+mPbG6b6iFqK6M7m1k412jsQIcO5D7l+b
+Wwa9Fn0sODgnYkxLf5jZkXPhHFoRmCCvHMnZsdT1LIfXNfZOxjS4TfQEIjLtEZi5
+0c7x38sCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAmBLFoFMLUYsJ5MXlTRO4BjER
+jI9Yw1x8vPewbICBHqiI974HBWlYFFHoFTmbvJx6f1bP4dF93hrme/0Vj5/lXAsu
+UB+jRnJvHuk7f8kkRV3GEA5qC2PqZpLYRk/CBEYxEKkDhtxNXHIkcujjwbs8RBo6
+7WCxqnzFWDL+FiYP82TFWJcZOGdG/bo8a70C8+qRdUFpuMj1X4nQjt+QDhPGV5WW
+VmIFM1JNMEtE+2W4kmYFm1FKrCgckuGzNR30CS1wDZ/V/FHf4q1JZtO07GLm1Fgf
+99mwd8+uCqBJZ/AKYZ+tYDcTurgrDDeQGLdWhfqow04akk2KKztpRAXgcdWecQ==
+-----END CERTIFICATE-----
diff --git a/mqtt_java_maven/pom.xml b/mqtt_java_maven/pom.xml
new file mode 100644
index 0000000..0025ae7
--- /dev/null
+++ b/mqtt_java_maven/pom.xml
@@ -0,0 +1,80 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.5.3
+
+
+ com.rehome
+ mqtt_java_maven
+ 0.0.1-SNAPSHOT
+ mqtt_java_maven
+ Demo project for Spring Boot
+
+ 1.8
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+ 1.2.0
+
+
+ org.apache.httpcomponents
+ httpcore
+ 4.4.13
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ 1.47
+
+
+ com.github.kittinunf.fuel
+ fuel-gson
+ 2.3.1
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.13
+
+
+ commons-io
+ commons-io
+ 2.7
+
+
+ org.projectlombok
+ lombok
+ 1.18.26
+
+
+ com.google.code.gson
+ gson
+ 2.8.7
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ForIterator.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ForIterator.java
new file mode 100644
index 0000000..d0881ea
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ForIterator.java
@@ -0,0 +1,102 @@
+package com.rehome.mqtt01;
+
+import com.google.gson.Gson;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class ForIterator {
+ public static void main(String[] args) {
+ //delete();
+ //delete1();
+ //delete2();
+ //delete3();
+ //delete4();
+ delete5();
+ }
+
+ public static void delete() {
+ List list = new ArrayList<>(4);
+ list.add("a");
+ list.add("ab");
+ list.add("abc");
+ list.add("abcd");
+
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ String item = iterator.next();
+ if (item.contains("a")) {
+ // 删除元素
+ iterator.remove();
+ }
+ }
+ System.out.println(list);
+ }
+ public static void delete1() {
+ List list = new ArrayList<>(4);
+ list.add("a");
+ list.add("ab");
+ list.add("abc");
+ list.add("abcd");
+
+ for (int i = 0; i < list.size(); i++) {
+ if (list.get(i).contains("a")) {
+ list.remove(i);
+ }
+ }
+ System.out.println(list);
+ }
+ public static void delete2() {
+ List list = new ArrayList<>(4);
+ list.add("a");
+ list.add("ab");
+ list.add("abc");
+ list.add("abcd");
+
+ for (String str : list) {
+ if (str.contains("a")) {
+ list.remove(str);
+ }
+ }
+ System.out.println(list);
+ }
+ public static void delete3() {
+ ArrayList list = new ArrayList<>();
+ list.add("111");
+ list.add("222");
+ list.add("333");
+ System.out.println(new Gson().toJson(list));
+ for (String i : list) {
+ list.remove("222");
+ }
+ System.out.println(new Gson().toJson(list));
+ }
+ public static void delete4() {
+ ArrayList list = new ArrayList<>();
+ list.add("111");
+ list.add("222");
+ list.add("333");
+ System.out.println(new Gson().toJson(list));
+ Iterator it = list.iterator();
+ while (it.hasNext()){
+ String next = it.next();
+ //if外使用list的remove方法还是会报错的
+ if(next.equals("222")){
+ it.remove();//这里使用的是迭代器里面的remove()方法,
+ // 当然如果使用list的remove方法在此删除质地感元素的话是成功的,比如:list.remove("222")
+ }
+ }
+ System.out.println(new Gson().toJson(list));
+ }
+ public static void delete5() {
+ ArrayList list = new ArrayList<>();
+ list.add("111");
+ list.add("222");
+ list.add("333");
+ System.out.println(new Gson().toJson(list));
+ //list.removeIf(s -> s.equals("222");
+ list.removeIf(item -> item.equals("222"));
+ System.out.println(new Gson().toJson(list));
+ }
+}
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/Mqtt01Application.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/Mqtt01Application.java
new file mode 100644
index 0000000..fd441a4
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/Mqtt01Application.java
@@ -0,0 +1,15 @@
+package com.rehome.mqtt01;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+
+@SpringBootApplication
+public class Mqtt01Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Mqtt01Application.class, args);
+ }
+
+}
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/package-info.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/package-info.java
new file mode 100644
index 0000000..30172b3
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/package-info.java
@@ -0,0 +1 @@
+package com.rehome.mqtt01;
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/AppSend.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/AppSend.java
new file mode 100644
index 0000000..8db1325
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/AppSend.java
@@ -0,0 +1,155 @@
+package com.rehome.mqtt01.rsa;
+
+
+/**
+ * @author huangwenfei
+ * @version v1.0.0.0
+ * Created DateTime 2021-07-31 14:52
+ * @description: mqtt 高可靠,断线重连 消息发布服务
+ */
+
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class AppSend {
+ /**
+ * 代理服务器ip地址
+ */
+ private final String HOST = "tcp://39.101.173.20:1883";
+ /**
+ * 订阅主题
+ */
+ private final String topic = "app_send";
+ /**
+ * 客户端唯一标识,相同的会被逼下线
+ */
+ private String clientid = "v1_server_app_send";
+ private MqttClient client;
+ private MqttConnectOptions options;
+ /**
+ * MQTT服务端连接账号
+ */
+ private final String userName = "admin";
+ /**
+ * MQTT服务端连接密码
+ */
+ private final String passWord = "public";
+ /**
+ * 消息发布质量
+ * 0:最多一次,即:<=1
+ * 1:至少一次,即:>=1
+ * 2:一次,即:=1
+ */
+ private int qos = 2;
+ // 推送消息
+ private MqttMessage message;
+ //定时器
+ private Timer timer;
+
+ public AppSend() {
+ // host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
+ try {
+ client = new MqttClient(HOST, clientid, new MemoryPersistence());
+ // MQTT的连接设置
+ options = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
+ options.setCleanSession(true);
+ // 设置连接的用户名
+ options.setUserName(userName);
+ // 设置连接的密码
+ options.setPassword(passWord.toCharArray());
+ // 设置超时时间 单位为秒
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ options.setKeepAliveInterval(20);
+ // 发布目的消息对象
+ message = new MqttMessage();
+ // 设置回调
+ client.setCallback(new MqttCallback() {
+
+ public void connectionLost(Throwable cause) {
+ System.out.println("connectionLost---------");
+ stop();//关闭
+ //start();//重新连接
+ }
+
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ System.out.println("***** get message start *****");
+ System.out.println(new Date());
+ System.out.println("topic:" + topic);
+ System.out.println("Qos:" + message.getQos());
+ System.out.println("message:" + new String(message.getPayload()));
+ System.out.println("***** get message end *****");
+ System.out.println();
+ }
+
+ public void deliveryComplete(IMqttDeliveryToken token) {
+ System.out.println("deliveryComplete---------" + token.isComplete());
+ }
+ });
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void start() {
+ try {
+ timer = new Timer();
+ timer.schedule(new TimerTask() {
+ public void run() {
+ System.out.println("-------设定要指定任务--------");
+ message.setQos(qos);
+ message.setRetained(true);
+ SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String time = "message from server->:"+clientid+"->:"+sd.format(new Date());
+ try {
+ String messageEn =RSAAndroid.encryptByPrivateKeyForSpiltStr(time, RSAAndroid.privateRsaKey);
+ message.setPayload(messageEn.getBytes());
+ //判断拦截状态,这里注意一下,如果没有这个判断,是非常坑的
+ if (!client.isConnected()) {
+ System.out.println("***** 没有连接到服务器 *****");
+ System.out.println("***** client to connect *****");
+ // 重新连接
+ client.connect(options);
+ }
+ if (client.isConnected()) {//连接成功,跳出连接
+ System.out.println("***** connect success *****");
+ System.out.println(time);
+ System.out.println(messageEn);
+ // 发布消息
+ client.publish(topic, message);
+ }
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ }
+ }, 10000,10000);
+ // 设定指定的时间time,此处为10000毫秒
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void stop() {
+ try {
+ // 断开连接
+ client.disconnect();
+ // 关闭客户端
+ client.close();
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ // 推送消息
+ AppSend appSend = new AppSend();
+ appSend.start();
+ }
+}
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/AppServer.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/AppServer.java
new file mode 100644
index 0000000..75ce3a1
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/AppServer.java
@@ -0,0 +1,107 @@
+package com.rehome.mqtt01.rsa;
+
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+
+public class AppServer {
+ /**
+ * 代理服务器ip地址
+ */
+ public static final String MQTT_BROKER_HOST = "tcp://39.101.173.20:1883";
+
+ /**
+ * 客户端唯一标识
+ */
+ public static final String MQTT_CLIENT_ID = "AppServer_01";
+
+ /**
+ *
+ */
+ public static final String USERNAME = "admin";
+ /**
+ * 密码
+ */
+ public static final String PASSWORD = "public";
+ /**
+ * 订阅标识
+ */
+ public static final String TOPIC_FILTER = "app_push";
+
+ private volatile static MqttClient mqttClient;
+ private static MqttConnectOptions options;
+ private static int qos = 2;
+
+
+
+ public static void main(String[] args) {
+ try {
+ // host为主机名,clientid即连接MQTT的客户端ID,一般以客户端唯一标识符表示,
+ // MemoryPersistence设置clientid的保存形式,默认为以内存保存
+
+ mqttClient = new MqttClient(MQTT_BROKER_HOST, MQTT_CLIENT_ID, new MemoryPersistence());
+ // 配置参数信息
+ options = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,
+ // 这里设置为true表示每次连接到服务器都以新的身份连接
+ options.setCleanSession(true);
+ // 设置用户名
+ options.setUserName(USERNAME);
+ // 设置密码
+ options.setPassword(PASSWORD.toCharArray());
+ // 设置超时时间 单位为秒
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ options.setKeepAliveInterval(20);
+ //断线重连
+ options.setAutomaticReconnect(true);
+ // 连接
+ mqttClient.connect(options);
+ // 订阅
+ mqttClient.subscribe(TOPIC_FILTER,qos);
+ // 设置回调
+ mqttClient.setCallback(new MqttCallbackExtended(){
+
+ @Override
+ public void connectionLost(Throwable throwable) {
+ System.out.println("connectionLost");
+ try {
+ mqttClient.reconnect();
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
+ System.out.println("topic:"+s);
+ System.out.println("Qos:"+mqttMessage.getQos());
+ System.out.println("message RSA:"+new String(mqttMessage.getPayload()));
+ try {
+ String messageDe = RSAAndroid.decryptByPrivateKeyForSpiltStr(new String(mqttMessage.getPayload()), RSAAndroid.privateRsaKey);
+ System.out.println("message content:"+messageDe);
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
+ System.out.println("deliveryComplete---------"+ iMqttDeliveryToken.isComplete());
+ }
+
+ @Override
+ public void connectComplete(boolean b, String s) {
+ //连接成功后调用
+ try {
+ mqttClient.subscribe(TOPIC_FILTER,qos);//具体订阅代码
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/MqttRSAPublishServer.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/MqttRSAPublishServer.java
new file mode 100644
index 0000000..ed21e87
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/MqttRSAPublishServer.java
@@ -0,0 +1,154 @@
+package com.rehome.mqtt01.rsa;
+
+/**
+ * @author huangwenfei
+ * @version v1.0.0.0
+ * Created DateTime 2021-07-31 14:52
+ * @description: mqtt 高可靠,断线重连 消息发布服务
+ */
+
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class MqttRSAPublishServer {
+ /**
+ * 代理服务器ip地址
+ */
+ private final String HOST = "tcp://39.101.173.20:1883";
+ /**
+ * 订阅主题
+ */
+ private final String topic = "app";
+ /**
+ * 客户端唯一标识,相同的会被逼下线
+ */
+ private String clientid = "v1_server_rsa_002";
+ private MqttClient client;
+ private MqttConnectOptions options;
+ /**
+ * MQTT服务端连接账号
+ */
+ private final String userName = "admin";
+ /**
+ * MQTT服务端连接密码
+ */
+ private final String passWord = "public";
+ /**
+ * 消息发布质量
+ * 0:最多一次,即:<=1
+ * 1:至少一次,即:>=1
+ * 2:一次,即:=1
+ */
+ private int qos = 2;
+ // 推送消息
+ private MqttMessage message;
+ //定时器
+ private Timer timer;
+
+ public MqttRSAPublishServer() {
+ // host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
+ try {
+ client = new MqttClient(HOST, clientid, new MemoryPersistence());
+ // MQTT的连接设置
+ options = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
+ options.setCleanSession(true);
+ // 设置连接的用户名
+ options.setUserName(userName);
+ // 设置连接的密码
+ options.setPassword(passWord.toCharArray());
+ // 设置超时时间 单位为秒
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ options.setKeepAliveInterval(20);
+ // 发布目的消息对象
+ message = new MqttMessage();
+ // 设置回调
+ client.setCallback(new MqttCallback() {
+
+ public void connectionLost(Throwable cause) {
+ System.out.println("connectionLost---------");
+ stop();//关闭
+ //start();//重新连接
+ }
+
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ System.out.println("***** get message start *****");
+ System.out.println(new Date());
+ System.out.println("topic:" + topic);
+ System.out.println("Qos:" + message.getQos());
+ System.out.println("message:" + new String(message.getPayload()));
+ System.out.println("***** get message end *****");
+ System.out.println();
+ }
+
+ public void deliveryComplete(IMqttDeliveryToken token) {
+ System.out.println("deliveryComplete---------" + token.isComplete());
+ }
+ });
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void start() {
+ try {
+ timer = new Timer();
+ timer.schedule(new TimerTask() {
+ public void run() {
+ System.out.println("-------设定要指定任务--------");
+ message.setQos(qos);
+ message.setRetained(true);
+ SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String time = "message from server->:"+clientid+"->:"+sd.format(new Date());
+ try {
+ String messageEn =RSAAndroid.encryptByPrivateKeyForSpiltStr(time, RSAAndroid.privateRsaKey);
+ message.setPayload(messageEn.getBytes());
+ //判断拦截状态,这里注意一下,如果没有这个判断,是非常坑的
+ if (!client.isConnected()) {
+ System.out.println("***** 没有连接到服务器 *****");
+ System.out.println("***** client to connect *****");
+ // 重新连接
+ client.connect(options);
+ }
+ if (client.isConnected()) {//连接成功,跳出连接
+ System.out.println("***** connect success *****");
+ System.out.println(time);
+ System.out.println(messageEn);
+ // 发布消息
+ client.publish(topic, message);
+ }
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ }
+ }, 10000,10000);
+ // 设定指定的时间time,此处为10000毫秒
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void stop() {
+ try {
+ // 断开连接
+ client.disconnect();
+ // 关闭客户端
+ client.close();
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ // 推送消息
+ MqttRSAPublishServer mqttPublishServer = new MqttRSAPublishServer();
+ mqttPublishServer.start();
+ }
+}
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAAndroid.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAAndroid.java
new file mode 100644
index 0000000..f4a729b
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAAndroid.java
@@ -0,0 +1,545 @@
+package com.rehome.mqtt01.rsa;
+
+/**
+ * @ Author : huangwenfei
+ * @ Date : Created in 2021/8/11 10:44 下午
+ * @ Version : $1.0.0.0
+ * @ Description:
+ */
+
+import org.apache.commons.codec.binary.Base64;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.List;
+import javax.crypto.Cipher;
+
+
+public class RSAAndroid {
+ private static String TAG = "RSAAndroid";
+ public static final String RSA = "RSA";// 非对称加密密钥算法
+ //public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";//加密填充方式
+ public static final String ECB_PKCS1_PADDING = "RSA";//加密填充方式 RSA/None/PKCS1Padding
+ public static final int DEFAULT_KEY_SIZE = 2048;//秘钥默认长度
+ public static final byte[] DEFAULT_SPLIT = "#PART#".getBytes(); // 当要加密的内容超过bufferSize,则采用partSplit进行分块加密
+ public static final int DEFAULT_BUFFERSIZE = (DEFAULT_KEY_SIZE / 8) - 11;// 当前秘钥支持加密的最大字节数
+ public static String publicRsaKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmMLyJw1CAl25lnDgEeYZvOps+1pSi93Q39djEniGNo5uUKVEkqDIayTli2zreX10HqT2jTtDN9APtwuEhWazP/VgOXoWsztbtZtSwJGM6Eg0R9zDCbKyQt5Qhg3jkTrXrvrGn7j/ZP56VNWELv/i5dsRCTccr1MeIyxjOC2pojCOsrTN4HZzgBj+GEUKPRLcKOiPfOsoP7HgkAua82vTOIgWpqIp+1PIfcjjCqzOsSv5PQnGP75+flIXtz75OKo/9hX9zl5JHNcH3SC6nS8Czii9E292XIsBtKdQijvNMn+YcmKFo6mZOUXHdO506NoKkxRny5fbKiPf/oqTA7Zx5QIDAQAB";
+ public static String privateRsaKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCYwvInDUICXbmWcOAR5hm86mz7WlKL3dDf12MSeIY2jm5QpUSSoMhrJOWLbOt5fXQepPaNO0M30A+3C4SFZrM/9WA5ehazO1u1m1LAkYzoSDRH3MMJsrJC3lCGDeOROteu+safuP9k/npU1YQu/+Ll2xEJNxyvUx4jLGM4LamiMI6ytM3gdnOAGP4YRQo9Etwo6I986yg/seCQC5rza9M4iBamoin7U8h9yOMKrM6xK/k9CcY/vn5+Uhe3Pvk4qj/2Ff3OXkkc1wfdILqdLwLOKL0Tb3ZciwG0p1CKO80yf5hyYoWjqZk5Rcd07nTo2gqTFGfLl9sqI9/+ipMDtnHlAgMBAAECggEATJd5yCC6lusdMRO5FOBUyUaUi9X2i1AU+RZKAynQySvSnbavUgExW58tRCHBUrGW9gJp59ft1N8J8hHhSO18NDY4H7laBlVdnwmYjRqtFo2VQO6sD4G8JRDION5f2iIxn/b2fYDI9H8vILfJRbNgtTSILyGlzTYUZzhLKxCh+8IsN96Nic8wa5COd1vZZmdhf2y8TG8clFWmozaScNSAATx7y+8XLVWjjWiIRZ6xQvx0uQPUParc9KihXXTKR2pA22yPIdz+U4MGD4kC0eczlcFKZ/dYv9e7OIGgnJfT0idSCu7nYb1pxJ1LxD9fS6IScNTF5dSe0OIL98e+XdyoAQKBgQDRep+5cW4iAKrEMH+djmcXAkoMiYtNVtnu0efLE8dP6vjYytQi368X9SdcASbfrQ31eEZmr/xQnlUF8oyHGkI38YS8dpAHzQcrkP3BljbbzB/3gJZaUdghGsDrK0xAJIzzmFKQpeKnGtr23vxUgaGrNsCYvQ0eQ7+5056KXS4r5QKBgQC6r8xtRSaje6L4WIydjWvYywsmRO0Of0aJLMDA/Wt2MWhHfh7ba9oI1cKGN80ap7xB2a9lQLgpv+C53wNtE5SpvjxsikAj96nUMMhGy9ojXrUith6HQhiINETz6Shnznd+AyrXP6KI/RpfA5nkDB5nrJxODwtYLP467IL7Cv7OAQKBgQCl4KxKdH/5fP28jYsAgJsxpSZt9xzQCU5Zxu396ZOSvUaApVyGoQpNtluMh3z48lhzYOKevgzW6gn5w69z7F8zXZT2iAxVoQ1kelP2z7RxKJrHqpNkwhqbXEwX7RlcUZUr8BqxYCqymJl7k+fMIzqaEalBSbLxnEReKi0I8/Bz4QKBgHK4b0ZCtVDHPEmimJ6E9l4dv/c/afF7swu+zaCK2ouiJvOwBCRQbYb6XPR/u/GCXASXUdpF4CX/vIhcDE3uN2/r8FO+zVWM7vbvF1OyF5WesG7pPW9e5ZZlkG3WvLa1wOZV6fCmMSo/ZwI2Q05JSDHrd43cXttLotrw1jiQ9C4BAoGBAKi4SOoOVQ5J5HQCDkBwPbG1AOLHFinzfoDl26GF/8Hy7fmmd1JiRTFldQp/A9VTAABz3sVYmMB92HSIaJhuDMoYJNI2Cf/cZifsv7vUL8cbLn+lPsKsebiuB0m0g4P2qLwLfegfNGEgA7lA5HIz3SELqbdp3iuqJeQl1fsJqD74";
+
+
+ public static byte[] decryptBASE64(String key) throws Exception {
+ return Base64.decodeBase64(key);
+ }
+
+ public static String encryptBASE64(byte[] key) throws Exception {
+ return Base64.encodeBase64String(key);
+ }
+
+ /**
+ * 随机生成RSA密钥对
+ *
+ * @param keyLength 密钥长度,范围:512~2048
+ * 一般1024
+ * @return
+ */
+ public static KeyPair generateRSAKeyPair(int keyLength) {
+ try {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
+ kpg.initialize(keyLength);
+ return kpg.genKeyPair();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * 用公钥对字符串进行加密
+ *
+ * @param data 原文
+ */
+ public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
+ // 得到公钥
+ byte[] decoded = Base64.decodeBase64(publicKey);
+ RSAPublicKey keyPublic = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
+ // 加密数据
+ Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
+ cp.init(Cipher.ENCRYPT_MODE, keyPublic);
+ return cp.doFinal(data);
+ }
+
+ /**
+ * 私钥加密
+ *
+ * @param data 待加密数据
+ * @param privateKey 密钥
+ * @return byte[] 加密数据
+ */
+ public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
+ // 得到私钥
+ byte[] decoded = Base64.decodeBase64(privateKey);
+ RSAPrivateKey keyPrivate = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
+ // 数据加密
+ Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
+ cipher.init(Cipher.ENCRYPT_MODE, keyPrivate);
+ return cipher.doFinal(data);
+ }
+
+ /**
+ * 公钥解密
+ *
+ * @param data 待解密数据
+ * @param publicKey 密钥
+ * @return byte[] 解密数据
+ */
+ public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
+ // 得到公钥
+ byte[] decoded = Base64.decodeBase64(publicKey);
+ RSAPublicKey keyPublic = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
+ // 数据解密
+ Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
+ cipher.init(Cipher.DECRYPT_MODE, keyPublic);
+ return cipher.doFinal(data);
+ }
+
+ /**
+ * 使用私钥进行解密
+ */
+ public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) throws Exception {
+ // 得到私钥
+ byte[] decoded = Base64.decodeBase64(privateKey);
+ RSAPrivateKey keyPrivate = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
+
+ // 解密数据
+ Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
+ cp.init(Cipher.DECRYPT_MODE, keyPrivate);
+ byte[] arr = cp.doFinal(encrypted);
+ return arr;
+ }
+
+ /**
+ * 用公钥对字符串进行分段加密
+ */
+ public static byte[] encryptByPublicKeyForSpilt(byte[] data, byte[] publicKey) throws Exception {
+ int dataLen = data.length;
+ if (dataLen <= DEFAULT_BUFFERSIZE) {
+ return encryptByPublicKey(data, publicKey);
+ }
+ List allBytes = new ArrayList(2048);
+ int bufIndex = 0;
+ int subDataLoop = 0;
+ byte[] buf = new byte[DEFAULT_BUFFERSIZE];
+ for (int i = 0; i < dataLen; i++) {
+ buf[bufIndex] = data[i];
+ if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
+ subDataLoop++;
+ if (subDataLoop != 1) {
+ for (byte b : DEFAULT_SPLIT) {
+ allBytes.add(b);
+ }
+ }
+ byte[] encryptBytes = encryptByPublicKey(buf, publicKey);
+ for (byte b : encryptBytes) {
+ allBytes.add(b);
+ }
+ bufIndex = 0;
+ if (i == dataLen - 1) {
+ buf = null;
+ } else {
+ buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
+ }
+ }
+ }
+ byte[] bytes = new byte[allBytes.size()];
+ {
+ int i = 0;
+ for (Byte b : allBytes) {
+ bytes[i++] = b.byteValue();
+ }
+ }
+ return bytes;
+ }
+
+
+
+ /**
+ * 使用私钥分段加密
+ *
+ * @param data 要加密的原始数据
+ * @param privateKey 秘钥
+ */
+ public static byte[] encryptByPrivateKeyForSpilt(byte[] data, byte[] privateKey) throws Exception {
+ int dataLen = data.length;
+ if (dataLen <= DEFAULT_BUFFERSIZE) {
+ return encryptByPrivateKey(data, privateKey);
+ }
+ List allBytes = new ArrayList(2048);
+ int bufIndex = 0;
+ int subDataLoop = 0;
+ byte[] buf = new byte[DEFAULT_BUFFERSIZE];
+ for (int i = 0; i < dataLen; i++) {
+ buf[bufIndex] = data[i];
+ if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
+ subDataLoop++;
+ if (subDataLoop != 1) {
+ for (byte b : DEFAULT_SPLIT) {
+ allBytes.add(b);
+ }
+ }
+ byte[] encryptBytes = encryptByPrivateKey(buf, privateKey);
+ for (byte b : encryptBytes) {
+ allBytes.add(b);
+ }
+ bufIndex = 0;
+ if (i == dataLen - 1) {
+ buf = null;
+ } else {
+ buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
+ }
+ }
+ }
+ byte[] bytes = new byte[allBytes.size()];
+ {
+ int i = 0;
+ for (Byte b : allBytes) {
+ bytes[i++] = b.byteValue();
+ }
+ }
+ return bytes;
+ }
+
+ /**
+ * 公钥分段解密
+ *
+ * @param encrypted 待解密数据
+ * @param publicKey 密钥
+ */
+ public static byte[] decryptByPublicKeyForSpilt(byte[] encrypted, byte[] publicKey) throws Exception {
+ int splitLen = DEFAULT_SPLIT.length;
+ if (splitLen <= 0) {
+ return decryptByPublicKey(encrypted, publicKey);
+ }
+ int dataLen = encrypted.length;
+ List allBytes = new ArrayList(1024);
+ int latestStartIndex = 0;
+ for (int i = 0; i < dataLen; i++) {
+ byte bt = encrypted[i];
+ boolean isMatchSplit = false;
+ if (i == dataLen - 1) {
+ // 到data的最后了
+ byte[] part = new byte[dataLen - latestStartIndex];
+ System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
+ byte[] decryptPart = decryptByPublicKey(part, publicKey);
+ for (byte b : decryptPart) {
+ allBytes.add(b);
+ }
+ latestStartIndex = i + splitLen;
+ i = latestStartIndex - 1;
+ } else if (bt == DEFAULT_SPLIT[0]) {
+ // 这个是以split[0]开头
+ if (splitLen > 1) {
+ if (i + splitLen < dataLen) {
+ // 没有超出data的范围
+ for (int j = 1; j < splitLen; j++) {
+ if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
+ break;
+ }
+ if (j == splitLen - 1) {
+ // 验证到split的最后一位,都没有break,则表明已经确认是split段
+ isMatchSplit = true;
+ }
+ }
+ }
+ } else {
+ // split只有一位,则已经匹配了
+ isMatchSplit = true;
+ }
+ }
+ if (isMatchSplit) {
+ byte[] part = new byte[i - latestStartIndex];
+ System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
+ byte[] decryptPart = decryptByPublicKey(part, publicKey);
+ for (byte b : decryptPart) {
+ allBytes.add(b);
+ }
+ latestStartIndex = i + splitLen;
+ i = latestStartIndex - 1;
+ }
+ }
+ byte[] bytes = new byte[allBytes.size()];
+ {
+ int i = 0;
+ for (Byte b : allBytes) {
+ bytes[i++] = b.byteValue();
+ }
+ }
+ return bytes;
+ }
+
+ /**
+ * 使用私钥分段解密
+ */
+ public static byte[] decryptByPrivateKeyForSpilt(byte[] encrypted, byte[] privateKey) throws Exception {
+ int splitLen = DEFAULT_SPLIT.length;
+ if (splitLen <= 0) {
+ return decryptByPrivateKey(encrypted, privateKey);
+ }
+ int dataLen = encrypted.length;
+ List allBytes = new ArrayList(1024);
+ int latestStartIndex = 0;
+ for (int i = 0; i < dataLen; i++) {
+ byte bt = encrypted[i];
+ boolean isMatchSplit = false;
+ if (i == dataLen - 1) {
+ // 到data的最后了
+ byte[] part = new byte[dataLen - latestStartIndex];
+ System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
+ byte[] decryptPart = decryptByPrivateKey(part, privateKey);
+ for (byte b : decryptPart) {
+ allBytes.add(b);
+ }
+ latestStartIndex = i + splitLen;
+ i = latestStartIndex - 1;
+ } else if (bt == DEFAULT_SPLIT[0]) {
+ // 这个是以split[0]开头
+ if (splitLen > 1) {
+ if (i + splitLen < dataLen) {
+ // 没有超出data的范围
+ for (int j = 1; j < splitLen; j++) {
+ if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
+ break;
+ }
+ if (j == splitLen - 1) {
+ // 验证到split的最后一位,都没有break,则表明已经确认是split段
+ isMatchSplit = true;
+ }
+ }
+ }
+ } else {
+ // split只有一位,则已经匹配了
+ isMatchSplit = true;
+ }
+ }
+ if (isMatchSplit) {
+ byte[] part = new byte[i - latestStartIndex];
+ System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
+ byte[] decryptPart = decryptByPrivateKey(part, privateKey);
+ for (byte b : decryptPart) {
+ allBytes.add(b);
+ }
+ latestStartIndex = i + splitLen;
+ i = latestStartIndex - 1;
+ }
+ }
+ byte[] bytes = new byte[allBytes.size()];
+ {
+ int i = 0;
+ for (Byte b : allBytes) {
+ bytes[i++] = b.byteValue();
+ }
+ }
+ return bytes;
+ }
+
+ /**
+ * 用公钥对字符串进行分段加密
+ */
+ public static String encryptByPublicKeyForSpiltStr(String data, String publicKey) throws Exception {
+ byte[] encryptBytes = encryptByPublicKeyForSpilt(data.getBytes(StandardCharsets.UTF_8), publicKey.getBytes());
+ return encryptBASE64(encryptBytes);
+ }
+
+ /**
+ * 使用私钥分段加密
+ *
+ * @param data 要加密的原始数据
+ * @param privateKey 秘钥
+ */
+ public static String encryptByPrivateKeyForSpiltStr(String data, String privateKey) throws Exception {
+ byte[] encryptBytes = encryptByPrivateKeyForSpilt(data.getBytes(StandardCharsets.UTF_8), privateKey.getBytes());
+ return encryptBASE64(encryptBytes);
+ }
+
+ /**
+ * 公钥分段解密
+ *
+ * @param encrypted 待解密数据
+ * @param publicKey 密钥
+ */
+ public static String decryptByPublicKeyForSpiltStr(String encrypted, String publicKey) throws Exception {
+ byte[] decryptBytes = decryptByPublicKeyForSpilt(decryptBASE64(encrypted), publicKey.getBytes());
+ return new String(decryptBytes,StandardCharsets.UTF_8);
+ }
+
+ /**
+ * 使用私钥分段解密
+ */
+ public static String decryptByPrivateKeyForSpiltStr(String encrypted, String privateKey) throws Exception {
+ byte[] decryptBytes = decryptByPrivateKeyForSpilt(decryptBASE64(encrypted), privateKey.getBytes());
+ return new String(decryptBytes,StandardCharsets.UTF_8);
+ }
+
+ public static void testEncrypt0(String content) {
+ //生成秘钥对
+ KeyPair keyPair = RSAAndroid.generateRSAKeyPair(RSAAndroid.DEFAULT_KEY_SIZE);
+ //公钥
+ PublicKey publicKey = keyPair.getPublic();
+ //私钥
+ PrivateKey privateKey = keyPair.getPrivate();
+
+
+ try {
+
+ System.out.println("公钥:" + encryptBASE64(publicKey.getEncoded()));
+ System.out.println("私钥:" + encryptBASE64(privateKey.getEncoded()));
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void testEncrypt1(String content) {
+ //生成秘钥对
+ KeyPair keyPair = RSAAndroid.generateRSAKeyPair(RSAAndroid.DEFAULT_KEY_SIZE);
+ //公钥
+ PublicKey publicKey = keyPair.getPublic();
+ //私钥
+ PrivateKey privateKey = keyPair.getPrivate();
+
+ long start;
+ long end;
+ byte[] encryptBytes = new byte[0];
+ byte[] decryptBytes = new byte[0];
+ String encryStr, decryStr;
+
+ try {
+
+ System.out.println("公钥:" + encryptBASE64(RSAAndroid.publicRsaKey.getBytes()));
+ //公钥加密
+ start = System.currentTimeMillis();
+
+ encryptBytes = RSAAndroid.encryptByPublicKeyForSpilt(content.getBytes(StandardCharsets.UTF_8), RSAAndroid.publicRsaKey.getBytes());
+ System.out.println("testEncrypt: 公钥加密 encryptBytes:" + encryptBytes);
+
+ end = System.currentTimeMillis();
+ System.out.println("公钥加密耗时 cost time---->" + (end - start));
+ //encryStr = BASE64Encoder.encode(encryptBytes);
+ encryStr = encryptBASE64(encryptBytes);
+// Log.e(TAG, "加密后json数据 --1-->" + encryStr);
+ System.out.println("加密后json数据长度 --1-->" + encryStr.length());
+ System.out.println("testEncrypt: encryStr:" + encryStr);
+ //私钥解密
+ System.out.println("私钥:" + encryptBASE64(RSAAndroid.privateRsaKey.getBytes()));
+ start = System.currentTimeMillis();
+ decryptBytes = RSAAndroid.decryptByPrivateKeyForSpilt(decryptBASE64(encryStr), RSAAndroid.privateRsaKey.getBytes());
+ decryStr = new String(decryptBytes);
+ System.out.println("testEncrypt: 私钥解密 decryStr:" + decryStr);
+ end = System.currentTimeMillis();
+ System.out.println("私钥解密耗时 cost time---->" + (end - start));
+ System.out.println("解密后json数据 --1-->" + decryStr);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ public static void testEncrypt2(String content) {
+ //生成秘钥对
+ KeyPair keyPair = RSAAndroid.generateRSAKeyPair(RSAAndroid.DEFAULT_KEY_SIZE);
+ //公钥
+ PublicKey publicKey = keyPair.getPublic();
+ //私钥
+ PrivateKey privateKey = keyPair.getPrivate();
+
+ long start;
+ long end;
+ byte[] encryptBytes = new byte[0];
+ byte[] decryptBytes = new byte[0];
+ String encryStr, decryStr;
+
+ try {
+
+ //私钥加密
+ start = System.currentTimeMillis();
+ encryptBytes = RSAAndroid.encryptByPrivateKeyForSpilt(content.getBytes(StandardCharsets.UTF_8), RSAAndroid.privateRsaKey.getBytes());
+ end = System.currentTimeMillis();
+ System.out.println("私钥加密密耗时 cost time---->" + (end - start));
+ encryStr = encryptBASE64(encryptBytes);
+
+// Log.e(TAG, "加密后json数据 --2-->" + encryStr);
+ System.out.println("加密后json数据长度 --2-->" + encryStr.length());
+ System.out.println("testEncrypt: 私钥加密密 encryStr:" + encryStr);
+ //公钥解密
+ start = System.currentTimeMillis();
+ decryptBytes = RSAAndroid.decryptByPublicKeyForSpilt(decryptBASE64(encryStr), RSAAndroid.publicRsaKey.getBytes());
+
+ decryStr = new String(decryptBytes);
+ System.out.println("testEncrypt: 公钥解密 decryStr:" + decryStr);
+ end = System.currentTimeMillis();
+ System.out.println("公钥解密耗时 cost time---->" + (end - start));
+ System.out.println("解密后json数据 --2-->" + decryStr);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void testEncrypt3(String content) {
+ long start;
+ long end;
+ String encryStr, decryStr;
+ try {
+ //公钥加密
+ System.out.println("公钥:" + RSAAndroid.publicRsaKey);
+ start = System.currentTimeMillis();
+ encryStr = RSAAndroid.encryptByPublicKeyForSpiltStr(content, RSAAndroid.publicRsaKey);
+ end = System.currentTimeMillis();
+ System.out.println("公钥加密耗时 cost time---->" + (end - start));
+ System.out.println("加密后json数据长度 --1-->" + encryStr.length());
+ System.out.println("testEncrypt: 公钥加密 encryStr:" + encryStr);
+ //私钥解密
+ System.out.println("私钥:" + RSAAndroid.privateRsaKey);
+ start = System.currentTimeMillis();
+ encryStr = "X6Ad0LpiBP7ze/cEgwGkYS53zG5ozY1Nrk2HzrrGlWqFZdyrmYihc1Fo3pjxxfOJi60zkZXguPt197vdtf2NHjtBCamvGt8DYhvfGUFP0YSod11GckQQaUslUkwPjQKTGJ46Kdy7Y2gMKK7EdEabEmTPl/XIT9fDFX/nMWgAutcQ15Gq5FRwWQH7sSVNF5bjrxxBs7Q/JwsCsU+xl0LraifUf+1O6NzCHc4ll7dmWq6EGORjaSVYka8ItuI4hhVWffcrOhY1vDqjFkY+Mzac9ppgk1nc5StMMNGyPC4OYsLkqZa5h8acK8YhSi7dpj58Lo/yJWqMmewiGDSskrcFXCNQQVJUI10H9WmD3b//98jW6cq3awLqmpoZmjuN3fm8vx1KPOCEZs2GlM7/wCEUMabV7O5EsTtRf+6pqHYTPzZfxt2lXEEJviktjguG1WI71nwg+1XyIx5tn818XiYvs0L02hi3sWpQkk/NJ4QaE3LziuCMrgDU/GcFzYLybU627yAPPPLjB9wVZGefwUdWjMtY5AzPMBa9eNjsMaHAGe2zbnopafuouwsjH+uEZd2rzT3Uacb7+pNjl94XiB/0Xhwl1n5bi6HbT3aY2jC6YbKqCp5XQaLCbuefaRVCLC6pOHmNX6NKni98/bYKQ6XfhDoA56gJAEVsAaj/a6vpzVIMsej5zDI=";
+ decryStr = RSAAndroid.decryptByPrivateKeyForSpiltStr(encryStr, RSAAndroid.privateRsaKey);
+ end = System.currentTimeMillis();
+ System.out.println("私钥解密耗时 cost time---->" + (end - start));
+ System.out.println("解密后json数据长度 --1-->" + decryStr.length());
+ System.out.println("testEncrypt: 私钥解密 decryStr:" + decryStr);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ public static void testEncrypt4(String content) {
+ long start;
+ long end;
+ String encryStr, decryStr;
+ try {
+ System.out.println("公钥:" + RSAAndroid.publicRsaKey);
+ //私钥加密
+ start = System.currentTimeMillis();
+ encryStr = RSAAndroid.encryptByPrivateKeyForSpiltStr(content, RSAAndroid.privateRsaKey);
+ end = System.currentTimeMillis();
+ System.out.println("私钥加密密耗时 cost time---->" + (end - start));
+ System.out.println("加密后json数据长度 --2-->" + encryStr.length());
+ System.out.println("testEncrypt: 私钥加密 encryStr:" + encryStr);
+ //公钥解密
+ System.out.println("私钥:" + RSAAndroid.privateRsaKey);
+ start = System.currentTimeMillis();
+ decryStr = RSAAndroid.decryptByPublicKeyForSpiltStr(encryStr, RSAAndroid.publicRsaKey);
+ end = System.currentTimeMillis();
+ System.out.println("公钥解密耗时 cost time---->" + (end - start));
+ System.out.println("解密后json数据 --2-->" + decryStr);
+ System.out.println("testEncrypt: 公钥解密 decryStr:" + decryStr);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ //RSAAndroid.testEncrypt3("8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。8月8日晚,东京国立竞技场的奥运圣火熄灭,场内电子屏上打出了“ARIGATO”(日语“谢谢”的罗马字)。57年前的那一夜,东京奥运会闭幕式大屏上留下的是“SAYONARA”(日语“再见”罗马字)。从告别到感谢,本届奥运会对日本而言,原本是一场赌上国运的体育盛事,而现实却朝着与理想相反的方向一路狂奔。");
+ RSAAndroid.testEncrypt0("123");
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAEncrypt.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAEncrypt.java
new file mode 100644
index 0000000..7b05436
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAEncrypt.java
@@ -0,0 +1,116 @@
+package com.rehome.mqtt01.rsa;
+
+/**
+ * @ Author : huangwenfei
+ * @ Date : Created in 2021/8/9 9:29 下午
+ * @ Version : $1.0.0.0
+ * @ Description:
+ */
+
+
+import javax.crypto.Cipher;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+public class RSAEncrypt {
+ private static Map keyMap = new HashMap(); //用于封装随机产生的公钥与私钥
+ public static String publicRsaKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmK/MMFq+agBpVaSN0R2r0vtuvaA7A4t/WM+Q3G1l1SFNCSUkfv5IlZ7hoJYudSfi+fKpFg3k9HEgeBN2uKkqLxggteTLB7ymqNtZCv3sI3YkMOGu2HxY2w8o4wRQbgr1WOiBr0hBsZ3gyvNzUZ4GH8zY/JCruKzTa5dhxp3ciAMfsXKo6yMCVj1/hwTYxrpR7pJdMSAG92DZjl8Q+fzYxZOul4Lt5eNDq6Tq3J7YE3iO/RBITQPEdxB8B1PhincQB6JOXwKRJZrNhD3mgH4O07+GXSXlj0FLGz4TdcBI3DepPbLmli1ogE57r0MlAslEu0iojmIiOvFlJ7p+qOS2VQIDAQAB";
+ public static String privateRsaKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCYr8wwWr5qAGlVpI3RHavS+269oDsDi39Yz5DcbWXVIU0JJSR+/kiVnuGgli51J+L58qkWDeT0cSB4E3a4qSovGCC15MsHvKao21kK/ewjdiQw4a7YfFjbDyjjBFBuCvVY6IGvSEGxneDK83NRngYfzNj8kKu4rNNrl2HGndyIAx+xcqjrIwJWPX+HBNjGulHukl0xIAb3YNmOXxD5/NjFk66Xgu3l40OrpOrcntgTeI79EEhNA8R3EHwHU+GKdxAHok5fApElms2EPeaAfg7Tv4ZdJeWPQUsbPhN1wEjcN6k9suaWLWiATnuvQyUCyUS7SKiOYiI68WUnun6o5LZVAgMBAAECggEAfaK521fvsn1gLy5V2yoVBmgJeVLs/D++q68vvZDu5+6c2teLLkvCIgs4ENFCrPgDFjQL2a/ZIyIq22L4n33izhmGYOVAAr/CStMic574vT0rDmXFXzECVE4nEJWuML4nn97BRx+nnqUQIS8tRo1G8Me4DCpmgnEDDlbkB3BB1E+kGKvO7mo/y3KzjjAUCSIBh92TNZ4IPvcU99yR2UF4wY/7uc3bBCO2ZBSFRv7RyWBDQK/gvAWStYGOQPLQL9frRAG9a/L7lfMkhQAazxUpv17hgQVXuMP4cEnDhMpjEfNatwgIMQppDYoSSoIHZUKpRSauNEEi63Yfbl/X8HiowQKBgQDoXHiY64+a5O3oD7A/vsUWOE1yULZJM8pMwlZfNXcdBYdj51eS3/2ii8LZEu0sQ9Kcz30uHgI0dNCAQWNDJqNKFKV3KONFYm+5EQaCigNkOkoOqjbQXFWqVEyCzb9xPFxdJm1N04JvbtOK67sPVexJrhq2gm0gQGpSR/R9sIhr+QKBgQCoOFA6FhwwsuWBQ4e+WSK6Sw1ZwdNNOwXCYSM+DLPnsf4erqSKE+hLecg4Emvfl9lO5/5dQz808SYrSm402wVFsqrNLV3M5uvL/zWusDXnQdmmOPHVKuO5EBQnh9YeI3BUQRxMo1LdFCluWqxCVzj9QU3x6zkid0fCnWQzFKHcPQKBgQC8seOJo7ox+nks/BiQG7bnjX9vNxZhKfq+DQ+hL8T0P3osakFW2CmcJ81rBRCv4sAVcfZhTiNSQA7WKMOYU7dFQLECrKSrwv2hl67msXeBnEhp0lbDLEixEtYzXyx5o6AKUVtwWTRSk/icl0SIdql1SDsPPamrCESPXzmwHH0c2QKBgGQ9CjFSs4GhWHjqUJzwaG0yA8aUZOEEZq4pS+LRlvJdcdu+nXVZ33X6H4CqGXWm+mq2ey//vk5B1Ei/lWQRjta1XGneuqI6iA+LB+YMQlKHPrZ6AEDRydig6CGWI9TZsTnDgqV4PQxX00ha54Kwjtj6bQPW8rjC8xPYzbhSdxDRAoGBALX3qVbywgAyeR3aaRFwlUMZZPc96Gaye0Ol53jRJDbEzBwetYiEhypjroNLmB/B/baCXXyMwJ7FZVQiG4VBwhYhqIEjNa+sZ5MDn6D5OM2ZFlq/Xii44+FHuZiz8WxTZ3G5S4hxASTVWae5Q/Is/ZROw+fgw1oA/W2osIYMrMVR";
+
+ public static void main(String[] args) throws Exception {
+ //生成公钥和私钥
+ genKeyPair();
+ //加密字符串
+ String message = "由于项目要用到非对称加密解密签名校验什么的,于是参考《Java加密解密的艺术》写一个RSA进行加密解密签名及校验的Demo,代码很简单,特此分享!";
+// System.out.println("随机生成的公钥为:" + keyMap.get(0));
+// System.out.println("随机生成的私钥为:" + keyMap.get(1));
+// String messageEn = encrypt(message,keyMap.get(0));
+// System.out.println(message + "\t加密后的字符串为:" + messageEn);
+// String messageDe = decrypt(messageEn,keyMap.get(1));
+// System.out.println("还原后的字符串为:" + messageDe);
+
+ //String messageEn = encrypt(message,publicRsaKey);
+ String messageEn = "YHUqrn0UPYqkvUPDzuM/DUR/7H+R05aPbtinAwrnWv/kU2Gt1NBvDOwXOUt6YBiv1ogTrk1k1xbw1YlN8PQ7eSvM0dtcEpRtRS7zT7bSDu3sQWofOwleuuJFQxX88uCy1ZfmP+QrS+iXREfpHOmCRylpyEBNQAJttPbDZYQUAJrAdjycmiXgac2IaWefs5IaKWiCjMm0c0ZJ3FYXSrz98Mn89lX63Z/rPgqm/QdHaNlkJ2cTW559Z3x1nRTGYLUb4emjmtk9tDjAvBnNjSvga4/ozPXl7lLoWNgK3z2GwIsgR9t20C2GfozRZtAC6SCf3IT17rc2nHxTy9YdByr9UA==";
+ System.out.println(message + "\t加密后的字符串为:" + messageEn);
+ String messageDe = decrypt(messageEn,privateRsaKey);
+ System.out.println("还原后的字符串为:" + messageDe);
+ }
+
+ /**
+ * 随机生成密钥对
+ * @throws NoSuchAlgorithmException
+ */
+ public static void genKeyPair() throws NoSuchAlgorithmException {
+ // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
+ KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
+ // 初始化密钥对生成器,密钥大小为96-1024位
+ keyPairGen.initialize(2048,new SecureRandom());
+ // 生成一个密钥对,保存在keyPair中
+ KeyPair keyPair = keyPairGen.generateKeyPair();
+ RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥
+ RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥
+
+ String publicKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded());
+ String privateKeyStr = Base64.getEncoder().encodeToString(privateKey.getEncoded());
+
+ String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
+ // 得到私钥字符串
+ String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());
+ // 将公钥和私钥保存到Map
+ keyMap.put(0,publicKeyString); //0表示公钥
+ keyMap.put(1,privateKeyString); //1表示私钥
+ }
+ /**
+ * RSA公钥加密
+ *
+ * @param str
+ * 加密字符串
+ * @param publicKey
+ * 公钥
+ * @return 密文
+ * @throws Exception
+ * 加密过程中的异常信息
+ */
+ public static String encrypt( String str, String publicKey ) throws Exception{
+ //base64编码的公钥
+ byte[] decoded = Base64.getDecoder().decode(publicKey);
+ RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
+ //RSA加密
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.ENCRYPT_MODE, pubKey);
+ String outStr = Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
+ return outStr;
+ }
+
+ /**
+ * RSA私钥解密
+ *
+ * @param str
+ * 加密字符串
+ * @param privateKey
+ * 私钥
+ * @return 铭文
+ * @throws Exception
+ * 解密过程中的异常信息
+ */
+ public static String decrypt(String str, String privateKey) throws Exception{
+ //64位解码加密后的字符串
+ byte[] inputByte = Base64.getDecoder().decode(str.getBytes(StandardCharsets.UTF_8));
+ //base64编码的私钥
+ byte[] decoded = Base64.getDecoder().decode(privateKey.getBytes(StandardCharsets.UTF_8));
+ RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
+ //RSA解密
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.DECRYPT_MODE, priKey);
+ String outStr = new String(cipher.doFinal(inputByte));
+ return outStr;
+ }
+
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAUtil.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAUtil.java
new file mode 100644
index 0000000..33b3566
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAUtil.java
@@ -0,0 +1,171 @@
+package com.rehome.mqtt01.rsa;
+
+
+
+import lombok.extern.slf4j.Slf4j;
+import javax.crypto.Cipher;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+public class RSAUtil {
+
+ public static final String KEY_ALGORITHM = "RSA";
+
+ private static final String PUBLIC_KEY = "RSAPublicKey";
+
+ private static final String PRIVATE_KEY = "RSAPrivateKey";
+
+ //RSA最大加密明文大小
+ private static final int MAX_ENCRYPT_BLOCK = 117;
+
+ //RSA最大解密密文大小
+ private static final int MAX_DECRYPT_BLOCK = 128;
+
+ //java默认加密填充方式 RSA/None/PKCS1Padding
+ public static final String ECB_None_PKCS1_PADDING = "RSA/None/PKCS1Padding";
+
+// // 1024 bits 的 RSA 密钥对,最大加密明文大小
+// private static final int MAX_ENCRYPT_BLOCK = 117;
+//
+// // 1024 bits 的 RSA 密钥对,最大解密密文大小
+// private static final int MAX_DECRYPT_BLOCK = 128;
+
+ // 生成密钥对
+ public static Map initKey(int keysize) throws Exception {
+ KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
+ // 设置密钥对的 bit 数,越大越安全
+ keyPairGen.initialize(keysize);
+ KeyPair keyPair = keyPairGen.generateKeyPair();
+
+ // 获取公钥
+ RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+ // 获取私钥
+ RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
+ Map keyMap = new HashMap<>(2);
+ keyMap.put(PUBLIC_KEY, publicKey);
+ keyMap.put(PRIVATE_KEY, privateKey);
+ return keyMap;
+ }
+
+ // 获取公钥字符串
+ public static String getPublicKeyStr(Map keyMap) {
+ // 获得 map 中的公钥对象,转为 key 对象
+ Key key = (Key) keyMap.get(PUBLIC_KEY);
+ // 编码返回字符串
+ return encryptBASE64(key.getEncoded());
+ }
+
+ // 获取私钥字符串
+ public static String getPrivateKeyStr(Map keyMap) {
+ // 获得 map 中的私钥对象,转为 key 对象
+ Key key = (Key) keyMap.get(PRIVATE_KEY);
+ // 编码返回字符串
+ return encryptBASE64(key.getEncoded());
+ }
+
+ // 获取公钥
+ public static PublicKey getPublicKey(String publicKeyString) throws NoSuchAlgorithmException, InvalidKeySpecException {
+ byte[] publicKeyByte = Base64.getDecoder().decode(publicKeyString);
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyByte);
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+ return keyFactory.generatePublic(keySpec);
+ }
+
+ // 获取私钥
+ public static PrivateKey getPrivateKey(String privateKeyString) throws Exception {
+ byte[] privateKeyByte = Base64.getDecoder().decode(privateKeyString);
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyByte);
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+ return keyFactory.generatePrivate(keySpec);
+ }
+
+ /**
+ * BASE64 编码返回加密字符串
+ *
+ * @param key 需要编码的字节数组
+ * @return 编码后的字符串
+ */
+ public static String encryptBASE64(byte[] key) {
+ return new String(Base64.getEncoder().encode(key));
+ }
+
+ /**
+ * BASE64 解码,返回字节数组
+ *
+ * @param key 待解码的字符串
+ * @return 解码后的字节数组
+ */
+ public static byte[] decryptBASE64(String key) {
+ return Base64.getDecoder().decode(key);
+ }
+
+ /**
+ * 公钥加密
+ *
+ * @param text 待加密的明文字符串
+ * @param publicKeyStr 公钥
+ * @return 加密后的密文
+ */
+ public static String encrypt(String text, String publicKeyStr) {
+ try {
+ log.info("明文字符串为:[{}]", text);
+ Cipher cipher = Cipher.getInstance(ECB_None_PKCS1_PADDING);
+ cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKeyStr));
+ byte[] tempBytes = cipher.doFinal(text.getBytes("UTF-8"));
+ return Base64.getEncoder().encodeToString(tempBytes);
+ } catch (Exception e) {
+ throw new RuntimeException("加密字符串[" + text + "]时遇到异常", e);
+ }
+ }
+
+ /**
+ * 私钥解密
+ *
+ * @param secretText 待解密的密文字符串
+ * @param privateKeyStr 私钥
+ * @return 解密后的明文
+ */
+ public static String decrypt(String secretText, String privateKeyStr) {
+ try {
+ // 生成私钥
+ Cipher cipher = Cipher.getInstance(ECB_None_PKCS1_PADDING);
+ cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKeyStr));
+ // 密文解码
+ byte[] secretTextDecoded = Base64.getDecoder().decode(secretText.getBytes("UTF-8"));
+ byte[] tempBytes = cipher.doFinal(secretTextDecoded);
+ return new String(tempBytes);
+ } catch (Exception e) {
+ throw new RuntimeException("解密字符串[" + secretText + "]时遇到异常", e);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ Map keyMap;
+ String cipherText;
+ // 原始明文
+ String content = "春江潮水连海平,海上明月共潮生。滟滟随波千万里,何处春江无月明。";
+
+ // 生成密钥对
+ keyMap = initKey(2048);
+ String publicKey = getPublicKeyStr(keyMap);
+ log.info("公钥:[{}],长度:[{}]", publicKey, publicKey.length());
+ String privateKey = getPrivateKeyStr(keyMap);
+ log.info("私钥:[{}],长度:[{}]", privateKey, privateKey.length());
+
+ // 加密
+ cipherText = encrypt(content, publicKey);
+ log.info("加密后的密文:[{}],长度:[{}]", cipherText, cipherText.length());
+
+ // 解密
+ String plainText = decrypt(cipherText, privateKey);
+ log.info("解密后明文:[{}]", plainText);
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAUtils.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAUtils.java
new file mode 100644
index 0000000..10ef9f7
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAUtils.java
@@ -0,0 +1,463 @@
+package com.rehome.mqtt01.rsa;
+
+
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+
+public class RSAUtils {
+
+ /**RSA算法*/
+ public static final String RSA = "RSA";
+ private static final String PUBLIC_KEY = "RSAPublicKey";
+ private static final String PRIVATE_KEY = "RSAPrivateKey";
+ public static final int DEFAULT_KEY_SIZE = 2048;//秘钥默认长度
+
+ //RSA最大加密明文大小 1024位是117 算法 最大加密明文大小 = 1024(bit) / 8 - 11(byte) = 117 byte 最大加密明文大小 = 2048(bit) / 8 - 11(byte) = 245 byte
+ //private static final int MAX_ENCRYPT_BLOCK = 245;
+ private static final int MAX_ENCRYPT_BLOCK = (DEFAULT_KEY_SIZE / 8) - 11;
+ //RSA最大解密密文大小 1024位是128 2048位是 256 依此类推
+ //private static final int MAX_DECRYPT_BLOCK = 256;
+ private static final int MAX_DECRYPT_BLOCK = DEFAULT_KEY_SIZE / 8;
+ //java默认加密填充方式 RSA 对应安卓 RSA/None/PKCS1Padding
+ public static final String ECB_None_PKCS1_PADDING = "RSA";
+ //安卓手机加密填充方式用 RSA/None/PKCS1Padding
+ //public static final String ECB_None_PKCS1_PADDING = "RSA/None/PKCS1Padding";
+
+ //C# RSA格式转JAVA格式 通用RSA
+// public static final String public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvz3ouaHLt2/KpVEahoFAsslxlIGyM6iRX9nmsiix9vE8HTBY3sjRSEMXB1IoZh/AZ8TLvkAJBIaPpPxweMoYcNvkbmSMv7+s2USTu+IEY0nGIVa4oJivaIz+ed6sRoQg7YXJzJoEojWQNlhK3QEJhgDH1ozYRJfTUD8IsexdNsXaCmlXEMN/a99sg8GXuuZqw4IaJcGqWgpKN5FpHIfok+3q6Av7nuG5JVtg3UPNUZP7lxyCQE4GT+UAXm1I2styr1sJkskHCs13266JBW3HCIwf3U1EZsZrpT7WHGPdih3ySymRGjPJfYo+yqKk1C0lC6BpQ7RnZiZC2vHaGClUGQIDAQAB";
+// public static final String private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/Pei5ocu3b8qlURqGgUCyyXGUgbIzqJFf2eayKLH28TwdMFjeyNFIQxcHUihmH8BnxMu+QAkEho+k/HB4yhhw2+RuZIy/v6zZRJO74gRjScYhVrigmK9ojP553qxGhCDthcnMmgSiNZA2WErdAQmGAMfWjNhEl9NQPwix7F02xdoKaVcQw39r32yDwZe65mrDgholwapaCko3kWkch+iT7eroC/ue4bklW2DdQ81Rk/uXHIJATgZP5QBebUjay3KvWwmSyQcKzXfbrokFbccIjB/dTURmxmulPtYcY92KHfJLKZEaM8l9ij7KoqTULSULoGlDtGdmJkLa8doYKVQZAgMBAAECggEBAKXKVuovELt7B9Pfhr5aaStVpciX01Qja7wL3IpQ609ofLPVSQYCVCRwPROUrv8xwYx0OCk7vFWXDgp66kpc8WlNyC/HrZlB4ugMIoL8As/Mkh4u3yoik9ZwfOBMIU+UljM0C+j7EM9K3jWuv1/u2UG5hYVDXu3ALWpg6vnMLlcfGGN9nrZTckt/sVOcclSrVSxIsFSWM35jBPXq9w+uNErS1D/mVqikcO8HI3NDdowins4HHPbXuIx+cloXnsbmpAjGpbYOs166vElvIyohfb0zM+bCuG6oBI26Eit5XpVx/rvjZNNN43lLk4JGhp1XF0IHh4n9JWH2T5Hmi4i7HZ0CgYEAz30VodORsFvct67vijo4R/JLGgHmqUMbmdWq8O4NVaiWzeb65tZZr/KZSzq+A9nxsGYG6oMYkKL3qws6sIBB3r/L24Nrq29+Tvws1L0rVEdRnO2npReahfSTdfroL1/yZ4FcI8S6GkBm5Ehtw5Qecj6ouomifAXjEYtKWrAtxfsCgYEA6/Rl+CIXVYthgFPouyBK5AxGD5NsKPDyG3yf8/V7q0AyzggEQCE0w+MbnRes1w3k9URHlvbbrcW7WJgEAVVKbJRs5IfEqV3ijO8LoVMu7MwVWxKw0GBVDYAe3Y/v6bzIjWEy0a46d+pGdsrixAafZY1Bdpqm8Jfjez4CRCA99fsCgYAqkdlMWGH9svs33HZc/9DoQffSoC048QHKsCHgSJcHyg0WtZsonTXNeZKl8qlllOOXc3dbygXSNv1lZGpoKAhbsTIcGXyPsdJSVj7EbwNiyTcfYUsR/iO/9AwFGrNkdOUBA3NqC0S7ehciIxISHGOawOxRSUfC9lo+ETvyG09o3QKBgAx/KjNlItU+B5DzYL0gbbb8S22hwjW85SW9iP8zvjQIt2ggFpGK8K97RMgiK95L9xdiYWRGeMYQVebQTk3/xWxQxB+qbSkHNut98aC+thqGiI8FQ2YV5AtOANR9PhikDf8m6bkfQCt/tfGutynoq+KGA7STZkoR0VOCqj4PcxinAoGATXGeSxQow9sXhJrYtZ7VJ+uKNUJDSlBw0ki4dr05TNS6PphhMkiIMQKfJT6vV/VrDNIr9DC+tX36wZnDSOMD1vTdJqbpIUT9hBDuIPuQ8KKyDsEcbFUTvr4S9BZK47sdXLqaAZdYOPSG5Dc3aVMIW3vkxWnLf+ieoImUO64aglM=";
+
+ public static final String public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnRh8MAqfpBZffouPsU3hToRZl3soo2ntYU4psQtc72QOvnprQ6Ua6UBY0WqemCJF/KxQ8p+vY7/r5eZ97Fw7Sq40PQTNKvyxFQuMGRAO8xTahSn2/79KViq7mVVLm2UAH8QaFmq7rJJbkCif3I1yiFMqzOF41ak231GF8eD62gr9+DFLiR1UKjv+/qXG4UjFQM6pa0cD1kAOsoYz0dSQlHFMbOaVf+VEWxSqFjKPiep6bYoViTlMRkdLqbUbHr/xk67C8lGqWO7wnB32T0+fYwnFWF952OJ9kov9oSnvOFXa+NwlAe7m2hZtFnW/NoBX1WxkQ6zTTTxJb8sRNft7qQIDAQAB";
+ public static final String private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCdGHwwCp+kFl9+i4+xTeFOhFmXeyijae1hTimxC1zvZA6+emtDpRrpQFjRap6YIkX8rFDyn69jv+vl5n3sXDtKrjQ9BM0q/LEVC4wZEA7zFNqFKfb/v0pWKruZVUubZQAfxBoWaruskluQKJ/cjXKIUyrM4XjVqTbfUYXx4PraCv34MUuJHVQqO/7+pcbhSMVAzqlrRwPWQA6yhjPR1JCUcUxs5pV/5URbFKoWMo+J6nptihWJOUxGR0uptRsev/GTrsLyUapY7vCcHfZPT59jCcVYX3nY4n2Si/2hKe84Vdr43CUB7ubaFm0Wdb82gFfVbGRDrNNNPElvyxE1+3upAgMBAAECggEAOcphHRc7ZRSp6paStMoOoWDEyJoQ+BSms84aPjwM4y/u0JmeThM11CrMwbU0RIkPMAV//dFKpypaMIfbOREw6qctJmlWxIKS7kgCMNIcfcXlIWmvqKOJSCuOObkMCE1ef1EXu7ll8vUgY+bd8DfEs2vM6fPkDM2kFwEZgkKeZYlkFcLLy8V701seLtNzbPaqAUa44S6m0DVH7gojad8+Ni/XsdNzSrd8Y2930M8LVZoOTLrwskJaF2v/WvjM3blOtHxLqDfXfD4uRm12b1SNzPx2djlL6vNptwbpYAtPOYol8W0LxJH2AHbTrUFv/KJdyuD4NVGSnGpYtWzD7QQetQKBgQDLqfaiq0uHQerAc3M30pOZSDF8PtiBd1jdqFoOVhuADkp4LPXm54s5evEi2r3tl4x8cAvUo6WaxDlG3IFO0POLcZY+Xf2sMhwMAxiwWqLVRGirjr6QAfnmWAToqqyh8brxNti4MC3X/yudrd6x/VJ1lQ3Pooiihf4Ir74QuY7wqwKBgQDFdwbFou07bQmxCElgC5MF78Aevn5JzsniGU2RhpxG7ajf2T9n6AjtVfvYLy6iYsfLm6RGC2uofBjMgL920ePXBSDv0fk1UEVoR/vCtspyCLBVXELdSS5DCnux1F15vKAJZQyODGyEv0d8h97qKRaq14EW75e9vPx4ahxXgaiM+wKBgGE0AonK9aZdmJw3veMDtvxuj2e8WvsXqitIwYqcIE3zBCntU4PcOP+7JMG84u816JAvrgXUASMnyip+7ZxfcA26rbmghIUd+XLmO29YIuVk3AwdeegjeVEt61Hcu74jMFUWF0N5gzfXCsscA/Cxdhy2gjv6V/oxt3gP4Mf8uDM3AoGAJMVhcXRBkQtg/qJ4Z3ZATp6yvAblJYFofr4Pf8X9XAftpqGh+QtwfiHA4CUJHhwe8H9vO8vspFdXlt1yygGT1/qQg5gqPA9SnXSqITxAvrN3gq3HlcWG490T462UKpNBif5TNDCEFMQ536q9jAVSv0WaOFctfpuuuA2qcXEnnfkCgYEAuFWzis7ICtcZTr8CZOC7FeVL6URzI1akwRlHDHRUrNRCTf47HGUG9bCC6N+v6ex7TD2XlaB0g3U9XXjYRyk9T2AWfgzPvgvw7H+tI9r+9yyDlUbb2pvaKdVQIgCnJ6Hg7Qw7MuwzjEiXLF7HMy5CFnrVnHAjYrNe1Gqgo0v3rsY=";
+
+
+ //湛江运行巡检
+ //public static final String public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhpRgDGj3dk8kaNnnQIJ6YjbaEDBYEzDkv3qR3a55odU4/fJ3LFtGQfHM7LzQ3bpYaC8cZiYAu0ByPENW0G7HzVmxPfKdbLZtrRe+9kH8Fm+M2B26/XZd9QfT9+F2NQtFq68UA6yV5Z4wvxDjp2ZEzVjd+6ODQHuxf5JzySyWtgg844sHdB47iSdC06PnDfjLGMp3AtYeCbQH1mNOjuV44vbiccoTP3gCLnm9BS9Ez4F0fM04kTnCLpOdphJub341gUUnuoFbo+CGrnM5NfwXnw1MUkl5H25BHwK4So/L9DwbBsktiFOuzC8L4DuWvJJSLZnKXIXmPGoRVqTe5zCMkQIDAQAB";
+ //public static final String private_key = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCGlGAMaPd2TyRo2edAgnpiNtoQMFgTMOS/epHdrnmh1Tj98ncsW0ZB8czsvNDdulhoLxxmJgC7QHI8Q1bQbsfNWbE98p1stm2tF772QfwWb4zYHbr9dl31B9P34XY1C0WrrxQDrJXlnjC/EOOnZkTNWN37o4NAe7F/knPJLJa2CDzjiwd0HjuJJ0LTo+cN+MsYyncC1h4JtAfWY06O5Xji9uJxyhM/eAIueb0FL0TPgXR8zTiROcIuk52mEm5vfjWBRSe6gVuj4Iauczk1/BefDUxSSXkfbkEfArhKj8v0PBsGyS2IU67MLwvgO5a8klItmcpcheY8ahFWpN7nMIyRAgMBAAECggEAPkrplnTzrlh9subByrNacKGRGBM4gVGNYDAc2m6LMGRgp/MWRHrPL3D7+MyBJVC+4SKFU6bdic8P0WMeCQZuB1gv2Uu2oH5kj81A//2U8NGbcOF6Dx496VBBRiifLXhVPF2itvyouYsaZyYrKe4FhMNQpMyP0UYv56vjWkgATqsbFmx2K8FLSGwpBvYys57gy4Evtep0yLTel6E4mnkQVdfTXnA7zylMn5Xz6Mk8u6H6o+Zhfxugw8/+CS9cDSCNxX0ZN8xgqONNtrHpAsM+AWbHuim89HnoVq2RrkHVnjCTXd2IG2Hs+lO7t7GYk3bqLwlpaupmR4rnOI+R+Rf3TQKBgQDpnMAY9l5Ro+r+SR7UjN+tSMBBX3S764NTAE0kNUSB3iBQnuLY60ziqbEbAupSFBnbkshWIVGaKdN6szH9lpoMSEyEWrN/EYY46WxFC6MT4iqvtl3Trqu/7h0DrjWsSY9e8ja8Zpv0lb7B8IEUiydeTfdkA+oTu4igz8gRs+BpuwKBgQCTegnoVlf15fLx8Czeo54YouHnD5fxzx5svsvXIFarMcQ89UMcUw/gBh3QGvx4BS6DUctitzmAeTQkQVtjVQZ3gNTMwILcB4NWibHursnsWQB6BIcRbww9FSIpARXPbXS2FbqjN+3aS8REEVJrIOPP2PQ62SeQSnA/eZBy1DjIIwKBgD4prtg1nq18v8hAbsrCXba/mCENJIPozH4mo2BSKFOiZtjtHpH4MvJRk0YLxYxnuuW5rkN1BEDQhmytCE1haMaB6pKBjCfw4tV8D4pj6VYeJZuyHE96uEsPMntLPQ8GV/c83qHNcAxqWGNE+yQbTzOB7aWYgQ4VJescvzEuuzWHAoGAZiUQ16t2IQqzyn7flRUeW1H1xWQ3iXQ7TnaYGNh9LvW5Rb9aTDP7ut6Bp7IJS9fK74mnpSfi2+kXBEWAVrx9TigdO/ParytE/JtCcl793IWInvqj0p9niqcokd3+jTzyqWtDaelDBP+VYM/elfSh1UQfZOMjU/064bwBIId9DKECgYBYXBe6oU7QiMYxa3YwAi9CcY9HXX6HRF4MpzOsOQ8wer8uJi6ca2th+jssz4SMeYZHnb7Ae+aORD7X+LefVuQiolwigAeTFgDihveb6WgxkKMarbqO8Ww7+laoGQjHvMQMTSkzt6KyhzeNu3F7Ma5HZkfCqwPAHzTOunGWUosRvg==";
+
+
+ public static byte[] decryptBASE64(String key) throws Exception {
+ return Base64.getDecoder().decode(key.getBytes());
+ }
+
+ public static String encryptBASE64(byte[] key) throws Exception {
+ return Base64.getEncoder().encodeToString(key);
+ }
+
+ /**
+ * 解密
+ * 用私钥解密
+ *
+ * @param data
+ * @param key
+ * @return
+ * @throws Exception
+ */
+ public static byte[] decryptByPrivateKey(byte[] data, String key)
+ throws Exception {
+ // 对密钥解密
+ byte[] keyBytes = decryptBASE64(key);
+ // 取得私钥
+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA);
+ Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
+ // 对数据解密
+ Cipher cipher = Cipher.getInstance(ECB_None_PKCS1_PADDING);
+ cipher.init(Cipher.DECRYPT_MODE, privateKey);
+ return cipher.doFinal(data);
+ }
+
+ /**
+ * 私钥分段解密
+ * @param encryptedData
+ * @param privateKey
+ * @return
+ * @throws Exception
+ */
+ public static byte[] decryptByPrivateKeyLongText(byte[] encryptedData, String privateKey) throws Exception {
+
+ byte[] keyBytes = decryptBASE64(privateKey);
+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA);
+ Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
+ Cipher cipher = Cipher.getInstance(ECB_None_PKCS1_PADDING);
+ cipher.init(Cipher.DECRYPT_MODE, privateK);
+
+ int inputLen = encryptedData.length;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int offSet = 0;
+ byte[] cache;
+ int i = 0;
+ // 对数据分段解密
+ while (inputLen - offSet > 0) {
+ if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
+
+ cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
+ } else {
+ cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
+ }
+ out.write(cache, 0, cache.length);
+ i++;
+ offSet = i * MAX_DECRYPT_BLOCK;
+ }
+ byte[] decryptedData = out.toByteArray();
+ out.close();
+ return decryptedData;
+ }
+
+ /**
+ * 解密
+ * 用公钥解密
+ *
+ * @param data
+ * @param key
+ * @return
+ * @throws Exception
+ */
+ public static byte[] decryptByPublicKey(byte[] data, String key)
+ throws Exception {
+ // 对密钥解密
+ byte[] keyBytes = decryptBASE64(key);
+ // 取得公钥
+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA);
+ Key publicKey = keyFactory.generatePublic(x509KeySpec);
+ // 对数据解密
+ Cipher cipher = Cipher.getInstance(ECB_None_PKCS1_PADDING);
+ cipher.init(Cipher.DECRYPT_MODE, publicKey);
+ return cipher.doFinal(data);
+ }
+
+ /**
+ * 用公钥分段解密
+ * @param encryptedData
+ * @param publicKey
+ * @return
+ * @throws Exception
+ */
+ public static byte[] decryptByPublicKeyLongText(byte[] encryptedData, String publicKey) throws Exception {
+
+ byte[] keyBytes = decryptBASE64(publicKey);
+
+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
+
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA);
+
+ Key publicK = keyFactory.generatePublic(x509KeySpec);
+
+ Cipher cipher = Cipher.getInstance(ECB_None_PKCS1_PADDING);
+
+ cipher.init(Cipher.DECRYPT_MODE, publicK);
+
+ int inputLen = encryptedData.length;
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ int offSet = 0;
+
+ byte[] cache;
+
+ int i = 0;
+
+ // 对数据分段解密
+
+ while (inputLen - offSet > 0) {
+
+ if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
+
+ cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
+
+ } else {
+
+ cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
+
+ }
+
+ out.write(cache, 0, cache.length);
+
+ i++;
+
+ offSet = i * MAX_DECRYPT_BLOCK;
+
+ }
+
+ byte[] decryptedData = out.toByteArray();
+
+ out.close();
+
+ return decryptedData;
+
+ }
+
+
+ /**
+ * 加密
+ * 用公钥加密
+ *
+ * @param data
+ * @param key
+ * @return
+ * @throws Exception
+ */
+ public static byte[] encryptByPublicKey(byte[] data, String key)
+ throws Exception {
+ // 对公钥解密
+ byte[] keyBytes = decryptBASE64(key);
+ // 取得公钥
+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA);
+ Key publicKey = keyFactory.generatePublic(x509KeySpec);
+ // 对数据加密
+ Cipher cipher = Cipher.getInstance(ECB_None_PKCS1_PADDING);
+ cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+ return cipher.doFinal(data);
+ }
+
+ /**
+ * 用公钥分段加密
+ * @param data
+ * @param publicKey
+ * @return
+ * @throws Exception
+ */
+ public static byte[] encryptByPublicKeyLongText(byte[] data, String publicKey) throws Exception {
+
+ byte[] keyBytes = decryptBASE64(publicKey);
+
+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
+
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA);
+
+ Key publicK = keyFactory.generatePublic(x509KeySpec);
+
+ // 对数据加密
+
+ Cipher cipher = Cipher.getInstance(ECB_None_PKCS1_PADDING);
+
+ cipher.init(Cipher.ENCRYPT_MODE, publicK);
+
+ int inputLen = data.length;
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ int offSet = 0;
+
+ byte[] cache;
+
+ int i = 0;
+
+ // 对数据分段加密
+
+ while (inputLen - offSet > 0) {
+
+ if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
+
+ cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
+
+ } else {
+
+ cache = cipher.doFinal(data, offSet, inputLen - offSet);
+
+ }
+
+ out.write(cache, 0, cache.length);
+
+ i++;
+
+ offSet = i * MAX_ENCRYPT_BLOCK;
+
+ }
+
+ byte[] encryptedData = out.toByteArray();
+
+ out.close();
+
+ return encryptedData;
+
+ }
+
+ /**
+ * 加密
+ * 用私钥加密
+ *
+ * @param data
+ * @param key
+ * @return
+ * @throws Exception
+ */
+ public static byte[] encryptByPrivateKey(byte[] data, String key)
+ throws Exception {
+ // 对密钥解密
+ byte[] keyBytes = decryptBASE64(key);
+ // 取得私钥
+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA);
+ Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
+ // 对数据加密
+ Cipher cipher = Cipher.getInstance(ECB_None_PKCS1_PADDING);
+ cipher.init(Cipher.ENCRYPT_MODE, privateKey);
+ return cipher.doFinal(data);
+ }
+
+ /**
+ * 用私钥分段加密
+ * @param data
+ * @param privateKey
+ * @return
+ * @throws Exception
+ */
+ public static byte[] encryptByPrivateKeyLongText(byte[] data, String privateKey) throws Exception {
+
+ byte[] keyBytes = decryptBASE64(privateKey);
+
+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA);
+
+ Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
+
+ Cipher cipher = Cipher.getInstance(ECB_None_PKCS1_PADDING);
+
+ cipher.init(Cipher.ENCRYPT_MODE, privateK);
+
+ int inputLen = data.length;
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ int offSet = 0;
+
+ byte[] cache;
+
+ int i = 0;
+
+ // 对数据分段加密
+
+ while (inputLen - offSet > 0) {
+
+ if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
+
+ cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
+
+ } else {
+
+ cache = cipher.doFinal(data, offSet, inputLen - offSet);
+
+ }
+
+ out.write(cache, 0, cache.length);
+
+ i++;
+
+ offSet = i * MAX_ENCRYPT_BLOCK;
+
+ }
+
+ byte[] encryptedData = out.toByteArray();
+
+ out.close();
+
+ return encryptedData;
+
+ }
+
+ /**
+ * 取得私钥
+ *
+ * @param keyMap
+ * @return
+ * @throws Exception
+ */
+ public static String getPrivateKey(Map keyMap)
+ throws Exception {
+ Key key = (Key) keyMap.get(PRIVATE_KEY);
+
+ return encryptBASE64(key.getEncoded());
+ }
+
+ /**
+ * 取得公钥
+ *
+ * @param keyMap
+ * @return
+ * @throws Exception
+ */
+ public static String getPublicKey(Map keyMap)
+ throws Exception {
+ Key key = (Key) keyMap.get(PUBLIC_KEY);
+ return encryptBASE64(key.getEncoded());
+ }
+
+ /**
+ * 初始化密钥
+ *
+ * @return
+ * @throws Exception
+ */
+ public static Map initKey() throws Exception {
+ KeyPairGenerator keyPairGen = KeyPairGenerator
+ .getInstance(RSA);
+ keyPairGen.initialize(DEFAULT_KEY_SIZE);
+ KeyPair keyPair = keyPairGen.generateKeyPair();
+ // 公钥
+ RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+ // 私钥
+ RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
+ Map keyMap = new HashMap(2);
+ keyMap.put(PUBLIC_KEY, publicKey);
+ keyMap.put(PRIVATE_KEY, privateKey);
+ return keyMap;
+ }
+
+ public static void main(String[] args) {
+ try {
+ Map key = RSAUtils.initKey();
+ String publicKey = RSAUtils.getPublicKey(key);
+ String privateKey = RSAUtils.getPrivateKey(key);
+ //String signbypub = RSAUtils.encryptBASE64(RSAUtils.encryptByPublicKeyLongText("310482".getBytes(),RSAUtils.public_key));
+ String text = "JAVA利用RSA加密算法的长度限制问题解决方案注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。 RSA加密对明文的长度是有限制的JAVA利用RSA加密算法的长度限制问题解决方案注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。 RSA加密对明文的长度是有限制的JAVA利用RSA加密算法的长度限制问题解决方案注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。 RSA加密对明文的长度是有限制的。JAVA利用RSA加密算法的长度限制问题解决方案注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。 RSA加密对明文的长度是有限制的JAVA利用RSA加密算法的长度限制问题解决方案注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。 RSA加密对明文的长度是有限制的JAVA利用RSA加密算法的长度限制问题解决方案注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。 RSA加密对明文的长度是有限制的.JAVA利用RSA加密算法的长度限制问题解决方案注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。 RSA加密对明文的长度是有限制的JAVA利用RSA加密算法的长度限制问题解决方案注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。 RSA加密对明文的长度是有限制的JAVA利用RSA加密算法的长度限制问题解决方案注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。 RSA加密对明文的长度是有限制的";
+
+ String signbypub = RSAUtils.encryptBASE64(RSAUtils.encryptByPublicKeyLongText(text.getBytes(StandardCharsets.UTF_8),RSAUtils.public_key));
+ //String signbypub ="GAMWcUb/Sv2QL/z8Uo1yA0907QCiZjTVLc6+wTqdM/XvRiX3RjgVeIfe0KK0H+4jnw658HTQZEVQJ4+o5SCccgJHyCJNwtYE0ZgaX0rRY/XUhqQJUDFJ/Ie2e12k+8aJzMcIBxV/rQJUSF+7cy1g5h78b4I3A3ckqWeGX1e3DXLt0kSPkmJ4yb6nMLJ+C1s6aj4vc17NnpSvlPCeY1p7GIy+P4OJjUD2RMeIY8bTRXceiGZQESJKtOjuhrVhpbw5v8EhZU/VRwNhI6Wq1apNAtM/dUfdGuLtat9txA+oWoBW+Q+UUVSu9a6wm9lfenjrXrk7ko/9qu7SvbB9OAVmi3ozzlphsZAcg/5RUYE+ePqdCkidrE+/n/Jf/dU2HapBPix9/qmjFeZdakHedV9mDyPcYBJe9IBRBkDruwrn/PTitDuOCrCV15ZPw5JaW2DEf+HIyobZaZ60HndYI/YU7dFVbha7EqF7lJt791zPfgYZyp0ftVyUb9K+ZKaxp2xia1VAZfq2oCRkQJa9+G2ACCpqkKGHjBZswhdkcvvQkPtYn3APaAORFmvW3vjMARLHAzTP2H4qyzgvLue1otmzHz7OfIxQqoodx89lasQEdilTFCIqzSbeIZB+3yb/WjvwgTVDw3ZGRm3Sm/C+Id5Y/dwPwn8aM1OTeXTNV0nijIkFFGXaMSPCKKzXTH4L+SDzITbruAOWvIZYnCOpJnEQx555y548clApDRvYws1DT7CruHJ22ik9hI1W8irb7C/lzJsmwQHXcxYaK+seEZIR02hv5Gb6TPQLAxPIiO0DOARVF+fMDR+w7tWDTyMruZH4+iYUsK7F4F3TmufBtiHlPKnGjSscfdHoMqDdNjzQodh2B+NN+ZzD/5CAjNq7LRx4umkZ3PHGP82Y1XJtn6cGgyyv8ofPYQqkGKag9rSiSMs9O3cT524cSN/zBkWiyMaTp3VyS1nK+q/EEBO2J7mfBN6hkjx6+mCjGF6yDFbO3mb5Ry3+WqN88fi4k9V/N3eWI2tDQMeMmd43qJr+Lm037hYW4nkUkyHL9eOyiGHk0/KTrnOFM5wvPsPWoaOSHKfUehD9bFGvWevBZAqaR2qMbchmo3ruQh62Z13chpP2MTO+v3YqBPziPeJP3wH2d2VofanzG0Ka6MEgT32RF84HwFAsmqKS6YEipwtjVaMS76UvZc1hhhXbO2lFLpatBb06Y3imgUng3ZNa0exXXE8gcZuY3n8hPkl0iw+vH40cm07ZwokCtrYs98mPwoQGmGc99T2UripJzPt2lN9BKmu5nFxVs5skunKg5yMvgclvNxzznpjkuf7zocpoRBNyQiT2hr7ZoltHYmP+2KdFlSiRcy1uLqYugttyflWmCrDt6OvkfLPrDfVrBS9Pevq/PDxRwaLYqhmAPrD0L5bV+IeXkmupMYoJ3McbiV/+otU3pYdHdoK5i78VjucxOLIrYSxsGXEOuphbzMopwwynlf3KDMndY2CSa+aVsthsF3Ogm5NHtqIKpjJ1rdHj/5TaQWZlFC2VQfli4sRVlGmcM9Ys46QiNm/qOP/+VCc2FjhIry5IqcLs2rizYbZXD6Tv/WEXzL/pHcl+/9zdS8kgtQSKjTCSehngy0cLDhTv7D02vh+XOV4K0tgDUuBgkQfnODQ4+IMXmeUonP6xb+hvaiscTBczgNyzPhwP2AwcDkBWa2E=";
+
+
+ byte[] decodeByte = RSAUtils.decryptBASE64(signbypub);
+ String decodeStr = new String(RSAUtils.decryptByPrivateKeyLongText(decodeByte,RSAUtils.private_key));
+ System.out.println("-----------公钥------------");
+ System.out.println(publicKey);
+ System.out.println("长度:"+publicKey.length());
+ System.out.println("-----------私钥------------");
+ System.out.println(privateKey);
+ System.out.println("长度:"+privateKey.length());
+ System.out.println("-----------公钥加密------------");
+ System.out.println(signbypub);
+ System.out.println("长度:"+signbypub.length());
+ System.out.println("-----------私钥解密------------");
+ System.out.println(decodeStr);
+ System.out.println("长度:"+decodeStr.length());
+ System.out.println(MAX_ENCRYPT_BLOCK);
+ System.out.println(MAX_DECRYPT_BLOCK);
+
+
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAUtilsJavaToDotNet.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAUtilsJavaToDotNet.java
new file mode 100644
index 0000000..5f7e68f
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/rsa/RSAUtilsJavaToDotNet.java
@@ -0,0 +1,4 @@
+package com.rehome.mqtt01.rsa;
+
+public class RSAUtilsJavaToDotNet {
+}
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ssl/MqttSSLPublishServer.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ssl/MqttSSLPublishServer.java
new file mode 100644
index 0000000..d94d2b4
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ssl/MqttSSLPublishServer.java
@@ -0,0 +1,175 @@
+package com.rehome.mqtt01.ssl;
+
+/**
+ * @author huangwenfei
+ * @version v1.0.0.0
+ * Created DateTime 2021-07-31 14:52
+ * @description: mqtt 高可靠,断线重连 消息发布服务
+ */
+
+import org.apache.commons.io.FileUtils;
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+import java.io.File;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class MqttSSLPublishServer {
+ /**
+ * 代理服务器ip地址
+ */
+ private final String HOST = "ssl://39.101.173.20:8883";
+ /**
+ * 订阅主题
+ */
+ private final String topic = "push";
+ /**
+ * 客户端唯一标识,相同的会被逼下线
+ */
+ private String clientid = "v1_server_ssl_002";
+ private MqttClient client;
+ private MqttConnectOptions options;
+ /**
+ * MQTT服务端连接账号
+ */
+ private final String userName = "admin";
+ /**
+ * MQTT服务端连接密码
+ */
+ private final String passWord = "public";
+ /**
+ * 消息发布质量
+ * 0:最多一次,即:<=1
+ * 1:至少一次,即:>=1
+ * 2:一次,即:=1
+ */
+ private int qos = 2;
+ // 推送消息
+ private MqttMessage message;
+ //定时器
+ private Timer timer;
+
+ public MqttSSLPublishServer() {
+ // host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
+ try {
+ client = new MqttClient(HOST, clientid, new MemoryPersistence());
+ // MQTT的连接设置
+ options = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
+ options.setCleanSession(true);
+ // 设置连接的用户名
+ options.setUserName(userName);
+ // 设置连接的密码
+ options.setPassword(passWord.toCharArray());
+ // 设置超时时间 单位为秒
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ options.setKeepAliveInterval(20);
+ //双向验证
+ InputStream inputStream1 = MqttSSLPublishServer.class.getClassLoader().getResourceAsStream("ssl_two_dir/client.pem");
+ InputStream inputStream2 = MqttSSLPublishServer.class.getClassLoader().getResourceAsStream("ssl_two_dir/client.key");
+ InputStream inputStream3 = MqttSSLPublishServer.class.getClassLoader().getResourceAsStream("ssl_two_dir/my_root_ca.pem");
+
+ File caClientFile = new File("client.pem");
+ File keyClientFile = new File("client.key");
+ File caServerFile = new File("my_root_ca.pem");
+
+ // 使用common-io的工具类即可转换
+ FileUtils.copyToFile(inputStream1,caClientFile);
+ // 使用common-io的工具类即可转换
+ FileUtils.copyToFile(inputStream2,keyClientFile);
+ // 使用common-io的工具类即可转换
+ FileUtils.copyToFile(inputStream3,caServerFile);
+
+ System.err.println("path4:" + caClientFile.getAbsolutePath());
+ System.err.println("path4:" + keyClientFile.getAbsolutePath());
+ System.err.println("path4:" + caServerFile.getAbsolutePath());
+ options.setSocketFactory(SslUtil.getSocketFactory(caServerFile.getAbsolutePath(),
+ caClientFile.getAbsolutePath(), keyClientFile.getAbsolutePath(), ""));
+
+ // 发布目的消息对象
+ message = new MqttMessage();
+ // 设置回调
+ client.setCallback(new MqttCallback() {
+
+ public void connectionLost(Throwable cause) {
+ System.out.println("connectionLost---------");
+ stop();//关闭
+ }
+
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ System.out.println("***** get message start *****");
+ System.out.println(new Date());
+ System.out.println("topic:" + topic);
+ System.out.println("Qos:" + message.getQos());
+ System.out.println("message:" + new String(message.getPayload()));
+ System.out.println("***** get message end *****");
+ System.out.println();
+ }
+
+ public void deliveryComplete(IMqttDeliveryToken token) {
+ System.out.println("deliveryComplete---------" + token.isComplete());
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void start() {
+ try {
+ timer = new Timer();
+ timer.schedule(new TimerTask() {
+ public void run() {
+ System.out.println("-------设定要指定任务--------");
+ message.setQos(qos);
+ message.setRetained(true);
+ SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String time = "message from server->:"+clientid+"->:"+sd.format(new Date());
+ message.setPayload(time.getBytes());
+ try {
+ //判断拦截状态,这里注意一下,如果没有这个判断,是非常坑的
+ if (!client.isConnected()) {
+ System.out.println("***** 没有连接到服务器 *****");
+ System.out.println("***** client to connect *****");
+ // 重新连接
+ client.connect(options);
+ }
+ if (client.isConnected()) {//连接成功,跳出连接
+ System.out.println("***** connect success *****");
+ System.out.println(time);
+ // 发布消息
+ client.publish(topic, message);
+ }
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }, 10000,10000);
+ // 设定指定的时间time,此处为10000毫秒
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void stop() {
+ try {
+ // 断开连接
+ client.disconnect();
+ // 关闭客户端
+ client.close();
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ // 推送消息
+ MqttSSLPublishServer mqttPublishServer = new MqttSSLPublishServer();
+ mqttPublishServer.start();
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ssl/MqttSslAsyncClient.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ssl/MqttSslAsyncClient.java
new file mode 100644
index 0000000..a773f04
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ssl/MqttSslAsyncClient.java
@@ -0,0 +1,487 @@
+package com.rehome.mqtt01.ssl;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.http.util.TextUtils;
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ResourceUtils;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimerTask;
+import java.util.Timer;
+
+public class MqttSslAsyncClient extends JFrame implements ActionListener {
+ private JPanel contentPane;
+ private Font useFont = new Font("微软雅黑", Font.BOLD, 12);
+ private JFormattedTextField frmserverIP;
+ private JFormattedTextField username;
+ private JButton button_connect;
+ private JButton button_disconnect;
+ private JFormattedTextField toptic_input;
+ private JFormattedTextField toptic_titile;
+ private JFormattedTextField send_msg_text;
+ private JLabel err_infoText;
+ private JComboBox comboBox;
+ private JButton sendbutton;
+ private JTextArea msgtextArea;
+ private String brokerIP;
+ private String clientId;
+ private String msgContent;
+ private String msgSendContent;
+ private String sub_topic, pub_topic;
+ private Boolean isSubject = false;
+ private Boolean isConnetc = false;
+ private Timer timer;
+ /**
+ * 消息发布质量
+ * 0:最多一次,即:<=1
+ * 1:至少一次,即:>=1
+ * 2:一次,即:=1
+ */
+ private int qos = 0;
+ private MqttAsyncClient sampleClient;
+ private MqttConnectOptions connOpts;
+ private String infoList = "";
+ private JButton subbutton;
+ private JButton noSubbutton;
+
+ /**
+ * MQTT服务端连接账号
+ */
+ private final String userName = "admin";
+ /**
+ * MQTT服务端连接密码
+ */
+ private final String passWord = "public";
+
+
+ public MqttSslAsyncClient() {
+ // 设置窗体大小位置
+ setBounds(100, 100, 484, 439);
+ setTitle("MQTT客户端");
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ contentPane = new JPanel();
+ contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
+ contentPane.setLayout(null);
+ setContentPane(contentPane);
+ //添加控件
+ JLabel lblMqtt = new JLabel("MQTT服务器地址:");
+ lblMqtt.setFont(useFont);
+ lblMqtt.setBounds(30, 10, 109, 15);
+ contentPane.add(lblMqtt);
+
+ frmserverIP = new JFormattedTextField();
+ frmserverIP.setText("ssl://192.168.2.111:8883");
+ frmserverIP.setBounds(139, 7, 258, 21);
+ contentPane.add(frmserverIP);
+
+ JLabel lblNewLabel = new JLabel("用户名:");
+ lblNewLabel.setFont(useFont);
+ lblNewLabel.setBounds(40, 41, 54, 15);
+ contentPane.add(lblNewLabel);
+
+ username = new JFormattedTextField();
+ username.setText("v1_server_timemqtt_ssl");
+ username.setBounds(139, 38, 199, 21);
+ contentPane.add(username);
+
+ button_connect = new JButton("连 接");
+ button_connect.setBounds(30, 66, 93, 23);
+ button_connect.setFont(useFont);
+ button_connect.addActionListener(this);
+ button_connect.setActionCommand("connect");
+ contentPane.add(button_connect);
+
+ button_disconnect = new JButton("断 开");
+ button_disconnect.setEnabled(false);
+ button_disconnect.setFont(useFont);
+ button_disconnect.addActionListener(this);
+ button_disconnect.setActionCommand("disconnect");
+ button_disconnect.setBounds(263, 66, 93, 23);
+ contentPane.add(button_disconnect);
+
+ JLabel label = new JLabel("订阅主题:");
+ label.setBounds(40, 111, 83, 15);
+ label.setFont(useFont);
+ contentPane.add(label);
+
+ toptic_input = new JFormattedTextField();
+ toptic_input.setText("push");
+ toptic_input.setBounds(100, 108, 99, 21);
+ contentPane.add(toptic_input);
+
+ JSeparator separator = new JSeparator();
+ separator.setBackground(Color.GREEN);
+ separator.setBounds(30, 99, 367, 2);
+ contentPane.add(separator);
+
+ subbutton = new JButton("订 阅");
+ subbutton.setFont(useFont);
+ subbutton.addActionListener(this);
+ subbutton.setActionCommand("sub");
+ subbutton.setBounds(193, 107, 83, 23);
+ contentPane.add(subbutton);
+
+ noSubbutton = new JButton("取消订阅");
+ noSubbutton.setFont(useFont);
+ noSubbutton.addActionListener(this);
+ noSubbutton.setActionCommand("noSub");
+ noSubbutton.setBounds(276, 107, 83, 23);
+ noSubbutton.setEnabled(false);
+ contentPane.add(noSubbutton);
+
+ JSeparator separator_1 = new JSeparator();
+ separator_1.setBounds(30, 139, 367, 2);
+ contentPane.add(separator_1);
+
+ JLabel label_1 = new JLabel("发布消息");
+ label_1.setFont(useFont);
+ label_1.setBounds(40, 151, 60, 15);
+ contentPane.add(label_1);
+
+ JLabel label_2 = new JLabel("主题");
+ label_2.setFont(useFont);
+ label_2.setBounds(104, 151, 30, 15);
+ contentPane.add(label_2);
+
+ toptic_titile = new JFormattedTextField();
+ toptic_titile.setText("push");
+ toptic_titile.setBounds(139, 148, 99, 21);
+ contentPane.add(toptic_titile);
+
+ JLabel label_3 = new JLabel("服务质量");
+ label_3.setFont(useFont);
+ label_3.setBounds(248, 151, 64, 15);
+ contentPane.add(label_3);
+
+ comboBox = new JComboBox();
+ comboBox.setBounds(305, 148, 64, 21);
+ comboBox.addItem("0");
+ comboBox.addItem("1");
+ comboBox.addItem("2");
+ comboBox.setSelectedItem("2");
+ contentPane.add(comboBox);
+
+ JLabel label_send = new JLabel("发布的消息内容");
+ label_send.setFont(useFont);
+ label_send.setBounds(40, 181, 100, 15);
+ contentPane.add(label_send);
+
+ send_msg_text = new JFormattedTextField();
+ send_msg_text.setText("MQTT客户端 发送消息 -->");
+ send_msg_text.setBounds(140, 179, 220, 21);
+ contentPane.add(send_msg_text);
+
+ sendbutton = new JButton("发 送");
+ sendbutton.setBounds(46, 378, 93, 23);
+ sendbutton.addActionListener(this);
+ sendbutton.setActionCommand("send");
+ contentPane.add(sendbutton);
+
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.setBounds(40, 219, 316, 149);
+ contentPane.add(scrollPane);
+
+ msgtextArea = new JTextArea();
+ scrollPane.setViewportView(msgtextArea);
+
+ err_infoText = new JLabel("");
+ err_infoText.setForeground(Color.RED);
+ err_infoText.setBounds(134, 69, 131, 15);
+ err_infoText.setFont(useFont);
+ contentPane.add(err_infoText);
+
+ JButton btnClear = new JButton("clear");
+ btnClear.setBounds(209, 378, 93, 23);
+ btnClear.addActionListener(this);
+ btnClear.setActionCommand("clear");
+ contentPane.add(btnClear);
+
+
+ }
+
+
+
+ private void start() {
+ try {
+ timer = new Timer();
+ timer.schedule(new TimerTask() {
+ public void run() {
+ System.out.println("-------设定要指定任务--------");
+ if (isConnetc == true) {
+ try {
+ //判断拦截状态,这里注意一下,如果没有这个判断,是非常坑的
+ if (!sampleClient.isConnected()) {
+ System.out.println("***** 没有连接到服务器 *****");
+ System.out.println("***** client to connect *****");
+ // 重新连接
+ sampleClient.connect(connOpts);
+ }
+ if (sampleClient.isConnected()) {//连接成功,跳出连接
+ System.out.println("***** connect success *****");
+ System.out.println("Connected");
+ err_infoText.setText("已连接");
+ button_disconnect.setEnabled(true);
+ button_connect.setEnabled(false);
+ if (isSubject == true) {
+ try {
+ sampleClient.subscribe(sub_topic, qos);
+ subbutton.setEnabled(false);
+ noSubbutton.setEnabled(true);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ }, 10000,10000);// 设定指定的时间time,此处为10000毫秒
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String command = e.getActionCommand();
+ String qosString = comboBox.getSelectedItem().toString();
+ qos = Integer.valueOf(qosString);
+ if (command.equals("connect")) {
+
+ MemoryPersistence persistence = new MemoryPersistence();
+ try {
+ brokerIP = frmserverIP.getText();
+ clientId = username.getText();
+ if (TextUtils.isEmpty(brokerIP)) {
+ err_infoText.setText("输入服务器地址");
+ return;
+ }
+ if (TextUtils.isEmpty(clientId)) {
+ err_infoText.setText("输入ID");
+ return;
+ }
+ sampleClient = new MqttAsyncClient(brokerIP, clientId, persistence);
+ connOpts = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
+ connOpts.setCleanSession(true);
+ // 设置连接的用户名
+ connOpts.setUserName(userName);
+ // 设置连接的密码
+ connOpts.setPassword(passWord.toCharArray());
+ // 设置超时时间 单位为秒
+ connOpts.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ connOpts.setKeepAliveInterval(20);
+ System.out.println("Connecting to broker: " + brokerIP);
+
+ //服务端单向验证
+// Resource caClientResource = new ClassPathResource("ssl/client.crt");
+// Resource keyClientResource = new ClassPathResource("ssl/client.key");
+// Resource caServerResource = new ClassPathResource("ssl/my_root_ca.pem");
+//
+// System.err.println("path4:" + caClientResource.getFile().getAbsolutePath());
+// System.err.println("path4:" + keyClientResource.getFile().getAbsolutePath());
+// System.err.println("path4:" + caServerResource.getFile().getAbsolutePath());
+
+ //connOpts.setSocketFactory(SslUtil.getSocketFactorySingleByCrt(caServerResource.getFile().getAbsolutePath()));
+ //connOpts.setSocketFactory(SslUtil.getSocketFactorySingleByPem(caServerResource.getFile().getAbsolutePath()));
+
+ //双向验证
+ InputStream inputStream1 = MqttSslAsyncClient.class.getClassLoader().getResourceAsStream("ssl/client.pem");
+ InputStream inputStream2 = MqttSslAsyncClient.class.getClassLoader().getResourceAsStream("ssl/client.key");
+ InputStream inputStream3 = MqttSslAsyncClient.class.getClassLoader().getResourceAsStream("ssl/my_root_ca.pem");
+
+ File caClientFile = new File("client.pem");
+ File keyClientFile = new File("client.key");
+ File caServerFile = new File("my_root_ca.pem");
+
+ // 使用common-io的工具类即可转换
+ FileUtils.copyToFile(inputStream1,caClientFile);
+ // 使用common-io的工具类即可转换
+ FileUtils.copyToFile(inputStream2,keyClientFile);
+ // 使用common-io的工具类即可转换
+ FileUtils.copyToFile(inputStream3,caServerFile);
+
+ System.err.println("path4:" + caClientFile.getAbsolutePath());
+ System.err.println("path4:" + keyClientFile.getAbsolutePath());
+ System.err.println("path4:" + caServerFile.getAbsolutePath());
+ connOpts.setSocketFactory(SslUtil.getSocketFactory(caServerFile.getAbsolutePath(),
+ caClientFile.getAbsolutePath(), keyClientFile.getAbsolutePath(), ""));
+
+
+
+ sampleClient.connect(connOpts);
+ System.out.println("Connected");
+ err_infoText.setText("已连接");
+ button_disconnect.setEnabled(true);
+ button_connect.setEnabled(false);
+ isConnetc = true;
+
+ sampleClient.setCallback(new MqttCallback() {
+
+ @Override
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ String msg = new String(message.getPayload());
+ System.out.println("接收消息主题 : " + topic);
+ System.out.println("接收消息Qos : " + message.getQos());
+ System.out.println("接收消息内容 : " + message.toString());
+ System.out.println("接收消息id : " + message.getId());
+
+ String info = message.toString();
+ infoList += info + "\n";
+ msgtextArea.setText(infoList);
+ }
+
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken arg0) {
+ System.out.println("deliveryComplete---------" + arg0.isComplete());
+ }
+
+ @Override
+ public void connectionLost(Throwable err) {
+ // 断开连接
+ try {
+ sampleClient.disconnect();
+ // 关闭客户端
+ sampleClient.close();
+ } catch (MqttException mqttException) {
+ mqttException.printStackTrace();
+ }
+ err_infoText.setText("连接丢失");
+ button_connect.setEnabled(true);
+ button_disconnect.setEnabled(false);
+ System.out.println("连接丢失");
+ System.out.println(err.getMessage());
+
+ }
+ });
+
+ } catch (MqttException me) {
+ System.out.println("reason " + me.getReasonCode());
+ System.out.println("msg " + me.getMessage());
+ System.out.println("loc " + me.getLocalizedMessage());
+ System.out.println("cause " + me.getCause());
+ System.out.println("excep " + me);
+ err_infoText.setText("hi:" + me.getMessage());
+ button_disconnect.setEnabled(false);
+ button_connect.setEnabled(true);
+ me.printStackTrace();
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ }
+
+ } else if (command.equals("sub")) {
+ sub_topic = toptic_input.getText();
+ if (TextUtils.isEmpty(sub_topic)) {
+ err_infoText.setText("输入订阅主题");
+ return;
+ }
+ try {
+ sampleClient.subscribe(sub_topic, qos);
+ subbutton.setEnabled(false);
+ noSubbutton.setEnabled(true);
+ isSubject = true;
+ toptic_input.setEnabled(false);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+
+ } else if (command.equals("noSub")) {
+ sub_topic = toptic_input.getText();
+ if (TextUtils.isEmpty(sub_topic)) {
+ err_infoText.setText("输入订阅主题");
+ return;
+ }
+ try {
+ sampleClient.unsubscribe(sub_topic);
+ subbutton.setEnabled(true);
+ noSubbutton.setEnabled(false);
+ isSubject = false;
+ toptic_input.setEnabled(true);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+
+ } else if (command.equals("send")) {
+ pub_topic = toptic_titile.getText();
+ msgSendContent = send_msg_text.getText();
+ if (TextUtils.isEmpty(pub_topic)) {
+ err_infoText.setText("输入发送主题");
+ return;
+ }
+ if (TextUtils.isEmpty(msgSendContent)) {
+ err_infoText.setText("输入消息内容");
+ return;
+ }
+ MqttMessage message = new MqttMessage(msgSendContent.getBytes());
+ message.setQos(qos);
+ try {
+ sampleClient.publish(pub_topic, message);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ err_infoText.setText(e1.getMessage());
+ }
+
+ } else if (command.equals("clear")) {
+ msgtextArea.setText("");
+ infoList = "";
+
+ } else if (command.equals("disconnect")) {
+ if (sampleClient != null) {
+ try {
+ // 断开连接
+ sampleClient.disconnect();
+ // 关闭客户端
+ sampleClient.close();
+ button_connect.setEnabled(true);
+ button_disconnect.setEnabled(false);
+ subbutton.setEnabled(true);
+ noSubbutton.setEnabled(false);
+ toptic_input.setEnabled(true);
+ isConnetc = false;
+ err_infoText.setText("已断开");
+ isSubject = false;
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ MqttSslAsyncClient frame = new MqttSslAsyncClient();
+ frame.setVisible(true);
+ frame.start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+}
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ssl/SslUtil.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ssl/SslUtil.java
new file mode 100644
index 0000000..d41f6dd
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/ssl/SslUtil.java
@@ -0,0 +1,150 @@
+package com.rehome.mqtt01.ssl;
+
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMReader;
+import org.bouncycastle.openssl.PasswordFinder;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.*;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+public class SslUtil {
+ /**
+ * @param caPemFile ca证书 *.pem
+ * @param clientPemFile 客户端pem证书 *.pem
+ * @param clientKeyFile 客户端证书密钥 *.key
+ * @param password 客户端证书密码
+ * @return
+ * @throws Exception
+ * pem格式 CA证书生成SSLSocketFactory
+ */
+ public static SSLSocketFactory getSocketFactory(final String caPemFile, final String clientPemFile, final String clientKeyFile,
+ final String password) throws Exception {
+ Security.addProvider(new BouncyCastleProvider());
+
+ // load CA certificate
+ PEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(File2byte(caPemFile))));
+ X509Certificate caCert = (X509Certificate)reader.readObject();
+ reader.close();
+
+ // load client certificate
+ reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(File2byte(clientPemFile))));
+ X509Certificate cert = (X509Certificate)reader.readObject();
+ reader.close();
+
+ // load client private key
+ reader = new PEMReader(
+ new InputStreamReader(new ByteArrayInputStream(File2byte(clientKeyFile))),
+ new PasswordFinder() {
+ @Override
+ public char[] getPassword() {
+ return password.toCharArray();
+ }
+ }
+ );
+ KeyPair key = (KeyPair)reader.readObject();
+ reader.close();
+
+ // CA certificate is used to authenticate server
+ KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
+ caKs.load(null, null);
+ caKs.setCertificateEntry("ca-certificate", caCert);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(caKs);
+
+ // client key and certificates are sent to server so it can authenticate us
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ ks.load(null, null);
+ ks.setCertificateEntry("certificate", cert);
+ ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(), new java.security.cert.Certificate[]{cert});
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(ks, password.toCharArray());
+
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+ return context.getSocketFactory();
+ }
+
+ /**
+ * @param caPemFile
+ * @return
+ * @throws Exception
+ * pem格式 CA证书生成SSLSocketFactory
+ */
+ public static SSLSocketFactory getSocketFactorySingleByPem(final String caPemFile) throws Exception {
+ Security.addProvider(new BouncyCastleProvider());
+ // load CA certificate
+ PEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(File2byte(caPemFile))));
+ X509Certificate caCert = (X509Certificate)reader.readObject();
+ reader.close();
+ // client key and certificates are sent to server so it can authenticate us
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());//"JKS"
+ ks.load(null, null);
+ ks.setCertificateEntry("ca-certificate", caCert);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());//"PKIX"
+ tmf.init(ks);
+ // finally, create SSL socket factory
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(null, tmf.getTrustManagers(), new SecureRandom());
+ return context.getSocketFactory();
+ }
+
+ /**
+ * @param caCrtFile
+ * @return
+ * @throws Exception
+ * crt格式 CA证书生成SSLSocketFactory
+ */
+ public static SSLSocketFactory getSocketFactorySingleByCrt(String caCrtFile) throws Exception {
+ // CA certificate is used to authenticate server
+ CertificateFactory cAf = CertificateFactory.getInstance("X.509");
+ FileInputStream caIn = new FileInputStream(caCrtFile);
+ X509Certificate ca = (X509Certificate) cAf.generateCertificate(caIn);
+ KeyStore caKs = KeyStore.getInstance("JKS");
+ caKs.load(null, null);
+ caKs.setCertificateEntry("ca-certificate", ca);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+ tmf.init(caKs);
+ // finally, create SSL socket factory
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(null, tmf.getTrustManagers(), new SecureRandom());
+ return context.getSocketFactory();
+ }
+ /**
+ * 将文件转换成byte数组
+ * @param filePath
+ * @return
+ */
+ public static byte[] File2byte(String filePath){
+ File tradeFile = new File(filePath);
+ byte[] buffer = null;
+ try
+ {
+ FileInputStream fis = new FileInputStream(tradeFile);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ byte[] b = new byte[1024];
+ int n;
+ while ((n = fis.read(b)) != -1)
+ {
+ bos.write(b, 0, n);
+ }
+ fis.close();
+ bos.close();
+ buffer = bos.toByteArray();
+ }catch (FileNotFoundException e){
+ e.printStackTrace();
+ }catch (IOException e){
+ e.printStackTrace();
+ }
+ return buffer;
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttAsyncClient.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttAsyncClient.java
new file mode 100644
index 0000000..3b3e5ab
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttAsyncClient.java
@@ -0,0 +1,428 @@
+package com.rehome.mqtt01.v1;
+
+import org.apache.http.util.TextUtils;
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.TimerTask;
+import java.util.Timer;
+
+public class MqttAsyncClient extends JFrame implements ActionListener {
+ private JPanel contentPane;
+ private Font useFont = new Font("微软雅黑", Font.BOLD, 12);
+ private JFormattedTextField frmserverIP;
+ private JFormattedTextField username;
+ private JButton button_connect;
+ private JButton button_disconnect;
+ private JFormattedTextField toptic_input;
+ private JFormattedTextField toptic_titile;
+ private JFormattedTextField send_msg_text;
+ private JLabel err_infoText;
+ private JComboBox comboBox;
+ private JButton sendbutton;
+ private JTextArea msgtextArea;
+ private String brokerIP;
+ private String clientId;
+ private String msgContent;
+ private String msgSendContent;
+ private String sub_topic, pub_topic;
+ private Boolean isSubject = false;
+ private Boolean isConnetc = false;
+ private Timer timer;
+ /**
+ * 消息发布质量
+ * 0:最多一次,即:<=1
+ * 1:至少一次,即:>=1
+ * 2:一次,即:=1
+ */
+ private int qos = 0;
+ private org.eclipse.paho.client.mqttv3.MqttAsyncClient sampleClient;
+ private MqttConnectOptions connOpts;
+ private String infoList = "";
+ private JButton subbutton;
+ private JButton noSubbutton;
+
+ /**
+ * MQTT服务端连接账号
+ */
+ private final String userName = "admin";
+ /**
+ * MQTT服务端连接密码
+ */
+ private final String passWord = "public";
+
+
+ public MqttAsyncClient() {
+ // 设置窗体大小位置
+ setBounds(100, 100, 484, 439);
+ setTitle("MQTT客户端");
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ contentPane = new JPanel();
+ contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
+ contentPane.setLayout(null);
+ setContentPane(contentPane);
+ //添加控件
+ JLabel lblMqtt = new JLabel("MQTT服务器地址:");
+ lblMqtt.setFont(useFont);
+ lblMqtt.setBounds(30, 10, 109, 15);
+ contentPane.add(lblMqtt);
+
+ frmserverIP = new JFormattedTextField();
+ frmserverIP.setText("tcp://39.101.173.20:1883");
+ frmserverIP.setBounds(139, 7, 258, 21);
+ contentPane.add(frmserverIP);
+
+ JLabel lblNewLabel = new JLabel("用户名:");
+ lblNewLabel.setFont(useFont);
+ lblNewLabel.setBounds(40, 41, 54, 15);
+ contentPane.add(lblNewLabel);
+
+ username = new JFormattedTextField();
+ username.setText("v1_server_timemqtt_06");
+ username.setBounds(139, 38, 199, 21);
+ contentPane.add(username);
+
+ button_connect = new JButton("连 接");
+ button_connect.setBounds(30, 66, 93, 23);
+ button_connect.setFont(useFont);
+ button_connect.addActionListener(this);
+ button_connect.setActionCommand("connect");
+ contentPane.add(button_connect);
+
+ button_disconnect = new JButton("断 开");
+ button_disconnect.setEnabled(false);
+ button_disconnect.setFont(useFont);
+ button_disconnect.addActionListener(this);
+ button_disconnect.setActionCommand("disconnect");
+ button_disconnect.setBounds(263, 66, 93, 23);
+ contentPane.add(button_disconnect);
+
+ JLabel label = new JLabel("订阅主题:");
+ label.setBounds(40, 111, 83, 15);
+ label.setFont(useFont);
+ contentPane.add(label);
+
+ toptic_input = new JFormattedTextField();
+ toptic_input.setText("push");
+ toptic_input.setBounds(100, 108, 99, 21);
+ contentPane.add(toptic_input);
+
+ JSeparator separator = new JSeparator();
+ separator.setBackground(Color.GREEN);
+ separator.setBounds(30, 99, 367, 2);
+ contentPane.add(separator);
+
+ subbutton = new JButton("订 阅");
+ subbutton.setFont(useFont);
+ subbutton.addActionListener(this);
+ subbutton.setActionCommand("sub");
+ subbutton.setBounds(193, 107, 83, 23);
+ contentPane.add(subbutton);
+
+ noSubbutton = new JButton("取消订阅");
+ noSubbutton.setFont(useFont);
+ noSubbutton.addActionListener(this);
+ noSubbutton.setActionCommand("noSub");
+ noSubbutton.setBounds(276, 107, 83, 23);
+ noSubbutton.setEnabled(false);
+ contentPane.add(noSubbutton);
+
+ JSeparator separator_1 = new JSeparator();
+ separator_1.setBounds(30, 139, 367, 2);
+ contentPane.add(separator_1);
+
+ JLabel label_1 = new JLabel("发布消息");
+ label_1.setFont(useFont);
+ label_1.setBounds(40, 151, 60, 15);
+ contentPane.add(label_1);
+
+ JLabel label_2 = new JLabel("主题");
+ label_2.setFont(useFont);
+ label_2.setBounds(104, 151, 30, 15);
+ contentPane.add(label_2);
+
+ toptic_titile = new JFormattedTextField();
+ toptic_titile.setText("push");
+ toptic_titile.setBounds(139, 148, 99, 21);
+ contentPane.add(toptic_titile);
+
+ JLabel label_3 = new JLabel("服务质量");
+ label_3.setFont(useFont);
+ label_3.setBounds(248, 151, 64, 15);
+ contentPane.add(label_3);
+
+ comboBox = new JComboBox();
+ comboBox.setBounds(305, 148, 64, 21);
+ comboBox.addItem("0");
+ comboBox.addItem("1");
+ comboBox.addItem("2");
+ comboBox.setSelectedItem("2");
+ contentPane.add(comboBox);
+
+ JLabel label_send = new JLabel("发布的消息内容");
+ label_send.setFont(useFont);
+ label_send.setBounds(40, 181, 100, 15);
+ contentPane.add(label_send);
+
+ send_msg_text = new JFormattedTextField();
+ send_msg_text.setText("MQTT客户端 发送消息 -->");
+ send_msg_text.setBounds(140, 179, 220, 21);
+ contentPane.add(send_msg_text);
+
+ sendbutton = new JButton("发 送");
+ sendbutton.setBounds(46, 378, 93, 23);
+ sendbutton.addActionListener(this);
+ sendbutton.setActionCommand("send");
+ contentPane.add(sendbutton);
+
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.setBounds(40, 219, 316, 149);
+ contentPane.add(scrollPane);
+
+ msgtextArea = new JTextArea();
+ scrollPane.setViewportView(msgtextArea);
+
+ err_infoText = new JLabel("");
+ err_infoText.setForeground(Color.RED);
+ err_infoText.setBounds(134, 69, 131, 15);
+ err_infoText.setFont(useFont);
+ contentPane.add(err_infoText);
+
+ JButton btnClear = new JButton("clear");
+ btnClear.setBounds(209, 378, 93, 23);
+ btnClear.addActionListener(this);
+ btnClear.setActionCommand("clear");
+ contentPane.add(btnClear);
+
+
+ }
+
+ private void start() {
+ try {
+ timer = new Timer();
+ timer.schedule(new TimerTask() {
+ public void run() {
+ System.out.println("-------设定要指定任务--------");
+ if (isConnetc == true) {
+ try {
+ //判断拦截状态,这里注意一下,如果没有这个判断,是非常坑的
+ if (!sampleClient.isConnected()) {
+ System.out.println("***** 没有连接到服务器 *****");
+ System.out.println("***** client to connect *****");
+ // 重新连接
+ sampleClient.connect(connOpts);
+ }
+ if (sampleClient.isConnected()) {//连接成功,跳出连接
+ System.out.println("***** connect success *****");
+ System.out.println("Connected");
+ err_infoText.setText("已连接");
+ button_disconnect.setEnabled(true);
+ button_connect.setEnabled(false);
+ if (isSubject == true) {
+ try {
+ sampleClient.subscribe(sub_topic, qos);
+ subbutton.setEnabled(false);
+ noSubbutton.setEnabled(true);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ }, 10000,10000);// 设定指定的时间time,此处为10000毫秒
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String command = e.getActionCommand();
+ String qosString = comboBox.getSelectedItem().toString();
+ qos = Integer.valueOf(qosString);
+ if (command.equals("connect")) {
+
+ MemoryPersistence persistence = new MemoryPersistence();
+ try {
+ brokerIP = frmserverIP.getText();
+ clientId = username.getText();
+ if (TextUtils.isEmpty(brokerIP)) {
+ err_infoText.setText("输入服务器地址");
+ return;
+ }
+ if (TextUtils.isEmpty(clientId)) {
+ err_infoText.setText("输入ID");
+ return;
+ }
+ sampleClient = new org.eclipse.paho.client.mqttv3.MqttAsyncClient(brokerIP, clientId, persistence);
+ connOpts = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
+ connOpts.setCleanSession(true);
+ // 设置连接的用户名
+ connOpts.setUserName(userName);
+ // 设置连接的密码
+ connOpts.setPassword(passWord.toCharArray());
+ // 设置超时时间 单位为秒
+ connOpts.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ connOpts.setKeepAliveInterval(20);
+ System.out.println("Connecting to broker: " + brokerIP);
+ sampleClient.connect(connOpts);
+
+ System.out.println("Connected");
+ err_infoText.setText("已连接");
+ button_disconnect.setEnabled(true);
+ button_connect.setEnabled(false);
+ isConnetc = true;
+
+ sampleClient.setCallback(new MqttCallback() {
+
+ @Override
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ String msg = new String(message.getPayload());
+ System.out.println("接收消息主题 : " + topic);
+ System.out.println("接收消息Qos : " + message.getQos());
+ System.out.println("接收消息内容 : " + message.toString());
+ System.out.println("接收消息id : " + message.getId());
+
+ String info = message.toString();
+ infoList += info + "\n";
+ msgtextArea.setText(infoList);
+ }
+
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken arg0) {
+ System.out.println("deliveryComplete---------" + arg0.isComplete());
+ }
+
+ @Override
+ public void connectionLost(Throwable err) {
+ // 断开连接
+ try {
+ sampleClient.disconnect();
+ // 关闭客户端
+ sampleClient.close();
+ } catch (MqttException mqttException) {
+ mqttException.printStackTrace();
+ }
+ err_infoText.setText("连接丢失");
+ button_connect.setEnabled(true);
+ button_disconnect.setEnabled(false);
+ System.out.println("连接丢失");
+ System.out.println(err.getMessage());
+
+ }
+ });
+
+ } catch (MqttException me) {
+ System.out.println("reason " + me.getReasonCode());
+ System.out.println("msg " + me.getMessage());
+ System.out.println("loc " + me.getLocalizedMessage());
+ System.out.println("cause " + me.getCause());
+ System.out.println("excep " + me);
+ err_infoText.setText("hi:" + me.getMessage());
+ button_disconnect.setEnabled(false);
+ button_connect.setEnabled(true);
+ me.printStackTrace();
+ }
+
+ } else if (command.equals("sub")) {
+ sub_topic = toptic_input.getText();
+ if (TextUtils.isEmpty(sub_topic)) {
+ err_infoText.setText("输入订阅主题");
+ return;
+ }
+ try {
+ sampleClient.subscribe(sub_topic, qos);
+ subbutton.setEnabled(false);
+ noSubbutton.setEnabled(true);
+ isSubject = true;
+ toptic_input.setEnabled(false);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+
+ } else if (command.equals("noSub")) {
+ sub_topic = toptic_input.getText();
+ if (TextUtils.isEmpty(sub_topic)) {
+ err_infoText.setText("输入订阅主题");
+ return;
+ }
+ try {
+ sampleClient.unsubscribe(sub_topic);
+ subbutton.setEnabled(true);
+ noSubbutton.setEnabled(false);
+ isSubject = false;
+ toptic_input.setEnabled(true);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+
+ } else if (command.equals("send")) {
+ pub_topic = toptic_titile.getText();
+ msgSendContent = send_msg_text.getText();
+ if (TextUtils.isEmpty(pub_topic)) {
+ err_infoText.setText("输入发送主题");
+ return;
+ }
+ if (TextUtils.isEmpty(msgSendContent)) {
+ err_infoText.setText("输入消息内容");
+ return;
+ }
+ MqttMessage message = new MqttMessage(msgSendContent.getBytes());
+ message.setQos(qos);
+ try {
+ sampleClient.publish(pub_topic, message);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ err_infoText.setText(e1.getMessage());
+ }
+
+ } else if (command.equals("clear")) {
+ msgtextArea.setText("");
+ infoList = "";
+
+ } else if (command.equals("disconnect")) {
+ if (sampleClient != null) {
+ try {
+ // 断开连接
+ sampleClient.disconnect();
+ // 关闭客户端
+ sampleClient.close();
+ button_connect.setEnabled(true);
+ button_disconnect.setEnabled(false);
+ subbutton.setEnabled(true);
+ noSubbutton.setEnabled(false);
+ toptic_input.setEnabled(true);
+ isConnetc = false;
+ err_infoText.setText("已断开");
+ isSubject = false;
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ MqttAsyncClient frame = new MqttAsyncClient();
+ frame.setVisible(true);
+ frame.start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttPublishServer.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttPublishServer.java
new file mode 100644
index 0000000..50164a1
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttPublishServer.java
@@ -0,0 +1,152 @@
+package com.rehome.mqtt01.v1;
+
+/**
+ * @author huangwenfei
+ * @version v1.0.0.0
+ * Created DateTime 2021-07-31 14:52
+ * @description: mqtt 高可靠,断线重连 消息发布服务
+ */
+
+import com.rehome.mqtt01.rsa.RSAEncrypt;
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class MqttPublishServer {
+ /**
+ * 代理服务器ip地址
+ */
+ private final String HOST = "tcp://39.101.173.20:1883";
+ /**
+ * 订阅主题
+ */
+ private final String topic = "push";
+ /**
+ * 客户端唯一标识,相同的会被逼下线
+ */
+ private String clientid = "v1_server_timemqtt_006";
+ private MqttClient client;
+ private MqttConnectOptions options;
+ /**
+ * MQTT服务端连接账号
+ */
+ private final String userName = "admin";
+ /**
+ * MQTT服务端连接密码
+ */
+ private final String passWord = "public";
+ /**
+ * 消息发布质量
+ * 0:最多一次,即:<=1
+ * 1:至少一次,即:>=1
+ * 2:一次,即:=1
+ */
+ private int qos = 2;
+ // 推送消息
+ private MqttMessage message;
+ //定时器
+ private Timer timer;
+
+ public MqttPublishServer() {
+ // host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
+ try {
+ client = new MqttClient(HOST, clientid, new MemoryPersistence());
+ // MQTT的连接设置
+ options = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
+ options.setCleanSession(true);
+ // 设置连接的用户名
+ options.setUserName(userName);
+ // 设置连接的密码
+ options.setPassword(passWord.toCharArray());
+ // 设置超时时间 单位为秒
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ options.setKeepAliveInterval(20);
+ // 发布目的消息对象
+ message = new MqttMessage();
+ // 设置回调
+ client.setCallback(new MqttCallback() {
+
+ public void connectionLost(Throwable cause) {
+ System.out.println("connectionLost---------");
+ stop();//关闭
+ //start();//重新连接
+ }
+
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ System.out.println("***** get message start *****");
+ System.out.println(new Date());
+ System.out.println("topic:" + topic);
+ System.out.println("Qos:" + message.getQos());
+ System.out.println("message:" + new String(message.getPayload()));
+ System.out.println("***** get message end *****");
+ System.out.println();
+ }
+
+ public void deliveryComplete(IMqttDeliveryToken token) {
+ System.out.println("deliveryComplete---------" + token.isComplete());
+ }
+ });
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void start() {
+ try {
+ timer = new Timer();
+ timer.schedule(new TimerTask() {
+ public void run() {
+ System.out.println("-------设定要指定任务--------");
+ message.setQos(qos);
+ message.setRetained(true);
+ SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String time = "message from server->:"+clientid+"->:"+sd.format(new Date());
+ message.setPayload(time.getBytes());
+ try {
+ //判断拦截状态,这里注意一下,如果没有这个判断,是非常坑的
+ if (!client.isConnected()) {
+ System.out.println("***** 没有连接到服务器 *****");
+ System.out.println("***** client to connect *****");
+ // 重新连接
+ client.connect(options);
+ }
+ if (client.isConnected()) {//连接成功,跳出连接
+ System.out.println("***** connect success *****");
+ System.out.println(time);
+ // 发布消息
+ client.publish(topic, message);
+ }
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ }
+ }, 10000,10000);
+ // 设定指定的时间time,此处为10000毫秒
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void stop() {
+ try {
+ // 断开连接
+ client.disconnect();
+ // 关闭客户端
+ client.close();
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ // 推送消息
+ MqttPublishServer mqttPublishServer = new MqttPublishServer();
+ mqttPublishServer.start();
+ }
+}
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttReceiveTest.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttReceiveTest.java
new file mode 100644
index 0000000..c0ea0a8
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttReceiveTest.java
@@ -0,0 +1,118 @@
+package com.rehome.mqtt01.v1;
+
+/**
+ * @author huangwenfei
+ * @version v1.0.0.0
+ * Created DateTime 2021-07-31 14:52
+ * @description: mqtt 高可靠,断线重连 消息发布服务测试
+ */
+
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class MqttReceiveTest {
+
+ private final String HOST = "tcp://39.101.173.20:1883";
+ private final String topic = "push";//订阅主题
+ private String clientid = "v1_server_timemqtt_05";//客户端ID唯一,相同的会被逼下线
+ private MqttClient client;
+ private MqttConnectOptions options;
+ private final String userName = "admin";//MQTT服务端连接账号
+ private final String passWord = "public";//MQTT服务端连接密码
+ private int qos = 1;
+ // 推送消息
+ private MqttMessage message;
+
+ public MqttReceiveTest() {
+ // host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
+ try {
+ message = new MqttMessage();
+ client = new MqttClient(HOST, clientid, new MemoryPersistence());
+ // MQTT的连接设置
+ options = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
+ options.setCleanSession(true);
+ // 设置连接的用户名
+ options.setUserName(userName);
+ // 设置连接的密码
+ options.setPassword(passWord.toCharArray());
+ // 设置超时时间 单位为秒
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ options.setKeepAliveInterval(20);
+ // 设置回调
+ client.setCallback(new MqttCallback() {
+
+ public void connectionLost(Throwable cause) {
+ System.out.println("connectionLost---------");
+ stop();//关闭
+ //start();//重新连接
+ }
+
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ System.out.println("***** get message start *****");
+ System.out.println(new Date());
+ System.out.println("topic:" + topic);
+ System.out.println("Qos:" + message.getQos());
+ System.out.println("message:" + new String(message.getPayload()));
+ System.out.println("***** get message end *****");
+ System.out.println();
+ }
+
+ public void deliveryComplete(IMqttDeliveryToken token) {
+ System.out.println("deliveryComplete---------" + token.isComplete());
+ }
+ });
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void start() {
+ try {
+ while (true) {
+ message.setQos(qos);
+ message.setRetained(true);
+ SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String time = "message from server->:"+clientid+"->:"+sd.format(new Date());
+ message.setPayload(time.getBytes());
+ try {
+ //判断拦截状态,这里注意一下,如果没有这个判断,是非常坑的
+ if (!client.isConnected()) {
+ System.out.println("***** client to connect *****");
+ client.connect(options);
+ }
+ if (client.isConnected()) {//连接成功,跳出连接
+ System.out.println("***** connect success *****");
+ // 发布消息
+ client.publish(topic, message);
+ }
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ Thread.sleep(10000);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void stop() {
+ try {
+ // 断开连接
+ client.disconnect();
+ // 关闭客户端
+ client.close();
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) throws MqttException {
+ MqttReceiveTest mqttReceiveTest = new MqttReceiveTest();
+ mqttReceiveTest.start();
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttServer2.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttServer2.java
new file mode 100644
index 0000000..6462d7d
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MqttServer2.java
@@ -0,0 +1,63 @@
+package com.rehome.mqtt01.v1;
+
+/**
+ * @ Author : huangwenfei
+ * @ Date : Created in 2021/7/29 7:54 下午
+ * @ Version : $1.0.0.0
+ * @ Description:
+ */
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+public class MqttServer2 {
+ /**
+ * 代理服务器ip地址
+ */
+ public static final String MQTT_BROKER_HOST = "tcp://39.101.173.20:61613";
+
+ /**
+ * 订阅标识
+ */
+ public static final String MQTT_TOPIC = "push";
+
+ private static String userName = "admin";
+ private static String password = "password";
+
+ /**
+ * 客户端唯一标识
+ */
+ public static final String MQTT_CLIENT_ID = "v1_server_00";
+ private static MqttTopic topic;
+ private static MqttClient client;
+
+ public static void main(String... args) {
+ // 推送消息
+ MqttMessage message = new MqttMessage();
+ try {
+ client = new MqttClient(MQTT_BROKER_HOST, MQTT_CLIENT_ID, new MemoryPersistence());
+ MqttConnectOptions options = new MqttConnectOptions();
+ options.setCleanSession(true);
+ options.setUserName(userName);
+ options.setPassword(password.toCharArray());
+ options.setConnectionTimeout(10);
+ options.setKeepAliveInterval(20);
+
+ topic = client.getTopic(MQTT_TOPIC);
+
+ message.setQos(1);
+ message.setRetained(false);
+ message.setPayload("message from server222222".getBytes());
+ client.connect(options);
+
+ while (true) {
+ MqttDeliveryToken token = topic.publish(message);
+ token.waitForCompletion();
+ System.out.println("已经发送222");
+ Thread.sleep(10000);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MyMqttClient.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MyMqttClient.java
new file mode 100644
index 0000000..6a51147
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/MyMqttClient.java
@@ -0,0 +1,87 @@
+package com.rehome.mqtt01.v1;
+
+/**
+ * @ Author : huangwenfei
+ * @ Date : Created in 2021/7/29 7:59 下午
+ * @ Version : $1.0.0.0
+ * @ Description:
+ */
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+public class MyMqttClient {
+ /**
+ * 代理服务器ip地址
+ */
+ public static final String MQTT_BROKER_HOST = "tcp://39.101.173.20:61613";
+
+ /**
+ * 客户端唯一标识
+ */
+ public static final String MQTT_CLIENT_ID = "v1_client_00";
+
+ /**
+ * 订阅标识
+ */
+// public static final String MQTT_TOPIC = "xiasuhuei321";
+
+ /**
+ *
+ */
+ public static final String USERNAME = "admin";
+ /**
+ * 密码
+ */
+ public static final String PASSWORD = "password";
+ public static final String TOPIC_FILTER = "push";
+
+ private volatile static MqttClient mqttClient;
+ private static MqttConnectOptions options;
+
+ public static void main(String... args) {
+ try {
+ // host为主机名,clientid即连接MQTT的客户端ID,一般以客户端唯一标识符表示,
+ // MemoryPersistence设置clientid的保存形式,默认为以内存保存
+
+ mqttClient = new MqttClient(MQTT_BROKER_HOST, MQTT_CLIENT_ID, new MemoryPersistence());
+ // 配置参数信息
+ options = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,
+ // 这里设置为true表示每次连接到服务器都以新的身份连接
+ options.setCleanSession(true);
+ // 设置用户名
+ options.setUserName(USERNAME);
+ // 设置密码
+ options.setPassword(PASSWORD.toCharArray());
+ // 设置超时时间 单位为秒
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ options.setKeepAliveInterval(20);
+ // 连接
+ mqttClient.connect(options);
+ // 订阅
+ mqttClient.subscribe(TOPIC_FILTER);
+ // 设置回调
+ mqttClient.setCallback(new MqttCallback() {
+ @Override
+ public void connectionLost(Throwable throwable) {
+ System.out.println("connectionLost");
+ }
+
+ @Override
+ public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
+ System.out.println("Topic: " + s + " Message: " + mqttMessage.toString());
+ }
+
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
+
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/PublishSample.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/PublishSample.java
new file mode 100644
index 0000000..a9d71dc
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/PublishSample.java
@@ -0,0 +1,62 @@
+package com.rehome.mqtt01.v1;
+
+/**
+ * @ Author : huangwenfei
+ * @ Date : Created in 2021/7/29 10:08 下午
+ * @ Version : $1.0.0.0
+ * @ Description:
+ */
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+/**
+ *发布端
+ */
+public class PublishSample {
+ public static void main(String[] args) {
+
+ String topic = "test2";
+ String content = "PublishSample hello 哈哈";
+ int qos = 1;
+ String broker = "tcp://39.101.173.20:61613";
+ String userName = "admin";
+ String password = "password";
+ String clientId = "PublishSample";
+ // 内存存储
+ MemoryPersistence persistence = new MemoryPersistence();
+
+ try {
+ // 创建客户端
+ MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
+ // 创建链接参数
+ MqttConnectOptions connOpts = new MqttConnectOptions();
+ // 在重新启动和重新连接时记住状态
+ connOpts.setCleanSession(false);
+ // 设置连接的用户名
+ connOpts.setUserName(userName);
+ connOpts.setPassword(password.toCharArray());
+ // 建立连接
+ sampleClient.connect(connOpts);
+ // 创建消息
+ MqttMessage message = new MqttMessage(content.getBytes());
+ // 设置消息的服务质量
+ message.setQos(qos);
+ // 发布消息
+ sampleClient.publish(topic, message);
+ // 断开连接
+ sampleClient.disconnect();
+ // 关闭客户端
+ sampleClient.close();
+ } catch (MqttException me) {
+ System.out.println("reason " + me.getReasonCode());
+ System.out.println("msg " + me.getMessage());
+ System.out.println("loc " + me.getLocalizedMessage());
+ System.out.println("cause " + me.getCause());
+ System.out.println("excep " + me);
+ me.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/SubscribeSample.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/SubscribeSample.java
new file mode 100644
index 0000000..52b628f
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v1/SubscribeSample.java
@@ -0,0 +1,65 @@
+package com.rehome.mqtt01.v1;
+
+/**
+ * @ Author : huangwenfei
+ * @ Date : Created in 2021/7/29 10:12 下午
+ * @ Version : $1.0.0.0
+ * @ Description:
+ */
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+/**
+ *订阅端
+ */
+public class SubscribeSample {
+
+ public static void main(String[] args) throws MqttException {
+ String HOST = "tcp://39.101.173.20:61613";
+ String TOPIC = "test2";
+ int qos = 1;
+ String clientid = "subClient";
+ String userName = "admin";
+ String passWord = "password";
+ try {
+ // host为主机名,test为clientid即连接MQTT的客户端ID,一般以客户端唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
+ MqttClient client = new MqttClient(HOST, clientid, new MemoryPersistence());
+ // MQTT的连接设置
+ MqttConnectOptions options = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
+ options.setCleanSession(true);
+ // 设置连接的用户名
+ options.setUserName(userName);
+ // 设置连接的密码
+ options.setPassword(passWord.toCharArray());
+ // 设置超时时间 单位为秒
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ options.setKeepAliveInterval(20);
+ // 设置回调函数
+ client.setCallback(new MqttCallback() {
+
+ public void connectionLost(Throwable cause) {
+ System.out.println("connectionLost");
+ }
+
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ System.out.println("topic:"+topic);
+ System.out.println("Qos:"+message.getQos());
+ System.out.println("message content:"+new String(message.getPayload()));
+
+ }
+
+ public void deliveryComplete(IMqttDeliveryToken token) {
+ System.out.println("deliveryComplete---------"+ token.isComplete());
+ }
+
+ });
+ client.connect(options);
+ //订阅消息
+ client.subscribe(TOPIC, qos);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/ClientMQTT.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/ClientMQTT.java
new file mode 100644
index 0000000..e96a608
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/ClientMQTT.java
@@ -0,0 +1,71 @@
+package com.rehome.mqtt01.v2;
+
+/**
+ * @ Author : huangwenfei
+ * @ Date : Created in 2021/7/29 10:43 下午
+ * @ Version : $1.0.0.0
+ * @ Description:
+ */
+
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttTopic;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * 模拟一个客户端接收消息
+ * @author rao
+ *
+ */
+public class ClientMQTT {
+
+ public static final String HOST = "tcp://39.101.173.20:61613";
+ public static final String TOPIC1 = "push";
+ private static final String clientid = "client11";
+ private MqttClient client;
+ private MqttConnectOptions options;
+ private String userName = "admin"; //非必须
+ private String passWord = "password"; //非必须
+ //@SuppressWarnings("unused")
+ private ScheduledExecutorService scheduler;
+
+ private void start() {
+ try {
+ // host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
+ client = new MqttClient(HOST, clientid, new MemoryPersistence());
+ // MQTT的连接设置
+ options = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,设置为true表示每次连接到服务器都以新的身份连接
+ options.setCleanSession(false);
+ // 设置连接的用户名
+ options.setUserName(userName);
+ // 设置连接的密码
+ options.setPassword(passWord.toCharArray());
+ // 设置超时时间 单位为秒
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ options.setKeepAliveInterval(20);
+ // 设置回调
+ client.setCallback(new PushCallback());
+ MqttTopic topic = client.getTopic(TOPIC1);
+ //setWill方法,如果项目中需要知道客户端是否掉线可以调用该方法。设置最终端口的通知消息
+//遗嘱 options.setWill(topic, "close".getBytes(), 2, true);
+ client.connect(options);
+ //订阅消息
+ int[] Qos = {1};
+ String[] topic1 = {TOPIC1};
+ client.subscribe(topic1, Qos);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) throws MqttException {
+ ClientMQTT client = new ClientMQTT();
+ client.start();
+ }
+}
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/PushCallback.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/PushCallback.java
new file mode 100644
index 0000000..d7fafa1
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/PushCallback.java
@@ -0,0 +1,47 @@
+package com.rehome.mqtt01.v2;
+
+/**
+ * @ Author : huangwenfei
+ * @ Date : Created in 2021/7/29 10:38 下午
+ * @ Version : $1.0.0.0
+ * @ Description:
+ */
+import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+
+/**
+ * 发布消息的回调类
+ *
+ * 必须实现MqttCallback的接口并实现对应的相关接口方法CallBack 类将实现 MqttCallBack。
+ * 每个客户机标识都需要一个回调实例。在此示例中,构造函数传递客户机标识以另存为实例数据。
+ * 在回调中,将它用来标识已经启动了该回调的哪个实例。
+ * 必须在回调类中实现三个方法:
+ *
+ * public void messageArrived(MqttTopic topic, MqttMessage message)接收已经预订的发布。
+ *
+ * public void connectionLost(Throwable cause)在断开连接时调用。
+ *
+ * public void deliveryComplete(MqttDeliveryToken token))
+ * 接收到已经发布的 QoS 1 或 QoS 2 消息的传递令牌时调用。
+ * 由 MqttClient.connect 激活此回调。
+ *
+ */
+public class PushCallback implements MqttCallback {
+
+ public void connectionLost(Throwable cause) {
+ // 连接丢失后,一般在这里面进行重连
+ System.out.println("连接断开,可以做重连");
+ }
+
+ public void deliveryComplete(IMqttDeliveryToken token) {
+ System.out.println("deliveryComplete---------" + token.isComplete());
+ }
+
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ // subscribe后得到的消息会执行到这里面
+ System.out.println("接收消息主题 : " + topic);
+ System.out.println("接收消息Qos : " + message.getQos());
+ System.out.println("接收消息内容 : " + new String(message.getPayload()));
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/ServerMQTT.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/ServerMQTT.java
new file mode 100644
index 0000000..62bc9cb
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/ServerMQTT.java
@@ -0,0 +1,95 @@
+package com.rehome.mqtt01.v2;
+
+/**
+ * @ Author : huangwenfei
+ * @ Date : Created in 2021/7/29 10:36 下午
+ * @ Version : $1.0.0.0
+ * @ Description:
+ */
+
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+/**
+ * Title:Server 这是发送消息的服务端
+ * Description: 服务器向多个客户端推送主题,即不同客户端可向服务器订阅相同主题
+ * @author rao
+ */
+public class ServerMQTT {
+
+ //tcp://MQTT安装的服务器地址:MQTT定义的端口号
+ public static final String HOST = "tcp://39.101.173.20:61613";
+ //定义一个主题
+ public static final String TOPIC = "push";
+ //定义MQTT的ID,可以在MQTT服务配置中指定
+ private static final String clientid = "server11";
+
+ private MqttClient client;
+ private MqttTopic topic11;
+ private String userName = "admin";
+ private String passWord = "password";
+
+ private MqttMessage message;
+
+ /**
+ * 构造函数
+ * @throws MqttException
+ */
+ public ServerMQTT() throws MqttException {
+ // MemoryPersistence设置clientid的保存形式,默认为以内存保存
+ client = new MqttClient(HOST, clientid, new MemoryPersistence());
+ connect();
+ }
+
+ /**
+ * 用来连接服务器
+ */
+ private void connect() {
+ MqttConnectOptions options = new MqttConnectOptions();
+ options.setCleanSession(false);
+ options.setUserName(userName);
+ options.setPassword(passWord.toCharArray());
+ // 设置超时时间
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间
+ options.setKeepAliveInterval(20);
+ try {
+ client.setCallback(new PushCallback());
+ client.connect(options);
+
+ topic11 = client.getTopic(TOPIC);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ * @param topic
+ * @param message
+ * @throws MqttPersistenceException
+ * @throws MqttException
+ */
+ public void publish(MqttTopic topic , MqttMessage message) throws MqttPersistenceException,
+ MqttException {
+ MqttDeliveryToken token = topic.publish(message);
+ token.waitForCompletion();
+ System.out.println("message is published completely! "
+ + token.isComplete());
+ }
+
+ /**
+ * 启动入口
+ * @param args
+ * @throws MqttException
+ */
+ public static void main(String[] args) throws MqttException {
+ ServerMQTT server = new ServerMQTT();
+ server.message = new MqttMessage();
+ server.message.setQos(1); //保证消息能到达一次
+ server.message.setRetained(true);
+ server.message.setPayload("这是推送消息的内容".getBytes());
+ server.publish(server.topic11 , server.message);
+ System.out.println(server.message.isRetained() + "------ratained状态");
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/ServerMQTTUtil.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/ServerMQTTUtil.java
new file mode 100644
index 0000000..369d6be
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v2/ServerMQTTUtil.java
@@ -0,0 +1,142 @@
+package com.rehome.mqtt01.v2;
+
+/**
+ * @ Author : huangwenfei
+ * @ Date : Created in 2021/7/29 10:50 下午
+ * @ Version : $1.0.0.0
+ * @ Description:
+ */
+
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+/**
+ * Title:Server 这是发送消息的服务端
+ * Description: 服务器向多个客户端推送主题,即不同客户端可向服务器订阅相同主题
+ * @author rao
+ */
+public class ServerMQTTUtil {
+
+ //tcp://MQTT安装的服务器地址:MQTT定义的端口号
+ public static final String HOST = "tcp://39.101.173.20:61613";
+ //定义MQTT的ID,可以在MQTT服务配置中指定
+ private static final String clientid = "server2";
+
+ private MqttClient client;
+ private MqttTopic mqttTopic;
+ private String userName = "admin";
+ private String passWord = "password";
+
+ /**
+ * 构造函数
+ * @throws MqttException
+ */
+ public ServerMQTTUtil(String topic) throws MqttException {
+ // MemoryPersistence设置clientid的保存形式,默认为以内存保存
+ client = new MqttClient(HOST, clientid, new MemoryPersistence());
+ connect(topic);
+ }
+
+ /**
+ * 用来连接服务器
+ */
+ private void connect(String topic) {
+ MqttConnectOptions options = new MqttConnectOptions();
+ options.setCleanSession(false);
+ options.setUserName(userName);
+ options.setPassword(passWord.toCharArray());
+ // 设置超时时间
+ options.setConnectionTimeout(10);
+ // 设置会话心跳时间
+ options.setKeepAliveInterval(20);
+ try {
+// client.setCallback(new PushCallback());
+ client.connect(options);
+ mqttTopic = client.getTopic(topic);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ //发送消息并获取回执
+ public void publish(MqttMessage message) throws
+ MqttException {
+ MqttDeliveryToken token = mqttTopic.publish(message);
+ token.waitForCompletion();
+ System.out.println("message is published completely! "
+ + token.isComplete());
+ System.out.println("messageId:" + token.getMessageId());
+ token.getResponse();
+ if (client.isConnected())
+ client.disconnect(10000);
+ System.out.println("Disconnected: delivery token \"" + token.hashCode()
+ + "\" received: " + token.isComplete());
+ }
+
+
+ public String getUserName() {
+ return userName;
+ }
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+ public String getPassWord() {
+ return passWord;
+ }
+ public void setPassWord(String passWord) {
+ this.passWord = passWord;
+ }
+
+ public MqttTopic getMqttTopic() {
+ return mqttTopic;
+ }
+
+ public void setMqttTopic(MqttTopic mqttTopic) {
+ this.mqttTopic = mqttTopic;
+ }
+
+ public static void main(String[] args) throws MqttException {
+ //设置推送消息体
+// String sendTime = TimeUtils.getTime();
+// String msgType = "html";
+// String title = message.getTitle();
+// String content = message.getContent();
+// String createTime = message.getCreateTime();
+// Map data = new HashMap();
+// data.put("messageId", messageId);
+// data.put("msgType", msgType);
+// data.put("title", title);
+// data.put("content", content);
+// data.put("createTime", createTime);
+// data.put("sendTime", sendTime);
+// msgType = "posMessage";
+// Map messageMap = new HashMap();
+// messageMap.put("msgType", msgType);
+// messageMap.put("data", data);
+// String MQTTObject = JSON.toJSONString(messageMap);
+// System.out.println(MQTTObject);
+ //将信息写入消息体
+ MqttMessage mqttMessage = new MqttMessage();
+ mqttMessage.setQos(1);
+ mqttMessage.setRetained(true);
+ String str = "ServerMQTTUtil";
+ mqttMessage.setPayload(str.getBytes());
+ //根据deviceIdList内容进行topic设置和发送推送
+// if (!deviceIdList.equals("all")) {
+// List deviceList = Arrays.asList(deviceIdList.split(","));
+// for (int i =0; i < deviceList.size(); i++) {
+//
+// String topic = "pos_message_" + deviceList.get(i);
+// ServerMQTTUtil serverMQTTUtil = new ServerMQTTUtil(topic);
+// serverMQTTUtil.publish(mqttMessage);
+// System.out.println(mqttMessage.isRetained() + "------ratained状态");
+// }
+// } else {
+ String topic = "push";
+ ServerMQTTUtil serverMQTTUtil = new ServerMQTTUtil(topic);
+ serverMQTTUtil.publish(mqttMessage);
+ System.out.println(mqttMessage.isRetained() + "------ratained状态");
+// }
+ }
+
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v3/MqttAsyncClientDemo.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v3/MqttAsyncClientDemo.java
new file mode 100644
index 0000000..710ad7b
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v3/MqttAsyncClientDemo.java
@@ -0,0 +1,335 @@
+package com.rehome.mqtt01.v3;
+
+
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JFormattedTextField;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JTextArea;
+import javax.swing.border.EmptyBorder;
+
+import org.apache.http.util.TextUtils;
+import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+
+public class MqttAsyncClientDemo extends JFrame implements ActionListener {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 560476157988482663L;
+ private JPanel contentPane;
+ private Font useFont = new Font("微软雅黑", Font.BOLD, 12);
+ private JFormattedTextField frmserverIP;
+ private JFormattedTextField username;
+ private JButton button_connect;
+ private JButton button_disconnect;
+ private JFormattedTextField toptic_input;
+ private JFormattedTextField toptic_titile;
+ private JLabel err_infoText;
+ private JComboBox comboBox;
+ private JButton sendbutton;
+ private JTextArea msgtextArea;
+ private String brokerIP;
+ private String clientId;
+ private String msgContent;
+ private String sub_topic, pub_topic;
+ private int qos = 0;
+ private MqttAsyncClient sampleClient;
+ private String infoList = "";
+ private JButton subbutton;
+
+ /**
+ * Launch the application.
+ */
+ public static void main(String[] args) {
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ MqttAsyncClientDemo frame = new MqttAsyncClientDemo();
+ frame.setVisible(true);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ /**
+ * Create the frame.
+ */
+ public MqttAsyncClientDemo() {
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setBounds(100, 100, 484, 419);
+ setTitle("MQTT客户端");
+ contentPane = new JPanel();
+ contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
+ contentPane.setLayout(null);
+ setContentPane(contentPane);
+
+ JLabel lblMqtt = new JLabel("MQTT服务器地址:");
+ lblMqtt.setFont(useFont);
+ lblMqtt.setBounds(30, 10, 109, 15);
+ contentPane.add(lblMqtt);
+
+ frmserverIP = new JFormattedTextField();
+ frmserverIP.setText("tcp://219.216.69.138:1883");
+ frmserverIP.setBounds(139, 7, 258, 21);
+ contentPane.add(frmserverIP);
+
+ JLabel lblNewLabel = new JLabel("用户名:");
+ lblNewLabel.setFont(useFont);
+ lblNewLabel.setBounds(40, 41, 54, 15);
+ contentPane.add(lblNewLabel);
+
+ username = new JFormattedTextField();
+ username.setText("chenbo");
+ username.setBounds(139, 38, 99, 21);
+ contentPane.add(username);
+
+ button_connect = new JButton("连 接");
+ button_connect.setBounds(30, 66, 93, 23);
+ button_connect.setFont(useFont);
+ button_connect.addActionListener(this);
+ button_connect.setActionCommand("connect");
+ contentPane.add(button_connect);
+
+ button_disconnect = new JButton("断 开");
+ button_disconnect.setEnabled(false);
+ button_disconnect.setFont(useFont);
+ button_disconnect.addActionListener(this);
+ button_disconnect.setActionCommand("disconnect");
+ button_disconnect.setBounds(263, 66, 93, 23);
+ contentPane.add(button_disconnect);
+
+ JLabel label = new JLabel("订阅主题:");
+ label.setBounds(40, 111, 83, 15);
+ label.setFont(useFont);
+ contentPane.add(label);
+
+ toptic_input = new JFormattedTextField();
+ toptic_input.setText("info");
+ toptic_input.setBounds(139, 108, 99, 21);
+ contentPane.add(toptic_input);
+
+ JSeparator separator = new JSeparator();
+ separator.setBounds(30, 99, 367, 2);
+ contentPane.add(separator);
+
+ subbutton = new JButton("订 阅");
+ subbutton.setFont(useFont);
+ subbutton.addActionListener(this);
+ subbutton.setActionCommand("sub");
+ subbutton.setBounds(263, 107, 93, 23);
+ contentPane.add(subbutton);
+
+ JSeparator separator_1 = new JSeparator();
+ separator_1.setBounds(30, 139, 367, 2);
+ contentPane.add(separator_1);
+
+ JLabel label_1 = new JLabel("发布消息");
+ label_1.setFont(useFont);
+ label_1.setBounds(40, 151, 60, 15);
+ contentPane.add(label_1);
+
+ JLabel label_2 = new JLabel("主题");
+ label_2.setFont(useFont);
+ label_2.setBounds(104, 151, 30, 15);
+ contentPane.add(label_2);
+
+ toptic_titile = new JFormattedTextField();
+ toptic_titile.setText("test");
+ toptic_titile.setBounds(139, 148, 99, 21);
+ contentPane.add(toptic_titile);
+
+ JLabel label_3 = new JLabel("服务质量");
+ label_3.setFont(useFont);
+ label_3.setBounds(248, 151, 54, 15);
+ contentPane.add(label_3);
+
+ comboBox = new JComboBox();
+ comboBox.setBounds(305, 148, 51, 21);
+ comboBox.addItem("0");
+ comboBox.addItem("1");
+ comboBox.addItem("2");
+ contentPane.add(comboBox);
+
+ sendbutton = new JButton("发 送");
+ sendbutton.setBounds(46, 338, 93, 23);
+ sendbutton.addActionListener(this);
+ sendbutton.setActionCommand("send");
+ contentPane.add(sendbutton);
+
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.setBounds(40, 179, 316, 149);
+ contentPane.add(scrollPane);
+
+ msgtextArea = new JTextArea();
+ scrollPane.setViewportView(msgtextArea);
+
+ err_infoText = new JLabel("");
+ err_infoText.setForeground(Color.RED);
+ err_infoText.setBounds(134, 69, 131, 15);
+ err_infoText.setFont(useFont);
+ contentPane.add(err_infoText);
+
+ JButton btnClear = new JButton("clear");
+ btnClear.setBounds(209, 338, 93, 23);
+ btnClear.addActionListener(this);
+ btnClear.setActionCommand("clear");
+ contentPane.add(btnClear);
+
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String command = e.getActionCommand();
+ if (command.equals("connect")) {
+
+ MemoryPersistence persistence = new MemoryPersistence();
+
+ try {
+ brokerIP = frmserverIP.getText();
+ clientId = username.getText();
+ if (TextUtils.isEmpty(brokerIP)) {
+ err_infoText.setText("输入服务器地址");
+ return;
+ }
+ if (TextUtils.isEmpty(clientId)) {
+ err_infoText.setText("输入ID");
+ return;
+ }
+ sampleClient = new MqttAsyncClient(brokerIP, clientId, persistence);
+ MqttConnectOptions connOpts = new MqttConnectOptions();
+ connOpts.setCleanSession(true);
+ System.out.println("Connecting to broker: " + brokerIP);
+ sampleClient.connect(connOpts);
+
+ System.out.println("Connected");
+ err_infoText.setText("已连接");
+ button_disconnect.setEnabled(true);
+ button_connect.setEnabled(false);
+
+ sampleClient.setCallback(new MqttCallback() {
+
+ @Override
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ String msg = new String(message.getPayload());
+
+ System.out.println("接收消息主题 : " + topic);
+ System.out.println("接收消息Qos : " + message.getQos());
+ System.out.println("接收消息内容 : " + message.toString());
+ System.out.println("接收消息id : " + message.getId());
+
+ String info = message.toString();
+ infoList += info + "\n";
+ msgtextArea.setText(infoList);
+ Thread.sleep(10000);
+ }
+
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken arg0) {
+ try {
+ System.out.println(arg0.getMessage());
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void connectionLost(Throwable err) {
+ err_infoText.setText("连接丢失");
+ System.out.println("连接丢失");
+ System.out.println(err.getMessage());
+
+ }
+ });
+
+ } catch (MqttException me) {
+ System.out.println("reason " + me.getReasonCode());
+ System.out.println("msg " + me.getMessage());
+ System.out.println("loc " + me.getLocalizedMessage());
+ System.out.println("cause " + me.getCause());
+ System.out.println("excep " + me);
+ err_infoText.setText("hi:" + me.getMessage());
+ button_disconnect.setEnabled(false);
+ button_connect.setEnabled(true);
+ me.printStackTrace();
+ }
+
+ } else if (command.equals("sub")) {
+ sub_topic = toptic_input.getText();
+ if (TextUtils.isEmpty(sub_topic)) {
+ err_infoText.setText("输入订阅主题");
+ return;
+ }
+ try {
+ sampleClient.subscribe(sub_topic, 0);
+ subbutton.setEnabled(false);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+
+ } else if (command.equals("send")) {
+ pub_topic = toptic_titile.getText();
+ msgContent = msgtextArea.getText();
+ if (TextUtils.isEmpty(pub_topic)) {
+ err_infoText.setText("输入发送主题");
+ return;
+ }
+ if (TextUtils.isEmpty(msgContent)) {
+ err_infoText.setText("输入消息内容");
+ return;
+ }
+ MqttMessage message = new MqttMessage(msgContent.getBytes());
+ String qoset = comboBox.getSelectedItem().toString();
+ if (qoset == "0") {
+ qos = 0;
+ } else if (qoset == "1") {
+ qos = 1;
+ } else {
+ qos = 2;
+ }
+ message.setQos(qos);
+ try {
+ sampleClient.publish(pub_topic, message);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ err_infoText.setText(e1.getMessage());
+ }
+
+ } else if (command.equals("clear")) {
+ msgtextArea.setText("");
+ infoList = "";
+
+ } else if (command.equals("disconnect")) {
+ if (sampleClient != null) {
+ try {
+ sampleClient.disconnect();
+ button_connect.setEnabled(true);
+ button_disconnect.setEnabled(false);
+ err_infoText.setText("已断开");
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v3/MqttAsyncClientDemo1.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v3/MqttAsyncClientDemo1.java
new file mode 100644
index 0000000..ea3b3e5
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v3/MqttAsyncClientDemo1.java
@@ -0,0 +1,431 @@
+package com.rehome.mqtt01.v3;
+
+import org.apache.http.util.TextUtils;
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimerTask;
+import java.util.Timer;
+
+public class MqttAsyncClientDemo1 extends JFrame implements ActionListener {
+ private JPanel contentPane;
+ private Font useFont = new Font("微软雅黑", Font.BOLD, 12);
+ private JFormattedTextField frmserverIP;
+ private JFormattedTextField username;
+ private JButton button_connect;
+ private JButton button_disconnect;
+ private JFormattedTextField toptic_input;
+ private JFormattedTextField toptic_titile;
+ private JFormattedTextField send_msg_text;
+ private JLabel err_infoText;
+ private JComboBox comboBox;
+ private JButton sendbutton;
+ private JTextArea msgtextArea;
+ private String brokerIP;
+ private String clientId;
+ private String msgContent;
+ private String msgSendContent;
+ private String sub_topic, pub_topic;
+ private Boolean isSubject = false;
+ private Boolean isConnetc = false;
+ private Timer timer;
+ /**
+ * 消息发布质量
+ * 0:最多一次,即:<=1
+ * 1:至少一次,即:>=1
+ * 2:一次,即:=1
+ */
+ private int qos = 0;
+ private MqttAsyncClient sampleClient;
+ private MqttConnectOptions connOpts;
+ private String infoList = "";
+ private JButton subbutton;
+ private JButton noSubbutton;
+
+ /**
+ * MQTT服务端连接账号
+ */
+ private final String userName = "admin";
+ /**
+ * MQTT服务端连接密码
+ */
+ private final String passWord = "public";
+
+
+ public MqttAsyncClientDemo1() {
+ // 设置窗体大小位置
+ setBounds(100, 100, 484, 439);
+ setTitle("MQTT客户端");
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ contentPane = new JPanel();
+ contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
+ contentPane.setLayout(null);
+ setContentPane(contentPane);
+ //添加控件
+ JLabel lblMqtt = new JLabel("MQTT服务器地址:");
+ lblMqtt.setFont(useFont);
+ lblMqtt.setBounds(30, 10, 109, 15);
+ contentPane.add(lblMqtt);
+
+ frmserverIP = new JFormattedTextField();
+ frmserverIP.setText("tcp://39.101.173.20:1883");
+ frmserverIP.setBounds(139, 7, 258, 21);
+ contentPane.add(frmserverIP);
+
+ JLabel lblNewLabel = new JLabel("用户名:");
+ lblNewLabel.setFont(useFont);
+ lblNewLabel.setBounds(40, 41, 54, 15);
+ contentPane.add(lblNewLabel);
+
+ username = new JFormattedTextField();
+ username.setText("v1_server_timemqtt_05");
+ username.setBounds(139, 38, 199, 21);
+ contentPane.add(username);
+
+ button_connect = new JButton("连 接");
+ button_connect.setBounds(30, 66, 93, 23);
+ button_connect.setFont(useFont);
+ button_connect.addActionListener(this);
+ button_connect.setActionCommand("connect");
+ contentPane.add(button_connect);
+
+ button_disconnect = new JButton("断 开");
+ button_disconnect.setEnabled(false);
+ button_disconnect.setFont(useFont);
+ button_disconnect.addActionListener(this);
+ button_disconnect.setActionCommand("disconnect");
+ button_disconnect.setBounds(263, 66, 93, 23);
+ contentPane.add(button_disconnect);
+
+ JLabel label = new JLabel("订阅主题:");
+ label.setBounds(40, 111, 83, 15);
+ label.setFont(useFont);
+ contentPane.add(label);
+
+ toptic_input = new JFormattedTextField();
+ toptic_input.setText("push");
+ toptic_input.setBounds(100, 108, 99, 21);
+ contentPane.add(toptic_input);
+
+ JSeparator separator = new JSeparator();
+ separator.setBackground(Color.GREEN);
+ separator.setBounds(30, 99, 367, 2);
+ contentPane.add(separator);
+
+ subbutton = new JButton("订 阅");
+ subbutton.setFont(useFont);
+ subbutton.addActionListener(this);
+ subbutton.setActionCommand("sub");
+ subbutton.setBounds(193, 107, 83, 23);
+ contentPane.add(subbutton);
+
+ noSubbutton = new JButton("取消订阅");
+ noSubbutton.setFont(useFont);
+ noSubbutton.addActionListener(this);
+ noSubbutton.setActionCommand("noSub");
+ noSubbutton.setBounds(276, 107, 83, 23);
+ noSubbutton.setEnabled(false);
+ contentPane.add(noSubbutton);
+
+ JSeparator separator_1 = new JSeparator();
+ separator_1.setBounds(30, 139, 367, 2);
+ contentPane.add(separator_1);
+
+ JLabel label_1 = new JLabel("发布消息");
+ label_1.setFont(useFont);
+ label_1.setBounds(40, 151, 60, 15);
+ contentPane.add(label_1);
+
+ JLabel label_2 = new JLabel("主题");
+ label_2.setFont(useFont);
+ label_2.setBounds(104, 151, 30, 15);
+ contentPane.add(label_2);
+
+ toptic_titile = new JFormattedTextField();
+ toptic_titile.setText("push");
+ toptic_titile.setBounds(139, 148, 99, 21);
+ contentPane.add(toptic_titile);
+
+ JLabel label_3 = new JLabel("服务质量");
+ label_3.setFont(useFont);
+ label_3.setBounds(248, 151, 64, 15);
+ contentPane.add(label_3);
+
+ comboBox = new JComboBox();
+ comboBox.setBounds(305, 148, 64, 21);
+ comboBox.addItem("0");
+ comboBox.addItem("1");
+ comboBox.addItem("2");
+ comboBox.setSelectedItem("2");
+ contentPane.add(comboBox);
+
+ JLabel label_send = new JLabel("发布的消息内容");
+ label_send.setFont(useFont);
+ label_send.setBounds(40, 181, 100, 15);
+ contentPane.add(label_send);
+
+ send_msg_text = new JFormattedTextField();
+ send_msg_text.setText("MQTT客户端 发送消息 -->");
+ send_msg_text.setBounds(140, 179, 220, 21);
+ contentPane.add(send_msg_text);
+
+ sendbutton = new JButton("发 送");
+ sendbutton.setBounds(46, 378, 93, 23);
+ sendbutton.addActionListener(this);
+ sendbutton.setActionCommand("send");
+ contentPane.add(sendbutton);
+
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.setBounds(40, 219, 316, 149);
+ contentPane.add(scrollPane);
+
+ msgtextArea = new JTextArea();
+ scrollPane.setViewportView(msgtextArea);
+
+ err_infoText = new JLabel("");
+ err_infoText.setForeground(Color.RED);
+ err_infoText.setBounds(134, 69, 131, 15);
+ err_infoText.setFont(useFont);
+ contentPane.add(err_infoText);
+
+ JButton btnClear = new JButton("clear");
+ btnClear.setBounds(209, 378, 93, 23);
+ btnClear.addActionListener(this);
+ btnClear.setActionCommand("clear");
+ contentPane.add(btnClear);
+
+
+ }
+
+ public static void main(String[] args) {
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ MqttAsyncClientDemo1 frame = new MqttAsyncClientDemo1();
+ frame.setVisible(true);
+ frame.start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ private void start() {
+ try {
+ timer = new Timer();
+ timer.schedule(new TimerTask() {
+ public void run() {
+ System.out.println("-------设定要指定任务--------");
+ if (isConnetc == true) {
+ try {
+ //判断拦截状态,这里注意一下,如果没有这个判断,是非常坑的
+ if (!sampleClient.isConnected()) {
+ System.out.println("***** 没有连接到服务器 *****");
+ System.out.println("***** client to connect *****");
+ // 重新连接
+ sampleClient.connect(connOpts);
+ }
+ if (sampleClient.isConnected()) {//连接成功,跳出连接
+ System.out.println("***** connect success *****");
+ System.out.println("Connected");
+ err_infoText.setText("已连接");
+ button_disconnect.setEnabled(true);
+ button_connect.setEnabled(false);
+ if (isSubject == true) {
+ try {
+ sampleClient.subscribe(sub_topic, qos);
+ subbutton.setEnabled(false);
+ noSubbutton.setEnabled(true);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ }, 10000,10000);// 设定指定的时间time,此处为10000毫秒
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String command = e.getActionCommand();
+ String qosString = comboBox.getSelectedItem().toString();
+ qos = Integer.valueOf(qosString);
+ if (command.equals("connect")) {
+
+ MemoryPersistence persistence = new MemoryPersistence();
+ try {
+ brokerIP = frmserverIP.getText();
+ clientId = username.getText();
+ if (TextUtils.isEmpty(brokerIP)) {
+ err_infoText.setText("输入服务器地址");
+ return;
+ }
+ if (TextUtils.isEmpty(clientId)) {
+ err_infoText.setText("输入ID");
+ return;
+ }
+ sampleClient = new MqttAsyncClient(brokerIP, clientId, persistence);
+ connOpts = new MqttConnectOptions();
+ // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
+ connOpts.setCleanSession(true);
+ // 设置连接的用户名
+ connOpts.setUserName(userName);
+ // 设置连接的密码
+ connOpts.setPassword(passWord.toCharArray());
+ // 设置超时时间 单位为秒
+ connOpts.setConnectionTimeout(10);
+ // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
+ connOpts.setKeepAliveInterval(20);
+ System.out.println("Connecting to broker: " + brokerIP);
+ sampleClient.connect(connOpts);
+
+ System.out.println("Connected");
+ err_infoText.setText("已连接");
+ button_disconnect.setEnabled(true);
+ button_connect.setEnabled(false);
+ isConnetc = true;
+
+ sampleClient.setCallback(new MqttCallback() {
+
+ @Override
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ String msg = new String(message.getPayload());
+ System.out.println("接收消息主题 : " + topic);
+ System.out.println("接收消息Qos : " + message.getQos());
+ System.out.println("接收消息内容 : " + message.toString());
+ System.out.println("接收消息id : " + message.getId());
+
+ String info = message.toString();
+ infoList += info + "\n";
+ msgtextArea.setText(infoList);
+ }
+
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken arg0) {
+ System.out.println("deliveryComplete---------" + arg0.isComplete());
+ }
+
+ @Override
+ public void connectionLost(Throwable err) {
+ // 断开连接
+ try {
+ sampleClient.disconnect();
+ // 关闭客户端
+ sampleClient.close();
+ } catch (MqttException mqttException) {
+ mqttException.printStackTrace();
+ }
+ err_infoText.setText("连接丢失");
+ button_connect.setEnabled(true);
+ button_disconnect.setEnabled(false);
+ System.out.println("连接丢失");
+ System.out.println(err.getMessage());
+
+ }
+ });
+
+ } catch (MqttException me) {
+ System.out.println("reason " + me.getReasonCode());
+ System.out.println("msg " + me.getMessage());
+ System.out.println("loc " + me.getLocalizedMessage());
+ System.out.println("cause " + me.getCause());
+ System.out.println("excep " + me);
+ err_infoText.setText("hi:" + me.getMessage());
+ button_disconnect.setEnabled(false);
+ button_connect.setEnabled(true);
+ me.printStackTrace();
+ }
+
+ } else if (command.equals("sub")) {
+ sub_topic = toptic_input.getText();
+ if (TextUtils.isEmpty(sub_topic)) {
+ err_infoText.setText("输入订阅主题");
+ return;
+ }
+ try {
+ sampleClient.subscribe(sub_topic, qos);
+ subbutton.setEnabled(false);
+ noSubbutton.setEnabled(true);
+ isSubject = true;
+ toptic_input.setEnabled(false);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+
+ } else if (command.equals("noSub")) {
+ sub_topic = toptic_input.getText();
+ if (TextUtils.isEmpty(sub_topic)) {
+ err_infoText.setText("输入订阅主题");
+ return;
+ }
+ try {
+ sampleClient.unsubscribe(sub_topic);
+ subbutton.setEnabled(true);
+ noSubbutton.setEnabled(false);
+ isSubject = false;
+ toptic_input.setEnabled(true);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+
+ } else if (command.equals("send")) {
+ pub_topic = toptic_titile.getText();
+ msgSendContent = send_msg_text.getText();
+ if (TextUtils.isEmpty(pub_topic)) {
+ err_infoText.setText("输入发送主题");
+ return;
+ }
+ if (TextUtils.isEmpty(msgSendContent)) {
+ err_infoText.setText("输入消息内容");
+ return;
+ }
+ MqttMessage message = new MqttMessage(msgSendContent.getBytes());
+ message.setQos(qos);
+ try {
+ sampleClient.publish(pub_topic, message);
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ err_infoText.setText(e1.getMessage());
+ }
+
+ } else if (command.equals("clear")) {
+ msgtextArea.setText("");
+ infoList = "";
+
+ } else if (command.equals("disconnect")) {
+ if (sampleClient != null) {
+ try {
+ // 断开连接
+ sampleClient.disconnect();
+ // 关闭客户端
+ sampleClient.close();
+ button_connect.setEnabled(true);
+ button_disconnect.setEnabled(false);
+ subbutton.setEnabled(true);
+ noSubbutton.setEnabled(false);
+ toptic_input.setEnabled(true);
+ isConnetc = false;
+ err_infoText.setText("已断开");
+ isSubject = false;
+ } catch (MqttException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v3/SwingSingleThreadDemo.java b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v3/SwingSingleThreadDemo.java
new file mode 100644
index 0000000..cda7b32
--- /dev/null
+++ b/mqtt_java_maven/src/main/java/com/rehome/mqtt01/v3/SwingSingleThreadDemo.java
@@ -0,0 +1,92 @@
+package com.rehome.mqtt01.v3;
+
+import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Vector;
+
+public class SwingSingleThreadDemo extends JFrame {
+
+ private ButtonGroup buttonGroup = new ButtonGroup(); // 按钮组
+ private JList list; // 列表组件
+ private Vector listData=new Vector(); // 列表数据
+
+ public SwingSingleThreadDemo() {
+ setBounds(100, 100, 236, 204); // 设置窗体大小位置
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ final JScrollPane scrollPane = new JScrollPane(); // 创建高度面板
+ getContentPane().add(scrollPane, BorderLayout.CENTER);
+ list = new JList(); // 创建列表组件
+ scrollPane.setViewportView(list); // 滚动面板控制列表
+ final JPanel buttonPanel = new JPanel(); // 创建按钮面板
+ getContentPane().add(buttonPanel, BorderLayout.SOUTH);
+ final JButton button = new JButton(); // 创建按钮
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(final ActionEvent e) {
+ do_button_actionPerformed(e); // 调用按钮事件处理方法
+ }
+ });
+ button.setText("添加列表选项"); // 设置按钮名称
+ buttonPanel.add(button);
+
+ final JPanel panel = new JPanel(); // 创建单选按钮面板
+ panel.setLayout(new GridLayout(0, 1)); // 使用网格布局
+ getContentPane().add(panel, BorderLayout.EAST);
+ final JRadioButton radioButton_1 = new JRadioButton(); // 创建单选按钮1
+ buttonGroup.add(radioButton_1);
+ radioButton_1.setText("单选1");
+ radioButton_1.setSelected(true);
+ panel.add(radioButton_1);
+ final JRadioButton radioButton_2 = new JRadioButton(); // 创建单选按钮2
+ buttonGroup.add(radioButton_2);
+ radioButton_2.setText("单选2");
+ panel.add(radioButton_2);
+ final JRadioButton radioButton_3 = new JRadioButton(); // 创建单选按钮3
+ buttonGroup.add(radioButton_3);
+ radioButton_3.setText("单选3");
+ panel.add(radioButton_3);
+ final JRadioButton radioButton_4 = new JRadioButton(); // 创建单选按钮4
+ buttonGroup.add(radioButton_4);
+ radioButton_4.setText("单选4");
+ panel.add(radioButton_4);
+ }
+
+ protected void do_button_actionPerformed(ActionEvent e) {//一点击按钮,自动添加数据了
+ new Thread(){//开辟一个新的线程执行费时业务
+ public void run(){
+ for(int i=0;i<10;i++){
+ Runnable runnable = new Runnable() {
+
+ @Override
+ public void run() {
+ listData.add("选项"+listData.size());
+ list.setListData(listData);
+ }
+ };
+ EventQueue.invokeLater(runnable);//在时间队列中执行Runnable对象
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ }
+ }
+ }.start();
+ }
+
+ public static void main(String[] args) {
+ EventQueue.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+ SwingSingleThreadDemo frame = new SwingSingleThreadDemo();
+ frame.setVisible(true);
+ }
+ });
+ }
+}
diff --git a/mqtt_java_maven/src/main/resources/application.properties b/mqtt_java_maven/src/main/resources/application.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/mqtt_java_maven/src/main/resources/application.properties
@@ -0,0 +1 @@
+
diff --git a/mqtt_java_maven/src/main/resources/ssl/client.crt b/mqtt_java_maven/src/main/resources/ssl/client.crt
new file mode 100644
index 0000000..016eeb8
Binary files /dev/null and b/mqtt_java_maven/src/main/resources/ssl/client.crt differ
diff --git a/mqtt_java_maven/src/main/resources/ssl/client.key b/mqtt_java_maven/src/main/resources/ssl/client.key
new file mode 100644
index 0000000..5cc1b5a
--- /dev/null
+++ b/mqtt_java_maven/src/main/resources/ssl/client.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA2Z/AwbQXzOff03cTCH+0fAArgiKRgY8YNDGt4/On09AGGzWf
+zcpEd8dRzPhkkSoBdWbN+JQeYF09+z9eIVIbhn99DI/s58L664ngW5FwycbmUP8t
+BwYb9wTeT2Mnygi9E8hGBZnbfT0efwlDqVKIBYmaVurWFOB2uylbF1li/4WG2IEV
+jvv0B72kqwZs4ZvQMWOqYZDtgOVzZiOXcPFM8XNwG/mrbtUfBYbDUmP/EFPZpkEr
+4aMnbX9LeTfWnt7NhExsEwjMPotqQzyZ3K8ui1sqIepiqs2pOsQ06Xynofnz7YnS
+iUHCQUGq68hMqYjYSqt9nA87vDrC299aRCEOJwIDAQABAoIBAGI6PlnwPPHrE1cy
+nu+uHLv/o6PIkJ7HBOjCJ7gFSZJMigUMDkZn7sGVwPFgiJwRNrlUHtH9oTxjuc9H
+CejGU9BAiSP7brYphvJ7uD38hsk8ssaKdzt9YW/8zY9NtS73BMkCE8EBclW0GajD
+eLvbmbPOKVDkDJ89tbnC7++5E/s658/ZCHNWJcOUvy0Bb1uF9z3nIh6DNQ6AgIHZ
+ds0XjcMR/6KbD6jk0hBt9oczFRZ6KONh3XiPCgzOx09TWRyRSQwQkL4sDJnoMFoC
+MipVsQnm6EqJ6FkL+qshFvZ91FnXniWsAKexbUyMRSTwTVBxBB2TBzyHlX5GA3bY
+zopTRlECgYEA7HiuBm1tOU+ZGFs6UbagBFUh83+GKbGtSWEUsoop6eKxVCbTFEmk
+zwWWovvuE77DB2a+S0NqbGG7KgyUaonU1sgNrSCH4UIyohoII9ZpRkmA2gHXfasw
+uHNVRaxKIGgdbDLkGb/is4fYQgvRLPFl5cN6MQaDIokdh+m0wCxgIrkCgYEA65id
+W3DOvCiDX9KVPnXJp+l1szMIrtWMp7FsmKLFY5sqhlRx3vv0uFLy6dCZzAvPiP6F
+MrDbvGfvVNIe2nMxdwWwIorI5Zpq6zngeHFuP/rRzeJiikbgqYK/PHAsJI26x2VD
+gJ+a/OoEenVZrzeDzx5fIipDPQ4lzxBZlQ4Nx98CgYAdtrBPWHKwD+Nx3wy99c+3
+m6bvfOez14KpxMwf/yJzJCwaIeLGGtbduJsMEdIBoyfIh02EEY2O3tzw1LHVjUo0
+TuEBDyRj1ricC99X+Xoy/ct2GWMlhFxT4RIm9hY+ajbAQMjOv4DSBFDVQ7zeA9tE
++sIg5OuXbFlMmb4/o5PU6QKBgF8OIl8kcqUEC417329mAsjWrwBwVM6Fpsx6D4C+
+G7oGfu/X3mHDcod0IEIqQgNLuJ5jYsaDCQVJQg0NAhnNZGXLS7eEG25YEU96+JBf
+48W4ozHYZz23PynlcNcnwwe0j2mn98ZLnzLwEIKAGoFResL0VBnqx1o4/RRAWoSD
+ORgtAoGBALx98NhsB1sQ1+fC8kHVHjiXTY/xenRcTYdTuGS4sYi30HjOl9BsBjLy
+JKR43AXt0+/2/ZYJiBo2VGlkkqKH4twtApiIOObK7qUtIkoM1sfIWCTB+gAISUJV
+1xpwbFpw00OvE5JTGSmGbTEPI+7nCD+0ZeQpf1PIiSaWVe3JbYXZ
+-----END RSA PRIVATE KEY-----
diff --git a/mqtt_java_maven/src/main/resources/ssl/my_root_ca.crt b/mqtt_java_maven/src/main/resources/ssl/my_root_ca.crt
new file mode 100644
index 0000000..f1722c4
Binary files /dev/null and b/mqtt_java_maven/src/main/resources/ssl/my_root_ca.crt differ
diff --git a/mqtt_java_maven/src/main/resources/ssl/my_root_ca.pem b/mqtt_java_maven/src/main/resources/ssl/my_root_ca.pem
new file mode 100644
index 0000000..240c9c5
--- /dev/null
+++ b/mqtt_java_maven/src/main/resources/ssl/my_root_ca.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDhjCCAm4CCQC1V5/VbnNtnDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC
+Q04xEjAQBgNVBAgMCWd1YW5nZG9uZzEPMA0GA1UEBwwGemh1aGFpMQ8wDQYDVQQK
+DAZyZWhvbWUxDzANBgNVBAsMBnJlaG9tZTEPMA0GA1UEAwwGcmVob21lMR0wGwYJ
+KoZIhvcNAQkBFg5od2Y0NTJAMTYzLmNvbTAeFw0yMTA4MDQwMzA0NTBaFw0zMTA4
+MDIwMzA0NTBaMIGEMQswCQYDVQQGEwJDTjESMBAGA1UECAwJZ3Vhbmdkb25nMQ8w
+DQYDVQQHDAZ6aHVoYWkxDzANBgNVBAoMBnJlaG9tZTEPMA0GA1UECwwGcmVob21l
+MQ8wDQYDVQQDDAZyZWhvbWUxHTAbBgkqhkiG9w0BCQEWDmh3ZjQ1MkAxNjMuY29t
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAube15VxwpVpCErD1+bfy
+5HVF/VqEQIAxmZrBOCzuBBIH+qU1i8pR7dla8fWSToBIgfHc7frvWDdF3z2PAE43
+3qLwQO8CA9qDIANMKLF1mZfvjb07ZB4MiKIYmOD0gUfm8HCy9mIM58aCEMeWxEJT
++7OQbJElNniJ4Ngf7U02JLXrpgKmEjSmhaTj0SdjKgIPoulJsBpLmYv/ADG3Z2kx
+hVHw/0SaIiitmQMt93ch5nR0UzDi6oMT8h/4JKdwswEr+cOtVwTBZMrMRDA8J6Hm
+Qf57wrmbzUHHVpzLsyRcffkC5UdLLYttKyGgiY06qAgntGbE9w7i6QGJU8Xs9n9f
+ywIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBvyhnxig355LlZFk2D1QXVU1Lj4xMB
+23Pzh+dW0pIMx4qZbepuV5RXSzNfhVnkq5WtCBBR/G8yLbwmbFY7WSNrzIX3C/EW
+b8vyR13y5lQvRdwnTBaNsyYNQ0TkLe3sg1lWWb9dIX4Oql0l/eZDHF6Y/Bj4NIfs
+9Ddi+M2mMu+gBIzCOJthZnKhDPPZgUN458BiU8k+0K58tmdNyH6ZyfWDy9PkI53q
++caRODG6sA+H/E2A64B7+0kjsAudZ4jid3zLAWzcaZw2QUYMMtm8x953f++L4H2s
+zXVxrtKAWaC3sJPeWjUdPmxCCg7GSLU8dTmmUrXavCNB+I8ERmU/D9Hu
+-----END CERTIFICATE-----
diff --git a/mqtt_java_maven/src/main/resources/ssl1/client.crt b/mqtt_java_maven/src/main/resources/ssl1/client.crt
new file mode 100644
index 0000000..016eeb8
Binary files /dev/null and b/mqtt_java_maven/src/main/resources/ssl1/client.crt differ
diff --git a/mqtt_java_maven/src/main/resources/ssl1/client.key b/mqtt_java_maven/src/main/resources/ssl1/client.key
new file mode 100644
index 0000000..5cc1b5a
--- /dev/null
+++ b/mqtt_java_maven/src/main/resources/ssl1/client.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA2Z/AwbQXzOff03cTCH+0fAArgiKRgY8YNDGt4/On09AGGzWf
+zcpEd8dRzPhkkSoBdWbN+JQeYF09+z9eIVIbhn99DI/s58L664ngW5FwycbmUP8t
+BwYb9wTeT2Mnygi9E8hGBZnbfT0efwlDqVKIBYmaVurWFOB2uylbF1li/4WG2IEV
+jvv0B72kqwZs4ZvQMWOqYZDtgOVzZiOXcPFM8XNwG/mrbtUfBYbDUmP/EFPZpkEr
+4aMnbX9LeTfWnt7NhExsEwjMPotqQzyZ3K8ui1sqIepiqs2pOsQ06Xynofnz7YnS
+iUHCQUGq68hMqYjYSqt9nA87vDrC299aRCEOJwIDAQABAoIBAGI6PlnwPPHrE1cy
+nu+uHLv/o6PIkJ7HBOjCJ7gFSZJMigUMDkZn7sGVwPFgiJwRNrlUHtH9oTxjuc9H
+CejGU9BAiSP7brYphvJ7uD38hsk8ssaKdzt9YW/8zY9NtS73BMkCE8EBclW0GajD
+eLvbmbPOKVDkDJ89tbnC7++5E/s658/ZCHNWJcOUvy0Bb1uF9z3nIh6DNQ6AgIHZ
+ds0XjcMR/6KbD6jk0hBt9oczFRZ6KONh3XiPCgzOx09TWRyRSQwQkL4sDJnoMFoC
+MipVsQnm6EqJ6FkL+qshFvZ91FnXniWsAKexbUyMRSTwTVBxBB2TBzyHlX5GA3bY
+zopTRlECgYEA7HiuBm1tOU+ZGFs6UbagBFUh83+GKbGtSWEUsoop6eKxVCbTFEmk
+zwWWovvuE77DB2a+S0NqbGG7KgyUaonU1sgNrSCH4UIyohoII9ZpRkmA2gHXfasw
+uHNVRaxKIGgdbDLkGb/is4fYQgvRLPFl5cN6MQaDIokdh+m0wCxgIrkCgYEA65id
+W3DOvCiDX9KVPnXJp+l1szMIrtWMp7FsmKLFY5sqhlRx3vv0uFLy6dCZzAvPiP6F
+MrDbvGfvVNIe2nMxdwWwIorI5Zpq6zngeHFuP/rRzeJiikbgqYK/PHAsJI26x2VD
+gJ+a/OoEenVZrzeDzx5fIipDPQ4lzxBZlQ4Nx98CgYAdtrBPWHKwD+Nx3wy99c+3
+m6bvfOez14KpxMwf/yJzJCwaIeLGGtbduJsMEdIBoyfIh02EEY2O3tzw1LHVjUo0
+TuEBDyRj1ricC99X+Xoy/ct2GWMlhFxT4RIm9hY+ajbAQMjOv4DSBFDVQ7zeA9tE
++sIg5OuXbFlMmb4/o5PU6QKBgF8OIl8kcqUEC417329mAsjWrwBwVM6Fpsx6D4C+
+G7oGfu/X3mHDcod0IEIqQgNLuJ5jYsaDCQVJQg0NAhnNZGXLS7eEG25YEU96+JBf
+48W4ozHYZz23PynlcNcnwwe0j2mn98ZLnzLwEIKAGoFResL0VBnqx1o4/RRAWoSD
+ORgtAoGBALx98NhsB1sQ1+fC8kHVHjiXTY/xenRcTYdTuGS4sYi30HjOl9BsBjLy
+JKR43AXt0+/2/ZYJiBo2VGlkkqKH4twtApiIOObK7qUtIkoM1sfIWCTB+gAISUJV
+1xpwbFpw00OvE5JTGSmGbTEPI+7nCD+0ZeQpf1PIiSaWVe3JbYXZ
+-----END RSA PRIVATE KEY-----
diff --git a/mqtt_java_maven/src/main/resources/ssl1/client.pem b/mqtt_java_maven/src/main/resources/ssl1/client.pem
new file mode 100644
index 0000000..fbe9052
--- /dev/null
+++ b/mqtt_java_maven/src/main/resources/ssl1/client.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVTCCAj0CCQDXjywWHSxSkTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMC
+Q04xEjAQBgNVBAgMCWd1YW5nZG9uZzEPMA0GA1UEBwwGemh1aGFpMQ8wDQYDVQQK
+DAZyZWhvbWUxDzANBgNVBAsMBnJlaG9tZTEPMA0GA1UEAwwGcmVob21lMR0wGwYJ
+KoZIhvcNAQkBFg5od2Y0NTJAMTYzLmNvbTAeFw0yMTA4MDQwNzUxMDNaFw0zMTA4
+MDIwNzUxMDNaMFQxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ2RvbmcxDzAN
+BgNVBAcMBlpodWhhaTEPMA0GA1UECgwGcmVob21lMQ8wDQYDVQQDDAZjbGllbnQw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZn8DBtBfM59/TdxMIf7R8
+ACuCIpGBjxg0Ma3j86fT0AYbNZ/NykR3x1HM+GSRKgF1Zs34lB5gXT37P14hUhuG
+f30Mj+znwvrrieBbkXDJxuZQ/y0HBhv3BN5PYyfKCL0TyEYFmdt9PR5/CUOpUogF
+iZpW6tYU4Ha7KVsXWWL/hYbYgRWO+/QHvaSrBmzhm9AxY6phkO2A5XNmI5dw8Uzx
+c3Ab+atu1R8FhsNSY/8QU9mmQSvhoydtf0t5N9ae3s2ETGwTCMw+i2pDPJncry6L
+Wyoh6mKqzak6xDTpfKeh+fPtidKJQcJBQarryEypiNhKq32cDzu8OsLb31pEIQ4n
+AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAMrOB3dQn9NSoimSAY+FBbvHmmxTHC68
+v94HHv+hWwOZGpMS1OEeYJuxTmxoDmnrFruFSJxFJVSLUuYfNSc25mbKsvx722nl
+8Wh2y1pfLR2ndh4Pjhrsfe+AW+Fw/wZC/tAJRA2gYmP8xYoSYv1RUhfaJ1qwB7kB
+7YfkbroD3078n4DlG9dQKz0qngCxV27U6ud0U+hz9vX8lceNfFa3LSYc6cZJep0r
+FmHQpq4QHEJrlImds4RZHQMcVCTG0ZWJb1HB+phSVqvk3b3ZxN7QE/46rSzJ1CxJ
+VFRSeCVWhNZEk8rGR2YCBLmIn0FGG27C4KzH1ipxb7N1x/JMCZl59Qw=
+-----END CERTIFICATE-----
diff --git a/mqtt_java_maven/src/main/resources/ssl1/my_root_ca.crt b/mqtt_java_maven/src/main/resources/ssl1/my_root_ca.crt
new file mode 100644
index 0000000..603b7a2
Binary files /dev/null and b/mqtt_java_maven/src/main/resources/ssl1/my_root_ca.crt differ
diff --git a/mqtt_java_maven/src/main/resources/ssl1/my_root_ca.pem b/mqtt_java_maven/src/main/resources/ssl1/my_root_ca.pem
new file mode 100644
index 0000000..baa96e3
--- /dev/null
+++ b/mqtt_java_maven/src/main/resources/ssl1/my_root_ca.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDhjCCAm4CCQCqYUL4JqVLWTANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC
+Q04xEjAQBgNVBAgMCWd1YW5nZG9uZzEPMA0GA1UEBwwGemh1aGFpMQ8wDQYDVQQK
+DAZyZWhvbWUxDzANBgNVBAsMBnJlaG9tZTEPMA0GA1UEAwwGcmVob21lMR0wGwYJ
+KoZIhvcNAQkBFg5od2Y0NTJAMTYzLmNvbTAeFw0yMTA4MDQwNzQ1NDhaFw0zMTA4
+MDIwNzQ1NDhaMIGEMQswCQYDVQQGEwJDTjESMBAGA1UECAwJZ3Vhbmdkb25nMQ8w
+DQYDVQQHDAZ6aHVoYWkxDzANBgNVBAoMBnJlaG9tZTEPMA0GA1UECwwGcmVob21l
+MQ8wDQYDVQQDDAZyZWhvbWUxHTAbBgkqhkiG9w0BCQEWDmh3ZjQ1MkAxNjMuY29t
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzhehcE4ADvQ4G9gTXcTx
+5pE4ZPihOa91ua+/h+oen+Be3iDof87CMm8Dq9QyXj1omwXwouEwDFQx1RJS50hi
+WWF7O1BH2u+yvKJOGKeh+gB5CBR6g/eJeSx0f59M6BOHAtKrCFOWNXw7GpTqjeOI
+vAGzl41su9CCVmsjf+sukyWXkPkVoOvMfR4L8lQuenzfFWgytQcq0c/DJH/JJB/V
+eFqqtoeM/hmUhh78DLse0mCXi/6qOK67qiJdHC8V6Fbij8v58G2A+Da22nd3EXzw
+m7IlvjL0lsVNtjPjURhJxylO1oLj9yTw/8Bv4ysWXYpd89MJJRfRSHlHTOluXOnD
+kQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQDBKs2KdFLbnEbtjz6Kr6OgLfu+TvGp
+CSDnscOgpBtdXSzDkaO4e3SOvTd/1ADuYjCMRZrNy1xFGCxJe7eeFOEl2pJzaXCS
+UQWHtN9EDDfF1ZnNNfHIAYpbUEuUxD2cBZQtlBb9Tb0H70ZpuoYR8SpdxBsZ7nuS
+qhRYhSZE8SUN2UCkBAmtP8PGGsGfS0j3GfhqkZonxT0wW3Jz2q9O2rpo7SjstXp+
+E+NJ8xSMnhf3va3+fckUfNNfrgVVDzWu7Dv61+JJgGL9KMZMXK0KJUM6Q/tPUFPW
+MOst0D2yXK0GTpva8BqjCouZuL5gfSYAYNb9PV5E/9AnHaoBr2j3Cv79
+-----END CERTIFICATE-----
diff --git a/mqtt_java_maven/src/main/resources/ssl_two_dir/client.key b/mqtt_java_maven/src/main/resources/ssl_two_dir/client.key
new file mode 100644
index 0000000..fb54e44
--- /dev/null
+++ b/mqtt_java_maven/src/main/resources/ssl_two_dir/client.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAvur5N8+LcHizZWj7zXZuhUesy48hxhPo781iVM9XdL9ywa8p
+kEJ9yN6qBjk/RAnUu1SnRgPB5L2zmN3jQhZX/sW2BIOx7I5kDMnTPKsvbPtJOWOs
+nYVjUWnNHBAmPILe9wd2SdkmGvOGn4cqn308xfuzSGZbbbeR6nmZHthZgHBJf9DI
+xVYJj2wbE03WQ7PjA+3/CUI3O3ACNSZl5qtN51g3ZITuscghAsg6/OIZa4UYuK/G
+SOfSP0f/427rOVIobXptuMYnSSIQyXxr/AO7gGOCZfTcR81pzsMcRU/t1KcI1aAu
+JhvaSdWiKUjO89xv+CDvf9xKp/KlBWJjwvzOiQIDAQABAoIBAQCr52NTT3tcYDIY
+A7mGvTayp2D9QPnGIrNBCQubFb7HjoLDxvaDwHsF3Qf25qECoF999bFQJ530WqNV
+56TzIq9E5b0Iv5P7ThLkOO4M2I6xcGn0VL1ecHaHHd7jf98N6UDd6UgnInFfHxt+
+lPRZ+yg3lHVPoWp9lia6m5a14VRlgiUH8yeBXrh6+C1GJ8BfL7qVdyOK98fXJPQ2
+ldalM4EeYqcWwOeHLvtnJNHjGgnBEbPkBBha5eEtk0Gmbiiikb41plFLEgz0HNbU
+Z8pJTk2WXO6qnFRYU60eu+3naTnZBn70RT7bDJyITHM8RoIeEswyWF6mXAZNbKwW
+CK21WaohAoGBAPasBmJvQUdxuq10ebmVrEkR29b745ktteZhk7Zsb2B6yR3sg68t
+17/tq/FJoIYsYgEZu9Kafzyucd4nlFsR+JNOaKGJjvZpGx6XwDgoeEBmEcN6ug+k
+Zshavtezh1c8EZvjvAmkEwIyq1x+8C00ujSqBrK4NfBBcEnKv1f3yroNAoGBAMYj
+NK41xwslu7wdgD4kFx/lli6sA3nZ7MPOL0YE0rcBbDADTCACufUsHp4NrtNuN9Vn
+MqWJVTWUfv0ImSNAebVL49fAu2CRsB3FWrgRmLnbZSaPxDRzH/IXO/6Er5GHIj7D
+56bWGEFgNVG/peubatOkXJu5PnDHjTRATKEZRzNtAoGAa6lRcA0W9NPSono/1pxZ
+AdtllEOEZwroZZEZI3nYcsekmAbuwrrDe+WEMl/sTCN68vgEXjtIZXfOAyRLQCRr
+1f9W84pSd4IQcB3Tq68eLR1fi245XzJmGfRhb0vQOmbhWKThIWQXV9I9sLVGprRo
+wSukmMSF5kLpe4ueUAq61NECgYB6CDzt/xk0eG0EE3dkzn2fm5u/6xnI9ruobVkY
+Wugc5rdnauB75rH5ms7QscS3W+7vdLvw0IC2m1sLJTyMRa2wR6lwvLerZo9+Bos1
+S0ExVzsZYPqLA0ztofnFbJtlmkExPx9x1fLicQrl6o+aaQKGj3iqQJGAjKcfQ2ru
+3c7IkQKBgDZfEzNBLbH+lr73FKoSJpH5bu/gEqt8m72vWlZiY1ozOUmK3qnQI0MI
+DQ/M77DTJ+nw4uRePzoivuhR8ElWJbW4QEwUIkDFH2WHYkl6lWGFOBYAVxqCiXWB
+iDa3fKx25ggV3GkjKl7Ct3ToNzP94qxbxLsJTCjBLNUxuIOJZfQd
+-----END RSA PRIVATE KEY-----
diff --git a/mqtt_java_maven/src/main/resources/ssl_two_dir/client.pem b/mqtt_java_maven/src/main/resources/ssl_two_dir/client.pem
new file mode 100644
index 0000000..6f01d2a
--- /dev/null
+++ b/mqtt_java_maven/src/main/resources/ssl_two_dir/client.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDhTCCAm0CCQCGLmLZ4MiwvjANBgkqhkiG9w0BAQUFADCBtjELMAkGA1UEBhMC
+Q04xEjAQBgNVBAgMCUd1YW5nZG9uZzEPMA0GA1UEBwwGWmh1aGFpMSUwIwYDVQQK
+DBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQLDBREb21haW4g
+VmFsaWRhdGVkIFNTTDEdMBsGA1UEAwwUVHJ1c3RBc2lhIFRMUyBSU0EgQ0ExHTAb
+BgkqhkiG9w0BCQEWDmh3ZjQ1M0AxNjMuY29tMB4XDTIxMDgwNTEyMzY1NVoXDTMx
+MDgwMzEyMzY1NVowUjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzEP
+MA0GA1UEBwwGWmh1aGFpMQ0wCwYDVQQKDARFTVFYMQ8wDQYDVQQDDAZjbGllbnQw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+6vk3z4tweLNlaPvNdm6F
+R6zLjyHGE+jvzWJUz1d0v3LBrymQQn3I3qoGOT9ECdS7VKdGA8HkvbOY3eNCFlf+
+xbYEg7HsjmQMydM8qy9s+0k5Y6ydhWNRac0cECY8gt73B3ZJ2SYa84afhyqffTzF
++7NIZlttt5HqeZke2FmAcEl/0MjFVgmPbBsTTdZDs+MD7f8JQjc7cAI1JmXmq03n
+WDdkhO6xyCECyDr84hlrhRi4r8ZI59I/R//jbus5Uihtem24xidJIhDJfGv8A7uA
+Y4Jl9NxHzWnOwxxFT+3UpwjVoC4mG9pJ1aIpSM7z3G/4IO9/3Eqn8qUFYmPC/M6J
+AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBADI5aypoagVc74HMrQ19xvAYkhXqvDfg
+L+xwD7XdUz0smL41psyYVgd7tWOIUGarMuMIqvzIXw4nDdWeuskGSi4As9rO8Aha
+Ms2k3nayXd7Bl8Wc0fkPJPf3g+POWyFX1dTi+2lgB1vNqJlf0rnmuWaA+2kS9b2V
+yUf+fFOf4Oe7KsPsYF/PWpa2+9wE5zGktiEOgXq2CDgUVH9c7Z/6uGQs0YRP1ZmP
+ErRwxzYi18De8M7kt9hbjUngi7V4WenX++xEQdXio9ZauKZGnIDtvpvAQykf74h7
+JneS1tGeTWHZVs6kwM7pb3zl6VRlOI3Tno9RJQBIdGLbNPHe/hA/Tcw=
+-----END CERTIFICATE-----
diff --git a/mqtt_java_maven/src/main/resources/ssl_two_dir/my_root_ca.pem b/mqtt_java_maven/src/main/resources/ssl_two_dir/my_root_ca.pem
new file mode 100644
index 0000000..52dfcbb
--- /dev/null
+++ b/mqtt_java_maven/src/main/resources/ssl_two_dir/my_root_ca.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID6jCCAtICCQDZhZupRjNreTANBgkqhkiG9w0BAQsFADCBtjELMAkGA1UEBhMC
+Q04xEjAQBgNVBAgMCUd1YW5nZG9uZzEPMA0GA1UEBwwGWmh1aGFpMSUwIwYDVQQK
+DBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQLDBREb21haW4g
+VmFsaWRhdGVkIFNTTDEdMBsGA1UEAwwUVHJ1c3RBc2lhIFRMUyBSU0EgQ0ExHTAb
+BgkqhkiG9w0BCQEWDmh3ZjQ1M0AxNjMuY29tMB4XDTIxMDgwNTEyMjk1MFoXDTMx
+MDgwMzEyMjk1MFowgbYxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ2Rvbmcx
+DzANBgNVBAcMBlpodWhhaTElMCMGA1UECgwcVHJ1c3RBc2lhIFRlY2hub2xvZ2ll
+cywgSW5jLjEdMBsGA1UECwwURG9tYWluIFZhbGlkYXRlZCBTU0wxHTAbBgNVBAMM
+FFRydXN0QXNpYSBUTFMgUlNBIENBMR0wGwYJKoZIhvcNAQkBFg5od2Y0NTNAMTYz
+LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqCs/p1Acvqdkhp
+zZGpr70bBU6w3VNURZQPFqtAmJwDz1sbhA4ek+aWUJz7aGqHv80EYsIaGmbZoaA1
+0/n5SfgQjaojD7syT7JRDaqBjCujvZ+4YRpeihcapRdAwnUf9iN87P27gh0GGaMS
+Q+aKMOdgChKBN8dBK+EZWx1CfFEyzOCuxajumN+jSNHLBJop55MB0jxQ2PldBV7Z
+mcKLtPpZTE1+PIsjowy8hhkaaLBtNn6+mPbG6b6iFqK6M7m1k412jsQIcO5D7l+b
+Wwa9Fn0sODgnYkxLf5jZkXPhHFoRmCCvHMnZsdT1LIfXNfZOxjS4TfQEIjLtEZi5
+0c7x38sCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAmBLFoFMLUYsJ5MXlTRO4BjER
+jI9Yw1x8vPewbICBHqiI974HBWlYFFHoFTmbvJx6f1bP4dF93hrme/0Vj5/lXAsu
+UB+jRnJvHuk7f8kkRV3GEA5qC2PqZpLYRk/CBEYxEKkDhtxNXHIkcujjwbs8RBo6
+7WCxqnzFWDL+FiYP82TFWJcZOGdG/bo8a70C8+qRdUFpuMj1X4nQjt+QDhPGV5WW
+VmIFM1JNMEtE+2W4kmYFm1FKrCgckuGzNR30CS1wDZ/V/FHf4q1JZtO07GLm1Fgf
+99mwd8+uCqBJZ/AKYZ+tYDcTurgrDDeQGLdWhfqow04akk2KKztpRAXgcdWecQ==
+-----END CERTIFICATE-----
diff --git a/mqtt_java_maven/src/test/java/com/rehome/mqtt01/Mqtt01ApplicationTests.java b/mqtt_java_maven/src/test/java/com/rehome/mqtt01/Mqtt01ApplicationTests.java
new file mode 100644
index 0000000..dc65e4e
--- /dev/null
+++ b/mqtt_java_maven/src/test/java/com/rehome/mqtt01/Mqtt01ApplicationTests.java
@@ -0,0 +1,13 @@
+package com.rehome.mqtt01;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class Mqtt01ApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}