Initial empty repository
Change-Id: Ie0685414be5495d9da50d659d9ec16ae51487e46
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..8a43039
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="CompilerConfiguration">
+ <excludeFromCompile>
+ <directory url="file://$PROJECT_DIR$/src/main/resources/archetype-resources" includeSubdirectories="true" />
+ </excludeFromCompile>
+ <annotationProcessing>
+ <profile default="true" name="Default" enabled="true" />
+ <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="echo-backend" />
+ </profile>
+ </annotationProcessing>
+ </component>
+ <component name="JavacSettings">
+ <option name="ADDITIONAL_OPTIONS_OVERRIDE">
+ <module name="echo-backend" options="-parameters --add-opens jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED" />
+ </option>
+ </component>
+</project>
\ No newline at end of file
diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml
new file mode 100644
index 0000000..bd22aef
--- /dev/null
+++ b/.idea/dbnavigator.xml
@@ -0,0 +1,526 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="DBNavigator.Project.DataEditorManager">
+ <record-view-column-sorting-type value="BY_INDEX" />
+ <value-preview-text-wrapping value="false" />
+ <value-preview-pinned value="false" />
+ </component>
+ <component name="DBNavigator.Project.DatabaseBrowserManager">
+ <autoscroll-to-editor value="false" />
+ <autoscroll-from-editor value="true" />
+ <show-object-properties value="true" />
+ <loaded-nodes />
+ </component>
+ <component name="DBNavigator.Project.DatabaseConsoleManager">
+ <connection id="4ded7242-84d3-4adb-86b5-537d4d1b5740">
+ <console name="Connection" type="STANDARD" schema="mysql" session="Main" />
+ </connection>
+ </component>
+ <component name="DBNavigator.Project.DatabaseEditorStateManager">
+ <last-used-providers />
+ </component>
+ <component name="DBNavigator.Project.DatabaseFileManager">
+ <open-files />
+ </component>
+ <component name="DBNavigator.Project.DatasetFilterManager">
+ <filter-actions connection-id="4ded7242-84d3-4adb-86b5-537d4d1b5740" dataset="avocado.class_student" active-filter-id="" />
+ <filter-actions connection-id="4ded7242-84d3-4adb-86b5-537d4d1b5740" dataset="avocado.user" active-filter-id="" />
+ </component>
+ <component name="DBNavigator.Project.ExecutionManager">
+ <retain-sticky-names value="false" />
+ </component>
+ <component name="DBNavigator.Project.ObjectQuickFilterManager">
+ <last-used-operator value="EQUAL" />
+ <filters />
+ </component>
+ <component name="DBNavigator.Project.ParserDiagnosticsManager">
+ <diagnostics-history />
+ </component>
+ <component name="DBNavigator.Project.Settings">
+ <connections>
+ <connection id="4ded7242-84d3-4adb-86b5-537d4d1b5740" active="true" signed="true">
+ <database>
+ <name value="Connection" />
+ <description value="" />
+ <database-type value="MYSQL" />
+ <config-type value="BASIC" />
+ <database-version value="8.0" />
+ <driver-source value="BUNDLED" />
+ <driver-library value="" />
+ <driver value="" />
+ <url-type value="DATABASE" />
+ <host value="localhost" />
+ <port value="3306" />
+ <database value="mysql" />
+ <tns-folder value="" />
+ <tns-profile value="" />
+ <type value="USER_PASSWORD" />
+ <user value="root" />
+ <deprecated-pwd value="cm9vdA==" />
+ </database>
+ <properties>
+ <auto-commit value="false" />
+ </properties>
+ <ssh-settings>
+ <active value="false" />
+ <proxy-host value="" />
+ <proxy-port value="22" />
+ <proxy-user value="" />
+ <deprecated-proxy-pwd value="" />
+ <auth-type value="PASSWORD" />
+ <key-file value="" />
+ <key-passphrase value="" />
+ </ssh-settings>
+ <ssl-settings>
+ <active value="false" />
+ <certificate-authority-file value="" />
+ <client-certificate-file value="" />
+ <client-key-file value="" />
+ </ssl-settings>
+ <details>
+ <charset value="UTF-8" />
+ <session-management value="true" />
+ <ddl-file-binding value="true" />
+ <database-logging value="true" />
+ <connect-automatically value="true" />
+ <restore-workspace value="true" />
+ <restore-workspace-deep value="false" />
+ <environment-type value="default" />
+ <connectivity-timeout value="30" />
+ <idle-time-to-disconnect value="30" />
+ <idle-time-to-disconnect-pool value="5" />
+ <credential-expiry-time value="10" />
+ <max-connection-pool-size value="7" />
+ <alternative-statement-delimiter value="" />
+ </details>
+ <object-filters hide-empty-schemas="false" hide-pseudo-columns="false">
+ <object-type-filter>
+ <object-type name="SCHEMA" enabled="true" />
+ <object-type name="USER" enabled="true" />
+ <object-type name="ROLE" enabled="true" />
+ <object-type name="PRIVILEGE" enabled="true" />
+ <object-type name="CHARSET" enabled="true" />
+ <object-type name="TABLE" enabled="true" />
+ <object-type name="VIEW" enabled="true" />
+ <object-type name="MATERIALIZED_VIEW" enabled="true" />
+ <object-type name="NESTED_TABLE" enabled="true" />
+ <object-type name="COLUMN" enabled="true" />
+ <object-type name="INDEX" enabled="true" />
+ <object-type name="CONSTRAINT" enabled="true" />
+ <object-type name="DATASET_TRIGGER" enabled="true" />
+ <object-type name="DATABASE_TRIGGER" enabled="true" />
+ <object-type name="SYNONYM" enabled="true" />
+ <object-type name="SEQUENCE" enabled="true" />
+ <object-type name="PROCEDURE" enabled="true" />
+ <object-type name="FUNCTION" enabled="true" />
+ <object-type name="PACKAGE" enabled="true" />
+ <object-type name="TYPE" enabled="true" />
+ <object-type name="TYPE_ATTRIBUTE" enabled="true" />
+ <object-type name="ARGUMENT" enabled="true" />
+ <object-type name="DIMENSION" enabled="true" />
+ <object-type name="CLUSTER" enabled="true" />
+ <object-type name="DBLINK" enabled="true" />
+ </object-type-filter>
+ <object-name-filters />
+ </object-filters>
+ </connection>
+ </connections>
+ <browser-settings>
+ <general>
+ <display-mode value="TABBED" />
+ <navigation-history-size value="100" />
+ <show-object-details value="false" />
+ </general>
+ <filters>
+ <object-type-filter>
+ <object-type name="SCHEMA" enabled="true" />
+ <object-type name="USER" enabled="true" />
+ <object-type name="ROLE" enabled="true" />
+ <object-type name="PRIVILEGE" enabled="true" />
+ <object-type name="CHARSET" enabled="true" />
+ <object-type name="TABLE" enabled="true" />
+ <object-type name="VIEW" enabled="true" />
+ <object-type name="MATERIALIZED_VIEW" enabled="true" />
+ <object-type name="NESTED_TABLE" enabled="true" />
+ <object-type name="COLUMN" enabled="true" />
+ <object-type name="INDEX" enabled="true" />
+ <object-type name="CONSTRAINT" enabled="true" />
+ <object-type name="DATASET_TRIGGER" enabled="true" />
+ <object-type name="DATABASE_TRIGGER" enabled="true" />
+ <object-type name="SYNONYM" enabled="true" />
+ <object-type name="SEQUENCE" enabled="true" />
+ <object-type name="PROCEDURE" enabled="true" />
+ <object-type name="FUNCTION" enabled="true" />
+ <object-type name="PACKAGE" enabled="true" />
+ <object-type name="TYPE" enabled="true" />
+ <object-type name="TYPE_ATTRIBUTE" enabled="true" />
+ <object-type name="ARGUMENT" enabled="true" />
+ <object-type name="DIMENSION" enabled="true" />
+ <object-type name="CLUSTER" enabled="true" />
+ <object-type name="DBLINK" enabled="true" />
+ </object-type-filter>
+ </filters>
+ <sorting>
+ <object-type name="COLUMN" sorting-type="NAME" />
+ <object-type name="FUNCTION" sorting-type="NAME" />
+ <object-type name="PROCEDURE" sorting-type="NAME" />
+ <object-type name="ARGUMENT" sorting-type="POSITION" />
+ <object-type name="TYPE ATTRIBUTE" sorting-type="POSITION" />
+ </sorting>
+ <default-editors>
+ <object-type name="VIEW" editor-type="SELECTION" />
+ <object-type name="PACKAGE" editor-type="SELECTION" />
+ <object-type name="TYPE" editor-type="SELECTION" />
+ </default-editors>
+ </browser-settings>
+ <navigation-settings>
+ <lookup-filters>
+ <lookup-objects>
+ <object-type name="SCHEMA" enabled="true" />
+ <object-type name="USER" enabled="false" />
+ <object-type name="ROLE" enabled="false" />
+ <object-type name="PRIVILEGE" enabled="false" />
+ <object-type name="CHARSET" enabled="false" />
+ <object-type name="TABLE" enabled="true" />
+ <object-type name="VIEW" enabled="true" />
+ <object-type name="MATERIALIZED VIEW" enabled="true" />
+ <object-type name="INDEX" enabled="true" />
+ <object-type name="CONSTRAINT" enabled="true" />
+ <object-type name="DATASET TRIGGER" enabled="true" />
+ <object-type name="DATABASE TRIGGER" enabled="true" />
+ <object-type name="SYNONYM" enabled="false" />
+ <object-type name="SEQUENCE" enabled="true" />
+ <object-type name="PROCEDURE" enabled="true" />
+ <object-type name="FUNCTION" enabled="true" />
+ <object-type name="PACKAGE" enabled="true" />
+ <object-type name="TYPE" enabled="true" />
+ <object-type name="DIMENSION" enabled="false" />
+ <object-type name="CLUSTER" enabled="false" />
+ <object-type name="DBLINK" enabled="true" />
+ </lookup-objects>
+ <force-database-load value="false" />
+ <prompt-connection-selection value="true" />
+ <prompt-schema-selection value="true" />
+ </lookup-filters>
+ </navigation-settings>
+ <dataset-grid-settings>
+ <general>
+ <enable-zooming value="true" />
+ <enable-column-tooltip value="true" />
+ </general>
+ <sorting>
+ <nulls-first value="true" />
+ <max-sorting-columns value="4" />
+ </sorting>
+ <audit-columns>
+ <column-names value="" />
+ <visible value="true" />
+ <editable value="false" />
+ </audit-columns>
+ </dataset-grid-settings>
+ <dataset-editor-settings>
+ <text-editor-popup>
+ <active value="false" />
+ <active-if-empty value="false" />
+ <data-length-threshold value="100" />
+ <popup-delay value="1000" />
+ </text-editor-popup>
+ <values-actions-popup>
+ <show-popup-button value="true" />
+ <element-count-threshold value="1000" />
+ <data-length-threshold value="250" />
+ </values-actions-popup>
+ <general>
+ <fetch-block-size value="100" />
+ <fetch-timeout value="30" />
+ <trim-whitespaces value="true" />
+ <convert-empty-strings-to-null value="true" />
+ <select-content-on-cell-edit value="true" />
+ <large-value-preview-active value="true" />
+ </general>
+ <filters>
+ <prompt-filter-dialog value="true" />
+ <default-filter-type value="BASIC" />
+ </filters>
+ <qualified-text-editor text-length-threshold="300">
+ <content-types>
+ <content-type name="Text" enabled="true" />
+ <content-type name="Properties" enabled="true" />
+ <content-type name="XML" enabled="true" />
+ <content-type name="DTD" enabled="true" />
+ <content-type name="HTML" enabled="true" />
+ <content-type name="XHTML" enabled="true" />
+ <content-type name="Java" enabled="true" />
+ <content-type name="SQL" enabled="true" />
+ <content-type name="PL/SQL" enabled="true" />
+ <content-type name="JSON" enabled="true" />
+ <content-type name="JSON5" enabled="true" />
+ <content-type name="Groovy" enabled="true" />
+ <content-type name="AIDL" enabled="true" />
+ <content-type name="YAML" enabled="true" />
+ <content-type name="Manifest" enabled="true" />
+ </content-types>
+ </qualified-text-editor>
+ <record-navigation>
+ <navigation-target value="VIEWER" />
+ </record-navigation>
+ </dataset-editor-settings>
+ <code-editor-settings>
+ <general>
+ <show-object-navigation-gutter value="false" />
+ <show-spec-declaration-navigation-gutter value="true" />
+ <enable-spellchecking value="true" />
+ <enable-reference-spellchecking value="false" />
+ </general>
+ <confirmations>
+ <save-changes value="false" />
+ <revert-changes value="true" />
+ </confirmations>
+ </code-editor-settings>
+ <code-completion-settings>
+ <filters>
+ <basic-filter>
+ <filter-element type="RESERVED_WORD" id="keyword" selected="true" />
+ <filter-element type="RESERVED_WORD" id="function" selected="true" />
+ <filter-element type="RESERVED_WORD" id="parameter" selected="true" />
+ <filter-element type="RESERVED_WORD" id="datatype" selected="true" />
+ <filter-element type="RESERVED_WORD" id="exception" selected="true" />
+ <filter-element type="OBJECT" id="schema" selected="true" />
+ <filter-element type="OBJECT" id="role" selected="true" />
+ <filter-element type="OBJECT" id="user" selected="true" />
+ <filter-element type="OBJECT" id="privilege" selected="true" />
+ <user-schema>
+ <filter-element type="OBJECT" id="table" selected="true" />
+ <filter-element type="OBJECT" id="view" selected="true" />
+ <filter-element type="OBJECT" id="materialized view" selected="true" />
+ <filter-element type="OBJECT" id="index" selected="true" />
+ <filter-element type="OBJECT" id="constraint" selected="true" />
+ <filter-element type="OBJECT" id="trigger" selected="true" />
+ <filter-element type="OBJECT" id="synonym" selected="false" />
+ <filter-element type="OBJECT" id="sequence" selected="true" />
+ <filter-element type="OBJECT" id="procedure" selected="true" />
+ <filter-element type="OBJECT" id="function" selected="true" />
+ <filter-element type="OBJECT" id="package" selected="true" />
+ <filter-element type="OBJECT" id="type" selected="true" />
+ <filter-element type="OBJECT" id="dimension" selected="true" />
+ <filter-element type="OBJECT" id="cluster" selected="true" />
+ <filter-element type="OBJECT" id="dblink" selected="true" />
+ </user-schema>
+ <public-schema>
+ <filter-element type="OBJECT" id="table" selected="false" />
+ <filter-element type="OBJECT" id="view" selected="false" />
+ <filter-element type="OBJECT" id="materialized view" selected="false" />
+ <filter-element type="OBJECT" id="index" selected="false" />
+ <filter-element type="OBJECT" id="constraint" selected="false" />
+ <filter-element type="OBJECT" id="trigger" selected="false" />
+ <filter-element type="OBJECT" id="synonym" selected="false" />
+ <filter-element type="OBJECT" id="sequence" selected="false" />
+ <filter-element type="OBJECT" id="procedure" selected="false" />
+ <filter-element type="OBJECT" id="function" selected="false" />
+ <filter-element type="OBJECT" id="package" selected="false" />
+ <filter-element type="OBJECT" id="type" selected="false" />
+ <filter-element type="OBJECT" id="dimension" selected="false" />
+ <filter-element type="OBJECT" id="cluster" selected="false" />
+ <filter-element type="OBJECT" id="dblink" selected="false" />
+ </public-schema>
+ <any-schema>
+ <filter-element type="OBJECT" id="table" selected="true" />
+ <filter-element type="OBJECT" id="view" selected="true" />
+ <filter-element type="OBJECT" id="materialized view" selected="true" />
+ <filter-element type="OBJECT" id="index" selected="true" />
+ <filter-element type="OBJECT" id="constraint" selected="true" />
+ <filter-element type="OBJECT" id="trigger" selected="true" />
+ <filter-element type="OBJECT" id="synonym" selected="true" />
+ <filter-element type="OBJECT" id="sequence" selected="true" />
+ <filter-element type="OBJECT" id="procedure" selected="true" />
+ <filter-element type="OBJECT" id="function" selected="true" />
+ <filter-element type="OBJECT" id="package" selected="true" />
+ <filter-element type="OBJECT" id="type" selected="true" />
+ <filter-element type="OBJECT" id="dimension" selected="true" />
+ <filter-element type="OBJECT" id="cluster" selected="true" />
+ <filter-element type="OBJECT" id="dblink" selected="true" />
+ </any-schema>
+ </basic-filter>
+ <extended-filter>
+ <filter-element type="RESERVED_WORD" id="keyword" selected="true" />
+ <filter-element type="RESERVED_WORD" id="function" selected="true" />
+ <filter-element type="RESERVED_WORD" id="parameter" selected="true" />
+ <filter-element type="RESERVED_WORD" id="datatype" selected="true" />
+ <filter-element type="RESERVED_WORD" id="exception" selected="true" />
+ <filter-element type="OBJECT" id="schema" selected="true" />
+ <filter-element type="OBJECT" id="user" selected="true" />
+ <filter-element type="OBJECT" id="role" selected="true" />
+ <filter-element type="OBJECT" id="privilege" selected="true" />
+ <user-schema>
+ <filter-element type="OBJECT" id="table" selected="true" />
+ <filter-element type="OBJECT" id="view" selected="true" />
+ <filter-element type="OBJECT" id="materialized view" selected="true" />
+ <filter-element type="OBJECT" id="index" selected="true" />
+ <filter-element type="OBJECT" id="constraint" selected="true" />
+ <filter-element type="OBJECT" id="trigger" selected="true" />
+ <filter-element type="OBJECT" id="synonym" selected="true" />
+ <filter-element type="OBJECT" id="sequence" selected="true" />
+ <filter-element type="OBJECT" id="procedure" selected="true" />
+ <filter-element type="OBJECT" id="function" selected="true" />
+ <filter-element type="OBJECT" id="package" selected="true" />
+ <filter-element type="OBJECT" id="type" selected="true" />
+ <filter-element type="OBJECT" id="dimension" selected="true" />
+ <filter-element type="OBJECT" id="cluster" selected="true" />
+ <filter-element type="OBJECT" id="dblink" selected="true" />
+ </user-schema>
+ <public-schema>
+ <filter-element type="OBJECT" id="table" selected="true" />
+ <filter-element type="OBJECT" id="view" selected="true" />
+ <filter-element type="OBJECT" id="materialized view" selected="true" />
+ <filter-element type="OBJECT" id="index" selected="true" />
+ <filter-element type="OBJECT" id="constraint" selected="true" />
+ <filter-element type="OBJECT" id="trigger" selected="true" />
+ <filter-element type="OBJECT" id="synonym" selected="true" />
+ <filter-element type="OBJECT" id="sequence" selected="true" />
+ <filter-element type="OBJECT" id="procedure" selected="true" />
+ <filter-element type="OBJECT" id="function" selected="true" />
+ <filter-element type="OBJECT" id="package" selected="true" />
+ <filter-element type="OBJECT" id="type" selected="true" />
+ <filter-element type="OBJECT" id="dimension" selected="true" />
+ <filter-element type="OBJECT" id="cluster" selected="true" />
+ <filter-element type="OBJECT" id="dblink" selected="true" />
+ </public-schema>
+ <any-schema>
+ <filter-element type="OBJECT" id="table" selected="true" />
+ <filter-element type="OBJECT" id="view" selected="true" />
+ <filter-element type="OBJECT" id="materialized view" selected="true" />
+ <filter-element type="OBJECT" id="index" selected="true" />
+ <filter-element type="OBJECT" id="constraint" selected="true" />
+ <filter-element type="OBJECT" id="trigger" selected="true" />
+ <filter-element type="OBJECT" id="synonym" selected="true" />
+ <filter-element type="OBJECT" id="sequence" selected="true" />
+ <filter-element type="OBJECT" id="procedure" selected="true" />
+ <filter-element type="OBJECT" id="function" selected="true" />
+ <filter-element type="OBJECT" id="package" selected="true" />
+ <filter-element type="OBJECT" id="type" selected="true" />
+ <filter-element type="OBJECT" id="dimension" selected="true" />
+ <filter-element type="OBJECT" id="cluster" selected="true" />
+ <filter-element type="OBJECT" id="dblink" selected="true" />
+ </any-schema>
+ </extended-filter>
+ </filters>
+ <sorting enabled="true">
+ <sorting-element type="RESERVED_WORD" id="keyword" />
+ <sorting-element type="RESERVED_WORD" id="datatype" />
+ <sorting-element type="OBJECT" id="column" />
+ <sorting-element type="OBJECT" id="table" />
+ <sorting-element type="OBJECT" id="view" />
+ <sorting-element type="OBJECT" id="materialized view" />
+ <sorting-element type="OBJECT" id="index" />
+ <sorting-element type="OBJECT" id="constraint" />
+ <sorting-element type="OBJECT" id="trigger" />
+ <sorting-element type="OBJECT" id="synonym" />
+ <sorting-element type="OBJECT" id="sequence" />
+ <sorting-element type="OBJECT" id="procedure" />
+ <sorting-element type="OBJECT" id="function" />
+ <sorting-element type="OBJECT" id="package" />
+ <sorting-element type="OBJECT" id="type" />
+ <sorting-element type="OBJECT" id="dimension" />
+ <sorting-element type="OBJECT" id="cluster" />
+ <sorting-element type="OBJECT" id="dblink" />
+ <sorting-element type="OBJECT" id="schema" />
+ <sorting-element type="OBJECT" id="role" />
+ <sorting-element type="OBJECT" id="user" />
+ <sorting-element type="RESERVED_WORD" id="function" />
+ <sorting-element type="RESERVED_WORD" id="parameter" />
+ </sorting>
+ <format>
+ <enforce-code-style-case value="true" />
+ </format>
+ </code-completion-settings>
+ <execution-engine-settings>
+ <statement-execution>
+ <fetch-block-size value="100" />
+ <execution-timeout value="20" />
+ <debug-execution-timeout value="600" />
+ <focus-result value="false" />
+ <prompt-execution value="false" />
+ </statement-execution>
+ <script-execution>
+ <command-line-interfaces />
+ <execution-timeout value="300" />
+ </script-execution>
+ <method-execution>
+ <execution-timeout value="30" />
+ <debug-execution-timeout value="600" />
+ <parameter-history-size value="10" />
+ </method-execution>
+ </execution-engine-settings>
+ <operation-settings>
+ <transactions>
+ <uncommitted-changes>
+ <on-project-close value="ASK" />
+ <on-disconnect value="ASK" />
+ <on-autocommit-toggle value="ASK" />
+ </uncommitted-changes>
+ <multiple-uncommitted-changes>
+ <on-commit value="ASK" />
+ <on-rollback value="ASK" />
+ </multiple-uncommitted-changes>
+ </transactions>
+ <session-browser>
+ <disconnect-session value="ASK" />
+ <kill-session value="ASK" />
+ <reload-on-filter-change value="false" />
+ </session-browser>
+ <compiler>
+ <compile-type value="KEEP" />
+ <compile-dependencies value="ASK" />
+ <always-show-controls value="false" />
+ </compiler>
+ <debugger>
+ <debugger-type value="ASK" />
+ <use-generic-runners value="true" />
+ </debugger>
+ </operation-settings>
+ <ddl-file-settings>
+ <extensions>
+ <mapping file-type-id="VIEW" extensions="vw" />
+ <mapping file-type-id="TRIGGER" extensions="trg" />
+ <mapping file-type-id="PROCEDURE" extensions="prc" />
+ <mapping file-type-id="FUNCTION" extensions="fnc" />
+ <mapping file-type-id="PACKAGE" extensions="pkg" />
+ <mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
+ <mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
+ <mapping file-type-id="TYPE" extensions="tpe" />
+ <mapping file-type-id="TYPE_SPEC" extensions="tps" />
+ <mapping file-type-id="TYPE_BODY" extensions="tpb" />
+ </extensions>
+ <general>
+ <lookup-ddl-files value="true" />
+ <create-ddl-files value="false" />
+ <synchronize-ddl-files value="true" />
+ <use-qualified-names value="false" />
+ <make-scripts-rerunnable value="true" />
+ </general>
+ </ddl-file-settings>
+ <general-settings>
+ <regional-settings>
+ <date-format value="MEDIUM" />
+ <number-format value="UNGROUPED" />
+ <locale value="SYSTEM_DEFAULT" />
+ <use-custom-formats value="false" />
+ </regional-settings>
+ <environment>
+ <environment-types>
+ <environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
+ <environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
+ <environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
+ <environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
+ </environment-types>
+ <visibility-settings>
+ <connection-tabs value="true" />
+ <dialog-headers value="true" />
+ <object-editor-tabs value="true" />
+ <script-editor-tabs value="false" />
+ <execution-result-tabs value="true" />
+ </visibility-settings>
+ </environment>
+ </general-settings>
+ </component>
+</project>
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Encoding">
+ <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
+ <file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
+ </component>
+</project>
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..712ab9d
--- /dev/null
+++ b/.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="Central Repository" />
+ <option name="url" value="https://repo.maven.apache.org/maven2" />
+ </remote-repository>
+ <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="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>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..82dbec8
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ExternalStorageConfigurationManager" enabled="true" />
+ <component name="MavenProjectsManager">
+ <option name="originalFiles">
+ <list>
+ <option value="$PROJECT_DIR$/pom.xml" />
+ </list>
+ </option>
+ </component>
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/out" />
+ </component>
+</project>
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..2b63946
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+<?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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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>
+</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.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>
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..0d5980a
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="AutoImportSettings">
+ <option name="autoReloadType" value="SELECTIVE" />
+ </component>
+ <component name="ChangeListManager">
+ <list default="true" id="f008fe30-0711-42e2-bb33-17dcfdbad387" name="Changes" comment="" />
+ <option name="SHOW_DIALOG" value="false" />
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
+ <option name="LAST_RESOLUTION" value="IGNORE" />
+ </component>
+ <component name="FileTemplateManagerImpl">
+ <option name="RECENT_TEMPLATES">
+ <list>
+ <option value="Class" />
+ </list>
+ </option>
+ </component>
+ <component name="Git.Settings">
+ <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
+ </component>
+ <component name="MarkdownSettingsMigration">
+ <option name="stateVersion" value="1" />
+ </component>
+ <component name="MavenImportPreferences">
+ <option name="importingSettings">
+ <MavenImportingSettings>
+ <option name="workspaceImportEnabled" value="true" />
+ </MavenImportingSettings>
+ </option>
+ </component>
+ <component name="ProjectId" id="2vZNfNTEFyHApdxmHZ7Y0rlJjKB" />
+ <component name="ProjectLevelVcsManager" settingsEditedManually="true" />
+ <component name="ProjectViewState">
+ <option name="hideEmptyMiddlePackages" value="true" />
+ <option name="showLibraryContents" value="true" />
+ </component>
+ <component name="PropertiesComponent"><![CDATA[{
+ "keyToString": {
+ "RunOnceActivity.OpenProjectViewOnStart": "true",
+ "RunOnceActivity.ShowReadmeOnStart": "true"
+ }
+}]]></component>
+ <component name="RecentsManager">
+ <key name="MoveFile.RECENT_KEYS">
+ <recent name="D:\study\学习资源\大三下\school\echo-backend\src\main\resources\mapper" />
+ </key>
+ </component>
+ <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
+ <component name="TaskManager">
+ <task active="true" id="Default" summary="Default task">
+ <changelist id="f008fe30-0711-42e2-bb33-17dcfdbad387" name="Changes" comment="" />
+ <created>1744348740342</created>
+ <option name="number" value="Default" />
+ <option name="presentableId" value="Default" />
+ <updated>1744348740342</updated>
+ </task>
+ <servers />
+ </component>
+</project>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..db6ed19
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,234 @@
+<?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>groupId</groupId>
+ <artifactId>echo-backend</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <parent>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-parent</artifactId>
+ <version>2.6.0</version> <!-- 使用你希望的Spring Boot版本 -->
+ <relativePath/> <!-- lookup parent from repository -->
+ </parent>
+
+ <properties>
+ <maven.compiler.source>17</maven.compiler.source>
+ <maven.compiler.target>17</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <!--引入hutool-->
+ <!-- Add Apache Commons IO -->
+ <dependency>
+ <groupId>com.baomidou</groupId>
+ <artifactId>mybatis-plus-boot-starter</artifactId>
+ <version>3.5.3.1</version>
+ </dependency>
+
+
+ <!-- Add Guava -->
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>31.0.1-jre</version> <!-- Replace with the latest version -->
+ </dependency>
+ <dependency>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-swagger2</artifactId>
+ <version>3.0.0</version> <!-- Replace with the latest version -->
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-redis</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-swagger-ui</artifactId>
+ <version>3.0.0</version> <!-- Replace with the latest version -->
+ </dependency>
+
+ <dependency>
+ <groupId>cn.hutool</groupId>
+ <artifactId>hutool-all</artifactId>
+ <version>5.3.9</version>
+ </dependency>
+ <!-- Spring Boot Starter Web -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+ <!-- Spring Boot Starter Data JPA -->
+ <!-- MySQL Connector -->
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ </dependency>
+ <!-- Spring Boot Starter Security -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </dependency>
+ <!-- JAXB API -->
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ </dependency>
+ <!-- Spring Web MVC -->
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-webmvc</artifactId>
+ </dependency>
+ <!-- Spring AOP -->
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-aop</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-mail</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.12.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>fastjson</artifactId>
+ <version>1.2.39</version>
+ </dependency>
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <version>1.18.30</version> <!-- 确保使用的是最新版本 -->
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.30</version> <!-- 版本可以根据需要调整 -->
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.3</version> <!-- 版本可以根据需要调整 -->
+ </dependency>
+ <dependency>
+ <groupId>commons-fileupload</groupId>
+ <artifactId>commons-fileupload</artifactId>
+ <version>1.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-validation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.baidubce</groupId>
+ <artifactId>qianfan</artifactId>
+ <version>0.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-webflux</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.1</version>
+ <configuration>
+ <source>17</source>
+ <target>17</target>
+ <compilerArgs>
+ <arg>--add-opens</arg>
+ <arg>jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
+ </compilerArgs>
+ </configuration>
+
+ </plugin>
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <version>0.8.8</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>report</id>
+ <phase>test</phase>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.9</version>
+ <configuration>
+ <!--suppress UnresolvedMavenProperty -->
+ <argLine>${surefireArgLine}</argLine>
+ <skipTests>false</skipTests>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <version>2.12.2</version>
+ <configuration>
+ <showSuccess>false</showSuccess>
+ </configuration>
+
+ </plugin>
+
+ </plugins>
+ <resources>
+ <resource>
+ <directory>src/main/java</directory>
+ <includes>
+ <include>**/*.xml</include>
+ </includes>
+ </resource>
+ </resources>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/MyProjectApplication.java b/src/main/java/com/example/myproject/MyProjectApplication.java
new file mode 100644
index 0000000..49cd5f0
--- /dev/null
+++ b/src/main/java/com/example/myproject/MyProjectApplication.java
@@ -0,0 +1,14 @@
+
+package com.example.myproject;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.example.myproject.mapper") // 扫描 Mapper 接口
+public class MyProjectApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyProjectApplication.class, args);
+ }
+}
diff --git a/src/main/java/com/example/myproject/config/GlobalCorsConfig.java b/src/main/java/com/example/myproject/config/GlobalCorsConfig.java
new file mode 100644
index 0000000..909ead8
--- /dev/null
+++ b/src/main/java/com/example/myproject/config/GlobalCorsConfig.java
@@ -0,0 +1,32 @@
+package com.example.myproject.config;
+
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@EnableWebMvc
+@Configuration
+public class GlobalCorsConfig {
+ @Bean
+ public WebMvcConfigurer corsConfigurer() {
+ return new WebMvcConfigurer() {
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**") //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置
+ .allowedOriginPatterns("*") //开放哪些ip、端口、域名的访问权限 SpringBoot2.4.0以后allowedOrigins被allowedOriginPatterns代替
+ .allowCredentials(true) //是否允许发送Cookie信息
+ .allowedMethods("GET", "POST", "PUT", "DELETE") //开放哪些Http方法,允许跨域访问
+ .allowedHeaders("*") //允许HTTP请求中的携带哪些Header信息
+ .exposedHeaders("*"); //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
+ }
+ };
+ }
+
+
+
+
+}
diff --git a/src/main/java/com/example/myproject/config/SecurityConfig.java b/src/main/java/com/example/myproject/config/SecurityConfig.java
new file mode 100644
index 0000000..05cba5d
--- /dev/null
+++ b/src/main/java/com/example/myproject/config/SecurityConfig.java
@@ -0,0 +1,57 @@
+package com.example.myproject.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@EnableWebSecurity //注解开启Spring Security的功能
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Bean
+ public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
+ return authenticationConfiguration.getAuthenticationManager();
+ }
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();//passwordEncoder的实现类
+ }
+
+ //构造一个内存框架对象,获取数据库中的数据
+/* @Bean
+ public UserDetailsService myUserDetailsService(){
+ return new TestUserServerImpl();
+ }*/
+ //也可以自动注入
+
+ //用户授权
+
+
+ //用户权限认证
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .csrf().disable() // 禁用 CSRF 保护
+ .authorizeRequests()
+ .antMatchers("/swagger-ui.html", "/webjars/**", "/v2/**", "/swagger-resources/**","/**").permitAll() // 允许无条件访问
+ .anyRequest().authenticated(); // 其他所有路径都需要身份验证
+ }
+
+
+ /**
+ * 核心过滤器配置,更多使用ignoring()用来忽略对静态资源的控制
+ */
+ @Override
+ public void configure(WebSecurity web) throws Exception {
+ web
+ .ignoring()
+ .antMatchers("/image/**");
+ }
+}
diff --git a/src/main/java/com/example/myproject/controller/UserController.java b/src/main/java/com/example/myproject/controller/UserController.java
new file mode 100644
index 0000000..4bf6adf
--- /dev/null
+++ b/src/main/java/com/example/myproject/controller/UserController.java
@@ -0,0 +1,153 @@
+package com.example.myproject.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.example.myproject.mapper.UserMapper;
+import com.example.myproject.mapper.VerificationTokenMapper;
+import com.example.myproject.entity.User;
+import com.example.myproject.entity.VerificationToken;
+import com.example.myproject.service.EmailService;
+import com.example.myproject.service.UserService;
+import com.example.myproject.utils.Result;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+
+@RestController
+@RequestMapping("/user")
+@Api(value = "用户管理接口", tags = {"用户管理"})
+public class UserController {
+
+ @Resource
+ private UserService userService;
+
+ @Autowired
+ private AuthenticationManager authenticationManager;
+
+ @Autowired
+ private UserMapper userMapper; // 使用 MyBatis-Plus
+
+ @Autowired
+ private VerificationTokenMapper verificationTokenMapper; // 替换 JPA
+
+ private static final Logger logger = LoggerFactory.getLogger(UserController.class);
+
+ @PostMapping("/login")
+ @ApiOperation(value = "用户登录", notes = "使用用户名和密码进行登录")
+ public Result loginController(@RequestParam @ApiParam(value = "用户名", required = true) String username,
+ @RequestParam @ApiParam(value = "密码", required = true) String password) {
+ try {
+ Authentication authentication = authenticationManager.authenticate(
+ new UsernamePasswordAuthenticationToken(username, password)
+ );
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+
+ // 使用 MyBatis-Plus 查询
+ User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
+
+ System.out.println("Login successful for user: " + username);
+ return Result.success(user);
+ } catch (AuthenticationException e) {
+ return Result.error("401", "登录失败:" + e.getMessage());
+ }
+ }
+
+ @PostMapping("/register")
+ @ApiOperation(value = "用户注册", notes = "使用用户信息进行注册")
+ public Result registerController(@RequestBody @ApiParam(value = "新用户信息", required = true) User newUser) {
+ if (userService.checkEmailExists(newUser.getEmail())) {
+ return Result.error("邮箱冲突", "邮箱已被使用,请使用其他邮箱注册或找回密码!");
+ }
+ boolean success = userService.preRegisterUser(newUser);
+ if (success) {
+ User responseUser = new User();
+ responseUser.setEmail(newUser.getEmail());
+ return Result.success(responseUser, "验证邮件已发送,请检查您的邮箱。");
+ } else {
+ return Result.error("注册失败", "账号已存在或注册失败!");
+ }
+ }
+
+ public static class VerificationRequest {
+ private String email;
+ private String code;
+
+ public String getEmail() { return email; }
+ public void setEmail(String email) { this.email = email; }
+ public String getCode() { return code; }
+ public void setCode(String code) { this.code = code; }
+ }
+
+ @PostMapping("/verify-code")
+ @ApiOperation(value = "验证邮箱验证码", notes = "验证用户邮箱的验证码")
+ public Result verifyEmailCode(@RequestBody @ApiParam(value = "验证请求信息", required = true) VerificationRequest verificationRequest) {
+ String email = verificationRequest.getEmail();
+ String code = verificationRequest.getCode();
+ boolean isVerified = userService.verifyEmail(email, code);
+ if (isVerified) {
+ return Result.success(null, "邮箱验证成功!");
+ } else {
+ return Result.error("验证失败", "验证码错误或已过期!");
+ }
+ }
+
+ @Autowired
+ private EmailService emailService;
+
+ public static class EmailRequest {
+ private String email;
+ public String getEmail() { return email; }
+ public void setEmail(String email) { this.email = email; }
+ }
+
+ @PostMapping("/get-verification-email")
+ @ApiOperation(value = "发送验证邮件", notes = "通过电子邮件发送验证邮件")
+ public ResponseEntity<Result> sendVerificationEmail(@RequestBody @ApiParam(value = "发送验证请求", required = true) EmailRequest emailVerificationRequest) {
+ String email = emailVerificationRequest.getEmail();
+ User user = userMapper.selectOne(new QueryWrapper<User>().eq("email", email));
+ if (user == null) {
+ logger.error("未找到与该邮箱地址相关联的用户: {}", email);
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(Result.error("1","未找到与该邮箱地址相关联的用户"));
+ }
+
+ // 生成验证码
+ String token = RandomStringUtils.randomNumeric(6);
+ Instant expiryDate = Instant.now().plus(1, ChronoUnit.HOURS);
+ logger.info("生成的验证令牌: {}, 过期时间: {}", token, expiryDate);
+
+ VerificationToken verificationToken = new VerificationToken(token, user.getUsername(), email, user.getPassword(), expiryDate);
+
+ // 保存到 MyBatis-Plus 数据库
+ verificationTokenMapper.insert(verificationToken);
+
+ logger.info("验证令牌已保存,用户: {}", user.getUsername());
+ emailService.sendVerificationEmail(email, token);
+
+ return ResponseEntity.ok(Result.success(200, "验证邮件已发送!"));
+ }
+ @PostMapping("/checkPassword")
+ public Result<String> checkPassword(@RequestParam Long userId, @RequestParam String password) {
+ boolean isPasswordCorrect = userService.checkPassword(userId, password);
+ if (isPasswordCorrect) {
+ return Result.success("200","原始密码输入正确");
+ } else {
+ return Result.error("305","原始密码输入错误");
+ }
+ }
+}
diff --git a/src/main/java/com/example/myproject/entity/User.java b/src/main/java/com/example/myproject/entity/User.java
new file mode 100644
index 0000000..20f7138
--- /dev/null
+++ b/src/main/java/com/example/myproject/entity/User.java
@@ -0,0 +1,55 @@
+package com.example.myproject.entity;
+
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@TableName("user") // 指定数据库表名
+@ApiModel("用户实体类") // 用于描述模型
+public class User {
+
+ @TableId(type = IdType.AUTO) // 指定主键策略
+ @ApiModelProperty(value = "用户ID", example = "1")
+ private Long id;
+
+ @JsonProperty("username")
+ @ApiModelProperty(value = "用户名", example = "22301115")
+ private String username;
+
+ @JsonProperty("nickname")
+ @ApiModelProperty(value = "昵称", example = "cyl")
+ private String nickname;
+
+ @JsonProperty("role")
+ @ApiModelProperty(value = "角色", example = "Student")
+ private String role;
+
+ @JsonProperty("password")
+ @ApiModelProperty(value = "密码", example = "123")
+ private String password;
+
+ @JsonProperty("status")
+ @ApiModelProperty(value = "用户状态", example = "1")
+ private int status;
+
+ @JsonProperty("email")
+ @ApiModelProperty(value = "电子邮件地址", example = "john_doe@example.com")
+ private String email;
+
+ @JsonProperty("email_verified")
+ @ApiModelProperty(value = "邮箱验证状态", example = "true")
+ private boolean emailVerified;
+
+ @JsonProperty("avatar")
+ @ApiModelProperty(value = "头像")
+ private String avatar;
+
+ public User() {
+ }
+}
diff --git a/src/main/java/com/example/myproject/entity/UserDetails.java b/src/main/java/com/example/myproject/entity/UserDetails.java
new file mode 100644
index 0000000..9af35f0
--- /dev/null
+++ b/src/main/java/com/example/myproject/entity/UserDetails.java
@@ -0,0 +1,23 @@
+package com.example.myproject.entity;
+
+import org.springframework.security.core.GrantedAuthority;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+public interface UserDetails extends Serializable {
+ Collection<? extends GrantedAuthority> getAuthorities();
+
+ String getPassword();
+
+ String getUsername();
+
+ boolean isAccountNonExpired();
+
+ boolean isAccountNonLocked();
+
+ boolean isCredentialsNonExpired();
+
+ boolean isEnabled();
+}
+
diff --git a/src/main/java/com/example/myproject/entity/VerificationToken.java b/src/main/java/com/example/myproject/entity/VerificationToken.java
new file mode 100644
index 0000000..231fd95
--- /dev/null
+++ b/src/main/java/com/example/myproject/entity/VerificationToken.java
@@ -0,0 +1,58 @@
+package com.example.myproject.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+import java.time.Instant;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@TableName("verification_token")
+@ApiModel("验证令牌实体类")
+public class VerificationToken {
+
+ @TableId(type = IdType.AUTO)
+ @ApiModelProperty(value = "令牌ID")
+ private Long id;
+
+ @ApiModelProperty(value = "令牌字符串")
+ @TableField("token")
+ private String token;
+
+ @ApiModelProperty(value = "令牌过期日期")
+ @TableField("expiry_date")
+ private Instant expiryDate;
+
+ @ApiModelProperty(value = "用户名")
+ @TableField("username")
+ private String username;
+
+ @ApiModelProperty(value = "电子邮件地址")
+ @TableField("email")
+ private String email;
+
+ @ApiModelProperty(value = "加密后的密码")
+ @TableField("password")
+ private String password;
+
+ public VerificationToken(String token, String username, String email, String password, Instant expiryDate) {
+ this.token = token;
+ this.username = username;
+ this.email = email;
+ this.password = password;
+ this.expiryDate = expiryDate;
+ }
+
+ /**
+ * 检查令牌是否过期
+ * @return true 如果令牌已过期
+ */
+ public boolean isExpired() {
+ return expiryDate.isBefore(Instant.now());
+ }
+}
diff --git a/src/main/java/com/example/myproject/mapper/UserMapper.java b/src/main/java/com/example/myproject/mapper/UserMapper.java
new file mode 100644
index 0000000..a070bb5
--- /dev/null
+++ b/src/main/java/com/example/myproject/mapper/UserMapper.java
@@ -0,0 +1,25 @@
+package com.example.myproject.mapper;
+import com.example.myproject.entity.User;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+
+@Mapper
+public interface UserMapper extends BaseMapper<User> {
+
+
+ User selectByUsername(@Param("username") String username);
+
+ User selectByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
+
+ User selectByEmail(@Param("email") String email);
+
+
+ // 根据用户名包含查找用户
+ List<User> selectByUsernameContaining(@Param("name") String name);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/mapper/VerificationTokenMapper.java b/src/main/java/com/example/myproject/mapper/VerificationTokenMapper.java
new file mode 100644
index 0000000..94a25ca
--- /dev/null
+++ b/src/main/java/com/example/myproject/mapper/VerificationTokenMapper.java
@@ -0,0 +1,13 @@
+package com.example.myproject.mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.example.myproject.entity.VerificationToken;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+
+@Mapper
+public interface VerificationTokenMapper extends BaseMapper<VerificationToken> {
+
+ VerificationToken findByTokenAndEmail(String token, String email);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/service/EmailService.java b/src/main/java/com/example/myproject/service/EmailService.java
new file mode 100644
index 0000000..1ecc8c4
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/EmailService.java
@@ -0,0 +1,20 @@
+
+package com.example.myproject.service;
+public interface EmailService {
+ /**
+ * 发送邮件给指定的邮箱。
+ *
+ * @param to 收件人邮箱地址
+ * @param subject 邮件主题
+ * @param text 邮件内容
+ * @return 发送是否成功
+ */
+ boolean sendEmail(String to, String subject, String text);
+ /**
+ * 生成并发送验证邮件
+ *
+ * @param email 收件人邮箱
+ * @param token
+ */
+ void sendVerificationEmail(String email, String token);
+}
diff --git a/src/main/java/com/example/myproject/service/UserDetailsService.java b/src/main/java/com/example/myproject/service/UserDetailsService.java
new file mode 100644
index 0000000..85d4da2
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/UserDetailsService.java
@@ -0,0 +1,4 @@
+package com.example.myproject.service;
+
+public class UserDetailsService {
+}
diff --git a/src/main/java/com/example/myproject/service/UserService.java b/src/main/java/com/example/myproject/service/UserService.java
new file mode 100644
index 0000000..535f635
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/UserService.java
@@ -0,0 +1,24 @@
+package com.example.myproject.service;
+
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import com.example.myproject.entity.User;
+
+public interface UserService extends IService<User> {
+ User loginService(String username, String password);
+
+
+ boolean preRegisterUser(User user);
+
+
+ boolean verifyEmail(String email, String token);
+
+
+ boolean checkEmailExists(String email);
+
+ boolean checkPassword(Long userId, String rawPassword);
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/service/serviceImpl/EmailServiceImpl.java b/src/main/java/com/example/myproject/service/serviceImpl/EmailServiceImpl.java
new file mode 100644
index 0000000..83500ea
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/serviceImpl/EmailServiceImpl.java
@@ -0,0 +1,51 @@
+
+package com.example.myproject.service.serviceImpl;
+import com.example.myproject.mapper.VerificationTokenMapper;
+import com.example.myproject.entity.VerificationToken;
+import com.example.myproject.service.EmailService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.stereotype.Service;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import java.time.Instant;
+@Service
+public class EmailServiceImpl implements EmailService {
+ private static final Logger log = LoggerFactory.getLogger(EmailServiceImpl.class);
+ @Autowired
+ private JavaMailSender mailSender;
+ @Autowired
+ private VerificationTokenMapper verificationTokenMapper;
+ @Value("${spring.mail.username}") // 从配置文件中注入发件人邮箱地址
+ private String fromEmail;
+ @Override
+ public boolean sendEmail(String to, String subject, String text) {
+ log.debug("开始发送验证邮件到:{},主题:{}", to, subject);
+ try {
+ MimeMessage message = mailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(message, true);
+ helper.setFrom(fromEmail);
+ helper.setTo(to);
+ helper.setSubject(subject);
+ helper.setText(text, true);
+ mailSender.send(message);
+ log.info("邮件成功发送到:{}", to);
+ return true;
+ } catch (MessagingException e) {
+ log.error("发送邮件失败,收件人:{},错误信息:{}", to, e.getMessage(), e);
+ return false;
+ }
+ }
+ @Override
+ public void sendVerificationEmail(String email, String token){
+ // 发送邮件
+ String message = "<h1>Email Verification</h1>" +
+ "<p>Your verification code is: <b>" + token + "</b></p>" +
+ "<p>This code will expire in 1 hour.</p>";
+ sendEmail(email, "Verify Your Email", message);
+ }
+}
diff --git a/src/main/java/com/example/myproject/service/serviceImpl/UserDetailsServiceImpl.java b/src/main/java/com/example/myproject/service/serviceImpl/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..4bbd5c3
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/serviceImpl/UserDetailsServiceImpl.java
@@ -0,0 +1,47 @@
+package com.example.myproject.service.serviceImpl;
+
+import com.example.myproject.mapper.UserMapper;
+import com.example.myproject.entity.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService {
+
+ @Autowired
+ private UserMapper userMapper;
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ //username参数,是在登陆时,用户传递的表单数据username
+ //主要读取数据库3个值 username password authorities
+ User user= userMapper.selectByUsername(username);
+ if (user == null) {
+ throw new UsernameNotFoundException("用户名未找到");
+ }
+
+ String authorityName = user.getRole();
+ //为了返回一个UserDetails 使用User
+ List<GrantedAuthority> authorities = new ArrayList<>();
+ GrantedAuthority authority = new SimpleGrantedAuthority(authorityName);
+ authorities.add(authority);
+ return new org.springframework.security.core.userdetails.User(
+ user.getUsername(),
+ user.getPassword(),
+ true, // accountEnabled
+ true, // accountNonExpired
+ true, // credentialsNonExpired
+ true, // accountNonLocked
+ AuthorityUtils.createAuthorityList("ROLE_USER") // 设置用户的角色或权限
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/service/serviceImpl/UserServiceImpl.java b/src/main/java/com/example/myproject/service/serviceImpl/UserServiceImpl.java
new file mode 100644
index 0000000..d0718fe
--- /dev/null
+++ b/src/main/java/com/example/myproject/service/serviceImpl/UserServiceImpl.java
@@ -0,0 +1,122 @@
+
+package com.example.myproject.service.serviceImpl;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.myproject.mapper.UserMapper;
+import com.example.myproject.mapper.VerificationTokenMapper;
+import com.example.myproject.entity.User;
+import com.example.myproject.entity.VerificationToken;
+import com.example.myproject.service.EmailService;
+import com.example.myproject.service.UserService;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+//登录注册
+@Service
+public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
+ private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
+ @Autowired
+ private UserMapper userMapper; // Using MyBatis-Plus mapper
+ @Autowired
+ private EmailServiceImpl emailService;
+ @Autowired
+ private VerificationTokenMapper verificationTokenMapper; // Using MyBatis-Plus mapper
+ @Autowired
+ private PasswordEncoder passwordEncoder; // Injecting password encoder
+ @Override
+ public User loginService(String username, String password) {
+ log.debug("Attempting login with username: {}, password: {}", username, password);
+ User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username).eq("password", password));
+ if (user != null) {
+ user.setPassword(""); // Clear the password before returning
+ log.debug("Login successful, User ID: {}", user.getId());
+ } else {
+ log.debug("Login failed, incorrect username or password.");
+ }
+ return user;
+ }
+ @Override
+ public boolean preRegisterUser(User user) {
+ log.debug("Pre-registering user, username: {}, email: {}", user.getUsername(), user.getEmail());
+ // 检查用户名或邮箱是否已存在
+ boolean userExists = userMapper.selectOne(new QueryWrapper<User>().eq("username", user.getUsername())) != null ||
+ userMapper.selectOne(new QueryWrapper<User>().eq("email", user.getEmail())) != null;
+ if (userExists) {
+ log.debug("Pre-registration failed, username or email already exists.");
+ return false; // 用户名或邮箱已经存在
+ }
+ // 加密密码
+ String encryptedPassword = passwordEncoder.encode(user.getPassword());
+ // 生成验证码
+ String token = RandomStringUtils.randomNumeric(6);
+ // 设置过期时间为当前时间加一小时
+ Instant expiryDate = Instant.now().plus(1, ChronoUnit.HOURS);
+ // 创建验证令牌对象
+ VerificationToken verificationToken = new VerificationToken(
+ token,
+ user.getUsername(),
+ user.getEmail(),
+ encryptedPassword,
+ expiryDate
+ );
+ // 插入验证令牌
+ int rowsInserted = verificationTokenMapper.insert(verificationToken);
+ if (rowsInserted > 0) {
+ // 发送验证邮件
+ emailService.sendVerificationEmail(user.getEmail(), token);
+ log.debug("Pre-registration successful, verification code: {}, expiry date: {}", token, expiryDate);
+ return true; // 注册前验证成功
+ } else {
+ log.error("Failed to insert verification token into database.");
+ return false; // 如果插入验证令牌失败,返回失败
+ }
+ }
+ @Override
+ public boolean verifyEmail(String email, String token) {
+ log.debug("Verifying email, email: {}, token: {}", email, token);
+ VerificationToken verificationToken = verificationTokenMapper.selectOne(
+ new QueryWrapper<VerificationToken>().eq("token", token).eq("email", email)
+ );
+ if (verificationToken != null && !verificationToken.isExpired()) {
+ log.debug("Verification code is valid, username: {}", verificationToken.getUsername());
+ User user = userMapper.selectOne(new QueryWrapper<User>().eq("email", email));
+ if (user == null) {
+ user = new User();
+ user.setEmail(email);
+ user.setUsername(verificationToken.getUsername());
+ user.setPassword(verificationToken.getPassword());
+ user.setEmailVerified(true);
+ userMapper.insert(user); // Save new user
+ log.debug("New user created, User ID: {}", user.getId());
+ } else {
+ user.setEmailVerified(true);
+ userMapper.updateById(user); // Update existing user
+ log.debug("User email verified, User ID: {}", user.getId());
+ }
+ verificationTokenMapper.delete(new QueryWrapper<VerificationToken>().eq("token", token)); // Clean up the token
+ log.debug("Verification code deleted.");
+ return true;
+ }
+ log.debug("Verification code is invalid or expired.");
+ return false;
+ }
+ public boolean checkEmailExists(String email) {
+ log.debug("检查邮箱是否存在,邮箱:{}", email);
+ boolean exists = userMapper.selectCount(new QueryWrapper<User>().eq("email", email)) > 0;
+ log.debug("邮箱存在状态:{}", exists);
+ return exists;
+ }
+ public boolean checkPassword(Long userId, String password) {
+ User user = userMapper.selectById(userId);
+ if (user == null) {
+ throw new RuntimeException("用户不存在");
+ }
+ String encryptedPassword = user.getPassword();
+ return passwordEncoder.matches(password, encryptedPassword);
+ }
+}
diff --git a/src/main/java/com/example/myproject/utils/Result.java b/src/main/java/com/example/myproject/utils/Result.java
new file mode 100644
index 0000000..e838a1c
--- /dev/null
+++ b/src/main/java/com/example/myproject/utils/Result.java
@@ -0,0 +1,129 @@
+package com.example.myproject.utils;
+
+
+public class Result<T> {
+ private String code;
+ private String msg;
+ private T data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public T getData() {
+ return data;
+ }
+
+ public void setData(T data) {
+ this.data = data;
+ }
+
+ public Result() {
+ }
+
+ public Result(T data) {
+ this.data = data;
+ }
+
+ public static Result success() {
+ Result result = new Result<>();
+ result.setCode("200");
+ result.setMsg("成功");
+ return result;
+ }
+
+ public static <T> Result<T> success(T data) {
+ Result<T> result = new Result<>(data);
+ result.setCode("200");
+ result.setMsg("成功");
+ return result;
+ }
+ public static <T> Result<T> success(String msg) {
+ Result result = new Result();
+ result.setCode("200");
+ result.setMsg("成功");
+ return result;
+ }
+
+ public static <T> Result<T> success(T data,String msg) {
+ Result<T> result = new Result<>(data);
+ result.setCode("200");
+ result.setMsg(msg);
+ return result;
+ }
+
+ public static Result error(String code, String msg) {
+ Result result = new Result();
+ result.setCode(code);
+ result.setMsg(msg);
+ return result;
+ }
+ /**
+ * 创建一个表示文件大小超出限制的结果对象。
+ *
+ * @return 构造的文件过大错误结果对象
+ */
+ public static Result fileTooLarge() {
+ Result result = new Result();
+ result.setCode("413");
+ result.setMsg("文件大小超出限制。");
+ return result;
+ }
+
+ /**
+ * 创建一个表示文件格式不支持的结果对象。
+ *
+ * @return 构造的文件格式错误结果对象
+ */
+ public static Result unsupportedFileType() {
+ Result result = new Result();
+ result.setCode("415");
+ result.setMsg("不支持的文件格式。");
+ return result;
+ }
+
+ /**
+ * 创建一个表示文件未找到的结果对象。
+ *
+ * @return 构造的文件未找到错误结果对象
+ */
+ public static Result fileNotFound() {
+ Result result = new Result();
+ result.setCode("404");
+ result.setMsg("文件未找到。");
+ return result;
+ }
+
+ /**
+ * 创建一个表示文件存储错误的结果对象。
+ *
+ * @param errorMsg 详细错误信息
+ * @return 构造的文件存储错误结果对象
+ */
+ public static Result fileStorageError(String errorMsg) {
+ Result result = new Result();
+ result.setCode("500");
+ result.setMsg("文件存储错误: " + errorMsg);
+ return result;
+ }
+
+ public static Result permissionDenied() {
+ Result result = new Result();
+ result.setCode("401");
+ result.setMsg("权限不足,无法执行该操作。");
+ return result;
+ }
+
+}
diff --git a/src/main/java/com/example/myproject/utils/VerifyCode.java b/src/main/java/com/example/myproject/utils/VerifyCode.java
new file mode 100644
index 0000000..689b8ce
--- /dev/null
+++ b/src/main/java/com/example/myproject/utils/VerifyCode.java
@@ -0,0 +1,156 @@
+package com.example.myproject.utils;
+
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Random;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Random;
+
+/*
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Random;
+
+/**
+ * @author 阿楠
+ * code生成工具类
+ */
+public class VerifyCode {
+ /**
+ * 生成验证码图片的宽度
+ */
+ private int width = 100;
+
+ /**
+ * 生成验证码图片的高度
+ */
+ private int height = 30;
+
+ /**
+ * 字符样式
+ */
+ private String[] fontNames = { "宋体", "楷体", "隶书", "微软雅黑" };
+
+ /**
+ * 定义验证码图片的背景颜色为白色
+ */
+ private Color bgColor = new Color(255, 255, 255);
+
+ /**
+ * 生成随机
+ */
+ private Random random = new Random();
+
+ /**
+ * 定义code字符
+ */
+ private String codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ /**
+ * 记录随机字符串
+ */
+ private String text;
+
+ /**
+ * 获取一个随意颜色
+ * @return
+ */
+ private Color randomColor() {
+ int red = random.nextInt(150);
+ int green = random.nextInt(150);
+ int blue = random.nextInt(150);
+ return new Color(red, green, blue);
+ }
+
+ /**
+ * 获取一个随机字体
+ *
+ * @return
+ */
+ private Font randomFont() {
+ String name = fontNames[random.nextInt(fontNames.length)];
+ int style = random.nextInt(4);
+ int size = random.nextInt(5) + 24;
+ return new Font(name, style, size);
+ }
+
+ /**
+ * 获取一个随机字符
+ *
+ * @return
+ */
+ private char randomChar() {
+ return codes.charAt(random.nextInt(codes.length()));
+ }
+
+ /**
+ * 创建一个空白的BufferedImage对象
+ *
+ * @return
+ */
+ private BufferedImage createImage() {
+ BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+ Graphics2D g2 = (Graphics2D) image.getGraphics();
+ //设置验证码图片的背景颜色
+ g2.setColor(bgColor);
+ g2.fillRect(0, 0, width, height);
+ return image;
+ }
+
+ public BufferedImage getImage() {
+ BufferedImage image = createImage();
+ Graphics2D g2 = (Graphics2D) image.getGraphics();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < 4; i++) {
+ String s = randomChar() + "";
+ sb.append(s);
+ g2.setColor(randomColor());
+ g2.setFont(randomFont());
+ float x = i * width * 1.0f / 4;
+ g2.drawString(s, x, height - 8);
+ }
+ this.text = sb.toString();
+ drawLine(image);
+ return image;
+ }
+
+ /**
+ * 绘制干扰线
+ *
+ * @param image
+ */
+ private void drawLine(BufferedImage image) {
+ Graphics2D g2 = (Graphics2D) image.getGraphics();
+ int num = 5;
+ for (int i = 0; i < num; i++) {
+ int x1 = random.nextInt(width);
+ int y1 = random.nextInt(height);
+ int x2 = random.nextInt(width);
+ int y2 = random.nextInt(height);
+ g2.setColor(randomColor());
+ g2.setStroke(new BasicStroke(1.5f));
+ g2.drawLine(x1, y1, x2, y2);
+ }
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public static void output(BufferedImage image, OutputStream out) throws IOException {
+ ImageIO.write(image, "JPEG", out);
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..b753da7
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,21 @@
+server.port=8080
+spring.datasource.url=jdbc:mysql://localhost:3306/pt
+spring.datasource.username=root
+spring.datasource.password=root
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+
+mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
+
+
+# Mail configuration
+spring.mail.password=tljnebonhzhqecda
+spring.mail.username=2370523716@qq.com
+spring.mail.host=smtp.qq.com
+spring.mail.properties.mail.smtp.ssl.enable=true
+spring.mail.properties.mail.smtp.auth=true
+spring.mail.properties.mail.smtp.starttls.enable=true
+
+
+spring.jpa.enabled=false
+spring.jpa.hibernate.ddl-auto=none
+spring.jpa.open-in-view=false
diff --git a/src/main/resources/mapper/UserMapper.xml b/src/main/resources/mapper/UserMapper.xml
new file mode 100644
index 0000000..f03ab0a
--- /dev/null
+++ b/src/main/resources/mapper/UserMapper.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.example.myproject.mapper.UserMapper">
+ <!-- 根据用户名查找用户 -->
+ <select id="selectByUsername" parameterType="string" resultType="com.example.myproject.entity.User">
+ SELECT * FROM user WHERE username = #{username}
+ </select>
+ <!-- 根据用户名和密码查找用户 -->
+ <select id="selectByUsernameAndPassword" parameterType="map" resultType="com.example.myproject.entity.User">
+ SELECT * FROM user WHERE username = #{username} AND password = #{password}
+ </select>
+ <!-- 根据邮箱查找用户 -->
+ <select id="selectByEmail" parameterType="string" resultType="com.example.myproject.entity.User">
+ SELECT * FROM user WHERE email = #{email}
+ </select>
+ <!-- 根据用户名包含查找用户 -->
+ <select id="selectByUsernameContaining" parameterType="string" resultType="com.example.myproject.entity.User">
+ SELECT * FROM user WHERE username LIKE CONCAT('%', #{name}, '%')
+ </select>
+</mapper>
diff --git a/src/main/resources/mapper/VerificationTokenMapper.xml b/src/main/resources/mapper/VerificationTokenMapper.xml
new file mode 100644
index 0000000..53b19a5
--- /dev/null
+++ b/src/main/resources/mapper/VerificationTokenMapper.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.example.myproject.mapper.VerificationTokenMapper">
+ <!-- 通过 token 和 email 查询 VerificationToken -->
+ <select id="findByTokenAndEmail" resultType="com.example.myproject.entity.VerificationToken">
+ SELECT * FROM verification_token
+ WHERE token = #{token} AND email = #{email}
+ </select>
+</mapper>
diff --git a/src/test/java/com/example/myproject/controller/UserControllerTest.java b/src/test/java/com/example/myproject/controller/UserControllerTest.java
new file mode 100644
index 0000000..8a09e53
--- /dev/null
+++ b/src/test/java/com/example/myproject/controller/UserControllerTest.java
@@ -0,0 +1,163 @@
+package com.example.myproject.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.example.myproject.entity.User;
+import com.example.myproject.service.EmailService;
+import com.example.myproject.service.UserService;
+import com.example.myproject.mapper.UserMapper;
+import com.example.myproject.mapper.VerificationTokenMapper;
+import com.example.myproject.utils.Result;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.*;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+class UserControllerTest {
+
+ @InjectMocks
+ private UserController userController;
+
+ @Mock
+ private UserService userService;
+ @Mock
+ private UserMapper userMapper;
+ @Mock
+ private EmailService emailService;
+ @Mock
+ private AuthenticationManager authenticationManager;
+ @Mock
+ private VerificationTokenMapper verificationTokenMapper;
+
+ @BeforeEach
+ void setup() {
+ MockitoAnnotations.openMocks(this);
+ }
+
+ @Test
+ void loginController_success() {
+ String username = "testuser";
+ String password = "testpass";
+ User mockUser = new User();
+ mockUser.setUsername(username);
+
+ Authentication mockAuth = mock(Authentication.class);
+ when(authenticationManager.authenticate(any())).thenReturn(mockAuth);
+ when(userMapper.selectOne(any(QueryWrapper.class))).thenReturn(mockUser);
+
+ Result result = userController.loginController(username, password);
+
+ assertEquals("200", result.getCode());
+ assertEquals(mockUser, result.getData());
+ }
+
+
+ @Test
+ void loginController_failure() {
+ String username = "user";
+ String password = "wrongpass";
+
+ // 模拟认证失败,抛出 Bad credentials 异常
+ when(authenticationManager.authenticate(any()))
+ .thenThrow(new AuthenticationException("Bad credentials") {});
+
+
+ // 调用登录接口
+ Result result = userController.loginController(username, password);
+
+ // 断言返回的状态码和消息
+ assertEquals("401", result.getCode());
+ assertTrue(result.getMsg().contains("登录失败"));
+ }
+
+ @Test
+ void registerController_emailExists() {
+ User user = new User();
+ user.setEmail("test@example.com");
+
+ when(userService.checkEmailExists(user.getEmail())).thenReturn(true);
+
+ Result result = userController.registerController(user);
+
+ assertEquals("邮箱冲突", result.getCode());
+ }
+
+ @Test
+ void registerController_success() {
+ User user = new User();
+ user.setEmail("test@example.com");
+
+ when(userService.checkEmailExists(user.getEmail())).thenReturn(false);
+ when(userService.preRegisterUser(user)).thenReturn(true);
+
+ Result result = userController.registerController(user);
+
+ assertEquals("200", result.getCode());
+ assertEquals(user.getEmail(), ((User) result.getData()).getEmail());
+ }
+
+ @Test
+ void verifyEmailCode_success() {
+ when(userService.verifyEmail("test@example.com", "123456")).thenReturn(true);
+
+ UserController.VerificationRequest request = new UserController.VerificationRequest();
+ request.setEmail("test@example.com");
+ request.setCode("123456");
+
+ Result result = userController.verifyEmailCode(request);
+
+ assertEquals("200", result.getCode());
+ }
+
+ @Test
+ void verifyEmailCode_failure() {
+ when(userService.verifyEmail("test@example.com", "000000")).thenReturn(false);
+
+ UserController.VerificationRequest request = new UserController.VerificationRequest();
+ request.setEmail("test@example.com");
+ request.setCode("000000");
+
+ Result result = userController.verifyEmailCode(request);
+
+ assertEquals("验证失败", result.getCode());
+ }
+
+ @Test
+ void checkPassword_success() {
+ when(userService.checkPassword(1L, "abc123")).thenReturn(true);
+
+ Result<String> result = userController.checkPassword(1L, "abc123");
+
+ assertEquals("200", result.getCode());
+ assertEquals("原始密码输入正确", result.getMsg());
+ }
+
+ @Test
+ void checkPassword_failure() {
+ when(userService.checkPassword(1L, "wrong")).thenReturn(false);
+
+ Result<String> result = userController.checkPassword(1L, "wrong");
+
+ assertEquals("305", result.getCode());
+ assertEquals("原始密码输入错误", result.getMsg());
+ }
+
+ @Test
+ void sendVerificationEmail_userNotFound() {
+ UserController.EmailRequest request = new UserController.EmailRequest();
+ request.setEmail("notfound@example.com");
+
+ when(userMapper.selectOne(any())).thenReturn(null);
+
+ ResponseEntity<Result> response = userController.sendVerificationEmail(request);
+
+ assertEquals(400, response.getStatusCodeValue());
+ assertEquals("1", response.getBody().getCode());
+ }
+}
diff --git a/target/classes/application.properties b/target/classes/application.properties
new file mode 100644
index 0000000..b753da7
--- /dev/null
+++ b/target/classes/application.properties
@@ -0,0 +1,21 @@
+server.port=8080
+spring.datasource.url=jdbc:mysql://localhost:3306/pt
+spring.datasource.username=root
+spring.datasource.password=root
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+
+mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
+
+
+# Mail configuration
+spring.mail.password=tljnebonhzhqecda
+spring.mail.username=2370523716@qq.com
+spring.mail.host=smtp.qq.com
+spring.mail.properties.mail.smtp.ssl.enable=true
+spring.mail.properties.mail.smtp.auth=true
+spring.mail.properties.mail.smtp.starttls.enable=true
+
+
+spring.jpa.enabled=false
+spring.jpa.hibernate.ddl-auto=none
+spring.jpa.open-in-view=false
diff --git a/target/classes/com/example/myproject/MyProjectApplication.class b/target/classes/com/example/myproject/MyProjectApplication.class
new file mode 100644
index 0000000..1ebd349
--- /dev/null
+++ b/target/classes/com/example/myproject/MyProjectApplication.class
Binary files differ
diff --git a/target/classes/com/example/myproject/config/GlobalCorsConfig$1.class b/target/classes/com/example/myproject/config/GlobalCorsConfig$1.class
new file mode 100644
index 0000000..a7271e1
--- /dev/null
+++ b/target/classes/com/example/myproject/config/GlobalCorsConfig$1.class
Binary files differ
diff --git a/target/classes/com/example/myproject/config/GlobalCorsConfig.class b/target/classes/com/example/myproject/config/GlobalCorsConfig.class
new file mode 100644
index 0000000..def5cdd
--- /dev/null
+++ b/target/classes/com/example/myproject/config/GlobalCorsConfig.class
Binary files differ
diff --git a/target/classes/com/example/myproject/config/SecurityConfig.class b/target/classes/com/example/myproject/config/SecurityConfig.class
new file mode 100644
index 0000000..dbd3c39
--- /dev/null
+++ b/target/classes/com/example/myproject/config/SecurityConfig.class
Binary files differ
diff --git a/target/classes/com/example/myproject/controller/UserController$EmailRequest.class b/target/classes/com/example/myproject/controller/UserController$EmailRequest.class
new file mode 100644
index 0000000..d12dede
--- /dev/null
+++ b/target/classes/com/example/myproject/controller/UserController$EmailRequest.class
Binary files differ
diff --git a/target/classes/com/example/myproject/controller/UserController$VerificationRequest.class b/target/classes/com/example/myproject/controller/UserController$VerificationRequest.class
new file mode 100644
index 0000000..aa1371e
--- /dev/null
+++ b/target/classes/com/example/myproject/controller/UserController$VerificationRequest.class
Binary files differ
diff --git a/target/classes/com/example/myproject/controller/UserController.class b/target/classes/com/example/myproject/controller/UserController.class
new file mode 100644
index 0000000..d1d685c
--- /dev/null
+++ b/target/classes/com/example/myproject/controller/UserController.class
Binary files differ
diff --git a/target/classes/com/example/myproject/entity/User.class b/target/classes/com/example/myproject/entity/User.class
new file mode 100644
index 0000000..62eb5a1
--- /dev/null
+++ b/target/classes/com/example/myproject/entity/User.class
Binary files differ
diff --git a/target/classes/com/example/myproject/entity/UserDetails.class b/target/classes/com/example/myproject/entity/UserDetails.class
new file mode 100644
index 0000000..64a006a
--- /dev/null
+++ b/target/classes/com/example/myproject/entity/UserDetails.class
Binary files differ
diff --git a/target/classes/com/example/myproject/entity/VerificationToken.class b/target/classes/com/example/myproject/entity/VerificationToken.class
new file mode 100644
index 0000000..4b1d318
--- /dev/null
+++ b/target/classes/com/example/myproject/entity/VerificationToken.class
Binary files differ
diff --git a/target/classes/com/example/myproject/mapper/UserMapper.class b/target/classes/com/example/myproject/mapper/UserMapper.class
new file mode 100644
index 0000000..7b80316
--- /dev/null
+++ b/target/classes/com/example/myproject/mapper/UserMapper.class
Binary files differ
diff --git a/target/classes/com/example/myproject/mapper/VerificationTokenMapper.class b/target/classes/com/example/myproject/mapper/VerificationTokenMapper.class
new file mode 100644
index 0000000..24f82a3
--- /dev/null
+++ b/target/classes/com/example/myproject/mapper/VerificationTokenMapper.class
Binary files differ
diff --git a/target/classes/com/example/myproject/service/EmailService.class b/target/classes/com/example/myproject/service/EmailService.class
new file mode 100644
index 0000000..4d119e6
--- /dev/null
+++ b/target/classes/com/example/myproject/service/EmailService.class
Binary files differ
diff --git a/target/classes/com/example/myproject/service/UserDetailsService.class b/target/classes/com/example/myproject/service/UserDetailsService.class
new file mode 100644
index 0000000..bdaa423
--- /dev/null
+++ b/target/classes/com/example/myproject/service/UserDetailsService.class
Binary files differ
diff --git a/target/classes/com/example/myproject/service/UserService.class b/target/classes/com/example/myproject/service/UserService.class
new file mode 100644
index 0000000..242bb1c
--- /dev/null
+++ b/target/classes/com/example/myproject/service/UserService.class
Binary files differ
diff --git a/target/classes/com/example/myproject/service/serviceImpl/EmailServiceImpl.class b/target/classes/com/example/myproject/service/serviceImpl/EmailServiceImpl.class
new file mode 100644
index 0000000..17b5343
--- /dev/null
+++ b/target/classes/com/example/myproject/service/serviceImpl/EmailServiceImpl.class
Binary files differ
diff --git a/target/classes/com/example/myproject/service/serviceImpl/UserDetailsServiceImpl.class b/target/classes/com/example/myproject/service/serviceImpl/UserDetailsServiceImpl.class
new file mode 100644
index 0000000..57470ed
--- /dev/null
+++ b/target/classes/com/example/myproject/service/serviceImpl/UserDetailsServiceImpl.class
Binary files differ
diff --git a/target/classes/com/example/myproject/service/serviceImpl/UserServiceImpl.class b/target/classes/com/example/myproject/service/serviceImpl/UserServiceImpl.class
new file mode 100644
index 0000000..cd97158
--- /dev/null
+++ b/target/classes/com/example/myproject/service/serviceImpl/UserServiceImpl.class
Binary files differ
diff --git a/target/classes/com/example/myproject/utils/Result.class b/target/classes/com/example/myproject/utils/Result.class
new file mode 100644
index 0000000..0a8e59e
--- /dev/null
+++ b/target/classes/com/example/myproject/utils/Result.class
Binary files differ
diff --git a/target/classes/com/example/myproject/utils/VerifyCode.class b/target/classes/com/example/myproject/utils/VerifyCode.class
new file mode 100644
index 0000000..991e277
--- /dev/null
+++ b/target/classes/com/example/myproject/utils/VerifyCode.class
Binary files differ