1901010113 4 rokov pred
commit
0830cad90c
79 zmenil súbory, kde vykonal 2499 pridanie a 0 odobranie
  1. 26 0
      .idea/$CACHE_FILE$
  2. 11 0
      .idea/$PROJECT_FILE$
  3. 8 0
      .idea/.gitignore
  4. 2 0
      .idea/chatroom.iml
  5. 13 0
      .idea/compiler.xml
  6. 6 0
      .idea/encodings.xml
  7. 36 0
      .idea/inspectionProfiles/Project_Default.xml
  8. 20 0
      .idea/jarRepositories.xml
  9. 26 0
      .idea/misc.xml
  10. 465 0
      .idea/qaplug_profiles.xml
  11. 127 0
      .idea/uiDesigner.xml
  12. 6 0
      .idea/vcs.xml
  13. BIN
      images/banner.png
  14. BIN
      images/chat.png
  15. BIN
      images/file.png
  16. BIN
      images/github.png
  17. BIN
      images/password.png
  18. BIN
      images/profiles/bear.png
  19. BIN
      images/profiles/bee.png
  20. BIN
      images/profiles/cat.png
  21. BIN
      images/profiles/cattle.png
  22. BIN
      images/profiles/deer.png
  23. BIN
      images/profiles/dog.png
  24. BIN
      images/profiles/giraffe.png
  25. BIN
      images/profiles/horse.png
  26. BIN
      images/profiles/lion.png
  27. BIN
      images/profiles/monkey.png
  28. BIN
      images/profiles/panda.png
  29. BIN
      images/profiles/pig.png
  30. BIN
      images/profiles/sheep.png
  31. BIN
      images/qq.png
  32. BIN
      images/secret.png
  33. BIN
      images/tencent.png
  34. BIN
      images/username.png
  35. 52 0
      pom.xml
  36. 114 0
      src/main/java/bean/Info.java
  37. 55 0
      src/main/java/bean/User.java
  38. 198 0
      src/main/java/service/LoginFrame.java
  39. 542 0
      src/main/java/service/ProfileFrame.java
  40. 14 0
      src/main/java/starter/Client.java
  41. 392 0
      src/main/java/starter/Server.java
  42. 168 0
      src/main/java/util/RedisUtils.java
  43. 51 0
      src/main/java/util/SwingUtils.java
  44. 151 0
      src/main/java/util/ToolUtils.java
  45. 16 0
      src/test/java/Test.java
  46. BIN
      target/classes/bean/Info.class
  47. BIN
      target/classes/bean/User.class
  48. BIN
      target/classes/javabean/Info.class
  49. BIN
      target/classes/javabean/User.class
  50. BIN
      target/classes/service/LoginFrame$1.class
  51. BIN
      target/classes/service/LoginFrame$2.class
  52. BIN
      target/classes/service/LoginFrame$3.class
  53. BIN
      target/classes/service/LoginFrame$4.class
  54. BIN
      target/classes/service/LoginFrame.class
  55. BIN
      target/classes/service/ProfileFrame$1.class
  56. BIN
      target/classes/service/ProfileFrame$10.class
  57. BIN
      target/classes/service/ProfileFrame$11.class
  58. BIN
      target/classes/service/ProfileFrame$2.class
  59. BIN
      target/classes/service/ProfileFrame$3.class
  60. BIN
      target/classes/service/ProfileFrame$4.class
  61. BIN
      target/classes/service/ProfileFrame$5.class
  62. BIN
      target/classes/service/ProfileFrame$6.class
  63. BIN
      target/classes/service/ProfileFrame$7.class
  64. BIN
      target/classes/service/ProfileFrame$8.class
  65. BIN
      target/classes/service/ProfileFrame$9$1.class
  66. BIN
      target/classes/service/ProfileFrame$9.class
  67. BIN
      target/classes/service/ProfileFrame.class
  68. BIN
      target/classes/starter/Client.class
  69. BIN
      target/classes/starter/Server$1.class
  70. BIN
      target/classes/starter/Server$2.class
  71. BIN
      target/classes/starter/Server$3$1.class
  72. BIN
      target/classes/starter/Server$3.class
  73. BIN
      target/classes/starter/Server$4.class
  74. BIN
      target/classes/starter/Server$SingleUser.class
  75. BIN
      target/classes/starter/Server.class
  76. BIN
      target/classes/util/RedisUtils.class
  77. BIN
      target/classes/util/SwingUtils.class
  78. BIN
      target/classes/util/ToolUtils.class
  79. BIN
      target/test-classes/Test.class

+ 26 - 0
.idea/$CACHE_FILE$

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectInspectionProfilesVisibleTreeState">
+    <entry key="Project Default">
+      <profile-state>
+        <expanded-state>
+          <State />
+          <State>
+            <id>Android</id>
+          </State>
+          <State>
+            <id>CorrectnessLintAndroid</id>
+          </State>
+          <State>
+            <id>LintAndroid</id>
+          </State>
+        </expanded-state>
+        <selected-state>
+          <State>
+            <id>Ali-Check</id>
+          </State>
+        </selected-state>
+      </profile-state>
+    </entry>
+  </component>
+</project>

+ 11 - 0
.idea/$PROJECT_FILE$

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="AnalysisProjectProfileManager">
+    <option name="PROJECT_PROFILE" />
+    <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+    <list size="0" />
+  </component>
+  <component name="SuppressionsComponent">
+    <option name="suppComments" value="[]" />
+  </component>
+</project>

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/

+ 2 - 0
.idea/chatroom.iml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4" />

+ 13 - 0
.idea/compiler.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <annotationProcessing>
+      <profile name="Maven default annotation processors profile" enabled="true">
+        <sourceOutputDir name="target/generated-sources/annotations" />
+        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
+        <outputRelativeToContentRoot value="true" />
+        <module name="chatroom" />
+      </profile>
+    </annotationProcessing>
+  </component>
+</project>

+ 6 - 0
.idea/encodings.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding" native2AsciiForPropertiesFiles="true" defaultCharsetForPropertiesFiles="UTF-8">
+    <file url="PROJECT" charset="UTF-8" />
+  </component>
+</project>

+ 36 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,36 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="TOP_LEVEL_CLASS_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="" />
+        </value>
+      </option>
+      <option name="INNER_CLASS_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="" />
+        </value>
+      </option>
+      <option name="METHOD_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
+        </value>
+      </option>
+      <option name="FIELD_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="" />
+        </value>
+      </option>
+      <option name="IGNORE_DEPRECATED" value="false" />
+      <option name="IGNORE_JAVADOC_PERIOD" value="true" />
+      <option name="IGNORE_DUPLICATED_THROWS" value="false" />
+      <option name="IGNORE_POINT_TO_ITSELF" value="false" />
+      <option name="myAdditionalJavadocTags" value="date" />
+    </inspection_tool>
+  </profile>
+</component>

+ 20 - 0
.idea/jarRepositories.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RemoteRepositoriesConfiguration">
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Maven Central repository" />
+      <option name="url" value="https://repo1.maven.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Central Repository" />
+      <option name="url" value="http://maven.aliyun.com/nexus/content/groups/public" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="jboss.community" />
+      <option name="name" value="JBoss Community repository" />
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+    </remote-repository>
+  </component>
+</project>

+ 26 - 0
.idea/misc.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="FindBugsConfigurable">
+    <option name="make" value="true" />
+    <option name="effort" value="default" />
+    <option name="priority" value="Medium" />
+    <option name="excludeFilter" value="" />
+  </component>
+  <component name="JavaScriptSettings">
+    <option name="languageLevel" value="ES6" />
+  </component>
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="11.0.5" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+  <component name="SuppressionsComponent">
+    <option name="suppComments" value="[]" />
+  </component>
+</project>

+ 465 - 0
.idea/qaplug_profiles.xml

@@ -0,0 +1,465 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="AnalysisProjectProfileManager">
+    <option name="PROJECT_PROFILE" value="Project Default" />
+    <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+    <scopes />
+    <profiles>
+      <profile profile_name="Project Default" version="1.0" is_locked="false">
+        <coding_rule class="AM_CREATES_EMPTY_JAR_FILE_ENTRY" level="MAJOR" enabled="true" />
+        <coding_rule class="AM_CREATES_EMPTY_ZIP_FILE_ENTRY" level="MAJOR" enabled="true" />
+        <coding_rule class="AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION" level="CRITICAL" enabled="false" />
+        <coding_rule class="BAC_BAD_APPLET_CONSTRUCTOR" level="MAJOR" enabled="false" />
+        <coding_rule class="BC_BAD_CAST_TO_ABSTRACT_COLLECTION" level="MAJOR" enabled="true" />
+        <coding_rule class="BC_BAD_CAST_TO_CONCRETE_COLLECTION" level="CRITICAL" enabled="true" />
+        <coding_rule class="BC_EQUALS_METHOD_SHOULD_WORK_FOR_ALL_OBJECTS" level="CRITICAL" enabled="true" />
+        <coding_rule class="BC_IMPOSSIBLE_CAST" level="BLOCKER" enabled="true" />
+        <coding_rule class="BC_IMPOSSIBLE_DOWNCAST" level="MAJOR" enabled="false" />
+        <coding_rule class="BC_IMPOSSIBLE_DOWNCAST_OF_TOARRAY" level="MAJOR" enabled="false" />
+        <coding_rule class="BC_IMPOSSIBLE_INSTANCEOF" level="CRITICAL" enabled="true" />
+        <coding_rule class="BC_UNCONFIRMED_CAST" level="CRITICAL" enabled="true" />
+        <coding_rule class="BC_UNCONFIRMED_CAST_OF_RETURN_VALUE" level="CRITICAL" enabled="false" />
+        <coding_rule class="BC_VACUOUS_INSTANCEOF" level="CRITICAL" enabled="true" />
+        <coding_rule class="BIT_ADD_OF_SIGNED_BYTE" level="CRITICAL" enabled="true" />
+        <coding_rule class="BIT_AND" level="CRITICAL" enabled="true" />
+        <coding_rule class="BIT_AND_ZZ" level="CRITICAL" enabled="true" />
+        <coding_rule class="BIT_IOR" level="CRITICAL" enabled="true" />
+        <coding_rule class="BIT_IOR_OF_SIGNED_BYTE" level="CRITICAL" enabled="true" />
+        <coding_rule class="BIT_SIGNED_CHECK" level="CRITICAL" enabled="true" />
+        <coding_rule class="BIT_SIGNED_CHECK_HIGH_BIT" level="CRITICAL" enabled="true" />
+        <coding_rule class="BOA_BADLY_OVERRIDDEN_ADAPTER" level="CRITICAL" enabled="true" />
+        <coding_rule class="BSHIFT_WRONG_ADD_PRIORITY" level="MAJOR" enabled="false" />
+        <coding_rule class="BX_BOXING_IMMEDIATELY_UNBOXED" level="MAJOR" enabled="true" />
+        <coding_rule class="BX_BOXING_IMMEDIATELY_UNBOXED_TO_PERFORM_COERCION" level="MAJOR" enabled="true" />
+        <coding_rule class="BX_UNBOXED_AND_COERCED_FOR_TERNARY_OPERATOR" level="MAJOR" enabled="true" />
+        <coding_rule class="BX_UNBOXING_IMMEDIATELY_REBOXED" level="CRITICAL" enabled="false" />
+        <coding_rule class="CAA_COVARIANT_ARRAY_ELEMENT_STORE" level="MAJOR" enabled="false" />
+        <coding_rule class="CAA_COVARIANT_ARRAY_FIELD" level="MAJOR" enabled="false" />
+        <coding_rule class="CAA_COVARIANT_ARRAY_LOCAL" level="MAJOR" enabled="false" />
+        <coding_rule class="CAA_COVARIANT_ARRAY_RETURN" level="MAJOR" enabled="false" />
+        <coding_rule class="CD_CIRCULAR_DEPENDENCY" level="MAJOR" enabled="false" />
+        <coding_rule class="CI_CONFUSED_INHERITANCE" level="MINOR" enabled="true" />
+        <coding_rule class="CNT_ROUGH_CONSTANT_VALUE" level="MAJOR" enabled="false" />
+        <coding_rule class="CN_IDIOM" level="MAJOR" enabled="true" />
+        <coding_rule class="CN_IDIOM_NO_SUPER_CALL" level="MAJOR" enabled="true" />
+        <coding_rule class="CN_IMPLEMENTS_CLONE_BUT_NOT_CLONEABLE" level="MAJOR" enabled="true" />
+        <coding_rule class="CO_ABSTRACT_SELF" level="MAJOR" enabled="true" />
+        <coding_rule class="CO_COMPARETO_INCORRECT_FLOATING" level="MAJOR" enabled="false" />
+        <coding_rule class="CO_COMPARETO_RESULTS_MIN_VALUE" level="CRITICAL" enabled="false" />
+        <coding_rule class="CO_SELF_NO_OBJECT" level="MAJOR" enabled="true" />
+        <coding_rule class="DB_DUPLICATE_BRANCHES" level="CRITICAL" enabled="true" />
+        <coding_rule class="DB_DUPLICATE_SWITCH_CLAUSES" level="CRITICAL" enabled="true" />
+        <coding_rule class="DC_DOUBLECHECK" level="MAJOR" enabled="true" />
+        <coding_rule class="DC_PARTIALLY_CONSTRUCTED" level="MAJOR" enabled="false" />
+        <coding_rule class="DE_MIGHT_DROP" level="MAJOR" enabled="true" />
+        <coding_rule class="DE_MIGHT_IGNORE" level="MAJOR" enabled="true" />
+        <coding_rule class="DLS_DEAD_LOCAL_INCREMENT_IN_RETURN" level="MAJOR" enabled="false" />
+        <coding_rule class="DLS_DEAD_LOCAL_STORE" level="CRITICAL" enabled="true" />
+        <coding_rule class="DLS_DEAD_LOCAL_STORE_IN_RETURN" level="CRITICAL" enabled="true" />
+        <coding_rule class="DLS_DEAD_LOCAL_STORE_OF_NULL" level="CRITICAL" enabled="true" />
+        <coding_rule class="DLS_DEAD_LOCAL_STORE_SHADOWS_FIELD" level="CRITICAL" enabled="false" />
+        <coding_rule class="DLS_DEAD_STORE_OF_CLASS_LITERAL" level="CRITICAL" enabled="true" />
+        <coding_rule class="DLS_OVERWRITTEN_INCREMENT" level="CRITICAL" enabled="true" />
+        <coding_rule class="DL_SYNCHRONIZATION_ON_BOOLEAN" level="CRITICAL" enabled="true" />
+        <coding_rule class="DL_SYNCHRONIZATION_ON_BOXED_PRIMITIVE" level="CRITICAL" enabled="true" />
+        <coding_rule class="DL_SYNCHRONIZATION_ON_SHARED_CONSTANT" level="CRITICAL" enabled="true" />
+        <coding_rule class="DL_SYNCHRONIZATION_ON_UNSHARED_BOXED_PRIMITIVE" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_ANNOTATION_IS_NOT_VISIBLE_TO_REFLECTION" level="MAJOR" enabled="true" />
+        <coding_rule class="DMI_ARGUMENTS_WRONG_ORDER" level="CRITICAL" enabled="false" />
+        <coding_rule class="DMI_BAD_MONTH" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_BIGDECIMAL_CONSTRUCTED_FROM_DOUBLE" level="CRITICAL" enabled="false" />
+        <coding_rule class="DMI_BLOCKING_METHODS_ON_URL" level="BLOCKER" enabled="true" />
+        <coding_rule class="DMI_CALLING_NEXT_FROM_HASNEXT" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_COLLECTIONS_SHOULD_NOT_CONTAIN_THEMSELVES" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_COLLECTION_OF_URLS" level="BLOCKER" enabled="true" />
+        <coding_rule class="DMI_CONSTANT_DB_PASSWORD" level="BLOCKER" enabled="true" />
+        <coding_rule class="DMI_DOH" level="CRITICAL" enabled="false" />
+        <coding_rule class="DMI_EMPTY_DB_PASSWORD" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_ENTRY_SETS_MAY_REUSE_ENTRY_OBJECTS" level="CRITICAL" enabled="false" />
+        <coding_rule class="DMI_FUTILE_ATTEMPT_TO_CHANGE_MAXPOOL_SIZE_OF_SCHEDULED_THREAD_POOL_EXECUTOR" level="MINOR" enabled="true" />
+        <coding_rule class="DMI_HARDCODED_ABSOLUTE_FILENAME" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_INVOKING_HASHCODE_ON_ARRAY" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_INVOKING_TOSTRING_ON_ANONYMOUS_ARRAY" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_INVOKING_TOSTRING_ON_ARRAY" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_LONG_BITS_TO_DOUBLE_INVOKED_ON_INT" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_NONSERIALIZABLE_OBJECT_WRITTEN" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_RANDOM_USED_ONLY_ONCE" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_SCHEDULED_THREAD_POOL_EXECUTOR_WITH_ZERO_CORE_THREADS" level="MINOR" enabled="true" />
+        <coding_rule class="DMI_THREAD_PASSED_WHERE_RUNNABLE_EXPECTED" level="MAJOR" enabled="true" />
+        <coding_rule class="DMI_UNSUPPORTED_METHOD" level="MAJOR" enabled="true" />
+        <coding_rule class="DMI_USELESS_SUBSTRING" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_USING_REMOVEALL_TO_CLEAR_COLLECTION" level="CRITICAL" enabled="true" />
+        <coding_rule class="DMI_VACUOUS_CALL_TO_EASYMOCK_METHOD" level="MINOR" enabled="true" />
+        <coding_rule class="DMI_VACUOUS_SELF_COLLECTION_CALL" level="CRITICAL" enabled="true" />
+        <coding_rule class="DM_BOOLEAN_CTOR" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_BOXED_PRIMITIVE_FOR_COMPARE" level="MAJOR" enabled="false" />
+        <coding_rule class="DM_BOXED_PRIMITIVE_FOR_PARSING" level="MAJOR" enabled="false" />
+        <coding_rule class="DM_BOXED_PRIMITIVE_TOSTRING" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_CONVERT_CASE" level="INFO" enabled="true" />
+        <coding_rule class="DM_DEFAULT_ENCODING" level="CRITICAL" enabled="false" />
+        <coding_rule class="DM_EXIT" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_FP_NUMBER_CTOR" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_GC" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_INVALID_MIN_MAX" level="MAJOR" enabled="false" />
+        <coding_rule class="DM_MONITOR_WAIT_ON_CONDITION" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_NEW_FOR_GETCLASS" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_NEXTINT_VIA_NEXTDOUBLE" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_NUMBER_CTOR" level="CRITICAL" enabled="true" />
+        <coding_rule class="DM_RUN_FINALIZERS_ON_EXIT" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_STRING_CTOR" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_STRING_TOSTRING" level="INFO" enabled="true" />
+        <coding_rule class="DM_STRING_VOID_CTOR" level="MAJOR" enabled="true" />
+        <coding_rule class="DM_USELESS_THREAD" level="MAJOR" enabled="true" />
+        <coding_rule class="DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED" level="MAJOR" enabled="true" />
+        <coding_rule class="DP_DO_INSIDE_DO_PRIVILEGED" level="MAJOR" enabled="true" />
+        <coding_rule class="EC_ARRAY_AND_NONARRAY" level="CRITICAL" enabled="true" />
+        <coding_rule class="EC_BAD_ARRAY_COMPARE" level="CRITICAL" enabled="true" />
+        <coding_rule class="EC_INCOMPATIBLE_ARRAY_COMPARE" level="MAJOR" enabled="false" />
+        <coding_rule class="EC_NULL_ARG" level="CRITICAL" enabled="true" />
+        <coding_rule class="EC_UNRELATED_CLASS_AND_INTERFACE" level="CRITICAL" enabled="true" />
+        <coding_rule class="EC_UNRELATED_INTERFACES" level="CRITICAL" enabled="true" />
+        <coding_rule class="EC_UNRELATED_TYPES" level="CRITICAL" enabled="true" />
+        <coding_rule class="EC_UNRELATED_TYPES_USING_POINTER_EQUALITY" level="CRITICAL" enabled="true" />
+        <coding_rule class="EI_EXPOSE_REP" level="MAJOR" enabled="true" />
+        <coding_rule class="EI_EXPOSE_REP2" level="MAJOR" enabled="true" />
+        <coding_rule class="EI_EXPOSE_STATIC_REP2" level="MAJOR" enabled="true" />
+        <coding_rule class="EQ_ABSTRACT_SELF" level="MAJOR" enabled="true" />
+        <coding_rule class="EQ_ALWAYS_FALSE" level="BLOCKER" enabled="true" />
+        <coding_rule class="EQ_ALWAYS_TRUE" level="BLOCKER" enabled="true" />
+        <coding_rule class="EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS" level="MAJOR" enabled="true" />
+        <coding_rule class="EQ_COMPARETO_USE_OBJECT_EQUALS" level="CRITICAL" enabled="true" />
+        <coding_rule class="EQ_COMPARING_CLASS_NAMES" level="MAJOR" enabled="true" />
+        <coding_rule class="EQ_DOESNT_OVERRIDE_EQUALS" level="MAJOR" enabled="false" />
+        <coding_rule class="EQ_DONT_DEFINE_EQUALS_FOR_ENUM" level="MAJOR" enabled="true" />
+        <coding_rule class="EQ_GETCLASS_AND_CLASS_CONSTANT" level="CRITICAL" enabled="true" />
+        <coding_rule class="EQ_OTHER_NO_OBJECT" level="MAJOR" enabled="true" />
+        <coding_rule class="EQ_OTHER_USE_OBJECT" level="MAJOR" enabled="true" />
+        <coding_rule class="EQ_OVERRIDING_EQUALS_NOT_SYMMETRIC" level="MAJOR" enabled="true" />
+        <coding_rule class="EQ_SELF_NO_OBJECT" level="MAJOR" enabled="true" />
+        <coding_rule class="EQ_SELF_USE_OBJECT" level="MAJOR" enabled="true" />
+        <coding_rule class="EQ_UNUSUAL" level="MINOR" enabled="true" />
+        <coding_rule class="ES_COMPARING_PARAMETER_STRING_WITH_EQ" level="MAJOR" enabled="true" />
+        <coding_rule class="ES_COMPARING_STRINGS_WITH_EQ" level="MAJOR" enabled="true" />
+        <coding_rule class="ESync_EMPTY_SYNC" level="MAJOR" enabled="true" />
+        <coding_rule class="FB_MISSING_EXPECTED_WARNING" level="CRITICAL" enabled="false" />
+        <coding_rule class="FB_UNEXPECTED_WARNING" level="CRITICAL" enabled="false" />
+        <coding_rule class="FE_FLOATING_POINT_EQUALITY" level="CRITICAL" enabled="true" />
+        <coding_rule class="FE_TEST_IF_EQUAL_TO_NOT_A_NUMBER" level="CRITICAL" enabled="true" />
+        <coding_rule class="FI_EMPTY" level="MAJOR" enabled="true" />
+        <coding_rule class="FI_EXPLICIT_INVOCATION" level="MAJOR" enabled="true" />
+        <coding_rule class="FI_FINALIZER_NULLS_FIELDS" level="MAJOR" enabled="true" />
+        <coding_rule class="FI_FINALIZER_ONLY_NULLS_FIELDS" level="MAJOR" enabled="true" />
+        <coding_rule class="FI_MISSING_SUPER_CALL" level="MAJOR" enabled="true" />
+        <coding_rule class="FI_NULLIFY_SUPER" level="CRITICAL" enabled="true" />
+        <coding_rule class="FI_PUBLIC_SHOULD_BE_PROTECTED" level="MAJOR" enabled="true" />
+        <coding_rule class="FI_USELESS" level="MINOR" enabled="true" />
+        <coding_rule class="FL_MATH_USING_FLOAT_PRECISION" level="CRITICAL" enabled="true" />
+        <coding_rule class="GC_UNCHECKED_TYPE_IN_GENERIC_CALL" level="CRITICAL" enabled="true" />
+        <coding_rule class="GC_UNRELATED_TYPES" level="CRITICAL" enabled="true" />
+        <coding_rule class="HE_EQUALS_NO_HASHCODE" level="MAJOR" enabled="true" />
+        <coding_rule class="HE_EQUALS_USE_HASHCODE" level="CRITICAL" enabled="true" />
+        <coding_rule class="HE_HASHCODE_NO_EQUALS" level="CRITICAL" enabled="true" />
+        <coding_rule class="HE_HASHCODE_USE_OBJECT_EQUALS" level="CRITICAL" enabled="true" />
+        <coding_rule class="HE_INHERITS_EQUALS_USE_HASHCODE" level="CRITICAL" enabled="true" />
+        <coding_rule class="HE_SIGNATURE_DECLARES_HASHING_OF_UNHASHABLE_CLASS" level="CRITICAL" enabled="true" />
+        <coding_rule class="HE_USE_OF_UNHASHABLE_CLASS" level="CRITICAL" enabled="true" />
+        <coding_rule class="HRS_REQUEST_PARAMETER_TO_COOKIE" level="MAJOR" enabled="true" />
+        <coding_rule class="HRS_REQUEST_PARAMETER_TO_HTTP_HEADER" level="MAJOR" enabled="true" />
+        <coding_rule class="HSC_HUGE_SHARED_STRING_CONSTANT" level="CRITICAL" enabled="true" />
+        <coding_rule class="IA_AMBIGUOUS_INVOCATION_OF_INHERITED_OR_OUTER_METHOD" level="MAJOR" enabled="true" />
+        <coding_rule class="ICAST_BAD_SHIFT_AMOUNT" level="CRITICAL" enabled="true" />
+        <coding_rule class="ICAST_IDIV_CAST_TO_DOUBLE" level="CRITICAL" enabled="true" />
+        <coding_rule class="ICAST_INTEGER_MULTIPLY_CAST_TO_LONG" level="CRITICAL" enabled="true" />
+        <coding_rule class="ICAST_INT_2_LONG_AS_INSTANT" level="CRITICAL" enabled="false" />
+        <coding_rule class="ICAST_INT_CAST_TO_DOUBLE_PASSED_TO_CEIL" level="CRITICAL" enabled="true" />
+        <coding_rule class="ICAST_INT_CAST_TO_FLOAT_PASSED_TO_ROUND" level="CRITICAL" enabled="true" />
+        <coding_rule class="ICAST_QUESTIONABLE_UNSIGNED_RIGHT_SHIFT" level="CRITICAL" enabled="true" />
+        <coding_rule class="IC_INIT_CIRCULARITY" level="CRITICAL" enabled="true" />
+        <coding_rule class="IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION" level="MAJOR" enabled="true" />
+        <coding_rule class="IIL_ELEMENTS_GET_LENGTH_IN_LOOP" level="MAJOR" enabled="false" />
+        <coding_rule class="IIL_PATTERN_COMPILE_IN_LOOP" level="MAJOR" enabled="false" />
+        <coding_rule class="IIL_PATTERN_COMPILE_IN_LOOP_INDIRECT" level="MAJOR" enabled="false" />
+        <coding_rule class="IIL_PREPARE_STATEMENT_IN_LOOP" level="MAJOR" enabled="false" />
+        <coding_rule class="IIO_INEFFICIENT_INDEX_OF" level="MAJOR" enabled="false" />
+        <coding_rule class="IIO_INEFFICIENT_LAST_INDEX_OF" level="MAJOR" enabled="false" />
+        <coding_rule class="IJU_ASSERT_METHOD_INVOKED_FROM_RUN_METHOD" level="CRITICAL" enabled="true" />
+        <coding_rule class="IJU_BAD_SUITE_METHOD" level="CRITICAL" enabled="true" />
+        <coding_rule class="IJU_NO_TESTS" level="CRITICAL" enabled="true" />
+        <coding_rule class="IJU_SETUP_NO_SUPER" level="CRITICAL" enabled="true" />
+        <coding_rule class="IJU_SUITE_NOT_STATIC" level="CRITICAL" enabled="true" />
+        <coding_rule class="IJU_TEARDOWN_NO_SUPER" level="CRITICAL" enabled="true" />
+        <coding_rule class="IL_CONTAINER_ADDED_TO_ITSELF" level="CRITICAL" enabled="true" />
+        <coding_rule class="IL_INFINITE_LOOP" level="CRITICAL" enabled="true" />
+        <coding_rule class="IL_INFINITE_RECURSIVE_LOOP" level="CRITICAL" enabled="true" />
+        <coding_rule class="IMA_INEFFICIENT_MEMBER_ACCESS" level="MAJOR" enabled="false" />
+        <coding_rule class="IMSE_DONT_CATCH_IMSE" level="MAJOR" enabled="true" />
+        <coding_rule class="IM_AVERAGE_COMPUTATION_COULD_OVERFLOW" level="CRITICAL" enabled="true" />
+        <coding_rule class="IM_BAD_CHECK_FOR_ODD" level="CRITICAL" enabled="true" />
+        <coding_rule class="IM_MULTIPLYING_RESULT_OF_IREM" level="CRITICAL" enabled="true" />
+        <coding_rule class="INT_BAD_COMPARISON_WITH_INT_VALUE" level="CRITICAL" enabled="false" />
+        <coding_rule class="INT_BAD_COMPARISON_WITH_NONNEGATIVE_VALUE" level="CRITICAL" enabled="true" />
+        <coding_rule class="INT_BAD_COMPARISON_WITH_SIGNED_BYTE" level="CRITICAL" enabled="true" />
+        <coding_rule class="INT_BAD_REM_BY_1" level="CRITICAL" enabled="true" />
+        <coding_rule class="INT_VACUOUS_BIT_OPERATION" level="CRITICAL" enabled="true" />
+        <coding_rule class="INT_VACUOUS_COMPARISON" level="CRITICAL" enabled="true" />
+        <coding_rule class="IO_APPENDING_TO_OBJECT_OUTPUT_STREAM" level="CRITICAL" enabled="true" />
+        <coding_rule class="IP_PARAMETER_IS_DEAD_BUT_OVERWRITTEN" level="CRITICAL" enabled="true" />
+        <coding_rule class="IS2_INCONSISTENT_SYNC" level="CRITICAL" enabled="true" />
+        <coding_rule class="ISC_INSTANTIATE_STATIC_CLASS" level="MAJOR" enabled="true" />
+        <coding_rule class="IS_FIELD_NOT_GUARDED" level="CRITICAL" enabled="true" />
+        <coding_rule class="ITA_INEFFICIENT_TO_ARRAY" level="CRITICAL" enabled="true" />
+        <coding_rule class="IT_NO_SUCH_ELEMENT" level="MINOR" enabled="true" />
+        <coding_rule class="J2EE_STORE_OF_NON_SERIALIZABLE_OBJECT_INTO_SESSION" level="CRITICAL" enabled="true" />
+        <coding_rule class="JCIP_FIELD_ISNT_FINAL_IN_IMMUTABLE_CLASS" level="MINOR" enabled="true" />
+        <coding_rule class="JLM_JSR166_LOCK_MONITORENTER" level="CRITICAL" enabled="true" />
+        <coding_rule class="JLM_JSR166_UTILCONCURRENT_MONITORENTER" level="CRITICAL" enabled="false" />
+        <coding_rule class="JML_JSR166_CALLING_WAIT_RATHER_THAN_AWAIT" level="CRITICAL" enabled="false" />
+        <coding_rule class="LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE" level="MAJOR" enabled="false" />
+        <coding_rule class="LI_LAZY_INIT_STATIC" level="CRITICAL" enabled="true" />
+        <coding_rule class="LI_LAZY_INIT_UPDATE_STATIC" level="CRITICAL" enabled="true" />
+        <coding_rule class="ME_ENUM_FIELD_SETTER" level="MAJOR" enabled="false" />
+        <coding_rule class="ME_MUTABLE_ENUM_FIELD" level="MAJOR" enabled="false" />
+        <coding_rule class="MF_CLASS_MASKS_FIELD" level="MAJOR" enabled="true" />
+        <coding_rule class="MF_METHOD_MASKS_FIELD" level="MAJOR" enabled="true" />
+        <coding_rule class="ML_SYNC_ON_FIELD_TO_GUARD_CHANGING_THAT_FIELD" level="MAJOR" enabled="true" />
+        <coding_rule class="ML_SYNC_ON_UPDATED_FIELD" level="MAJOR" enabled="true" />
+        <coding_rule class="MSF_MUTABLE_SERVLET_FIELD" level="MAJOR" enabled="true" />
+        <coding_rule class="MS_CANNOT_BE_FINAL" level="MAJOR" enabled="true" />
+        <coding_rule class="MS_EXPOSE_REP" level="CRITICAL" enabled="true" />
+        <coding_rule class="MS_FINAL_PKGPROTECT" level="MAJOR" enabled="true" />
+        <coding_rule class="MS_MUTABLE_ARRAY" level="MAJOR" enabled="true" />
+        <coding_rule class="MS_MUTABLE_COLLECTION" level="MAJOR" enabled="false" />
+        <coding_rule class="MS_MUTABLE_COLLECTION_PKGPROTECT" level="MAJOR" enabled="false" />
+        <coding_rule class="MS_MUTABLE_HASHTABLE" level="MAJOR" enabled="true" />
+        <coding_rule class="MS_OOI_PKGPROTECT" level="MAJOR" enabled="true" />
+        <coding_rule class="MS_PKGPROTECT" level="MAJOR" enabled="true" />
+        <coding_rule class="MS_SHOULD_BE_FINAL" level="MAJOR" enabled="true" />
+        <coding_rule class="MS_SHOULD_BE_REFACTORED_TO_BE_FINAL" level="CRITICAL" enabled="false" />
+        <coding_rule class="MTIA_SUSPECT_SERVLET_INSTANCE_FIELD" level="CRITICAL" enabled="true" />
+        <coding_rule class="MTIA_SUSPECT_STRUTS_INSTANCE_FIELD" level="CRITICAL" enabled="true" />
+        <coding_rule class="MWN_MISMATCHED_NOTIFY" level="CRITICAL" enabled="true" />
+        <coding_rule class="MWN_MISMATCHED_WAIT" level="CRITICAL" enabled="true" />
+        <coding_rule class="NM_BAD_EQUAL" level="MAJOR" enabled="false" />
+        <coding_rule class="NM_CLASS_NAMING_CONVENTION" level="MAJOR" enabled="false" />
+        <coding_rule class="NM_CLASS_NOT_EXCEPTION" level="MAJOR" enabled="true" />
+        <coding_rule class="NM_CONFUSING" level="MAJOR" enabled="true" />
+        <coding_rule class="NM_FIELD_NAMING_CONVENTION" level="MAJOR" enabled="false" />
+        <coding_rule class="NM_FUTURE_KEYWORD_USED_AS_IDENTIFIER" level="MAJOR" enabled="true" />
+        <coding_rule class="NM_FUTURE_KEYWORD_USED_AS_MEMBER_IDENTIFIER" level="MAJOR" enabled="true" />
+        <coding_rule class="NM_LCASE_HASHCODE" level="MAJOR" enabled="false" />
+        <coding_rule class="NM_LCASE_TOSTRING" level="MAJOR" enabled="false" />
+        <coding_rule class="NM_METHOD_CONSTRUCTOR_CONFUSION" level="MAJOR" enabled="true" />
+        <coding_rule class="NM_METHOD_NAMING_CONVENTION" level="MAJOR" enabled="false" />
+        <coding_rule class="NM_SAME_SIMPLE_NAME_AS_INTERFACE" level="MAJOR" enabled="true" />
+        <coding_rule class="NM_SAME_SIMPLE_NAME_AS_SUPERCLASS" level="MAJOR" enabled="true" />
+        <coding_rule class="NM_VERY_CONFUSING" level="MAJOR" enabled="true" />
+        <coding_rule class="NM_VERY_CONFUSING_INTENTIONAL" level="MAJOR" enabled="true" />
+        <coding_rule class="NM_WRONG_PACKAGE" level="MAJOR" enabled="true" />
+        <coding_rule class="NM_WRONG_PACKAGE_INTENTIONAL" level="MAJOR" enabled="true" />
+        <coding_rule class="NN_NAKED_NOTIFY" level="CRITICAL" enabled="true" />
+        <coding_rule class="NOISE_FIELD_REFERENCE" level="MAJOR" enabled="false" />
+        <coding_rule class="NOISE_METHOD_CALL" level="MAJOR" enabled="false" />
+        <coding_rule class="NOISE_NULL_DEREFERENCE" level="MAJOR" enabled="false" />
+        <coding_rule class="NOISE_OPERATION" level="MAJOR" enabled="false" />
+        <coding_rule class="NO_NOTIFY_NOT_NOTIFYALL" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_ALWAYS_NULL" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_ALWAYS_NULL_EXCEPTION" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_ARGUMENT_MIGHT_BE_NULL" level="MAJOR" enabled="true" />
+        <coding_rule class="NP_BOOLEAN_RETURN_NULL" level="MAJOR" enabled="true" />
+        <coding_rule class="NP_CLONE_COULD_RETURN_NULL" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_CLOSING_NULL" level="MAJOR" enabled="false" />
+        <coding_rule class="NP_DEREFERENCE_OF_READLINE_VALUE" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_EQUALS_SHOULD_HANDLE_NULL_ARGUMENT" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_GUARANTEED_DEREF" level="BLOCKER" enabled="true" />
+        <coding_rule class="NP_GUARANTEED_DEREF_ON_EXCEPTION_PATH" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_IMMEDIATE_DEREFERENCE_OF_READLINE" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_LOAD_OF_KNOWN_NULL_VALUE" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_METHOD_PARAMETER_TIGHTENS_ANNOTATION" level="MAJOR" enabled="false" />
+        <coding_rule class="NP_METHOD_RETURN_RELAXING_ANNOTATION" level="MAJOR" enabled="false" />
+        <coding_rule class="NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" level="CRITICAL" enabled="false" />
+        <coding_rule class="NP_NONNULL_PARAM_VIOLATION" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_NONNULL_RETURN_VIOLATION" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_NULL_INSTANCEOF" level="BLOCKER" enabled="true" />
+        <coding_rule class="NP_NULL_ON_SOME_PATH" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_NULL_ON_SOME_PATH_EXCEPTION" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_NULL_ON_SOME_PATH_MIGHT_BE_INFEASIBLE" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_NULL_PARAM_DEREF" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_NULL_PARAM_DEREF_NONVIRTUAL" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_OPTIONAL_RETURN_NULL" level="MAJOR" enabled="false" />
+        <coding_rule class="NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_STORE_INTO_NONNULL_FIELD" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_SYNC_AND_NULL_CHECK_FIELD" level="MAJOR" enabled="true" />
+        <coding_rule class="NP_TOSTRING_COULD_RETURN_NULL" level="CRITICAL" enabled="true" />
+        <coding_rule class="NP_UNWRITTEN_FIELD" level="MAJOR" enabled="false" />
+        <coding_rule class="NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD" level="CRITICAL" enabled="false" />
+        <coding_rule class="NS_DANGEROUS_NON_SHORT_CIRCUIT" level="CRITICAL" enabled="true" />
+        <coding_rule class="NS_NON_SHORT_CIRCUIT" level="MAJOR" enabled="true" />
+        <coding_rule class="OBL_UNSATISFIED_OBLIGATION" level="CRITICAL" enabled="false" />
+        <coding_rule class="OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE" level="CRITICAL" enabled="false" />
+        <coding_rule class="ODR_OPEN_DATABASE_RESOURCE" level="CRITICAL" enabled="true" />
+        <coding_rule class="ODR_OPEN_DATABASE_RESOURCE_EXCEPTION_PATH" level="CRITICAL" enabled="true" />
+        <coding_rule class="OS_OPEN_STREAM" level="CRITICAL" enabled="true" />
+        <coding_rule class="OS_OPEN_STREAM_EXCEPTION_PATH" level="CRITICAL" enabled="true" />
+        <coding_rule class="PS_PUBLIC_SEMAPHORES" level="CRITICAL" enabled="true" />
+        <coding_rule class="PT_ABSOLUTE_PATH_TRAVERSAL" level="CRITICAL" enabled="false" />
+        <coding_rule class="PT_RELATIVE_PATH_TRAVERSAL" level="CRITICAL" enabled="false" />
+        <coding_rule class="PZLA_PREFER_ZERO_LENGTH_ARRAYS" level="MAJOR" enabled="true" />
+        <coding_rule class="PZ_DONT_REUSE_ENTRY_OBJECTS_IN_ITERATORS" level="CRITICAL" enabled="false" />
+        <coding_rule class="QBA_QUESTIONABLE_BOOLEAN_ASSIGNMENT" level="CRITICAL" enabled="true" />
+        <coding_rule class="QF_QUESTIONABLE_FOR_LOOP" level="CRITICAL" enabled="true" />
+        <coding_rule class="RANGE_ARRAY_INDEX" level="MAJOR" enabled="false" />
+        <coding_rule class="RANGE_ARRAY_LENGTH" level="MAJOR" enabled="false" />
+        <coding_rule class="RANGE_ARRAY_OFFSET" level="MAJOR" enabled="false" />
+        <coding_rule class="RANGE_STRING_INDEX" level="MAJOR" enabled="false" />
+        <coding_rule class="RCN_REDUNDANT_COMPARISON_OF_NULL_AND_NONNULL_VALUE" level="CRITICAL" enabled="true" />
+        <coding_rule class="RCN_REDUNDANT_COMPARISON_TWO_NULL_VALUES" level="CRITICAL" enabled="true" />
+        <coding_rule class="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE" level="CRITICAL" enabled="true" />
+        <coding_rule class="RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE" level="CRITICAL" enabled="true" />
+        <coding_rule class="RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE" level="CRITICAL" enabled="true" />
+        <coding_rule class="RC_REF_COMPARISON" level="CRITICAL" enabled="true" />
+        <coding_rule class="RC_REF_COMPARISON_BAD_PRACTICE" level="MAJOR" enabled="false" />
+        <coding_rule class="RC_REF_COMPARISON_BAD_PRACTICE_BOOLEAN" level="MAJOR" enabled="false" />
+        <coding_rule class="REC_CATCH_EXCEPTION" level="MAJOR" enabled="true" />
+        <coding_rule class="RE_BAD_SYNTAX_FOR_REGULAR_EXPRESSION" level="CRITICAL" enabled="true" />
+        <coding_rule class="RE_CANT_USE_FILE_SEPARATOR_AS_REGULAR_EXPRESSION" level="CRITICAL" enabled="true" />
+        <coding_rule class="RE_POSSIBLE_UNINTENDED_PATTERN" level="CRITICAL" enabled="true" />
+        <coding_rule class="RI_REDUNDANT_INTERFACES" level="MAJOR" enabled="true" />
+        <coding_rule class="RR_NOT_CHECKED" level="MAJOR" enabled="true" />
+        <coding_rule class="RS_READOBJECT_SYNC" level="CRITICAL" enabled="true" />
+        <coding_rule class="RU_INVOKE_RUN" level="MAJOR" enabled="true" />
+        <coding_rule class="RV_01_TO_INT" level="MAJOR" enabled="true" />
+        <coding_rule class="RV_ABSOLUTE_VALUE_OF_HASHCODE" level="CRITICAL" enabled="true" />
+        <coding_rule class="RV_ABSOLUTE_VALUE_OF_RANDOM_INT" level="CRITICAL" enabled="true" />
+        <coding_rule class="RV_CHECK_COMPARETO_FOR_SPECIFIC_RETURN_VALUE" level="CRITICAL" enabled="false" />
+        <coding_rule class="RV_CHECK_FOR_POSITIVE_INDEXOF" level="MINOR" enabled="true" />
+        <coding_rule class="RV_DONT_JUST_NULL_CHECK_READLINE" level="MAJOR" enabled="true" />
+        <coding_rule class="RV_EXCEPTION_NOT_THROWN" level="CRITICAL" enabled="true" />
+        <coding_rule class="RV_NEGATING_RESULT_OF_COMPARETO" level="CRITICAL" enabled="false" />
+        <coding_rule class="RV_REM_OF_HASHCODE" level="CRITICAL" enabled="true" />
+        <coding_rule class="RV_REM_OF_RANDOM_INT" level="CRITICAL" enabled="true" />
+        <coding_rule class="RV_RETURN_VALUE_IGNORED" level="MINOR" enabled="true" />
+        <coding_rule class="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE" level="MAJOR" enabled="true" />
+        <coding_rule class="RV_RETURN_VALUE_IGNORED_INFERRED" level="CRITICAL" enabled="false" />
+        <coding_rule class="RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT" level="MAJOR" enabled="false" />
+        <coding_rule class="RV_RETURN_VALUE_OF_PUTIFABSENT_IGNORED" level="MAJOR" enabled="false" />
+        <coding_rule class="RpC_REPEATED_CONDITIONAL_TEST" level="MAJOR" enabled="true" />
+        <coding_rule class="SA_FIELD_DOUBLE_ASSIGNMENT" level="CRITICAL" enabled="true" />
+        <coding_rule class="SA_FIELD_SELF_ASSIGNMENT" level="CRITICAL" enabled="true" />
+        <coding_rule class="SA_FIELD_SELF_COMPARISON" level="CRITICAL" enabled="true" />
+        <coding_rule class="SA_FIELD_SELF_COMPUTATION" level="CRITICAL" enabled="true" />
+        <coding_rule class="SA_LOCAL_DOUBLE_ASSIGNMENT" level="CRITICAL" enabled="true" />
+        <coding_rule class="SA_LOCAL_SELF_ASSIGNMENT" level="CRITICAL" enabled="true" />
+        <coding_rule class="SA_LOCAL_SELF_ASSIGNMENT_INSTEAD_OF_FIELD" level="CRITICAL" enabled="false" />
+        <coding_rule class="SA_LOCAL_SELF_COMPARISON" level="CRITICAL" enabled="true" />
+        <coding_rule class="SA_LOCAL_SELF_COMPUTATION" level="CRITICAL" enabled="true" />
+        <coding_rule class="SBSC_USE_STRINGBUFFER_CONCATENATION" level="CRITICAL" enabled="true" />
+        <coding_rule class="SC_START_IN_CTOR" level="CRITICAL" enabled="true" />
+        <coding_rule class="SE_BAD_FIELD" level="MINOR" enabled="false" />
+        <coding_rule class="SE_BAD_FIELD_INNER_CLASS" level="MINOR" enabled="true" />
+        <coding_rule class="SE_BAD_FIELD_STORE" level="CRITICAL" enabled="true" />
+        <coding_rule class="SE_COMPARATOR_SHOULD_BE_SERIALIZABLE" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_INNER_CLASS" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_METHOD_MUST_BE_PRIVATE" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_NONFINAL_SERIALVERSIONID" level="CRITICAL" enabled="true" />
+        <coding_rule class="SE_NONLONG_SERIALVERSIONID" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_NONSTATIC_SERIALVERSIONID" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_NO_SERIALVERSIONID" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_NO_SUITABLE_CONSTRUCTOR" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_NO_SUITABLE_CONSTRUCTOR_FOR_EXTERNALIZATION" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_PRIVATE_READ_RESOLVE_NOT_INHERITED" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_READ_RESOLVE_IS_STATIC" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_READ_RESOLVE_MUST_RETURN_OBJECT" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_TRANSIENT_FIELD_NOT_RESTORED" level="MAJOR" enabled="true" />
+        <coding_rule class="SE_TRANSIENT_FIELD_OF_NONSERIALIZABLE_CLASS" level="MAJOR" enabled="true" />
+        <coding_rule class="SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH" level="MAJOR" enabled="false" />
+        <coding_rule class="SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH_TO_THROW" level="MAJOR" enabled="false" />
+        <coding_rule class="SF_SWITCH_FALLTHROUGH" level="MAJOR" enabled="false" />
+        <coding_rule class="SF_SWITCH_NO_DEFAULT" level="MAJOR" enabled="false" />
+        <coding_rule class="SIC_INNER_SHOULD_BE_STATIC" level="MAJOR" enabled="true" />
+        <coding_rule class="SIC_INNER_SHOULD_BE_STATIC_ANON" level="MAJOR" enabled="true" />
+        <coding_rule class="SIC_INNER_SHOULD_BE_STATIC_NEEDS_THIS" level="MAJOR" enabled="true" />
+        <coding_rule class="SIC_THREADLOCAL_DEADLY_EMBRACE" level="MAJOR" enabled="false" />
+        <coding_rule class="SIO_SUPERFLUOUS_INSTANCEOF" level="CRITICAL" enabled="true" />
+        <coding_rule class="SI_INSTANCE_BEFORE_FINALS_ASSIGNED" level="CRITICAL" enabled="true" />
+        <coding_rule class="SP_SPIN_ON_FIELD" level="MAJOR" enabled="true" />
+        <coding_rule class="SQL_BAD_PREPARED_STATEMENT_ACCESS" level="CRITICAL" enabled="true" />
+        <coding_rule class="SQL_BAD_RESULTSET_ACCESS" level="CRITICAL" enabled="true" />
+        <coding_rule class="SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE" level="CRITICAL" enabled="true" />
+        <coding_rule class="SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING" level="CRITICAL" enabled="true" />
+        <coding_rule class="SR_NOT_CHECKED" level="MAJOR" enabled="true" />
+        <coding_rule class="SS_SHOULD_BE_STATIC" level="MAJOR" enabled="true" />
+        <coding_rule class="STCAL_INVOKE_ON_STATIC_CALENDAR_INSTANCE" level="CRITICAL" enabled="true" />
+        <coding_rule class="STCAL_INVOKE_ON_STATIC_DATE_FORMAT_INSTANCE" level="CRITICAL" enabled="true" />
+        <coding_rule class="STCAL_STATIC_CALENDAR_INSTANCE" level="CRITICAL" enabled="true" />
+        <coding_rule class="STCAL_STATIC_SIMPLE_DATE_FORMAT_INSTANCE" level="CRITICAL" enabled="true" />
+        <coding_rule class="STI_INTERRUPTED_ON_CURRENTTHREAD" level="CRITICAL" enabled="true" />
+        <coding_rule class="STI_INTERRUPTED_ON_UNKNOWNTHREAD" level="CRITICAL" enabled="true" />
+        <coding_rule class="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" level="CRITICAL" enabled="true" />
+        <coding_rule class="SWL_SLEEP_WITH_LOCK_HELD" level="CRITICAL" enabled="true" />
+        <coding_rule class="SW_SWING_METHODS_INVOKED_IN_SWING_THREAD" level="MAJOR" enabled="true" />
+        <coding_rule class="TLW_TWO_LOCK_WAIT" level="MAJOR" enabled="true" />
+        <coding_rule class="TQ_ALWAYS_VALUE_USED_WHERE_NEVER_REQUIRED" level="CRITICAL" enabled="true" />
+        <coding_rule class="TQ_COMPARING_VALUES_WITH_INCOMPATIBLE_TYPE_QUALIFIERS" level="CRITICAL" enabled="false" />
+        <coding_rule class="TQ_EXPLICIT_UNKNOWN_SOURCE_VALUE_REACHES_ALWAYS_SINK" level="CRITICAL" enabled="true" />
+        <coding_rule class="TQ_EXPLICIT_UNKNOWN_SOURCE_VALUE_REACHES_NEVER_SINK" level="CRITICAL" enabled="true" />
+        <coding_rule class="TQ_MAYBE_SOURCE_VALUE_REACHES_ALWAYS_SINK" level="CRITICAL" enabled="true" />
+        <coding_rule class="TQ_MAYBE_SOURCE_VALUE_REACHES_NEVER_SINK" level="CRITICAL" enabled="true" />
+        <coding_rule class="TQ_NEVER_VALUE_USED_WHERE_ALWAYS_REQUIRED" level="CRITICAL" enabled="true" />
+        <coding_rule class="TQ_UNKNOWN_VALUE_USED_WHERE_ALWAYS_STRICTLY_REQUIRED" level="CRITICAL" enabled="false" />
+        <coding_rule class="UCF_USELESS_CONTROL_FLOW" level="CRITICAL" enabled="true" />
+        <coding_rule class="UCF_USELESS_CONTROL_FLOW_NEXT_LINE" level="CRITICAL" enabled="true" />
+        <coding_rule class="UC_USELESS_CONDITION" level="MAJOR" enabled="false" />
+        <coding_rule class="UC_USELESS_CONDITION_TYPE" level="MAJOR" enabled="false" />
+        <coding_rule class="UC_USELESS_OBJECT" level="MAJOR" enabled="false" />
+        <coding_rule class="UC_USELESS_OBJECT_STACK" level="MAJOR" enabled="false" />
+        <coding_rule class="UC_USELESS_VOID_METHOD" level="MAJOR" enabled="false" />
+        <coding_rule class="UG_SYNC_SET_UNSYNC_GET" level="MAJOR" enabled="true" />
+        <coding_rule class="UI_INHERITANCE_UNSAFE_GETRESOURCE" level="MAJOR" enabled="true" />
+        <coding_rule class="UL_UNRELEASED_LOCK" level="CRITICAL" enabled="true" />
+        <coding_rule class="UL_UNRELEASED_LOCK_EXCEPTION_PATH" level="CRITICAL" enabled="true" />
+        <coding_rule class="UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS" level="CRITICAL" enabled="true" />
+        <coding_rule class="UM_UNNECESSARY_MATH" level="CRITICAL" enabled="true" />
+        <coding_rule class="UPM_UNCALLED_PRIVATE_METHOD" level="CRITICAL" enabled="true" />
+        <coding_rule class="URF_UNREAD_FIELD" level="MAJOR" enabled="true" />
+        <coding_rule class="URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD" level="CRITICAL" enabled="false" />
+        <coding_rule class="UR_UNINIT_READ" level="MAJOR" enabled="true" />
+        <coding_rule class="UR_UNINIT_READ_CALLED_FROM_SUPER_CONSTRUCTOR" level="MAJOR" enabled="false" />
+        <coding_rule class="USM_USELESS_ABSTRACT_METHOD" level="MAJOR" enabled="false" />
+        <coding_rule class="USM_USELESS_SUBCLASS_METHOD" level="MAJOR" enabled="false" />
+        <coding_rule class="UUF_UNUSED_FIELD" level="MAJOR" enabled="true" />
+        <coding_rule class="UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD" level="CRITICAL" enabled="false" />
+        <coding_rule class="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" level="MAJOR" enabled="false" />
+        <coding_rule class="UWF_NULL_FIELD" level="CRITICAL" enabled="true" />
+        <coding_rule class="UWF_UNWRITTEN_FIELD" level="MAJOR" enabled="false" />
+        <coding_rule class="UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD" level="CRITICAL" enabled="false" />
+        <coding_rule class="UW_UNCOND_WAIT" level="MAJOR" enabled="true" />
+        <coding_rule class="VA_FORMAT_STRING_BAD_ARGUMENT" level="CRITICAL" enabled="true" />
+        <coding_rule class="VA_FORMAT_STRING_BAD_CONVERSION" level="CRITICAL" enabled="true" />
+        <coding_rule class="VA_FORMAT_STRING_BAD_CONVERSION_FROM_ARRAY" level="MAJOR" enabled="true" />
+        <coding_rule class="VA_FORMAT_STRING_BAD_CONVERSION_TO_BOOLEAN" level="MAJOR" enabled="true" />
+        <coding_rule class="VA_FORMAT_STRING_EXPECTED_MESSAGE_FORMAT_SUPPLIED" level="MAJOR" enabled="false" />
+        <coding_rule class="VA_FORMAT_STRING_EXTRA_ARGUMENTS_PASSED" level="MAJOR" enabled="true" />
+        <coding_rule class="VA_FORMAT_STRING_ILLEGAL" level="CRITICAL" enabled="true" />
+        <coding_rule class="VA_FORMAT_STRING_MISSING_ARGUMENT" level="CRITICAL" enabled="true" />
+        <coding_rule class="VA_FORMAT_STRING_NO_PREVIOUS_ARGUMENT" level="CRITICAL" enabled="true" />
+        <coding_rule class="VA_FORMAT_STRING_USES_NEWLINE" level="CRITICAL" enabled="false" />
+        <coding_rule class="VA_PRIMITIVE_ARRAY_PASSED_TO_OBJECT_VARARG" level="CRITICAL" enabled="true" />
+        <coding_rule class="VO_VOLATILE_INCREMENT" level="CRITICAL" enabled="false" />
+        <coding_rule class="VO_VOLATILE_REFERENCE_TO_ARRAY" level="MAJOR" enabled="true" />
+        <coding_rule class="VR_UNRESOLVABLE_REFERENCE" level="MAJOR" enabled="false" />
+        <coding_rule class="WA_AWAIT_NOT_IN_LOOP" level="CRITICAL" enabled="true" />
+        <coding_rule class="WA_NOT_IN_LOOP" level="CRITICAL" enabled="true" />
+        <coding_rule class="WL_USING_GETCLASS_RATHER_THAN_CLASS_LITERAL" level="CRITICAL" enabled="true" />
+        <coding_rule class="WMI_WRONG_MAP_ITERATOR" level="CRITICAL" enabled="true" />
+        <coding_rule class="WS_WRITEOBJECT_SYNC" level="CRITICAL" enabled="true" />
+        <coding_rule class="XFB_XML_FACTORY_BYPASS" level="CRITICAL" enabled="true" />
+        <coding_rule class="XSS_REQUEST_PARAMETER_TO_JSP_WRITER" level="CRITICAL" enabled="true" />
+        <coding_rule class="XSS_REQUEST_PARAMETER_TO_SEND_ERROR" level="CRITICAL" enabled="true" />
+        <coding_rule class="XSS_REQUEST_PARAMETER_TO_SERVLET_WRITER" level="CRITICAL" enabled="true" />
+      </profile>
+    </profiles>
+    <list size="0" />
+  </component>
+</project>

+ 127 - 0
.idea/uiDesigner.xml

@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
+  <component name="uidesigner-configuration">
+    <option name="DEFAULT_LAYOUT_MANAGER" value="GridBagLayout" />
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

BIN
images/banner.png


BIN
images/chat.png


BIN
images/file.png


BIN
images/github.png


BIN
images/password.png


BIN
images/profiles/bear.png


BIN
images/profiles/bee.png


BIN
images/profiles/cat.png


BIN
images/profiles/cattle.png


BIN
images/profiles/deer.png


BIN
images/profiles/dog.png


BIN
images/profiles/giraffe.png


BIN
images/profiles/horse.png


BIN
images/profiles/lion.png


BIN
images/profiles/monkey.png


BIN
images/profiles/panda.png


BIN
images/profiles/pig.png


BIN
images/profiles/sheep.png


BIN
images/qq.png


BIN
images/secret.png


BIN
images/tencent.png


BIN
images/username.png


+ 52 - 0
pom.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.example</groupId>
+    <artifactId>chatroom</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>11</source>
+                    <target>11</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <!-- https://mvnrepository.com/artifact/com.formdev/flatlaf -->
+        <dependency>
+            <groupId>com.formdev</groupId>
+            <artifactId>flatlaf</artifactId>
+            <version>0.26</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.10</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.71</version>
+        </dependency>
+
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>3.0.0</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 114 - 0
src/main/java/bean/Info.java

@@ -0,0 +1,114 @@
+package bean;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author DFella
+ * @date 2020/12/21 20:55
+ */
+
+/**
+ * 服务器和客户端之间的消息协议
+ * 0-C/S第一次握手信息
+ * 1-client请求广播信息
+ * 2-保留
+ * 3-client请求上传文件
+ * 4-client查询在线人数
+ * 5-server返回系统在线人数
+ * 6-server返回反馈消息
+ * 7-client查询在线用户列表
+ * 8-server返回在线用户列表
+ * 9-client私聊发送信息
+ * 10-client私聊发送文件
+ * 11-server转发私聊文件
+ * @author DFella
+ */
+public class Info implements Serializable {
+    /**
+     * 消息类型
+     */
+    private int type;
+    /**
+     * 消息内容
+     */
+    private String content;
+    /**
+     * 消息发送者用户名
+     */
+    private String source;
+    /**
+     * 消息接收者用户名
+     */
+    private String dest;
+
+    /**
+     * 文件名
+     */
+    private String fileName;
+
+    /**
+     * 附件
+     */
+    private List attach;
+
+    public Info(int type) {
+        this.type = type;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public List getAttach() {
+        return attach;
+    }
+
+    public void setAttach(List onlineUsers) {
+        this.attach = onlineUsers;
+    }
+
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+    public void setDest(String dest) {
+        this.dest = dest;
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+    public String getSource() {
+        return source;
+    }
+
+    public String getDest() {
+        return dest;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    @Override
+    public String toString() {
+        return "Info{" +
+                "type=" + type +
+                ", content='" + content + '\'' +
+                ", source='" + source + '\'' +
+                ", dest='" + dest + '\'' +
+                ", fileName='" + fileName + '\'' +
+                ", attach=" + attach +
+                '}';
+    }
+}

+ 55 - 0
src/main/java/bean/User.java

@@ -0,0 +1,55 @@
+package bean;
+
+import java.io.Serializable;
+
+/**
+ * @author DFella
+ * @date 2020/12/21 15:48
+ */
+public class User implements Serializable {
+
+    /**
+     * 用户名
+     */
+    private String username;
+    /**
+     * 密码
+     */
+    private String password;
+    /**
+     * 头像
+     */
+    private String image;
+
+    public String getImage() {
+        return image;
+    }
+
+    public void setImage(String image) {
+        this.image = image;
+    }
+
+    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;
+    }
+
+    @Override
+    public String toString() {
+        return "javabean.User{" +
+                "username='" + username + '\'' +
+                ", password='" + password + '\'' +
+                '}';
+    }
+}

+ 198 - 0
src/main/java/service/LoginFrame.java

@@ -0,0 +1,198 @@
+package service;
+
+import bean.User;
+import com.formdev.flatlaf.FlatIntelliJLaf;
+import org.apache.commons.lang3.StringUtils;
+import util.RedisUtils;
+import util.SwingUtils;
+import util.ToolUtils;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.RoundRectangle2D;
+
+/**
+ * @author DFella
+ * @date 2020/12/21 15:45
+ * 登录界面
+ **/
+
+public class LoginFrame extends JFrame {
+
+    /**
+     * 轻量级容器
+     */
+    private static JPanel contentPane;
+
+    /**
+     * 用户名编辑框
+     */
+    private JTextField username_edit;
+
+    /**
+     * 密码编辑框
+     **/
+    private JPasswordField password_edit;
+
+    public LoginFrame() {
+        setBounds(100, 100, 450, 300);
+        contentPane = new JPanel();
+        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
+        setContentPane(contentPane);
+        contentPane.setLayout(null);
+        setLocationRelativeTo(null);
+
+        JLabel banner_jLabel = new JLabel();
+        banner_jLabel.setIcon(new ImageIcon("images/tencent.png"));
+        banner_jLabel.setBounds(0, 0, 436, 84);
+        contentPane.add(banner_jLabel);
+
+        JButton register_btn = new JButton("注册");
+        register_btn.setBounds(10, 190, 97, 23);
+        contentPane.add(register_btn);
+
+        JButton login_btn = new JButton("登录");
+        login_btn.setBounds(117, 190, 97, 23);
+        contentPane.add(login_btn);
+
+        JLabel username_jLabel = new JLabel("用户名");
+        username_jLabel.setBounds(77, 106, 58, 15);
+        contentPane.add(username_jLabel);
+
+        JLabel password_jLabel = new JLabel("密码");
+        password_jLabel.setBounds(77, 144, 58, 15);
+        contentPane.add(password_jLabel);
+
+        username_edit = new JTextField();
+        username_edit.setBounds(145, 103, 116, 21);
+        contentPane.add(username_edit);
+        username_edit.setColumns(10);
+
+        password_edit = new JPasswordField();
+        password_edit.setBounds(145, 141, 116, 21);
+        contentPane.add(password_edit);
+
+        JButton modify_btn = new JButton("修改密码");
+        modify_btn.setBounds(224, 190, 97, 23);
+        contentPane.add(modify_btn);
+
+        /**
+         * 登录点击事件
+         */
+        login_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                String username = username_edit.getText().trim();
+                String password = new String(password_edit.getPassword());
+                if (username == null || password == null) {
+                    JOptionPane.showMessageDialog(null,"用户名、密码不许为空!", "用户登录", JOptionPane.INFORMATION_MESSAGE);
+                }
+                final int recv = RedisUtils.validUser(username, password);
+                if (recv == 0) {
+                    JOptionPane.showMessageDialog(null,"用户不存在,请先注册!", "用户登录", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+                if (recv == 1) {
+                    JOptionPane.showMessageDialog(null,"密码错误!", "用户登录", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+                if (RedisUtils.isAlive(username)) {
+                    JOptionPane.showMessageDialog(null,"你已经登录了,不能重复登录!", "用户登录", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+                JOptionPane.showMessageDialog(null,"登录成功!", "用户登录", JOptionPane.INFORMATION_MESSAGE);
+                final User user = new User();
+                user.setUsername(username);
+                user.setPassword(password);
+                user.setImage(ToolUtils.getProfile());
+                ProfileFrame.launch(user);
+                dispose();
+            }
+        });
+
+        /**
+         * 修改密码点击事件
+         */
+        modify_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                String username = username_edit.getText().trim();
+                String password = new String(password_edit.getPassword());
+                if (username == null || password == null) {
+                    JOptionPane.showMessageDialog(null,"用户名、密码不许为空!", "修改密码", JOptionPane.INFORMATION_MESSAGE);
+                }
+                final int recv = RedisUtils.validUser(username, password);
+                if (recv == 0) {
+                    JOptionPane.showMessageDialog(null,"用户不存在,请先注册!", "修改密码", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+                if (recv == 1) {
+                    JOptionPane.showMessageDialog(null,"密码错误!", "修改密码", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+                final String newPassword = (String) JOptionPane.showInputDialog(null, "请输入新密码", "修改密码", JOptionPane.INFORMATION_MESSAGE, null, null, null);
+                System.out.println(newPassword);
+                if (StringUtils.isBlank(newPassword)) {
+                    JOptionPane.showMessageDialog(null,"新密码不许为空!", "修改密码", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+                RedisUtils.modifyUser(username, newPassword);
+            }
+        });
+
+        /**
+         * 注册点击事件
+         */
+        register_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                String username = username_edit.getText().trim();
+                String password = new String(password_edit.getPassword());
+                if (username == null || password == null) {
+                    JOptionPane.showMessageDialog(null,"用户名、密码不许为空!", "注册", JOptionPane.INFORMATION_MESSAGE);
+                }
+                final int recv = RedisUtils.insertUser(username, password);
+                if (recv == 0) {
+                    JOptionPane.showMessageDialog(null,"用户已存在,请直接登录!", "注册", JOptionPane.INFORMATION_MESSAGE);
+                }
+                if (recv == 1) {
+                    JOptionPane.showMessageDialog(null,"注册失败!", "注册", JOptionPane.INFORMATION_MESSAGE);
+                }
+                if (recv == 2 ) {
+                    JOptionPane.showMessageDialog(null,"注册成功!", "注册", JOptionPane.INFORMATION_MESSAGE);
+                }
+            }
+        });
+
+    }
+
+    /**
+     * 对外提供的启动函数
+     */
+    public static void launch() {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+
+                try {
+                    UIManager.setLookAndFeel(new FlatIntelliJLaf());
+                } catch (Exception e) {
+                    JOptionPane.showMessageDialog(null, e.getMessage(), "UI风格设置", JOptionPane.WARNING_MESSAGE);
+                    return;
+                }
+                LoginFrame loginFrame = new LoginFrame();
+                loginFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+                SwingUtils.setSize(loginFrame, 0.24, 0.3);
+                loginFrame.setTitle("Login");
+                loginFrame.setIconImage(new ImageIcon("images/github.png").getImage());
+                loginFrame.setResizable(false);
+                loginFrame.setVisible(true);
+            }
+        });
+    }
+
+
+}

+ 542 - 0
src/main/java/service/ProfileFrame.java

@@ -0,0 +1,542 @@
+package service;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.formdev.flatlaf.FlatDarculaLaf;
+import bean.Info;
+import bean.User;
+import com.formdev.flatlaf.FlatIntelliJLaf;
+import org.apache.commons.lang3.StringUtils;
+import util.RedisUtils;
+import util.SwingUtils;
+import util.ToolUtils;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.filechooser.FileSystemView;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.*;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author DFella
+ * @date 2020/12/21 15:57
+ */
+public class ProfileFrame extends JFrame {
+    /**
+     * 客户端实体
+     */
+    private static User user;
+    /**
+     * 轻量级组件容器
+     */
+    private JPanel contentPanel;
+    /**
+     * 连接的服务器ip
+     */
+    private JTextField host_edit;
+    /**
+     * 连接的服务器port
+     */
+    private JTextField port_edit;
+    /**
+     * 文本输出流
+     */
+    private PrintWriter printWriter;
+    /**
+     * 字符缓存输入流
+     */
+    private BufferedReader bufferedReader;
+    /**
+     * 聊天框
+     */
+    private JTextArea textArea;
+    /**
+     * 客户端套接字
+     */
+    private Socket socket;
+    /**
+     * 在线人数编辑框
+     */
+    private JTextField count_edit;
+    /**
+     * 系统时钟编辑框
+     */
+    private JTextField time_edit;
+    /**
+     * 显示在线用户的列表
+     */
+    JList list;
+    /**
+     * 接收服务器回复的在线人数,线程安全
+     */
+    private static AtomicInteger counts = new AtomicInteger(0);
+    /**
+     * 私聊用户名
+     */
+    private String secretUser;
+    /**
+     * 私聊用户名编辑框
+     */
+    private JTextField secret_edit;
+
+    /**
+     * 对外提供的启动函数
+     * @param u 用户实体
+     */
+    public static void launch(User u) {
+        user = u;
+        try {
+            UIManager.setLookAndFeel(new FlatIntelliJLaf());
+        } catch (Exception e) {
+            JOptionPane.showMessageDialog(null, e.getMessage(), "UI风格设置", JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+        final ProfileFrame profileFrame = new ProfileFrame();
+        profileFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+        SwingUtils.setSize(profileFrame, 0.55, 0.88);
+        profileFrame.setTitle(user.getUsername());
+        profileFrame.setIconImage(new ImageIcon("images/github.png").getImage());
+        profileFrame.setLocationRelativeTo(null);
+        profileFrame.setResizable(false);
+        profileFrame.setVisible(true);
+    }
+
+    public ProfileFrame() {
+        contentPanel = new JPanel();
+        contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
+        setContentPane(contentPanel);
+        contentPanel.setLayout(null);
+
+        JPanel banner = new JPanel();
+        banner.setBounds(0, 10, 446, 142);
+        contentPanel.add(banner);
+        banner.setLayout(null);
+
+        JLabel profile_jLabel = new JLabel();
+        profile_jLabel.setBounds(10, 5, 147, 114);
+        profile_jLabel.setIcon(SwingUtils.scaleImageIcon(new ImageIcon(user.getImage())
+                , profile_jLabel.getSize().getWidth()
+                , profile_jLabel.getSize().getHeight()));
+        banner.add(profile_jLabel);
+
+        JLabel name_jLabel = new JLabel("id:");
+        name_jLabel.setBounds(207, 60, 58, 36);
+        banner.add(name_jLabel);
+
+        JLabel username_jLabel = new JLabel(user.getUsername());
+        username_jLabel.setBounds(270, 60, 91, 36);
+        banner.add(username_jLabel);
+
+        JPanel content_jPanel = new JPanel();
+        content_jPanel.setBounds(20, 161, 770, 50);
+//        content_jPanel.setBackground(new Color(36, 36, 36, 0));
+        contentPanel.add(content_jPanel);
+
+        JButton profile_btn = new JButton("更换头像");
+        profile_btn.setBounds(35, 110, 97, 23);
+        banner.add(profile_btn);
+
+        JLabel host_jLabel = new JLabel("服务器ip");
+        host_jLabel.setBounds(10, 2, 59, 33);
+        content_jPanel.add(host_jLabel);
+
+        host_edit = new JTextField();
+        host_edit.setBounds(80, 3, 109, 31);
+        host_edit.setText("localhost");
+        host_edit.setEnabled(false);
+        content_jPanel.add(host_edit);
+        host_edit.setColumns(10);
+
+        JLabel port_jLabel = new JLabel("服务器port");
+        port_jLabel.setBounds(203, 1, 68, 35);
+        content_jPanel.add(port_jLabel);
+
+        port_edit = new JTextField();
+        port_edit.setBounds(280, 3, 109, 31);
+        content_jPanel.add(port_edit);
+        port_edit.setColumns(10);
+
+        JButton connect_btn = new JButton("连接服务器");
+        connect_btn.setBounds(35, 35, 110, 42);
+        content_jPanel.add(connect_btn);
+
+        JButton clear_btn = new JButton("清空内容");
+        clear_btn.setBounds(80, 725, 110, 42);
+        content_jPanel.add(clear_btn);
+
+        textArea = new JTextArea();
+        textArea.setBounds(10, 256, 426, 368);
+        contentPanel.add(textArea);
+
+        final JScrollPane jScrollPane = new JScrollPane();
+        jScrollPane.setBounds(10, 256, 426, 368);
+        jScrollPane.setViewportView(textArea);
+        contentPanel.add(jScrollPane);
+
+        JTextArea send_textArea = new JTextArea();
+        send_textArea.setBounds(10, 652, 333, 55);
+        contentPanel.add(send_textArea);
+
+        final JScrollPane send_scroll = new JScrollPane();
+        send_scroll.setBounds(10, 652, 333, 55);
+        send_scroll.setViewportView(send_textArea);
+        contentPanel.add(send_scroll);
+
+        JButton broadcast_btn = new JButton("广播发送");
+        broadcast_btn.setBounds(227, 726, 116, 38);
+        contentPanel.add(broadcast_btn);
+
+        JButton doc_btn = new JButton();
+        doc_btn.setBounds(10, 726, 30, 30);
+        doc_btn.setIcon(SwingUtils.scaleImageIcon(new ImageIcon("images/file.png")
+                , doc_btn.getSize().getWidth()
+                , doc_btn.getSize().getHeight()));
+        contentPanel.add(doc_btn);
+
+        JLabel count_jLabel = new JLabel("系统当前人数");
+        count_jLabel.setBounds(472, 276, 83, 38);
+        contentPanel.add(count_jLabel);
+
+        count_edit = new JTextField();
+        count_edit.setBounds(565, 276, 97, 38);
+        contentPanel.add(count_edit);
+        count_edit.setText("0");
+        count_edit.setEnabled(false);
+        count_edit.setColumns(10);
+
+        JLabel time_jLabel = new JLabel("当前系统时间");
+        time_jLabel.setBounds(472, 324, 83, 38);
+        contentPanel.add(time_jLabel);
+
+        time_edit = new JTextField();
+        time_edit.setColumns(10);
+        time_edit.setBounds(565, 324, 97, 38);
+        time_edit.setEnabled(false);
+        contentPanel.add(time_edit);
+
+        list = new JList(new Object[]{"用户还未连接服务器"});
+        list.setVisibleRowCount(3);
+        list.setLayoutOrientation(JList.VERTICAL);
+        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        list.setBounds(470, 420, 258, 140);
+        list.setVisible(true);
+        contentPanel.add(list);
+
+        JTextArea secretSend_textArea = new JTextArea();
+        secretSend_textArea.setBounds(472, 572, 272, 55);
+        contentPanel.add(secretSend_textArea);
+
+
+        final JScrollPane secret_scroll = new JScrollPane();
+        secret_scroll.setViewportView(secretSend_textArea);
+        secret_scroll.setBounds(472, 652, 272, 55);
+        contentPanel.add(secret_scroll);
+
+        JLabel secret_jLabel = new JLabel("私聊对象:");
+        secret_jLabel.setBounds(472, 598, 83, 32);
+        contentPanel.add(secret_jLabel);
+
+        secret_edit = new JTextField();
+        secret_edit.setBounds(565, 598, 97, 32);
+        secret_edit.setEnabled(false);
+        contentPanel.add(secret_edit);
+        secret_edit.setColumns(10);
+
+        JButton secretFile_btn = new JButton();
+        secretFile_btn.setBounds(471, 728, 32, 32);
+        secretFile_btn.setIcon(SwingUtils.scaleImageIcon(new ImageIcon("images/secret.png")
+                , secretFile_btn.getSize().getWidth()
+                , secretFile_btn.getSize().getHeight()));
+        contentPanel.add(secretFile_btn);
+
+        JButton secret_btn = new JButton("私聊发送");
+        secret_btn.setBounds(631, 725, 111, 38);
+        contentPanel.add(secret_btn);
+
+        /**
+         * 私聊内容发送
+         */
+        secret_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                String sendData = secretSend_textArea.getText();
+                if (StringUtils.isBlank(sendData)) {
+                    JOptionPane.showMessageDialog(null, "发送内容不能为空!", "发送私聊内容", JOptionPane.WARNING_MESSAGE);
+                    return;
+                }
+                if (secretUser == null) {
+                    JOptionPane.showMessageDialog(null, "未选择私聊对象!", "发送私聊内容", JOptionPane.WARNING_MESSAGE);
+                    return;
+                }
+                // 报文头为2号,代表客户端请求发送私聊信息
+                final Info info = new Info(9);
+                info.setContent(sendData);
+                info.setSource(user.getUsername());
+                info.setDest(secretUser);
+                printWriter.println(JSON.toJSONString(info));
+                list.setEnabled(true);
+            }
+        });
+
+        /**
+         * 私聊传文件
+         */
+        secretFile_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                JFileChooser jFileChooser = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
+                jFileChooser.setDialogTitle("打开");
+                final int state = jFileChooser.showOpenDialog(null);
+                if (state == JFileChooser.APPROVE_OPTION) {
+                    try {
+                        final File selectedFile = jFileChooser.getSelectedFile();
+                        final String fileContent = new String(ToolUtils.codeFile(selectedFile), StandardCharsets.UTF_8);
+                        // 私聊传输文件,报文头为10
+                        final Info info = new Info(10);
+                        info.setContent(fileContent);
+                        info.setSource(user.getUsername());
+                        info.setFileName(selectedFile.getName());
+                        if (secretUser == null) {
+                            JOptionPane.showMessageDialog(null, "未选择私聊对象!", "发送私聊文件", JOptionPane.WARNING_MESSAGE);
+                            return;
+                        }
+                        info.setDest(secretUser);
+                        printWriter.println(JSON.toJSONString(info));
+                        list.setEnabled(true);
+                    } catch (IOException ioException) {
+                        JOptionPane.showMessageDialog(null, ioException.getMessage(), "发送私聊文件", JOptionPane.WARNING_MESSAGE);
+                        return;
+                    }
+                }
+            }
+        });
+
+        /**
+         * 选择私聊用户点击事件
+         */
+        list.addListSelectionListener(new ListSelectionListener() {
+            @Override
+            public void valueChanged(ListSelectionEvent e) {
+                final Object value = list.getSelectedValue();
+                if (value != null) {
+                    final int recv = JOptionPane.showConfirmDialog(null, user.getUsername() + ",你要选择" + value + "为私聊对象吗", "选择好友私聊", JOptionPane.YES_NO_OPTION);
+                    // 选择成功
+                    if (recv == 0) {
+                        if (user.getUsername().equals(value)) {
+                            JOptionPane.showMessageDialog(null, "不能选择你自己", "选择私聊对象", JOptionPane.WARNING_MESSAGE);
+                            return;
+                        }
+                        secretUser = (String) value;
+                        secret_edit.setText(secretUser);
+                        list.setEnabled(false);
+                    }
+                }
+            }
+        });
+
+        /**
+         * 定时执行,查询在线人数
+         */
+        final ActionListener actionListener = new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                if (printWriter != null) {
+                    // 空报头即可
+                    final Info info = new Info(4);
+                    printWriter.println(JSON.toJSONString(info));
+                }
+                count_edit.setText(String.valueOf(counts.get()));
+            }
+        };
+        new Timer(3000, actionListener).start();
+
+        /**
+         * 定时执行,更新在线用户列表
+         */
+        final ActionListener actionListener1 = new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                if (printWriter != null) {
+                    final Set aliveUsers = RedisUtils.getAliveUsers();
+                    final DefaultListModel<String> defaultListModel = new DefaultListModel<>();
+                    for (Object aliveUser : aliveUsers) {
+                        defaultListModel.addElement((String) aliveUser);
+                        list.setModel(defaultListModel);
+                    }
+                }
+            }
+        };
+        new Timer(5000, actionListener1).start();
+
+
+        /**
+         * 实时更新时间
+         */
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                while (true) {
+                    time_edit.setText(ToolUtils.getRealTimeByHour());
+                }
+            }
+        }).start();
+
+
+        /**
+         * 上传文件点击事件
+         */
+        doc_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                JFileChooser jFileChooser = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
+                jFileChooser.setDialogTitle("打开");
+                final int state = jFileChooser.showOpenDialog(null);
+                if (state == JFileChooser.APPROVE_OPTION) {
+                    try {
+                        final File selectedFile = jFileChooser.getSelectedFile();
+                        final String fileContent = new String(ToolUtils.codeFile(selectedFile), StandardCharsets.UTF_8);
+                        // 传输文件
+                        final Info info = new Info(3);
+                        info.setContent(fileContent);
+                        info.setSource(user.getUsername());
+                        info.setFileName(selectedFile.getName());
+                        printWriter.println(JSON.toJSONString(info));
+                    } catch (IOException ioException) {
+                        ioException.printStackTrace();
+                        return;
+                    }
+                }
+
+            }
+        });
+
+        /**
+         * 广播消息点击事件
+         */
+        broadcast_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                String sendData = send_textArea.getText();
+                if (StringUtils.isBlank(sendData)) {
+                    JOptionPane.showMessageDialog(null, "发送消息不能为空!", "广播消息", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+                if (socket == null || socket.isClosed()) {
+                    JOptionPane.showMessageDialog(null, "你已掉线,请重新登陆!", "广播消息", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+                // JSON格式发送
+                final Info info = new Info(1);
+                info.setContent(sendData);
+                info.setSource(user.getUsername());
+                printWriter.println(JSON.toJSONString(info));
+            }
+        });
+
+
+        /**
+         * 连接服务器点击事件
+         */
+        connect_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                String host = host_edit.getText().trim();
+                String port = port_edit.getText().trim();
+                if (StringUtils.isBlank(host) || StringUtils.isBlank(port)) {
+                    JOptionPane.showMessageDialog(null, "ip和port禁止为空!", "连接服务器", JOptionPane.INFORMATION_MESSAGE);
+                }
+                try {
+                    socket = new Socket(host, Integer.parseInt(port));
+                    if (socket.isConnected()) {
+                        connect_btn.setEnabled(false);
+                    }
+                    bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+                    printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
+                    // json格式传输二进制流
+                    final Info info = new Info(0);
+                    info.setSource(user.getUsername());
+                    printWriter.println(JSON.toJSONString(info));
+
+                    new Thread(new Runnable() {
+                        @Override
+                        public void run() {
+                            String recv = null;
+                            while (socket.isConnected()) {
+                                try {
+                                    while ((recv = bufferedReader.readLine()) != null) {
+                                        final JSONObject jsonObject = JSON.parseObject(recv);
+                                        final int type = jsonObject.getIntValue("type");
+                                        final String content = jsonObject.getString("content");
+                                        System.out.println("服务器发来消息,类型:" + type + ",内容" + content);
+                                        // 服务器反馈信息
+                                        if (type == 6) {
+                                            textArea.append(content + "\n");
+                                        }
+                                        // 服务器返回系统人数
+                                        if (type == 5) {
+                                            counts.set(Integer.parseInt(content));
+                                        }
+                                        // 服务器转发私聊文件
+                                        if (type == 11) {
+                                            final String source = jsonObject.getString("source");
+                                            final String fileContent = jsonObject.getString("content");
+                                            final String fileName = jsonObject.getString("fileName");
+                                            ToolUtils.decodeFile(fileContent, System.getProperty("user.dir") + "\\files\\" + source + "私聊的文件_" + ToolUtils.getRealTime("yyyy-MM-dd HH:mm:ss") + "_" + fileName);
+                                            System.out.println("接收" + source + "私聊文件" + fileContent);
+                                        }
+                                    }
+                                } catch (IOException ioException) {
+                                    JOptionPane.showMessageDialog(null, "连接服务器失败,请稍候重连!", "服务器启动", JOptionPane.INFORMATION_MESSAGE);
+                                    return;
+                                }
+                            }
+                        }
+                    }).start();
+                } catch (IOException ioException) {
+                    JOptionPane.showMessageDialog(null, "连接服务器失败,请稍候重连!", "服务器启动", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+            }
+        });
+
+        /**
+         * 清空聊天区点击事件
+         */
+        clear_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                textArea.setText("");
+            }
+        });
+
+        /**
+         * 更换头像点击事件
+         */
+        profile_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                final JFileChooser jFileChooser = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
+                final FileNameExtensionFilter fileNameExtensionFilter = new FileNameExtensionFilter("仅照片", "jpg", "gif", "png");
+                jFileChooser.setFileFilter(fileNameExtensionFilter);
+                final int recv = jFileChooser.showOpenDialog(null);
+                if (recv == JFileChooser.APPROVE_OPTION) {
+                    final File selectedFile = jFileChooser.getSelectedFile();
+                    profile_jLabel.setIcon(SwingUtils.scaleImageIcon(new ImageIcon(selectedFile.getAbsolutePath())
+                            , profile_jLabel.getSize().getWidth()
+                            , profile_jLabel.getSize().getHeight()));
+                }
+            }
+        });
+    }
+
+
+}

+ 14 - 0
src/main/java/starter/Client.java

@@ -0,0 +1,14 @@
+package starter;
+
+import service.LoginFrame;
+
+/**
+ * @author DFella
+ * @date 2020/12/21 15:57
+ */
+public class Client {
+
+    public static void main(String[] args) {
+        LoginFrame.launch();
+    }
+}

+ 392 - 0
src/main/java/starter/Server.java

@@ -0,0 +1,392 @@
+package starter;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.formdev.flatlaf.FlatDarkLaf;
+import bean.Info;
+import util.RedisUtils;
+import util.SwingUtils;
+import util.ToolUtils;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author DFella
+ * @date 2020/12/21 15:56
+ */
+public class Server extends JFrame {
+    /**
+     * 项目根路径
+     */
+    private static final String rootPath = System.getProperty("user.dir");
+    /**
+     * 服务器端口
+     */
+    private static final int PORT = 8080;
+    /**
+     * 保存在线用户信息,用户名-文本输出流
+     */
+    private static HashMap userMap = new HashMap<String, PrintWriter>();
+    /**
+     * 轻量级容器组件
+     */
+    private JPanel contentPane;
+    /**
+     * 服务器ip编辑框
+     */
+    private JTextField host_edit;
+    /**
+     * 服务器port编辑框
+     */
+    private JTextField port_edit;
+    /**
+     * 聊天框
+     */
+    private static JTextArea textArea;
+    /**
+     * 服务器套接字
+     */
+    private static ServerSocket serverSocket;
+    /**
+     * 线程安全计数器,统计在线人数
+     */
+    private static AtomicInteger userCount = new AtomicInteger(0);
+
+
+    public Server() {
+        contentPane = new JPanel();
+        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
+        setContentPane(contentPane);
+        contentPane.setLayout(null);
+
+        JLabel host_jLabel = new JLabel("服务器ip");
+        host_jLabel.setBounds(10, 10, 70, 30);
+        contentPane.add(host_jLabel);
+
+        host_edit = new JTextField();
+        host_edit.setBounds(98, 9, 97, 33);
+        host_edit.setText("localhost");
+        host_edit.setEnabled(false);
+        contentPane.add(host_edit);
+        host_edit.setColumns(10);
+
+        JLabel port_jLabel = new JLabel("服务器port");
+        port_jLabel.setBounds(222, 10, 70, 30);
+        contentPane.add(port_jLabel);
+
+        port_edit = new JTextField();
+        port_edit.setBounds(302, 10, 87, 30);
+        contentPane.add(port_edit);
+        port_edit.setColumns(10);
+
+        JButton start_btn = new JButton("开启服务");
+        start_btn.setBounds(20, 50, 97, 23);
+        contentPane.add(start_btn);
+
+        textArea = new JTextArea();
+        textArea.setBounds(10, 83, 744, 303);
+        contentPane.add(textArea);
+
+        final JScrollPane jScrollPane = new JScrollPane();
+        jScrollPane.setBounds(10, 83, 744, 303);
+        jScrollPane.setViewportView(textArea);
+        contentPane.add(jScrollPane);
+
+        JButton close_btn = new JButton("关闭服务");
+        close_btn.setBounds(127, 50, 97, 23);
+        contentPane.add(close_btn);
+
+        JButton clear_btn = new JButton("清空内容");
+        clear_btn.setBounds(234, 50, 97, 23);
+        contentPane.add(clear_btn);
+
+
+
+        /**
+         * 关闭服务器点击事件
+         */
+        close_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                // TODO: 2020/6/26
+                try {
+                    if (! serverSocket.isClosed()) {
+                        //仅可以在连接前关闭
+                        serverSocket.close();
+                        textArea.append(ToolUtils.getRealTime() + ",服务器关闭成功\n");  }
+                }catch (IOException ex) {
+                    ex.printStackTrace();
+                }
+            }
+        });
+
+        /**
+         * 清空聊天框点击事件
+         */
+        clear_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                textArea.setText(" ");
+            }
+        });
+
+        /**
+         * 开启服务器点击事件
+         */
+        start_btn.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                new Thread(new Runnable() {
+                    @Override
+                    public void run() {
+                        int PORT = Integer.parseInt(port_edit.getText());
+                        try {
+                            serverSocket = new ServerSocket(PORT);
+                            serverSocket.setSoTimeout(5*10000);
+                            if (! serverSocket.isClosed()) {
+//                                start_btn.setEnabled(false);
+                                textArea.append(ToolUtils.getRealTime() + ",服务器开启成功\n");
+                            }
+                            while (true) {
+                                Socket accept = serverSocket.accept();
+                                new SingleUser(accept).start();
+                            }
+                        } catch (IOException ioException) {
+//                            JOptionPane.showMessageDialog(null, ioException.getMessage(), "服务器开启", JOptionPane.WARNING_MESSAGE);
+                            JOptionPane.showMessageDialog(null, "服务器已被中断");
+                        }
+                    }
+                }).start();
+            }
+        });
+
+    }
+
+    public static void main(String[] args) {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    UIManager.setLookAndFeel(new FlatDarkLaf());
+                } catch (Exception e) {
+                    JOptionPane.showMessageDialog(null, e.getMessage(), "UI风格设置", JOptionPane.WARNING_MESSAGE);
+                    return;
+                }
+                final Server server = new Server();
+                server.setDefaultCloseOperation(EXIT_ON_CLOSE);
+                server.setTitle("服务器程序");
+                SwingUtils.setSize(server, 0.55, 0.5);
+                server.setResizable(false);
+                server.setVisible(true);
+            }
+        });
+    }
+
+
+    /**
+     * 服务器转发客户端广播消息
+     * @param sendData 广播内容
+     * @param sender 发送者
+     */
+    private static void broadcast(String sendData, String sender) {
+        final Collection values = userMap.values();
+        for (Object value : values) {
+            PrintWriter printWriter = (PrintWriter) value;
+            // 回复
+            final Info info = new Info(6);
+            info.setContent(ToolUtils.getRealTime() + ",用户" + sender + ",广播了消息:" + sendData);
+            info.setSource(sender);
+            printWriter.println(JSON.toJSONString(info));
+        }
+    }
+
+    /**
+     * 用户私聊发送文件
+     * @param source 发送用户名
+     * @param fileContent 文件内容
+     * @param dest 私聊用户名
+     * @param fileName 文件名
+     */
+    private static void transferDoc(String source, String fileContent, String dest, String fileName) {
+        final PrintWriter destWriter = (PrintWriter) userMap.get(dest);
+        final PrintWriter sourceWriter = (PrintWriter) userMap.get(source);
+        if (destWriter == null) {
+            if (sourceWriter != null) {
+                final Info info1 = new Info(6);
+                info1.setContent(ToolUtils.getRealTime() + ",你私聊发送文件失败,用户" + dest + "已下线");
+                sourceWriter.println(JSON.toJSONString(info1));
+                textArea.append(ToolUtils.getRealTime() + ",用户" + source + "和" + dest + "私聊文件失败\n");
+            }
+        }
+        else {
+            final Info info = new Info(11);
+            info.setDest(dest);
+            info.setContent(fileContent);
+            info.setSource(source);
+            info.setFileName(fileName);
+            destWriter.println(JSON.toJSONString(info));
+            if (sourceWriter != null) {
+                final Info info1 = new Info(6);
+                info1.setContent(ToolUtils.getRealTime() + ",你私聊发送文件给用户" + dest + "成功");
+                sourceWriter.println(JSON.toJSONString(info1));
+                textArea.append(ToolUtils.getRealTime() + ",用户" + source + "和" + dest + "私聊文件成功\n");
+            }
+        }
+    }
+
+    /**
+     * 用户私聊发送数据
+     * @param sendData 私聊内容
+     * @param dest 私聊用户名
+     * @param username 发送用户名
+     */
+    private static void transferData(String username, String sendData, String dest) {
+        final PrintWriter sourceWriter = (PrintWriter) userMap.get(username);
+        final PrintWriter destWriter = (PrintWriter) userMap.get(dest);
+        // 私聊对象已下线
+        if (destWriter == null) {
+            // 私聊发起人在线
+            if (sourceWriter != null) {
+                final Info info = new Info(6);
+                info.setContent(ToolUtils.getRealTime() + ",抱歉,用户" + dest + ",已下线,请稍候重发");
+                sourceWriter.println(JSON.toJSONString(info));
+                textArea.append(ToolUtils.getRealTime() + ",用户" + username + "和" + dest + "私聊失败\n");
+            }
+        }
+        // 私聊对象在线
+        else {
+            final Info info = new Info(6);
+            info.setContent(ToolUtils.getRealTime() + ",用户" + username + ",私聊你如下内容:" + sendData);
+            destWriter.println(JSON.toJSONString(info));
+            textArea.append(ToolUtils.getRealTime() + ",用户" + username + "和" + dest + "私聊成功\n");
+            // 私聊发起人在线
+            if (sourceWriter != null) {
+                final Info info1 = new Info(6);
+                info1.setContent(ToolUtils.getRealTime() + ",你刚刚私聊给用户" + dest + "已发送成功");
+                sourceWriter.println(JSON.toJSONString(info1));
+            }
+        }
+    }
+
+
+    /**
+     * 内部静态类,负责与单独的客户端线程的通信工作
+     */
+    private static class SingleUser extends Thread {
+        /**
+         * 服务端与客户端对应的套接字
+         */
+        private Socket socket;
+        /**
+         * 缓冲字符输入流
+         */
+        private BufferedReader bufferedReader;
+        /**
+         * 文本输出流
+         */
+        private PrintWriter printWriter;
+        /**
+         * 用户名
+         */
+        private String id;
+
+        public SingleUser(Socket socket) {
+            this.socket = socket;
+            // 在线人数+1
+            userCount.incrementAndGet();
+        }
+
+        @Override
+        public void run() {
+            try {
+                printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
+                bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+                String recv = null;
+                while (socket.isConnected()) {
+                    while ( (recv = bufferedReader.readLine()) != null ) {
+                        final JSONObject jsonObject = JSON.parseObject(recv);
+                        final int type = jsonObject.getIntValue("type");
+                        // 客户端、服务器第一次握手
+                        if (type == 0) {
+                            final String username = jsonObject.getString("source");
+                            id = username;
+                            System.out.println("-----------------------");
+                            System.out.println(id);
+                            userMap.put(username, printWriter);
+                            // 添加在线用户进缓存
+                            RedisUtils.addAliveUser(id);
+                            textArea.append(ToolUtils.getRealTime() + ",用户" + username + "连接成功\n");
+                            // 回复
+                            final Info info = new Info(6);
+                            info.setContent(ToolUtils.getRealTime() + ",用户" + username + "连接成功");
+                            printWriter.println(JSON.toJSONString(info));
+                        }
+                        // 客户端请求广播消息
+                        if (type == 1) {
+                            final String content = jsonObject.getString("content");
+                            final String username = jsonObject.getString("source");
+                            broadcast(content, username);
+                            textArea.append(ToolUtils.getRealTime() + ",用户" + username + "广播了消息\n");
+                        }
+                        // 客户端上传文件
+                        if (type == 3) {
+                            final String content = jsonObject.getString("content");
+                            final String username = jsonObject.getString("source");
+                            final String fileName = (String) jsonObject.get("fileName");
+                            // 服务器保存文件制定路径
+                            String path = rootPath + "\\files\\" + username + "广播的文件_" + ToolUtils.getRealTime("yyyy-MM-dd HH:mm:ss") + "_" + fileName;
+                            System.out.println(path);
+                            ToolUtils.decodeFile(content, path);
+                            textArea.append(ToolUtils.getRealTime() + ",用户" + username + "上传了文件\n");
+                            // 回复
+                            final Info info = new Info(6);
+                            info.setContent(ToolUtils.getRealTime() + ",用户" + username + "上传了文件" + fileName);
+                            printWriter.println(JSON.toJSONString(info));
+                        }
+                        // 客户端查询在线人数
+                        if (type == 4) {
+                            // 回复
+                            final Info info = new Info(5);
+                            info.setContent(String.valueOf(userCount.get()));
+                            printWriter.println(JSON.toJSONString(info));
+                        }
+                        // 客户端请求转发私聊信息
+                        if (type == 9) {
+                            final String content = jsonObject.getString("content");
+                            final String dest = jsonObject.getString("dest");
+                            final String source = jsonObject.getString("source");
+                            transferData(source, content, dest);
+                        }
+                        // 客户端私聊发送文件
+                        if (type == 10) {
+                            final String content = jsonObject.getString("content");
+                            final String dest = jsonObject.getString("dest");
+                            final String source = jsonObject.getString("source");
+                            final String fileName = (String) jsonObject.get("fileName");
+                            transferDoc(source, content, dest, fileName);
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                // 不给出提示框,直接结束方便finally直接执行
+                return;
+            } finally {
+                // 删除用户缓存
+                userMap.remove(id);
+                RedisUtils.delAliveUser(id);
+                // 在线人数-1
+                userCount.decrementAndGet();
+            }
+        }
+    }
+}

+ 168 - 0
src/main/java/util/RedisUtils.java

@@ -0,0 +1,168 @@
+package util;
+
+import redis.clients.jedis.Jedis;
+
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * @author DFella
+ * @date 2020/12/21 15:48
+ * 功能:完成于redis数据库的交互工作,包括用户名、密码的保存、缓存的增加与删除等
+ */
+public class RedisUtils {
+    /**
+     * redis操作实体
+     */
+    private static Jedis jedis;
+    /**
+     * 远程服务器ip地址
+     */
+    private static final String HOST = "127.0.0.1";
+    /**
+     * 操作正确的返回值
+     */
+    private static final String OK = "OK";
+    /**
+     * 存储在线用户的集合
+     */
+    private static String ALIVEUSERS = "aliveUsers";
+
+    /**
+     * 建立连接
+     */
+    public static Jedis init() {
+        jedis = new Jedis(HOST);
+        jedis.select(1);
+        ToolUtils.getLogger().info(ToolUtils.getRealTime() + "\t" + jedis.ping());
+        return jedis;
+    }
+
+    /**
+     * 验证用户
+     * @param username 用户名
+     * @return 0-用户不存在,1-用户存在,密码错误,2-用户存在,密码正确
+     */
+    public static int validUser(String username, String password) {
+        if (jedis == null) {
+            RedisUtils.init();
+        }
+        if (! isExists(username)) {
+            return 0;
+        }
+        String recv = jedis.get(username);
+        if (! Objects.equals(recv,password)) {
+            return 1;
+        }
+        return 2;
+    }
+
+    /**
+     * 验证用户名是否存在
+     * @param username 用户名
+     * @return
+     */
+    private static boolean isExists(String username) {
+        if (jedis == null) {
+            RedisUtils.init();
+        }
+        if (username == null) {
+            return false;
+        }
+        return jedis.exists(username);
+    }
+
+    /**
+     * 注册用户
+     * @param username 用户名
+     * @param password 密码
+     * @return 0-用户已存在,1-注册失败,2-注册成功
+     */
+    public static int insertUser(String username, String password) {
+        if (jedis == null) {
+            RedisUtils.init();
+        }
+        if (isExists(username)) {
+            return 0;
+        }
+        final String recv = jedis.set(username, password);
+        if (OK.equals(recv)) {
+            return 2;
+        }
+        return 1;
+    }
+
+    /**
+     * 修改密码
+     * @param username 用户名
+     * @param password  老密码
+     * @return
+     */
+    public static void modifyUser(String username, String password) {
+        if (jedis == null) {
+            RedisUtils.init();
+        }
+        jedis.set(username, password);
+    }
+
+    /**
+     * 关闭连接
+     */
+    public static void close() {
+        if (jedis == null) {
+            return;
+        }
+        if (jedis.isConnected()) {
+            jedis.close();
+        }
+    }
+
+
+    /**
+     * 增添在线用户缓存
+     * @param username 用户名
+     */
+    public static long addAliveUser(String username) {
+        if (jedis == null) {
+            RedisUtils.init();
+        }
+        jedis.select(1);
+        return jedis.sadd(ALIVEUSERS, username);
+    }
+
+    /**
+     * 删除在线用户缓存
+     * @param username 用户名
+     */
+    public static long delAliveUser(String username) {
+        if (jedis == null) {
+            RedisUtils.init();
+        }
+        jedis.select(1);
+        return jedis.srem(ALIVEUSERS, username);
+    }
+
+    /**
+     * 获得在线用户缓存
+     * @return 缓存集合
+     */
+    public static Set getAliveUsers() {
+        if (jedis == null) {
+            RedisUtils.init();
+        }
+        jedis.select(1);
+        return jedis.smembers(ALIVEUSERS);
+    }
+
+    /**
+     * 验证用户是否已登录
+     * @param username 用户名
+     * @return true-用户已经登录,false-用户未登录
+     */
+    public static boolean isAlive(String username) {
+        if (jedis == null) {
+            RedisUtils.init();
+        }
+        return jedis.sismember(ALIVEUSERS, username);
+    }
+}

+ 51 - 0
src/main/java/util/SwingUtils.java

@@ -0,0 +1,51 @@
+package util;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author DFella
+ * @date 2020/12/21 15:56 16:31
+ */
+public class SwingUtils {
+
+    /**
+     * 设置大小为电脑屏幕的指定比例
+     * @param jFrame 窗口
+     * @param w 电脑屏幕宽度的w倍,w<=1
+     * @param h 电脑屏幕高度的h倍,h<=1
+     */
+    public static void setSize(JFrame jFrame, double w, double h){
+        int width = (int) (getScreenWidth() * w);
+        int height = (int) (getScreenHeight() * h);
+        jFrame.setSize(width, height);
+    }
+
+    /**
+     * 获得电脑屏幕宽度
+     * @return
+     */
+    public static double getScreenWidth() {
+        return Toolkit.getDefaultToolkit().getScreenSize().getWidth();
+    }
+
+    /**
+     * 获得电脑屏幕宽度
+     * @return
+     */
+    public static double getScreenHeight() {
+        return Toolkit.getDefaultToolkit().getScreenSize().getHeight();
+    }
+
+    /**
+     * 按照width、height比例调整图标大小
+     * @param imageIcon 要调整的图标
+     * @param width 调整后的图像宽度
+     * @param height 调整后的图像高度
+     * @return
+     */
+    public static ImageIcon scaleImageIcon(ImageIcon imageIcon, double width, double height) {
+        imageIcon.setImage(imageIcon.getImage().getScaledInstance((int)width, (int)height, Image.SCALE_SMOOTH));
+        return imageIcon;
+    }
+}

+ 151 - 0
src/main/java/util/ToolUtils.java

@@ -0,0 +1,151 @@
+package util;
+
+import java.io.*;
+import java.nio.file.Path;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Random;
+import java.util.logging.Logger;
+
+/**
+ * @author DFella
+ * @date 2020/12/21 15:47
+ * 工具类,完成一些常用、公共的功能
+ */
+public class ToolUtils {
+    /**
+     * 全局唯一日志对象
+     */
+    private static Logger logger = Logger.getLogger("聊天室日志");
+    /**
+     * 存储头像列表
+     */
+    private static ArrayList profile_list;
+    /**
+     * 存储路径前缀
+     */
+    private static final String pathPrefix = "images/profiles/";
+    /**
+     * 存储头像列表大小
+     */
+    private static Integer num;
+
+    /**
+     * 添加头像文件名到列表
+     */
+    static {
+        profile_list = new ArrayList<String>();
+        profile_list.add(pathPrefix + "bear.png");
+        profile_list.add(pathPrefix + "bee.png");
+        profile_list.add(pathPrefix + "cat.png");
+        profile_list.add(pathPrefix + "cattle.png");
+        profile_list.add(pathPrefix + "deer.png");
+        profile_list.add(pathPrefix + "dog.png");
+        profile_list.add(pathPrefix + "giraffe.png");
+        profile_list.add(pathPrefix + "horse.png");
+        profile_list.add(pathPrefix + "lion.png");
+        profile_list.add(pathPrefix + "monkey.png");
+        profile_list.add(pathPrefix + "panda.png");
+        profile_list.add(pathPrefix + "pig.png");
+        profile_list.add(pathPrefix + "sheep.png");
+        num = profile_list.size();
+    }
+
+    /**
+     * 获得时间,年-月-日-时-分-秒
+     * @return
+     */
+    public static String getRealTime() {
+        return getRealTime("yyyy-MM-dd HH:mm:ss");
+    }
+
+    /**
+     * 获得时间,时/分/秒
+     * @return
+     */
+    public static String getRealTimeByHour() {
+        return getRealTimeByHour("HH:mm:ss");
+    }
+
+    /**
+     * 获得时间,时分秒
+     * @param pattern 提供的格式输出时间
+     * @return
+     */
+    public static String getRealTimeByHour(String pattern) {
+        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(pattern));
+    }
+
+    /**
+     * 获得时间
+     * @param pattern 按照指定的格式输出日期
+     * @return
+     */
+    public static String getRealTime(String pattern) {
+        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(pattern));
+    }
+
+    /**
+     * 获得单例日志对象
+     * @return
+     */
+    public static Logger getLogger() {
+        return logger;
+    }
+
+    /**
+     * 给用户随机分配动物头像
+     * @return
+     */
+    public static String getProfile() {
+        return (String) profile_list.get(new Random().nextInt(num));
+    }
+
+
+    /**
+     * 编码文件成二进制流
+     * @param file 文件对象
+     * @return 文件字节流
+     * @throws FileNotFoundException
+     */
+    public static byte[] codeFile(File file) throws IOException {
+        try (final FileInputStream fileInputStream = new FileInputStream(file))
+        {
+            return fileInputStream.readAllBytes();
+        }
+    }
+
+
+    /**
+     * 解码二进制成文件,并写入内容
+     * @param content 文件内容
+     * @param absolutePath 绝对路径
+     * @return
+     */
+    public static void decodeFile(String content, String absolutePath) throws IOException {
+        final File file = Path.of(absolutePath).toFile();
+        if (! file.exists()) {
+            file.createNewFile();
+        }
+        try (final FileOutputStream fileOutputStream = new FileOutputStream(file,true))
+        {
+            fileOutputStream.write(content.getBytes());
+            fileOutputStream.flush();
+        }
+    }
+
+    /**
+     * 解析出文件后缀名
+     * @param fileName 完整文件名,包括后缀名
+     * @return 文件后缀名
+     */
+    public static String getFileExt(String fileName) {
+        return fileName.substring(fileName.lastIndexOf("."));
+    }
+
+
+
+
+
+}

+ 16 - 0
src/test/java/Test.java

@@ -0,0 +1,16 @@
+import javax.swing.filechooser.FileSystemView;
+import java.io.DataInputStream;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * @author zhupengcheng
+ * @date 2020/6/19 15:53
+ */
+public class Test {
+
+    public static void main(String[] args) {
+//        System.out.println(SwingUtils.getScreenWidth() * 0.5 + "\t" + SwingUtils.getScreenHeight() * 1);
+        System.out.println(FileSystemView.getFileSystemView().getHomeDirectory() + "/");
+
+    }
+}

BIN
target/classes/bean/Info.class


BIN
target/classes/bean/User.class


BIN
target/classes/javabean/Info.class


BIN
target/classes/javabean/User.class


BIN
target/classes/service/LoginFrame$1.class


BIN
target/classes/service/LoginFrame$2.class


BIN
target/classes/service/LoginFrame$3.class


BIN
target/classes/service/LoginFrame$4.class


BIN
target/classes/service/LoginFrame.class


BIN
target/classes/service/ProfileFrame$1.class


BIN
target/classes/service/ProfileFrame$10.class


BIN
target/classes/service/ProfileFrame$11.class


BIN
target/classes/service/ProfileFrame$2.class


BIN
target/classes/service/ProfileFrame$3.class


BIN
target/classes/service/ProfileFrame$4.class


BIN
target/classes/service/ProfileFrame$5.class


BIN
target/classes/service/ProfileFrame$6.class


BIN
target/classes/service/ProfileFrame$7.class


BIN
target/classes/service/ProfileFrame$8.class


BIN
target/classes/service/ProfileFrame$9$1.class


BIN
target/classes/service/ProfileFrame$9.class


BIN
target/classes/service/ProfileFrame.class


BIN
target/classes/starter/Client.class


BIN
target/classes/starter/Server$1.class


BIN
target/classes/starter/Server$2.class


BIN
target/classes/starter/Server$3$1.class


BIN
target/classes/starter/Server$3.class


BIN
target/classes/starter/Server$4.class


BIN
target/classes/starter/Server$SingleUser.class


BIN
target/classes/starter/Server.class


BIN
target/classes/util/RedisUtils.class


BIN
target/classes/util/SwingUtils.class


BIN
target/classes/util/ToolUtils.class


BIN
target/test-classes/Test.class