AgileBoot V1.0 发布 基于Ruoyi改造 基本都已重构
This commit is contained in:
parent
e3349d3575
commit
41cf60b3d8
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
custom: http://doc.ruoyi.vip/ruoyi-vue/other/donate.html
|
||||
48
.gitignore
vendored
Normal file
48
.gitignore
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
######################################################################
|
||||
# Build Tools
|
||||
|
||||
.gradle
|
||||
/build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
######################################################################
|
||||
# IDE
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### JRebel ###
|
||||
rebel.xml
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/*
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
.nb-gradle/
|
||||
|
||||
######################################################################
|
||||
# Others
|
||||
*.log
|
||||
*.xml.versionsBackup
|
||||
*.swp
|
||||
|
||||
!*/build/*.java
|
||||
!*/build/*.html
|
||||
!*/build/*.xml
|
||||
/agileboot-admin/src/main/resources/application-dev.yml
|
||||
567
GoogleStyle.xml
Normal file
567
GoogleStyle.xml
Normal file
@ -0,0 +1,567 @@
|
||||
<code_scheme name="GoogleStyle" version="173">
|
||||
<option name="OTHER_INDENT_OPTIONS">
|
||||
<value>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="RIGHT_MARGIN" value="100" />
|
||||
<AndroidXmlCodeStyleSettings>
|
||||
<option name="USE_CUSTOM_SETTINGS" value="true" />
|
||||
<option name="LAYOUT_SETTINGS">
|
||||
<value>
|
||||
<option name="INSERT_BLANK_LINE_BEFORE_TAG" value="false" />
|
||||
</value>
|
||||
</option>
|
||||
</AndroidXmlCodeStyleSettings>
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="INDENT_CHAINED_CALLS" value="false" />
|
||||
</JSCodeStyleSettings>
|
||||
<JavaCodeStyleSettings>
|
||||
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
|
||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
|
||||
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
|
||||
<value />
|
||||
</option>
|
||||
<option name="IMPORT_LAYOUT_TABLE">
|
||||
<value>
|
||||
<package name="" withSubpackages="true" static="true" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="false" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
|
||||
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
|
||||
<option name="JD_P_AT_EMPTY_LINES" value="false" />
|
||||
<option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
|
||||
<option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
|
||||
<option name="JD_KEEP_EMPTY_RETURN" value="false" />
|
||||
</JavaCodeStyleSettings>
|
||||
<Objective-C>
|
||||
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
|
||||
<option name="INDENT_C_STRUCT_MEMBERS" value="2" />
|
||||
<option name="INDENT_CLASS_MEMBERS" value="2" />
|
||||
<option name="INDENT_VISIBILITY_KEYWORDS" value="1" />
|
||||
<option name="INDENT_INSIDE_CODE_BLOCK" value="2" />
|
||||
<option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" />
|
||||
<option name="FUNCTION_PARAMETERS_WRAP" value="5" />
|
||||
<option name="FUNCTION_CALL_ARGUMENTS_WRAP" value="5" />
|
||||
<option name="TEMPLATE_CALL_ARGUMENTS_WRAP" value="5" />
|
||||
<option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE" value="true" />
|
||||
<option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" />
|
||||
<option name="SPACE_BEFORE_SUPERCLASS_COLON" value="false" />
|
||||
</Objective-C>
|
||||
<Objective-C-extensions>
|
||||
<option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
|
||||
<option name="RELEASE_STYLE" value="IVAR" />
|
||||
<option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
|
||||
<file>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
||||
</file>
|
||||
<class>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
||||
</class>
|
||||
<extensions>
|
||||
<pair source="cc" header="h" />
|
||||
<pair source="c" header="h" />
|
||||
</extensions>
|
||||
</Objective-C-extensions>
|
||||
<Python>
|
||||
<option name="USE_CONTINUATION_INDENT_FOR_ARGUMENTS" value="true" />
|
||||
</Python>
|
||||
<TypeScriptCodeStyleSettings version="0">
|
||||
<option name="INDENT_CHAINED_CALLS" value="false" />
|
||||
</TypeScriptCodeStyleSettings>
|
||||
<XML>
|
||||
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
|
||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
||||
</XML>
|
||||
<codeStyleSettings language="CSS">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="ECMA Script Level 4">
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="ALIGN_MULTILINE_FOR" value="false" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||
<option name="EXTENDS_LIST_WRAP" value="1" />
|
||||
<option name="BINARY_OPERATION_WRAP" value="1" />
|
||||
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
|
||||
<option name="TERNARY_OPERATION_WRAP" value="1" />
|
||||
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
|
||||
<option name="FOR_STATEMENT_WRAP" value="1" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="HTML">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="RIGHT_MARGIN" value="120" />
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="ALIGN_MULTILINE_RESOURCES" value="false" />
|
||||
<option name="ALIGN_MULTILINE_FOR" value="false" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||
<option name="EXTENDS_LIST_WRAP" value="1" />
|
||||
<option name="THROWS_KEYWORD_WRAP" value="1" />
|
||||
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
||||
<option name="BINARY_OPERATION_WRAP" value="1" />
|
||||
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
|
||||
<option name="TERNARY_OPERATION_WRAP" value="1" />
|
||||
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
|
||||
<option name="FOR_STATEMENT_WRAP" value="1" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
||||
<option name="WRAP_COMMENTS" value="true" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<option name="WRAP_ON_TYPING" value="0" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JSON">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="RIGHT_MARGIN" value="80" />
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="ALIGN_MULTILINE_FOR" value="false" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||
<option name="BINARY_OPERATION_WRAP" value="1" />
|
||||
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
|
||||
<option name="TERNARY_OPERATION_WRAP" value="1" />
|
||||
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
|
||||
<option name="FOR_STATEMENT_WRAP" value="1" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="ObjectiveC">
|
||||
<option name="RIGHT_MARGIN" value="80" />
|
||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
|
||||
<option name="BLANK_LINES_BEFORE_IMPORTS" value="0" />
|
||||
<option name="BLANK_LINES_AFTER_IMPORTS" value="0" />
|
||||
<option name="BLANK_LINES_AROUND_CLASS" value="0" />
|
||||
<option name="BLANK_LINES_AROUND_METHOD" value="0" />
|
||||
<option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="0" />
|
||||
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="false" />
|
||||
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
|
||||
<option name="FOR_STATEMENT_WRAP" value="1" />
|
||||
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="PROTO">
|
||||
<option name="RIGHT_MARGIN" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Python">
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
<option name="RIGHT_MARGIN" value="80" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="SASS">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="SCSS">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="TypeScript">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:.*Style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_width</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_height</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_weight</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_margin</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_marginTop</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_marginBottom</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_marginStart</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_marginEnd</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_marginLeft</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_marginRight</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:padding</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:paddingTop</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:paddingBottom</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:paddingStart</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:paddingEnd</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:paddingLeft</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:paddingRight</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res-auto</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/tools</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="protobuf">
|
||||
<option name="RIGHT_MARGIN" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
103
README.md
Normal file
103
README.md
Normal file
@ -0,0 +1,103 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.8.2</h1>
|
||||
<h4 align="center">基于SpringBoot+Vue前后端分离的Java快速开发框架</h4>
|
||||
<p align="center">
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue/stargazers"><img src="https://gitee.com/y_project/RuoYi-Vue/badge/star.svg?theme=dark"></a>
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.8.2-brightgreen.svg"></a>
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
|
||||
</p>
|
||||
|
||||
## 平台简介
|
||||
|
||||
AgileBoot是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
|
||||
|
||||
* 前端采用Vue、Element UI。
|
||||
* 后端采用Spring Boot、Spring Security、Redis & Jwt。
|
||||
* 权限认证使用Jwt,支持多终端认证系统。
|
||||
* 支持加载动态权限菜单,多方式轻松权限控制。
|
||||
* 高效率开发,使用代码生成器可以一键生成前后端代码。
|
||||
* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Vue3](https://github.com/yangzongzhuan/RuoYi-Vue3),保持同步更新。
|
||||
* 提供了单应用版本[RuoYi-Vue-fast](https://github.com/yangzongzhuan/RuoYi-Vue-fast),Oracle版本[RuoYi-Vue-Oracle](https://github.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。
|
||||
* 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
|
||||
* 特别鸣谢:[element](https://github.com/ElemeFE/element),[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin),[eladmin-web](https://github.com/elunez/eladmin-web)。
|
||||
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)
|
||||
* 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)
|
||||
|
||||
## 内置功能
|
||||
|
||||
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
|
||||
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
|
||||
3. 岗位管理:配置系统用户所属担任职务。
|
||||
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
|
||||
5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
|
||||
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
|
||||
7. 参数管理:对系统动态配置常用参数。
|
||||
8. 通知公告:系统通知公告信息发布维护。
|
||||
9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
|
||||
10. 登录日志:系统登录日志记录查询包含登录异常。
|
||||
11. 在线用户:当前系统中活跃用户状态监控。
|
||||
12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
|
||||
13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。
|
||||
14. 系统接口:根据业务代码自动生成相关的api接口文档。
|
||||
15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
|
||||
16. 缓存监控:对系统的缓存信息查询,命令统计等。
|
||||
17. 在线构建器:拖动表单元素生成相应的HTML代码。
|
||||
18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
|
||||
|
||||
## 在线体验
|
||||
|
||||
- admin/admin123
|
||||
- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
|
||||
|
||||
演示地址:http://vue.ruoyi.vip
|
||||
文档地址:http://doc.ruoyi.vip
|
||||
|
||||
## 演示图
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/cd1f90be5f2684f4560c9519c0f2a232ee8.jpg"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-8074972883b5ba0622e13246738ebba237a.png"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-9f88719cdfca9af2e58b352a20e23d43b12.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-39bf2584ec3a529b0d5a3b70d15c9b37646.png"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-936ec82d1f4872e1bc980927654b6007307.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-b2d62ceb95d2dd9b3fbe157bb70d26001e9.png"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-d67451d308b7a79ad6819723396f7c3d77a.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-8370a0d02977eebf6dbf854c8450293c937.png"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-49003ed83f60f633e7153609a53a2b644f7.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-d4fe726319ece268d4746602c39cffc0621.png"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
## AG前后端分离交流群
|
||||
|
||||
QQ群: [](https://jq.qq.com/?_wv=1027&k=5bVB1og) [](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [](https://jq.qq.com/?_wv=1027&k=51G72yr) [](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) 点击按钮入群。
|
||||
|
||||
TODO
|
||||
plan to do encrypt request and response. reference:https://github.com/ishuibo/rsa-encrypt-body-spring-boot
|
||||
|
||||
|
||||
### 如果老是出现项目中能找到包 但是编译的时候却找不到 可以运行 mvn clean install
|
||||
58
agileboot-admin/pom.xml
Normal file
58
agileboot-admin/pom.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>agileboot</artifactId>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>agileboot-admin</artifactId>
|
||||
|
||||
<description>
|
||||
web服务入口
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- spring-boot-devtools -->
|
||||
<!--<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<!– 表示依赖不会传递 –>
|
||||
<optional>true</optional>
|
||||
</dependency>-->
|
||||
|
||||
|
||||
|
||||
<!-- Mysql驱动包 -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 核心模块-->
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-infrastructure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 定时任务-->
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 代码生成-->
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-domain</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,123 @@
|
||||
package com.agileboot.admin.controller.common;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.file.FileNameUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.admin.response.UploadDTO;
|
||||
import com.agileboot.common.config.AgileBootConfig;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.utils.ServletHolderUtil;
|
||||
import com.agileboot.common.utils.file.FileUploadUtils;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 通用请求处理
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/file")
|
||||
@Slf4j
|
||||
public class FileController {
|
||||
|
||||
|
||||
/**
|
||||
* 通用下载请求
|
||||
*
|
||||
* @param fileName 文件名称
|
||||
*/
|
||||
@GetMapping("/download")
|
||||
public ResponseEntity<byte[]> fileDownload(String fileName, HttpServletResponse response) {
|
||||
try {
|
||||
if (!FileUploadUtils.isAllowDownload(fileName)) {
|
||||
throw new Exception(StrUtil.format("文件名称({})非法,不允许下载。 ", fileName));
|
||||
}
|
||||
|
||||
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
|
||||
String filePath = AgileBootConfig.getDownloadPath() + fileName;
|
||||
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("Content-Disposition", String.format("attachment;filename=%s", realFileName));
|
||||
return new ResponseEntity<>(FileUtil.readBytes(filePath), headers, HttpStatus.OK);
|
||||
} catch (Exception e) {
|
||||
log.error("下载文件失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用上传请求(单个)
|
||||
*/
|
||||
@PostMapping("/upload")
|
||||
public ResponseDTO<UploadDTO> uploadFile(MultipartFile file) throws IOException {
|
||||
if (file == null) {
|
||||
throw new ApiException(ErrorCode.Business.UPLOAD_FILE_IS_EMPTY);
|
||||
}
|
||||
|
||||
// 上传文件路径
|
||||
String filePath = AgileBootConfig.getUploadPath();
|
||||
// 上传并返回新文件名称
|
||||
String fileName = FileUploadUtils.upload(filePath, file);
|
||||
|
||||
String url = ServletHolderUtil.getContextUrl() + fileName;
|
||||
|
||||
UploadDTO uploadDTO = UploadDTO.builder()
|
||||
.url(url)
|
||||
.fileName(fileName)
|
||||
.newFileName(FileNameUtil.getName(fileName))
|
||||
.originalFilename(file.getOriginalFilename()).build();
|
||||
|
||||
return ResponseDTO.ok(uploadDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用上传请求(多个)
|
||||
*/
|
||||
@PostMapping("/uploads")
|
||||
public ResponseDTO<List<UploadDTO>> uploadFiles(List<MultipartFile> files) throws Exception {
|
||||
if (CollUtil.isEmpty(files)) {
|
||||
throw new ApiException(ErrorCode.Business.UPLOAD_FILE_IS_EMPTY);
|
||||
}
|
||||
|
||||
// 上传文件路径
|
||||
String filePath = AgileBootConfig.getUploadPath();
|
||||
|
||||
List<UploadDTO> uploads = new ArrayList<>();
|
||||
|
||||
for (MultipartFile file : files) {
|
||||
if (file != null) {
|
||||
// 上传并返回新文件名称
|
||||
String fileName = FileUploadUtils.upload(filePath, file);
|
||||
String url = ServletHolderUtil.getContextUrl() + fileName;
|
||||
UploadDTO uploadDTO = UploadDTO.builder()
|
||||
.url(url)
|
||||
.fileName(fileName)
|
||||
.newFileName(FileNameUtil.getName(fileName))
|
||||
.originalFilename(file.getOriginalFilename()).build();
|
||||
|
||||
uploads.add(uploadDTO);
|
||||
|
||||
}
|
||||
}
|
||||
return ResponseDTO.ok(uploads);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
package com.agileboot.admin.controller.common;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.admin.request.LoginDTO;
|
||||
import com.agileboot.admin.request.RegisterDTO;
|
||||
import com.agileboot.admin.response.UserPermissionDTO;
|
||||
import com.agileboot.common.config.AgileBootConfig;
|
||||
import com.agileboot.common.constant.Constants.Token;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Business;
|
||||
import com.agileboot.domain.system.menu.MenuDomainService;
|
||||
import com.agileboot.domain.system.menu.RouterVo;
|
||||
import com.agileboot.domain.system.user.UserDTO;
|
||||
import com.agileboot.infrastructure.cache.map.MapCache;
|
||||
import com.agileboot.infrastructure.web.domain.login.CaptchaDTO;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import com.agileboot.infrastructure.web.service.LoginService;
|
||||
import com.agileboot.infrastructure.web.util.AuthenticationUtils;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 首页
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@RestController
|
||||
public class LoginController {
|
||||
|
||||
private final LoginService loginService;
|
||||
|
||||
private final MenuDomainService menuDomainService;
|
||||
/**
|
||||
* 系统基础配置
|
||||
*/
|
||||
private final AgileBootConfig agileBootConfig;
|
||||
|
||||
public LoginController(LoginService loginService,
|
||||
MenuDomainService menuDomainService, AgileBootConfig agileBootConfig) {
|
||||
this.loginService = loginService;
|
||||
this.menuDomainService = menuDomainService;
|
||||
this.agileBootConfig = agileBootConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 访问首页,提示语
|
||||
*/
|
||||
@RequestMapping("/")
|
||||
public String index() {
|
||||
return StrUtil.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。",
|
||||
agileBootConfig.getName(), agileBootConfig.getVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成验证码
|
||||
*/
|
||||
@GetMapping("/captchaImage")
|
||||
public ResponseDTO<CaptchaDTO> getCaptchaImg() {
|
||||
CaptchaDTO captchaImg = loginService.getCaptchaImg();
|
||||
return ResponseDTO.ok(captchaImg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
*
|
||||
* @param loginDTO 登录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public ResponseDTO<Map> login(@RequestBody LoginDTO loginDTO) {
|
||||
// 生成令牌
|
||||
String token = loginService.login(loginDTO.getUsername(), loginDTO.getPassword(), loginDTO.getCode(),
|
||||
loginDTO.getUuid());
|
||||
|
||||
return ResponseDTO.ok(MapUtil.of(Token.TOKEN_FIELD, token));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*
|
||||
* @return 用户信息
|
||||
*/
|
||||
@GetMapping("/getLoginUserInfo")
|
||||
public ResponseDTO getLoginUserInfo() {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
|
||||
UserPermissionDTO permissionDTO = new UserPermissionDTO();
|
||||
permissionDTO.setUser(new UserDTO(loginUser.getEntity()));
|
||||
permissionDTO.setRoleKey(loginUser.getRoleKey());
|
||||
permissionDTO.setPermissions(loginUser.getMenuPermissions());
|
||||
permissionDTO.setDictTypes(MapCache.dictionaryCache());
|
||||
|
||||
return ResponseDTO.ok(permissionDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取路由信息
|
||||
*
|
||||
* @return 路由信息
|
||||
*/
|
||||
@GetMapping("/getRouters")
|
||||
public ResponseDTO<List<RouterVo>> getRouters() {
|
||||
Long userId = AuthenticationUtils.getUserId();
|
||||
List<RouterVo> routerTree = menuDomainService.getRouterTree(userId);
|
||||
return ResponseDTO.ok(routerTree);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/register")
|
||||
public ResponseDTO register(@RequestBody RegisterDTO user) {
|
||||
return ResponseDTO.fail(Business.UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
package com.agileboot.admin.controller.monitor;
|
||||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.system.monitor.MonitorDomainService;
|
||||
import com.agileboot.domain.system.monitor.dto.RedisCacheInfoDTO;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.infrastructure.cache.redis.RedisCacheService;
|
||||
import com.agileboot.infrastructure.web.domain.OnlineUser;
|
||||
import com.agileboot.infrastructure.web.domain.server.ServerInfo;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 缓存监控
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor")
|
||||
public class MonitorController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private MonitorDomainService monitorDomainService;
|
||||
|
||||
@Autowired
|
||||
private RedisCacheService redisCacheService;
|
||||
|
||||
@PreAuthorize("@ss.hasPerm('monitor:cache:list')")
|
||||
@GetMapping("/cacheInfo")
|
||||
public ResponseDTO<RedisCacheInfoDTO> getRedisCacheInfo() {
|
||||
RedisCacheInfoDTO redisCacheInfo = monitorDomainService.getRedisCacheInfo();
|
||||
return ResponseDTO.ok(redisCacheInfo);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("@ss.hasPerm('monitor:server:list')")
|
||||
@GetMapping("/serverInfo")
|
||||
public ResponseDTO<ServerInfo> getServerInfo() {
|
||||
ServerInfo serverInfo = monitorDomainService.getServerInfo();
|
||||
return ResponseDTO.ok(serverInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取在线用户列表
|
||||
* @param ipaddr
|
||||
* @param userName
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('monitor:online:list')")
|
||||
@GetMapping("/onlineUser/list")
|
||||
public ResponseDTO<PageDTO> list(String ipaddr, String userName) {
|
||||
List<OnlineUser> onlineUserList = monitorDomainService.getOnlineUserList(userName, ipaddr);
|
||||
return ResponseDTO.ok(new PageDTO(onlineUserList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 强退用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('monitor:online:forceLogout')")
|
||||
@AccessLog(title = "在线用户", businessType = BusinessType.FORCE)
|
||||
@DeleteMapping("/onlineUser/{tokenId}")
|
||||
public ResponseDTO<Object> forceLogout(@PathVariable String tokenId) {
|
||||
redisCacheService.loginUserCache.delete(tokenId);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
package com.agileboot.admin.controller.system;
|
||||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.system.config.ConfigDTO;
|
||||
import com.agileboot.domain.system.config.ConfigDomainService;
|
||||
import com.agileboot.domain.system.config.ConfigQuery;
|
||||
import com.agileboot.domain.system.config.ConfigUpdateCommand;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.infrastructure.cache.guava.GuavaCacheService;
|
||||
import com.agileboot.infrastructure.cache.map.MapCache;
|
||||
import com.agileboot.infrastructure.web.util.AuthenticationUtils;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import com.agileboot.orm.result.DictionaryData;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Positive;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 参数配置 信息操作处理
|
||||
* @author valarchie
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/config")
|
||||
@Validated
|
||||
public class SysConfigController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private ConfigDomainService configDomainService;
|
||||
|
||||
@Autowired
|
||||
private GuavaCacheService guavaCacheService;
|
||||
|
||||
/**
|
||||
* 获取参数配置列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:config:list')")
|
||||
@GetMapping("/list")
|
||||
public ResponseDTO<PageDTO> list(ConfigQuery query) {
|
||||
PageDTO page = configDomainService.getConfigList(query);
|
||||
return ResponseDTO.ok(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典类型查询字典数据信息
|
||||
* 换成用Enum
|
||||
*/
|
||||
@GetMapping(value = "/dict/{dictType}")
|
||||
public ResponseDTO<List<DictionaryData>> dictType(@PathVariable String dictType) {
|
||||
List<DictionaryData> dictionaryData = MapCache.dictionaryCache().get(dictType);
|
||||
return ResponseDTO.ok(dictionaryData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据参数编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:config:query')")
|
||||
@GetMapping(value = "/{configId}")
|
||||
public ResponseDTO<ConfigDTO> getInfo(@NotNull @Positive @PathVariable Long configId) {
|
||||
ConfigDTO config = configDomainService.getConfigInfo(configId);
|
||||
return ResponseDTO.ok(config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改参数配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:config:edit')")
|
||||
@AccessLog(title = "参数管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public ResponseDTO edit(@RequestBody ConfigUpdateCommand config) {
|
||||
configDomainService.updateConfig(config, AuthenticationUtils.getLoginUser());
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新参数缓存
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:config:remove')")
|
||||
@AccessLog(title = "参数管理", businessType = BusinessType.CLEAN)
|
||||
@DeleteMapping("/refreshCache")
|
||||
public ResponseDTO<?> refreshCache() {
|
||||
guavaCacheService.configCache.invalidateAll();
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
package com.agileboot.admin.controller.system;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.domain.system.TreeSelectedDTO;
|
||||
import com.agileboot.domain.system.dept.AddDeptCommand;
|
||||
import com.agileboot.domain.system.dept.DeptDTO;
|
||||
import com.agileboot.domain.system.dept.DeptDomainService;
|
||||
import com.agileboot.domain.system.dept.DeptQuery;
|
||||
import com.agileboot.domain.system.dept.UpdateDeptCommand;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.infrastructure.web.util.AuthenticationUtils;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 部门信息
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/dept")
|
||||
@Validated
|
||||
public class SysDeptController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private DeptDomainService deptDomainService;
|
||||
|
||||
/**
|
||||
* 获取部门列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:dept:list')")
|
||||
@GetMapping("/list")
|
||||
public ResponseDTO list(DeptQuery query) {
|
||||
List<DeptDTO> deptList = deptDomainService.getDeptList(query);
|
||||
return ResponseDTO.ok(deptList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询部门列表(排除当前部门,比如在修改部门的上级部门的时候,需要排除自身当前的部门,因为上级部门不能选自己)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:dept:list')")
|
||||
@GetMapping("/list/exclude/{deptId}")
|
||||
public ResponseDTO excludeCurrentDeptItself(@PathVariable(value = "deptId", required = false) Long deptId) {
|
||||
DeptQuery query = new DeptQuery();
|
||||
query.setDeptId(deptId);
|
||||
query.setExcludeCurrentDept(true);
|
||||
|
||||
List<DeptDTO> deptList = deptDomainService.getDeptList(query);
|
||||
return ResponseDTO.ok(deptList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:dept:query')")
|
||||
@GetMapping(value = "/{deptId}")
|
||||
public ResponseDTO<DeptDTO> getInfo(@PathVariable Long deptId) {
|
||||
DeptDTO dept = deptDomainService.getDeptInfo(deptId);
|
||||
return ResponseDTO.ok(dept);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门下拉树列表
|
||||
*/
|
||||
@GetMapping("/dropdownList")
|
||||
public ResponseDTO<List> dropdownList() {
|
||||
List<Tree<Long>> deptTree = deptDomainService.getDeptTree();
|
||||
return ResponseDTO.ok(deptTree);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载对应角色部门列表树
|
||||
*/
|
||||
@GetMapping(value = "/dropdownList/role/{roleId}")
|
||||
public ResponseDTO dropdownListForRole(@PathVariable("roleId") Long roleId) {
|
||||
TreeSelectedDTO deptTreeForRole = deptDomainService.getDeptTreeForRole(roleId);
|
||||
return ResponseDTO.ok(deptTreeForRole);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增部门
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:dept:add')")
|
||||
@AccessLog(title = "部门管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public ResponseDTO add(@RequestBody AddDeptCommand addCommand) {
|
||||
deptDomainService.addDept(addCommand, AuthenticationUtils.getLoginUser());
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改部门
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:dept:edit') AND @ss.checkDataScopeWithDeptId(#updateCommand.deptId)")
|
||||
@AccessLog(title = "部门管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public ResponseDTO edit(@RequestBody UpdateDeptCommand updateCommand) {
|
||||
deptDomainService.updateDept(updateCommand, AuthenticationUtils.getLoginUser());
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除部门
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:dept:remove') AND @ss.checkDataScopeWithDeptId(#deptId)")
|
||||
@AccessLog(title = "部门管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{deptId}")
|
||||
public ResponseDTO remove(@PathVariable @NotNull Long deptId) {
|
||||
deptDomainService.removeDept(deptId);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package com.agileboot.admin.controller.system;
|
||||
|
||||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.utils.poi.CustomExcelUtil;
|
||||
import com.agileboot.domain.common.BulkOperationCommand;
|
||||
import com.agileboot.domain.system.loginInfo.LoginInfoDTO;
|
||||
import com.agileboot.domain.system.loginInfo.LoginInfoDomainService;
|
||||
import com.agileboot.domain.system.loginInfo.LoginInfoQuery;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 系统访问记录
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/loginInfo")
|
||||
@Validated
|
||||
public class SysLoginInfoController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private LoginInfoDomainService loginInfoDomainService;
|
||||
|
||||
@PreAuthorize("@ss.hasPerm('monitor:logininfor:list')")
|
||||
@GetMapping("/list")
|
||||
public ResponseDTO<PageDTO> list(LoginInfoQuery query) {
|
||||
PageDTO pageDTO = loginInfoDomainService.getLoginInfoList(query);
|
||||
return ResponseDTO.ok(pageDTO);
|
||||
}
|
||||
|
||||
@AccessLog(title = "登录日志", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPerm('monitor:logininfor:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, LoginInfoQuery query) {
|
||||
PageDTO pageDTO = loginInfoDomainService.getLoginInfoList(query);
|
||||
CustomExcelUtil.writeToResponse(pageDTO.getRows(), LoginInfoDTO.class, response);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPerm('monitor:logininfor:remove')")
|
||||
@AccessLog(title = "登录日志", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{infoIds}")
|
||||
public ResponseDTO remove(@PathVariable @NotNull @NotEmpty List<Long> infoIds) {
|
||||
loginInfoDomainService.deleteLoginInfo(new BulkOperationCommand<>(infoIds));
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPerm('monitor:logininfor:remove')")
|
||||
@AccessLog(title = "登录日志", businessType = BusinessType.CLEAN)
|
||||
@DeleteMapping("/clean")
|
||||
public ResponseDTO clean() {
|
||||
return ResponseDTO.fail(ErrorCode.Business.UNSUPPORTED_OPERATION);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
package com.agileboot.admin.controller.system;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.domain.system.TreeSelectedDTO;
|
||||
import com.agileboot.domain.system.menu.AddMenuCommand;
|
||||
import com.agileboot.domain.system.menu.MenuDTO;
|
||||
import com.agileboot.domain.system.menu.MenuDomainService;
|
||||
import com.agileboot.domain.system.menu.MenuQuery;
|
||||
import com.agileboot.domain.system.menu.UpdateMenuCommand;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import com.agileboot.infrastructure.web.util.AuthenticationUtils;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 菜单信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/menu")
|
||||
@Validated
|
||||
public class SysMenuController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
MenuDomainService menuDomainService;
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:menu:list')")
|
||||
@GetMapping("/list")
|
||||
public ResponseDTO<List> list(MenuQuery query) {
|
||||
List<MenuDTO> menuList = menuDomainService.getMenuList(query);
|
||||
return ResponseDTO.ok(menuList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据菜单编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:menu:query')")
|
||||
@GetMapping(value = "/{menuId}")
|
||||
public ResponseDTO<MenuDTO> getInfo(@PathVariable @NotNull @PositiveOrZero Long menuId) {
|
||||
MenuDTO menu = menuDomainService.getMenuInfo(menuId);
|
||||
return ResponseDTO.ok(menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单下拉树列表
|
||||
*/
|
||||
@GetMapping("/dropdownList")
|
||||
public ResponseDTO dropdownList() {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
List<Tree<Long>> dropdownList = menuDomainService.getDropdownList(loginUser);
|
||||
return ResponseDTO.ok(dropdownList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载对应角色菜单列表树
|
||||
*/
|
||||
@GetMapping(value = "/roleMenuTreeSelect/{roleId}")
|
||||
public ResponseDTO roleMenuTreeSelect(@PathVariable("roleId") Long roleId) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
TreeSelectedDTO roleDropdownList = menuDomainService.getRoleDropdownList(loginUser, roleId);
|
||||
return ResponseDTO.ok(roleDropdownList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增菜单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:menu:add')")
|
||||
@AccessLog(title = "菜单管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public ResponseDTO add(@RequestBody AddMenuCommand addCommand) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
menuDomainService.addMenu(addCommand, loginUser);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改菜单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:menu:edit')")
|
||||
@AccessLog(title = "菜单管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public ResponseDTO edit(@RequestBody UpdateMenuCommand updateCommand) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
menuDomainService.updateMenu(updateCommand, loginUser);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:menu:remove')")
|
||||
@AccessLog(title = "菜单管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{menuId}")
|
||||
public ResponseDTO remove(@PathVariable("menuId") Long menuId) {
|
||||
menuDomainService.remove(menuId);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
package com.agileboot.admin.controller.system;
|
||||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.BulkOperationCommand;
|
||||
import com.agileboot.domain.system.notice.NoticeAddCommand;
|
||||
import com.agileboot.domain.system.notice.NoticeDTO;
|
||||
import com.agileboot.domain.system.notice.NoticeDomainService;
|
||||
import com.agileboot.domain.system.notice.NoticeQuery;
|
||||
import com.agileboot.domain.system.notice.NoticeUpdateCommand;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.infrastructure.web.util.AuthenticationUtils;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Positive;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 公告 信息操作处理
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/notice")
|
||||
@Validated
|
||||
public class SysNoticeController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private NoticeDomainService noticeDomainService;
|
||||
|
||||
/**
|
||||
* 获取通知公告列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:notice:list')")
|
||||
@GetMapping("/list")
|
||||
public ResponseDTO<PageDTO> list(NoticeQuery query) {
|
||||
PageDTO pageDTO = noticeDomainService.getNoticeList(query);
|
||||
return ResponseDTO.ok(pageDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据通知公告编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:notice:query')")
|
||||
@GetMapping(value = "/{noticeId}")
|
||||
public ResponseDTO<NoticeDTO> getInfo(@PathVariable @NotNull @Positive Long noticeId) {
|
||||
return ResponseDTO.ok(noticeDomainService.getNoticeInfo(noticeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增通知公告
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:notice:add')")
|
||||
@AccessLog(title = "通知公告", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public ResponseDTO add(@RequestBody NoticeAddCommand addCommand) {
|
||||
noticeDomainService.addNotice(addCommand, AuthenticationUtils.getLoginUser());
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改通知公告
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:notice:edit')")
|
||||
@AccessLog(title = "通知公告", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public ResponseDTO edit(@RequestBody NoticeUpdateCommand updateCommand) {
|
||||
noticeDomainService.updateNotice(updateCommand, AuthenticationUtils.getLoginUser());
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除通知公告
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:notice:remove')")
|
||||
@AccessLog(title = "通知公告", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{noticeIds}")
|
||||
public ResponseDTO remove(@PathVariable List<Long> noticeIds) {
|
||||
noticeDomainService.deleteNotice(new BulkOperationCommand<>(noticeIds));
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
package com.agileboot.admin.controller.system;
|
||||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.utils.poi.CustomExcelUtil;
|
||||
import com.agileboot.domain.common.BulkOperationCommand;
|
||||
import com.agileboot.domain.system.operationLog.OperationLogDTO;
|
||||
import com.agileboot.domain.system.operationLog.OperationLogDomainService;
|
||||
import com.agileboot.domain.system.operationLog.OperationLogQuery;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 操作日志记录
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/operationLog")
|
||||
public class SysOperationLogController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private OperationLogDomainService operationLogDomainService;
|
||||
|
||||
@PreAuthorize("@ss.hasPerm('monitor:operlog:list')")
|
||||
@GetMapping("/list")
|
||||
public ResponseDTO<PageDTO> list(OperationLogQuery query, HttpServletRequest request) {
|
||||
PageDTO pageDTO = operationLogDomainService.getOperationLogList(query);
|
||||
return ResponseDTO.ok(pageDTO);
|
||||
}
|
||||
|
||||
@AccessLog(title = "操作日志", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPerm('monitor:operlog:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, OperationLogQuery query) {
|
||||
PageDTO pageDTO = operationLogDomainService.getOperationLogList(query);
|
||||
CustomExcelUtil.writeToResponse(pageDTO.getRows(), OperationLogDTO.class, response);
|
||||
}
|
||||
|
||||
@AccessLog(title = "操作日志", businessType = BusinessType.DELETE)
|
||||
@PreAuthorize("@ss.hasPerm('monitor:operlog:remove')")
|
||||
@DeleteMapping("/{operationIds}")
|
||||
public ResponseDTO remove(@PathVariable List<Long> operationIds) {
|
||||
operationLogDomainService.deleteOperationLog(new BulkOperationCommand<>(operationIds));
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@AccessLog(title = "操作日志", businessType = BusinessType.CLEAN)
|
||||
@PreAuthorize("@ss.hasPerm('monitor:operlog:remove')")
|
||||
@DeleteMapping("/clean")
|
||||
public ResponseDTO clean() {
|
||||
return ResponseDTO.fail(ErrorCode.Business.UNSUPPORTED_OPERATION);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,104 @@
|
||||
package com.agileboot.admin.controller.system;
|
||||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.utils.poi.CustomExcelUtil;
|
||||
import com.agileboot.domain.common.BulkOperationCommand;
|
||||
import com.agileboot.domain.system.post.AddPostCommand;
|
||||
import com.agileboot.domain.system.post.PostDTO;
|
||||
import com.agileboot.domain.system.post.PostDomainService;
|
||||
import com.agileboot.domain.system.post.PostQuery;
|
||||
import com.agileboot.domain.system.post.UpdatePostCommand;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.infrastructure.web.util.AuthenticationUtils;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 岗位信息操作处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/post")
|
||||
@Validated
|
||||
public class SysPostController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private PostDomainService postDomainService;
|
||||
|
||||
/**
|
||||
* 获取岗位列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:post:list')")
|
||||
@GetMapping("/list")
|
||||
public ResponseDTO<PageDTO> list(PostQuery query) {
|
||||
PageDTO pageDTO = postDomainService.getPostList(query);
|
||||
return ResponseDTO.ok(pageDTO);
|
||||
}
|
||||
|
||||
@AccessLog(title = "岗位管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPerm('system:post:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, PostQuery query) {
|
||||
PageDTO pageDTO = postDomainService.getPostList(query);
|
||||
CustomExcelUtil.writeToResponse(pageDTO.getRows(), PostDTO.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据岗位编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:post:query')")
|
||||
@GetMapping(value = "/{postId}")
|
||||
public ResponseDTO getInfo(@PathVariable Long postId) {
|
||||
PostDTO post = postDomainService.getPostInfo(postId);
|
||||
return ResponseDTO.ok(post);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增岗位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:post:add')")
|
||||
@AccessLog(title = "岗位管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public ResponseDTO add(@RequestBody AddPostCommand addCommand) {
|
||||
postDomainService.addPost(addCommand, AuthenticationUtils.getLoginUser());
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改岗位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:post:edit')")
|
||||
@AccessLog(title = "岗位管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public ResponseDTO edit(@RequestBody UpdatePostCommand updateCommand) {
|
||||
postDomainService.updatePost(updateCommand, AuthenticationUtils.getLoginUser());
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除岗位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:post:remove')")
|
||||
@AccessLog(title = "岗位管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{postIds}")
|
||||
public ResponseDTO remove(@PathVariable List<Long> postIds) {
|
||||
postDomainService.deletePost(new BulkOperationCommand<>(postIds));
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.agileboot.admin.controller.system;
|
||||
|
||||
import com.agileboot.common.config.AgileBootConfig;
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.utils.file.FileUploadUtils;
|
||||
import com.agileboot.domain.common.UploadFileDTO;
|
||||
import com.agileboot.domain.system.user.UserDomainService;
|
||||
import com.agileboot.domain.system.user.UserProfileDTO;
|
||||
import com.agileboot.domain.system.user.command.UpdateProfileCommand;
|
||||
import com.agileboot.domain.system.user.command.UpdateUserAvatarCommand;
|
||||
import com.agileboot.domain.system.user.command.UpdateUserPasswordCommand;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import com.agileboot.infrastructure.web.util.AuthenticationUtils;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import java.io.IOException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 个人信息 业务处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/user/profile")
|
||||
public class SysProfileController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private UserDomainService userDomainService;
|
||||
|
||||
/**
|
||||
* 个人信息
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseDTO profile() {
|
||||
LoginUser user = AuthenticationUtils.getLoginUser();
|
||||
UserProfileDTO userProfile = userDomainService.getUserProfile(user.getUserId());
|
||||
return ResponseDTO.ok(userProfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户
|
||||
*/
|
||||
@AccessLog(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public ResponseDTO updateProfile(@RequestBody UpdateProfileCommand command) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
command.setUserId(loginUser.getUserId());
|
||||
userDomainService.updateUserProfile(command, loginUser);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
@AccessLog(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/password")
|
||||
public ResponseDTO updatePassword(@RequestBody UpdateUserPasswordCommand command) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
command.setUserId(loginUser.getUserId());
|
||||
userDomainService.updateUserPassword(loginUser, command);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 头像上传
|
||||
*/
|
||||
@AccessLog(title = "用户头像", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/avatar")
|
||||
public ResponseDTO avatar(@RequestParam("avatarfile") MultipartFile file) throws IOException {
|
||||
if (file.isEmpty()) {
|
||||
throw new ApiException(ErrorCode.Business.USER_UPLOAD_FILE_FAILED);
|
||||
}
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
String avatar = FileUploadUtils.upload(AgileBootConfig.getAvatarPath(), file);
|
||||
|
||||
userDomainService.updateUserAvatar(loginUser, new UpdateUserAvatarCommand(loginUser.getUserId(), avatar));
|
||||
return ResponseDTO.ok(new UploadFileDTO(avatar));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,192 @@
|
||||
package com.agileboot.admin.controller.system;
|
||||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.utils.poi.CustomExcelUtil;
|
||||
import com.agileboot.domain.system.role.AddRoleCommand;
|
||||
import com.agileboot.domain.system.role.AllocatedRoleQuery;
|
||||
import com.agileboot.domain.system.role.RoleDTO;
|
||||
import com.agileboot.domain.system.role.RoleDomainService;
|
||||
import com.agileboot.domain.system.role.RoleQuery;
|
||||
import com.agileboot.domain.system.role.UnallocatedRoleQuery;
|
||||
import com.agileboot.domain.system.role.UpdateDataScopeCommand;
|
||||
import com.agileboot.domain.system.role.UpdateRoleCommand;
|
||||
import com.agileboot.domain.system.role.UpdateStatusCommand;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import com.agileboot.infrastructure.web.util.AuthenticationUtils;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 角色信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/role")
|
||||
@Validated
|
||||
public class SysRoleController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private RoleDomainService roleDomainService;
|
||||
|
||||
@PreAuthorize("@ss.hasPerm('system:role:list')")
|
||||
@GetMapping("/list")
|
||||
public ResponseDTO<PageDTO> list(RoleQuery query) {
|
||||
PageDTO pageDTO = roleDomainService.getRoleList(query);
|
||||
return ResponseDTO.ok(pageDTO);
|
||||
}
|
||||
|
||||
@AccessLog(title = "角色管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPerm('system:role:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, RoleQuery query) {
|
||||
PageDTO pageDTO = roleDomainService.getRoleList(query);
|
||||
CustomExcelUtil.writeToResponse(pageDTO.getRows(), RoleDTO.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:query')")
|
||||
@GetMapping(value = "/{roleId}")
|
||||
public ResponseDTO getInfo(@PathVariable @NotNull Long roleId) {
|
||||
RoleDTO roleInfo = roleDomainService.getRoleInfo(roleId);
|
||||
return ResponseDTO.ok(roleInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:add')")
|
||||
@AccessLog(title = "角色管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public ResponseDTO add(@RequestBody AddRoleCommand addCommand) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
roleDomainService.addRole(addCommand, loginUser);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:remove')")
|
||||
@AccessLog(title = "角色管理", businessType = BusinessType.INSERT)
|
||||
@DeleteMapping(value = "/{roleId}")
|
||||
public ResponseDTO remove(@PathVariable("roleId")List<Long> roleIds) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
roleDomainService.deleteRoleByBulk(roleIds, loginUser);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:edit')")
|
||||
@AccessLog(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public ResponseDTO edit(@Validated @RequestBody UpdateRoleCommand updateCommand) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
roleDomainService.updateRole(updateCommand, loginUser);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存数据权限
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:edit')")
|
||||
@AccessLog(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{roleId}/dataScope")
|
||||
public ResponseDTO dataScope(@PathVariable("roleId")Long roleId, @RequestBody UpdateDataScopeCommand command) {
|
||||
command.setRoleId(roleId);
|
||||
|
||||
roleDomainService.updateDataScope(command);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态修改
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:edit')")
|
||||
@AccessLog(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{roleId}/status")
|
||||
public ResponseDTO changeStatus(@PathVariable("roleId")Long roleId, @RequestBody UpdateStatusCommand command) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
command.setRoleId(roleId);
|
||||
|
||||
roleDomainService.updateStatus(command, loginUser);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询已分配用户角色列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:list')")
|
||||
@GetMapping("/{roleId}/allocated/list")
|
||||
public ResponseDTO<PageDTO> allocatedUserList(@PathVariable("roleId")Long roleId, AllocatedRoleQuery query) {
|
||||
query.setRoleId(roleId);
|
||||
PageDTO page = roleDomainService.getAllocatedUserList(query);
|
||||
return ResponseDTO.ok(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询未分配用户角色列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:list')")
|
||||
@GetMapping("/{roleId}/unallocated/list")
|
||||
public ResponseDTO<PageDTO> unallocatedUserList(@PathVariable("roleId")Long roleId, UnallocatedRoleQuery query) {
|
||||
query.setRoleId(roleId);
|
||||
PageDTO page = roleDomainService.getUnallocatedUserList(query);
|
||||
return ResponseDTO.ok(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消授权用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:edit')")
|
||||
@AccessLog(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@DeleteMapping("/{roleId}/user/grant")
|
||||
public ResponseDTO deleteRoleOfUser(@PathVariable("roleId")Long roleId, @RequestBody Long userId) {
|
||||
roleDomainService.deleteRoleOfUser(userId);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量取消授权用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:edit')")
|
||||
@AccessLog(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@DeleteMapping("/users/{userIds}/grant/bulk")
|
||||
public ResponseDTO deleteRoleOfUserByBulk(@PathVariable("userIds") List<Long> userIds) {
|
||||
roleDomainService.deleteRoleOfUserByBulk(userIds);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量选择用户授权
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:role:edit')")
|
||||
@AccessLog(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@PostMapping("/{roleId}/users/{userIds}/grant/bulk")
|
||||
public ResponseDTO addRoleForUserByBulk(@PathVariable("roleId") Long roleId,
|
||||
@PathVariable("userIds") List<Long> userIds) {
|
||||
roleDomainService.addRoleOfUserByBulk(roleId, userIds);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,171 @@
|
||||
package com.agileboot.admin.controller.system;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.utils.poi.CustomExcelUtil;
|
||||
import com.agileboot.domain.common.BulkOperationCommand;
|
||||
import com.agileboot.domain.system.loginInfo.SearchUserQuery;
|
||||
import com.agileboot.domain.system.user.UserDTO;
|
||||
import com.agileboot.domain.system.user.UserDetailDTO;
|
||||
import com.agileboot.domain.system.user.UserDomainService;
|
||||
import com.agileboot.domain.system.user.UserInfoDTO;
|
||||
import com.agileboot.domain.system.user.command.AddUserCommand;
|
||||
import com.agileboot.domain.system.user.command.ChangeStatusCommand;
|
||||
import com.agileboot.domain.system.user.command.ResetPasswordCommand;
|
||||
import com.agileboot.domain.system.user.command.UpdateUserCommand;
|
||||
import com.agileboot.infrastructure.annotations.AccessLog;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import com.agileboot.infrastructure.web.util.AuthenticationUtils;
|
||||
import com.agileboot.orm.enums.BusinessType;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/user")
|
||||
public class SysUserController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private UserDomainService userDomainService;
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:user:list') AND @ss.checkDataScopeWithDeptId(#query.deptId)")
|
||||
@GetMapping("/list")
|
||||
public ResponseDTO<PageDTO> list(SearchUserQuery query) {
|
||||
PageDTO page = userDomainService.getUserList(query);
|
||||
return ResponseDTO.ok(page);
|
||||
}
|
||||
|
||||
@AccessLog(title = "用户管理", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPerm('system:user:export')")
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SearchUserQuery query) {
|
||||
PageDTO userList = userDomainService.getUserList(query);
|
||||
CustomExcelUtil.writeToResponse(userList.getRows(), UserDTO.class, response);
|
||||
}
|
||||
|
||||
@AccessLog(title = "用户管理", businessType = BusinessType.IMPORT)
|
||||
@PreAuthorize("@ss.hasPerm('system:user:import')")
|
||||
@PostMapping("/importData")
|
||||
public ResponseDTO importData(MultipartFile file) {
|
||||
List<?> commands = CustomExcelUtil.readFromResponse(AddUserCommand.class, file);
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
|
||||
for (Object command : commands) {
|
||||
AddUserCommand addUserCommand = (AddUserCommand) command;
|
||||
userDomainService.addUser(loginUser, addUserCommand);
|
||||
}
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@PostMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response) {
|
||||
CustomExcelUtil.writeToResponse(ListUtil.toList(new AddUserCommand()), AddUserCommand.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户编号获取详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:user:query')")
|
||||
@GetMapping(value = {"/", "/{userId}"})
|
||||
public ResponseDTO<UserDetailDTO> getUserDetailInfo(@PathVariable(value = "userId", required = false) Long userId) {
|
||||
UserDetailDTO userDetailInfo = userDomainService.getUserDetailInfo(userId);
|
||||
return ResponseDTO.ok(userDetailInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:user:add') AND @ss.checkDataScopeWithDeptId(#command.deptId)")
|
||||
@AccessLog(title = "用户管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public ResponseDTO add(@Validated @RequestBody AddUserCommand command) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
userDomainService.addUser(loginUser, command);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:user:edit') AND @ss.checkDataScopeWithUserId(#command.userId)")
|
||||
@AccessLog(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public ResponseDTO edit(@Validated @RequestBody UpdateUserCommand command) {
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
userDomainService.updateUser(loginUser, command);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:user:remove') AND @ss.checkDataScopeWithUserIds(#userIds)")
|
||||
@AccessLog(title = "用户管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{userIds}")
|
||||
public ResponseDTO remove(@PathVariable List<Long> userIds) {
|
||||
BulkOperationCommand<Long> bulkDeleteCommand = new BulkOperationCommand(userIds);
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
userDomainService.deleteUsers(loginUser, bulkDeleteCommand);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:user:resetPwd') AND @ss.checkDataScopeWithUserId(#userId)")
|
||||
@AccessLog(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{userId}/password/reset")
|
||||
public ResponseDTO resetPassword(@PathVariable Long userId, @RequestBody ResetPasswordCommand command) {
|
||||
command.setUserId(userId);
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
userDomainService.resetUserPassword(loginUser, command);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态修改
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:user:edit') AND @ss.checkDataScopeWithUserId(#command.userId)")
|
||||
@AccessLog(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{userId}/status")
|
||||
public ResponseDTO changeStatus(@PathVariable Long userId, @RequestBody ChangeStatusCommand command) {
|
||||
command.setUserId(userId);
|
||||
LoginUser loginUser = AuthenticationUtils.getLoginUser();
|
||||
userDomainService.changeUserStatus(loginUser, command);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户编号获取授权角色
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPerm('system:user:query')")
|
||||
@GetMapping("/{userId}/role")
|
||||
public ResponseDTO<UserInfoDTO> getRoleOfUser(@PathVariable("userId") Long userId) {
|
||||
UserInfoDTO userWithRole = userDomainService.getUserWithRole(userId);
|
||||
return ResponseDTO.ok(userWithRole);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.agileboot.admin.controller.tool;
|
||||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* swagger 接口
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/tool/swagger")
|
||||
public class SwaggerController extends BaseController {
|
||||
|
||||
@PreAuthorize("@ss.hasPerm('tool:swagger:view')")
|
||||
@GetMapping()
|
||||
public String index() {
|
||||
return redirect("/swagger-ui.html");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
package com.agileboot.admin.controller.tool;
|
||||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/test/user")
|
||||
/**
|
||||
* swagger 用户测试方法
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Api("用户信息管理")
|
||||
public class SwaggerTemplateController extends BaseController {
|
||||
|
||||
private final static Map<Integer, UserEntity> USER_ENTITY_MAP = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
USER_ENTITY_MAP.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
|
||||
USER_ENTITY_MAP.put(2, new UserEntity(2, "agileBoot", "admin123", "15666666666"));
|
||||
}
|
||||
|
||||
@ApiOperation("获取用户列表")
|
||||
@GetMapping("/list")
|
||||
public ResponseDTO<List<UserEntity>> userList() {
|
||||
List<UserEntity> userList = new ArrayList<>(USER_ENTITY_MAP.values());
|
||||
return ResponseDTO.ok(userList);
|
||||
}
|
||||
|
||||
@ApiOperation("获取用户详细")
|
||||
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path",
|
||||
dataTypeClass = Integer.class)
|
||||
@GetMapping("/{userId}")
|
||||
public ResponseDTO<UserEntity> getUser(@PathVariable Integer userId) {
|
||||
if (!USER_ENTITY_MAP.isEmpty() && USER_ENTITY_MAP.containsKey(userId)) {
|
||||
return ResponseDTO.ok(USER_ENTITY_MAP.get(userId));
|
||||
} else {
|
||||
return ResponseDTO.fail(ErrorCode.Business.USER_NON_EXIST);
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation("新增用户")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class),
|
||||
@ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
|
||||
})
|
||||
@PostMapping("/save")
|
||||
public ResponseDTO<String> save(UserEntity user) {
|
||||
if (user == null || user.getUserId() == null) {
|
||||
return ResponseDTO.fail("用户ID不能为空");
|
||||
}
|
||||
USER_ENTITY_MAP.put(user.getUserId(), user);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@ApiOperation("更新用户")
|
||||
@PutMapping("/update")
|
||||
public ResponseDTO<String> update(@RequestBody UserEntity user) {
|
||||
if (user == null || user.getUserId() == null) {
|
||||
return ResponseDTO.fail("用户ID不能为空");
|
||||
}
|
||||
if (USER_ENTITY_MAP.isEmpty() || !USER_ENTITY_MAP.containsKey(user.getUserId())) {
|
||||
return ResponseDTO.fail("用户不存在");
|
||||
}
|
||||
USER_ENTITY_MAP.remove(user.getUserId());
|
||||
USER_ENTITY_MAP.put(user.getUserId(), user);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@ApiOperation("删除用户信息")
|
||||
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path",
|
||||
dataTypeClass = Integer.class)
|
||||
@DeleteMapping("/{userId}")
|
||||
public ResponseDTO<String> delete(@PathVariable Integer userId) {
|
||||
if (!USER_ENTITY_MAP.isEmpty() && USER_ENTITY_MAP.containsKey(userId)) {
|
||||
USER_ENTITY_MAP.remove(userId);
|
||||
return ResponseDTO.ok();
|
||||
} else {
|
||||
return ResponseDTO.fail("用户不存在");
|
||||
}
|
||||
}
|
||||
|
||||
@ApiModel(value = "UserEntity", description = "用户实体")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
static class UserEntity {
|
||||
|
||||
@ApiModelProperty("用户ID")
|
||||
private Integer userId;
|
||||
|
||||
@ApiModelProperty("用户名称")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty("用户密码")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty("用户手机")
|
||||
private String mobile;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
package com.agileboot.admin.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户登录对象
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class LoginDTO {
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 验证码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 唯一标识
|
||||
*/
|
||||
private String uuid;
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.agileboot.admin.request;
|
||||
|
||||
import com.agileboot.domain.system.user.RegisterUserModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 用户注册对象
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class RegisterDTO extends LoginDTO {
|
||||
|
||||
public RegisterUserModel toModel() {
|
||||
RegisterUserModel model = new RegisterUserModel();
|
||||
|
||||
model.setCode(this.getCode());
|
||||
model.setUuid(this.getUuid());
|
||||
model.setUsername(this.getUsername());
|
||||
model.setPassword(this.getPassword());
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.agileboot.admin.response;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class UploadDTO {
|
||||
|
||||
private String url;
|
||||
private String fileName;
|
||||
private String newFileName;
|
||||
private String originalFilename;
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.agileboot.admin.response;
|
||||
|
||||
import com.agileboot.domain.system.user.UserDTO;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserPermissionDTO {
|
||||
|
||||
private UserDTO user;
|
||||
private String roleKey;
|
||||
private Set<String> permissions;
|
||||
private Map dictTypes;
|
||||
|
||||
}
|
||||
40
agileboot-api/pom.xml
Normal file
40
agileboot-api/pom.xml
Normal file
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>agileboot</artifactId>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>agileboot-api</artifactId>
|
||||
|
||||
<description>
|
||||
quartz定时任务
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- 定时任务 -->
|
||||
<dependency>
|
||||
<groupId>org.quartz-scheduler</groupId>
|
||||
<artifactId>quartz</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.mchange</groupId>
|
||||
<artifactId>c3p0</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,16 @@
|
||||
package com.agileboot.api.controller;
|
||||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 调度日志操作处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/order")
|
||||
public class OrderController extends BaseController {
|
||||
|
||||
}
|
||||
166
agileboot-common/pom.xml
Normal file
166
agileboot-common/pom.xml
Normal file
@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>agileboot</artifactId>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>agileboot-common</artifactId>
|
||||
|
||||
<description>
|
||||
common通用工具
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- Spring框架基本的核心工具 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringWeb模块 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- spring security 安全认证 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- pagehelper 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 自定义验证注解 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON工具类 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- io常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 文件上传工具类 -->
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- excel工具 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- yml解析器 -->
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Token生成与解析-->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Jaxb -->
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- redis 缓存操作 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- pool 对象池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 解析客户端操作系统、浏览器等 -->
|
||||
<dependency>
|
||||
<groupId>eu.bitwalker</groupId>
|
||||
<artifactId>UserAgentUtils</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- servlet包 -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.module</groupId>
|
||||
<artifactId>jackson-module-parameter-names</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jdk8</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- swagger3-->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.lionsoul</groupId>
|
||||
<artifactId>ip2region</artifactId>
|
||||
<version>2.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 -->
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
<version>1.6.2</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,19 @@
|
||||
package com.agileboot.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 自定义导出Excel数据注解
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface ExcelColumn {
|
||||
|
||||
String name() default "";
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.agileboot.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface ExcelSheet {
|
||||
|
||||
/**
|
||||
* sheet名称
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
package com.agileboot.common.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 读取项目相关配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "agileboot")
|
||||
public class AgileBootConfig {
|
||||
|
||||
/**
|
||||
* 项目名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 版权年份
|
||||
*/
|
||||
private String copyrightYear;
|
||||
|
||||
/**
|
||||
* 实例演示开关
|
||||
*/
|
||||
private boolean demoEnabled;
|
||||
|
||||
/**
|
||||
* 上传路径
|
||||
*/
|
||||
private static String profile;
|
||||
|
||||
/**
|
||||
* 获取地址开关
|
||||
*/
|
||||
private static boolean addressEnabled;
|
||||
|
||||
/**
|
||||
* 验证码类型
|
||||
*/
|
||||
private static String captchaType;
|
||||
|
||||
/**
|
||||
* rsa private key 静态属性的注入!! set方法一定不能是static 方法
|
||||
*/
|
||||
private static String rsaPrivateKey;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getCopyrightYear() {
|
||||
return copyrightYear;
|
||||
}
|
||||
|
||||
public void setCopyrightYear(String copyrightYear) {
|
||||
this.copyrightYear = copyrightYear;
|
||||
}
|
||||
|
||||
public boolean isDemoEnabled() {
|
||||
return demoEnabled;
|
||||
}
|
||||
|
||||
public void setDemoEnabled(boolean demoEnabled) {
|
||||
this.demoEnabled = demoEnabled;
|
||||
}
|
||||
|
||||
public static String getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setProfile(String profile) {
|
||||
AgileBootConfig.profile = profile;
|
||||
}
|
||||
|
||||
public static boolean isAddressEnabled() {
|
||||
return addressEnabled;
|
||||
}
|
||||
|
||||
public void setAddressEnabled(boolean addressEnabled) {
|
||||
AgileBootConfig.addressEnabled = addressEnabled;
|
||||
}
|
||||
|
||||
public static String getCaptchaType() {
|
||||
return captchaType;
|
||||
}
|
||||
|
||||
public void setCaptchaType(String captchaType) {
|
||||
AgileBootConfig.captchaType = captchaType;
|
||||
}
|
||||
|
||||
public static String getRsaPrivateKey() {
|
||||
return rsaPrivateKey;
|
||||
}
|
||||
|
||||
public void setRsaPrivateKey(String rsaPrivateKey) {
|
||||
AgileBootConfig.rsaPrivateKey = rsaPrivateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导入上传路径
|
||||
*/
|
||||
public static String getImportPath() {
|
||||
return getProfile() + "/import";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头像上传路径
|
||||
*/
|
||||
public static String getAvatarPath() {
|
||||
return getProfile() + "/avatar";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载路径
|
||||
*/
|
||||
public static String getDownloadPath() {
|
||||
return getProfile() + "/download/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传路径
|
||||
*/
|
||||
public static String getUploadPath() {
|
||||
return getProfile() + "/upload";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package com.agileboot.common.constant;
|
||||
|
||||
|
||||
/**
|
||||
* 通用常量信息
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
public static final int KB = 1024;
|
||||
|
||||
public static final int MB = KB * 1024;
|
||||
|
||||
public static final int GB = MB * 1024;
|
||||
|
||||
/**
|
||||
* http请求
|
||||
*/
|
||||
public static final String HTTP = "http://";
|
||||
|
||||
/**
|
||||
* https请求
|
||||
*/
|
||||
public static final String HTTPS = "https://";
|
||||
|
||||
/**
|
||||
* 资源映射路径 前缀
|
||||
*/
|
||||
public static final String RESOURCE_PREFIX = "/profile";
|
||||
|
||||
|
||||
public static class Token {
|
||||
/**
|
||||
* 令牌
|
||||
*/
|
||||
public static final String TOKEN_FIELD = "token";
|
||||
|
||||
/**
|
||||
* 令牌前缀
|
||||
*/
|
||||
public static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
/**
|
||||
* 令牌前缀
|
||||
*/
|
||||
public static final String LOGIN_USER_KEY = "login_user_key";
|
||||
|
||||
}
|
||||
|
||||
public static class Captcha {
|
||||
/**
|
||||
* 令牌
|
||||
*/
|
||||
public static final String MATH_TYPE = "math";
|
||||
|
||||
/**
|
||||
* 令牌前缀
|
||||
*/
|
||||
public static final String CHAR_TYPE = "char";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.agileboot.common.core.base;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.Date;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Slf4j
|
||||
public class BaseController {
|
||||
|
||||
/**
|
||||
*
|
||||
* 将前台传递过来的日期格式的字符串,自动转化为Date类型
|
||||
*/
|
||||
@InitBinder
|
||||
public void initBinder(WebDataBinder binder) {
|
||||
// Date 类型转换
|
||||
binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
|
||||
@Override
|
||||
public void setAsText(String text) {
|
||||
setValue(DateUtil.parseDate(text));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面跳转
|
||||
*/
|
||||
public String redirect(String url) {
|
||||
return StrUtil.format("redirect:{}", url);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.agileboot.common.core.base;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Entity基类
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class BaseEntity<T extends Model<?>> extends Model<T> {
|
||||
|
||||
@ApiModelProperty("创建者ID")
|
||||
@TableField("creator_id")
|
||||
private Long creatorId;
|
||||
|
||||
@ApiModelProperty("创建者")
|
||||
@TableField("creator_name")
|
||||
private String creatorName;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
@TableField(value = "create_time", fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty("更新者ID")
|
||||
@TableField("updater_id")
|
||||
private Long updaterId;
|
||||
|
||||
@ApiModelProperty("更新者")
|
||||
@TableField("updater_name")
|
||||
private String updaterName;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
|
||||
@ApiModelProperty("删除标志(0代表存在 1代表删除)")
|
||||
@TableField("deleted")
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
public void logCreator(BaseUser user) {
|
||||
if (user != null) {
|
||||
this.creatorId = user.getUserId();
|
||||
this.creatorName = user.getUsername();
|
||||
}
|
||||
}
|
||||
|
||||
public void logUpdater(BaseUser user) {
|
||||
if (user != null) {
|
||||
this.updaterId = user.getUserId();
|
||||
this.updaterName = user.getUsername();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.agileboot.common.core.base;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BaseUser {
|
||||
|
||||
private Long userId;
|
||||
private String username;
|
||||
private Long deptId;
|
||||
private Long roleId;
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.agileboot.common.core.dto;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.exception.error.ErrorCodeInterface;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 响应信息主体
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ResponseDTO<T> {
|
||||
|
||||
private Integer code;
|
||||
|
||||
private String msg;
|
||||
|
||||
private T data;
|
||||
|
||||
public static <T> ResponseDTO<T> ok() {
|
||||
return build(null, ErrorCode.SUCCESS);
|
||||
}
|
||||
|
||||
public static <T> ResponseDTO<T> ok(T data) {
|
||||
return build(data, ErrorCode.SUCCESS);
|
||||
}
|
||||
|
||||
public static <T> ResponseDTO<T> fail() {
|
||||
return build(null, ErrorCode.FAIL);
|
||||
}
|
||||
|
||||
public static <T> ResponseDTO<T> fail(ErrorCodeInterface code) {
|
||||
return build(null, code);
|
||||
}
|
||||
|
||||
public static <T> ResponseDTO<T> fail(ApiException exception) {
|
||||
return new ResponseDTO<>(exception.getErrorCode().code(), exception.getMessage(), null);
|
||||
}
|
||||
|
||||
public static <T> ResponseDTO<T> fail(ErrorCodeInterface code, Object... args) {
|
||||
return build( code, args);
|
||||
}
|
||||
|
||||
public static <T> ResponseDTO<T> fail(T data) { return build(ErrorCode.FAIL, data); }
|
||||
|
||||
public static <T> ResponseDTO<T> build(T data, ErrorCodeInterface code) {
|
||||
return new ResponseDTO<>(code.code(), code.message(), data);
|
||||
}
|
||||
|
||||
public static <T> ResponseDTO<T> build(ErrorCodeInterface code, Object... args) {
|
||||
return new ResponseDTO<>(code.code(), StrUtil.format(code.message(), args), null);
|
||||
}
|
||||
|
||||
public static <T> ResponseDTO<T> build(T data, ErrorCodeInterface code, Object... args) {
|
||||
return new ResponseDTO<>(code.code(), StrUtil.format(code.message(), args), data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
package com.agileboot.common.core.page;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class PageDTO {
|
||||
/**
|
||||
* 总记录数
|
||||
*/
|
||||
private Long total;
|
||||
|
||||
/**
|
||||
* 列表数据
|
||||
*/
|
||||
private List<?> rows;
|
||||
|
||||
public PageDTO(List<?> list) {
|
||||
this.rows = list;
|
||||
this.total = (long) list.size();
|
||||
}
|
||||
|
||||
public PageDTO(Page page) {
|
||||
this.rows = page.getRecords();
|
||||
this.total = page.getTotal();
|
||||
}
|
||||
|
||||
public PageDTO(List<?> list, Long count) {
|
||||
this.rows = list;
|
||||
this.total = count;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.agileboot.common.enums;
|
||||
|
||||
/**
|
||||
* 数据源
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public enum DataSourceType {
|
||||
/**
|
||||
* 主库
|
||||
*/
|
||||
MASTER,
|
||||
|
||||
/**
|
||||
* 从库
|
||||
*/
|
||||
SLAVE
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.agileboot.common.enums;
|
||||
|
||||
/**
|
||||
* 限流类型
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
|
||||
public enum LimitType {
|
||||
/**
|
||||
* 默认策略全局限流
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* 根据请求者IP进行限流
|
||||
*/
|
||||
IP
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package com.agileboot.common.exception;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.exception.error.ErrorCodeInterface;
|
||||
import com.agileboot.common.utils.i18n.MessageUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Slf4j
|
||||
public class ApiException extends RuntimeException{
|
||||
|
||||
|
||||
protected ErrorCodeInterface errorCode;
|
||||
|
||||
protected String message;
|
||||
|
||||
protected Object[] args;
|
||||
|
||||
protected String formattedMessage;
|
||||
protected String i18nFormattedMessage;
|
||||
|
||||
public ApiException(Throwable e, ErrorCodeInterface errorCode, Object... args) {
|
||||
super(e);
|
||||
fillErrorCode(errorCode, args);
|
||||
}
|
||||
|
||||
public ApiException(Throwable e, ErrorCodeInterface errorCode) {
|
||||
super(e);
|
||||
fillErrorCode(errorCode);
|
||||
}
|
||||
|
||||
public ApiException(ErrorCodeInterface errorCode, Object... args) {
|
||||
fillErrorCode(errorCode, args);
|
||||
}
|
||||
|
||||
public ApiException(ErrorCodeInterface errorCode) {
|
||||
fillErrorCode(errorCode);
|
||||
}
|
||||
|
||||
private void fillErrorCode(ErrorCodeInterface errorCode, Object... args) {
|
||||
this.errorCode = errorCode;
|
||||
this.message = errorCode.message();
|
||||
this.args = args;
|
||||
|
||||
this.formattedMessage = StrUtil.format(this.message, args);
|
||||
|
||||
try {
|
||||
this.i18nFormattedMessage = MessageUtils.message(errorCode.i18n(), args);
|
||||
} catch (Exception e) {
|
||||
log.error("could not found i18n error i18nMessage entry : " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public ErrorCodeInterface getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public void setErrorCode(ErrorCodeInterface errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return i18nFormattedMessage != null ? i18nFormattedMessage : formattedMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalizedMessage() {
|
||||
return i18nFormattedMessage;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,322 @@
|
||||
package com.agileboot.common.exception.error;
|
||||
|
||||
/**
|
||||
* 常用错误码 以及 保留错误码
|
||||
* @author valarchie
|
||||
*/
|
||||
public enum ErrorCode implements ErrorCodeInterface {
|
||||
|
||||
/**
|
||||
* 错误码集合
|
||||
* 1~9999 为保留错误码 或者 常用错误码
|
||||
* 10000~19999 为内部错误码
|
||||
* 20000~29999 客户端错误码 (客户端异常调用之类的错误)
|
||||
* 30000~39999 为第三方错误码 (代码正常,但是第三方异常)
|
||||
* 40000~49999 为业务逻辑 错误码 (无异常,代码正常流转,并返回提示给用户)
|
||||
* 由于系统内的错误码都是独一无二的,所以错误码应该放在common包集中管理
|
||||
*/
|
||||
// -------------- 普通错误码 及保留错误码 ---------------
|
||||
SUCCESS(0,"操作成功"),
|
||||
FAIL(9999, "操作失败"),
|
||||
|
||||
|
||||
UNKNOWN_ERROR(99999,"未知错误");
|
||||
|
||||
private final int code;
|
||||
private final String msg;
|
||||
|
||||
|
||||
ErrorCode(int code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int code() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String message() {
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 40000~49999 为业务逻辑 错误码 (无代码异常,代码正常流转,并返回提示给用户)
|
||||
*/
|
||||
public enum Business implements ErrorCodeInterface{
|
||||
|
||||
// ----------------------------- Common -----------------------------------------
|
||||
|
||||
OBJECT_NOT_FOUND(Module.COMMON, 1, "找不到ID为%s 的%s"),
|
||||
|
||||
UNSUPPORTED_OPERATION(Module.COMMON, 2, "不支持的操作"),
|
||||
|
||||
BULK_DELETE_IDS_IS_INVALID(Module.COMMON, 3, "批量参数ID列表为空"),
|
||||
|
||||
// ----------------------------- Permission -----------------------------------------
|
||||
|
||||
FORBIDDEN_TO_MODIFY_ADMIN(Module.PERMISSION, 1, "不允许修改管理员的信息"),
|
||||
|
||||
NO_PERMISSION_TO_OPERATE(Module.PERMISSION, 2, "没有权限进行此操作,请联系管理员"),
|
||||
|
||||
// ----------------------------- Login -----------------------------------------
|
||||
|
||||
LOGIN_WRONG_USER_PASSWORD(Module.LOGIN, 1, "用户密码错误,请重输"),
|
||||
|
||||
LOGIN_ERROR(Module.LOGIN, 2, "登录失败:{}"),
|
||||
|
||||
CAPTCHA_CODE_WRONG(Module.LOGIN, 3, "验证码错误"),
|
||||
|
||||
CAPTCHA_CODE_EXPIRE(Module.LOGIN, 4, "验证码过期"),
|
||||
|
||||
CAPTCHA_CODE_NULL(Module.LOGIN, 5, "验证码为空"),
|
||||
|
||||
|
||||
// ----------------------------- Upload -----------------------------------------
|
||||
|
||||
UPLOAD_FILE_TYPE_NOT_ALLOWED(Module.UPLOAD, 1, "不允许上传的文件类型,仅允许:%s"),
|
||||
|
||||
UPLOAD_FILE_NAME_EXCEED_MAX_LENGTH(Module.UPLOAD, 2, "文件名长度超过:%s "),
|
||||
|
||||
UPLOAD_FILE_SIZE_EXCEED_MAX_SIZE(Module.UPLOAD, 3, "文件名大小超过:%s MB"),
|
||||
|
||||
UPLOAD_IMPORT_EXCEL_FAILED(Module.UPLOAD, 4, "导入excel失败:%s"),
|
||||
|
||||
UPLOAD_FILE_IS_EMPTY(Module.UPLOAD, 5, "上传文件为空"),
|
||||
|
||||
// ----------------------------- Config -----------------------------------------
|
||||
|
||||
CONFIG_VALUE_IS_NOT_ALLOW_TO_EMPTY(Module.CONFIG, 1, "参数键值不允许为空"),
|
||||
|
||||
CONFIG_VALUE_IS_NOT_IN_OPTIONS(Module.CONFIG, 2, "参数键值不存在列表中"),
|
||||
|
||||
// ----------------------------- Post -----------------------------------------
|
||||
|
||||
POST_NAME_IS_NOT_UNIQUE(Module.POST, 1, "岗位名称:%s, 已存在"),
|
||||
|
||||
POST_CODE_IS_NOT_UNIQUE(Module.POST, 2, "岗位编号:%s, 已存在"),
|
||||
|
||||
POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED(Module.POST, 3, "职位已分配给用户,请先取消分配再删除"),
|
||||
|
||||
// ------------------------------- Dept ---------------------------------------------
|
||||
|
||||
DEPT_NAME_IS_NOT_UNIQUE(Module.DEPT, 1, "部门名称:%s, 已存在"),
|
||||
|
||||
DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF(Module.DEPT, 2, "父级部门不能选择自己"),
|
||||
|
||||
DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE(Module.DEPT, 3, "子部门还有正在启用的部门,暂时不能停用该部门"),
|
||||
|
||||
DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE(Module.DEPT, 4, "该部门存在下级部门不允许删除"),
|
||||
|
||||
DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE(Module.DEPT, 5, "该部门存在关联的用户不允许删除"),
|
||||
|
||||
DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED(Module.DEPT, 6, "该父级部门不存在或已停用"),
|
||||
|
||||
// ------------------------------- Menu -------------------------------------------------------
|
||||
|
||||
MENU_NAME_IS_NOT_UNIQUE(Module.MENU, 1, "新增菜单:%s 失败,菜单名称已存在"),
|
||||
|
||||
MENU_EXTERNAL_LINK_MUST_BE_HTTP(Module.MENU, 2, "菜单外链必须以 http(s)://开头"),
|
||||
|
||||
MENU_PARENT_ID_NOT_ALLOW_SELF(Module.MENU, 3, "父级菜单不能选择自身"),
|
||||
|
||||
MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE(Module.MENU, 4, "存在子菜单不允许删除"),
|
||||
|
||||
MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE(Module.MENU, 5, "菜单已分配给角色,不允许"),
|
||||
|
||||
// -------------------------------- Role ----------------------------------------------------
|
||||
|
||||
ROLE_NAME_IS_NOT_UNIQUE(Module.ROLE, 1, "角色名称:%s, 已存在"),
|
||||
|
||||
ROLE_KEY_IS_NOT_UNIQUE(Module.ROLE, 2, "角色标识:%s, 已存在"),
|
||||
|
||||
ROLE_DATA_SCOPE_DUPLICATED_DEPT(Module.ROLE, 3, "重复的部门id"),
|
||||
|
||||
ROLE_ALREADY_ASSIGN_TO_USER(Module.ROLE, 4, "角色已分配给用户,请先取消分配,再删除角色"),
|
||||
|
||||
|
||||
// ------------------------ User ------------------------------
|
||||
|
||||
|
||||
USER_NON_EXIST(Module.USER, 1, "登录用户:%s 不存在"),
|
||||
|
||||
USER_IS_DISABLE(Module.USER, 2, "对不起, 您的账号:{} 已停用"),
|
||||
|
||||
USER_CACHE_IS_EXPIRE(Module.USER, 3, "用户缓存信息已经过期"),
|
||||
|
||||
USER_FAIL_TO_GET_USER_ID(Module.USER, 3, "获取用户ID失败"),
|
||||
|
||||
USER_FAIL_TO_GET_DEPT_ID(Module.USER, 4, "获取用户部门ID失败"),
|
||||
|
||||
USER_FAIL_TO_GET_ACCOUNT(Module.USER, 5, "获取用户账户失败"),
|
||||
|
||||
USER_FAIL_TO_GET_USER_INFO(Module.USER, 6, "获取用户信息失败"),
|
||||
|
||||
USER_IMPORT_DATA_IS_NULL(Module.USER, 7, "导入的用户为空"),
|
||||
|
||||
USER_PHONE_NUMBER_IS_NOT_UNIQUE(Module.USER, 8, "该电话号码已被其他用户占用"),
|
||||
|
||||
USER_EMAIL_IS_NOT_UNIQUE(Module.USER, 9, "该邮件地址已被其他用户占用"),
|
||||
|
||||
USER_PASSWORD_IS_NOT_CORRECT(Module.USER, 10, "用户密码错误"),
|
||||
|
||||
USER_NEW_PASSWORD_IS_THE_SAME_AS_OLD(Module.USER, 11, "用户新密码与旧密码相同"),
|
||||
|
||||
USER_UPLOAD_FILE_FAILED(Module.USER, 12, "用户上传文件失败"),
|
||||
|
||||
USER_NAME_IS_NOT_UNIQUE(Module.USER, 13, "用户名已被其他用户占用"),
|
||||
|
||||
USER_CURRENT_USER_CAN_NOT_BE_DELETE(Module.USER, 14, "当前用户不允许被删除"),
|
||||
|
||||
;
|
||||
|
||||
|
||||
private final int code;
|
||||
private final String msg;
|
||||
|
||||
private static final int BASE_CODE = 40000;
|
||||
|
||||
Business(Module module, int code, String msg) {
|
||||
this.code = BASE_CODE + module.code() + code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int code() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String message() {
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 30000~39999是外部错误码 比如调用支付失败
|
||||
*/
|
||||
public enum External implements ErrorCodeInterface {
|
||||
|
||||
/**
|
||||
* 支付宝调用失败
|
||||
*/
|
||||
FAIL_TO_PAY_ON_ALIPAY(Module.COMMON, 1,"支付宝调用失败");
|
||||
|
||||
|
||||
private final int code;
|
||||
private final String msg;
|
||||
|
||||
private static final int BASE_CODE = 30000;
|
||||
|
||||
External(Module module, int code, String msg) {
|
||||
this.code = BASE_CODE + module.code() + code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int code() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String message() { return this.msg; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 20000~29999是客户端错误码
|
||||
*/
|
||||
public enum Client implements ErrorCodeInterface {
|
||||
|
||||
|
||||
/**
|
||||
* 客户端错误码
|
||||
*/
|
||||
COMMON_FORBIDDEN_TO_CALL(Module.COMMON, 1,"禁止调用"),
|
||||
|
||||
COMMON_REQUEST_TO_OFTEN(Module.COMMON, 2, "调用太过频繁"),
|
||||
|
||||
COMMON_REQUEST_PARAMETERS_INVALID(Module.COMMON, 3, "请求参数异常,%s"),
|
||||
|
||||
COMMON_REQUEST_METHOD_INVALID(Module.COMMON, 4, "请求方式不支持"),
|
||||
|
||||
COMMON_NO_AUTHORIZATION(Module.PERMISSION, 1, "请求接口:%s 失败,用户未授权"),
|
||||
|
||||
;
|
||||
|
||||
|
||||
private final int code;
|
||||
private final String msg;
|
||||
|
||||
private static final int BASE_CODE = 20000;
|
||||
|
||||
Client(Module module, int code, String msg) {
|
||||
this.code = BASE_CODE + module.code() + code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int code() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String message() {
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 10000~19999是内部错误码 例如 框架有问题之类的
|
||||
*/
|
||||
public enum Internal implements ErrorCodeInterface {
|
||||
|
||||
/**
|
||||
* 内部错误码
|
||||
*/
|
||||
INVALID_PARAMETER(Module.COMMON, 1,"参数异常"),
|
||||
|
||||
UNKNOWN_ERROR(Module.COMMON, 2,"未知异常: %s"),
|
||||
|
||||
GET_ENUM_FAILED(Module.COMMON, 3,"获取枚举类型失败, 枚举类:%s"),
|
||||
|
||||
LOGIN_CAPTCHA_GENERATE_FAIL(Module.LOGIN, 1,"验证码生成失败"),
|
||||
|
||||
INVALID_TOKEN(Module.PERMISSION, 1,"token异常"),
|
||||
|
||||
DB_INTERNAL_ERROR(Module.DB, 1, "数据库异常:%s"),
|
||||
|
||||
;
|
||||
|
||||
|
||||
private final int code;
|
||||
private final String msg;
|
||||
|
||||
private static final int BASE_CODE = 10000;
|
||||
|
||||
Internal(Module module, int code, String msg) {
|
||||
this.code = BASE_CODE + module.code() + code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int code() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String message() {
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.agileboot.common.exception.error;
|
||||
|
||||
public interface ErrorCodeInterface {
|
||||
|
||||
String name();
|
||||
|
||||
int code();
|
||||
|
||||
String message();
|
||||
|
||||
default String i18n() {
|
||||
return code() + "_" + name();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.agileboot.common.exception.error;
|
||||
|
||||
/**
|
||||
* 系统内的模块
|
||||
*/
|
||||
public enum Module {
|
||||
|
||||
/**
|
||||
* 普通模块
|
||||
*/
|
||||
COMMON(0),
|
||||
|
||||
/**
|
||||
* 权限模块
|
||||
*/
|
||||
PERMISSION(1),
|
||||
|
||||
LOGIN(2),
|
||||
|
||||
DB(3),
|
||||
|
||||
UPLOAD(4),
|
||||
|
||||
USER(5),
|
||||
|
||||
CONFIG(6),
|
||||
|
||||
POST(7),
|
||||
|
||||
DEPT(8),
|
||||
|
||||
MENU(9),
|
||||
|
||||
ROLE(10),
|
||||
|
||||
|
||||
;
|
||||
|
||||
|
||||
private final int code;
|
||||
|
||||
Module(int code) { this.code = code * 100; }
|
||||
|
||||
public int code() {return code; }
|
||||
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package com.agileboot.common.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* 客户端工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class ServletHolderUtil {
|
||||
|
||||
/**
|
||||
* 获取request
|
||||
*/
|
||||
public static HttpServletRequest getRequest() {
|
||||
return getRequestAttributes().getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取response
|
||||
*/
|
||||
public static HttpServletResponse getResponse() {
|
||||
return getRequestAttributes().getResponse();
|
||||
}
|
||||
|
||||
|
||||
public static ServletRequestAttributes getRequestAttributes() {
|
||||
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
|
||||
return (ServletRequestAttributes) attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串渲染到客户端
|
||||
*
|
||||
* @param response 渲染对象
|
||||
* @param string 待渲染的字符串
|
||||
*/
|
||||
public static void renderString(HttpServletResponse response, String string) {
|
||||
try {
|
||||
response.setStatus(200);
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
response.getWriter().print(string);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取仅含有项目根路径的url
|
||||
* 比如 localhost:8080/agileboot/user/list
|
||||
* 返回 localhost:8080/agileboot
|
||||
* @return
|
||||
*/
|
||||
public static String getContextUrl() {
|
||||
HttpServletRequest request = getRequest();
|
||||
StringBuffer url = request.getRequestURL();
|
||||
String contextPath = request.getServletContext().getContextPath();
|
||||
String strip = StrUtil.strip(url, null, request.getRequestURI());
|
||||
return strip + contextPath;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,216 @@
|
||||
package com.agileboot.common.utils.file;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.file.FileNameUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import com.agileboot.common.config.AgileBootConfig;
|
||||
import com.agileboot.common.constant.Constants;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 文件上传工具类
|
||||
*
|
||||
* @author ruoyi 待改进
|
||||
*/
|
||||
public class FileUploadUtils {
|
||||
|
||||
/**
|
||||
* 默认大小 50M
|
||||
*/
|
||||
public static final long MAX_FILE_SIZE = 50 * Constants.MB;
|
||||
|
||||
/**
|
||||
* 默认的文件名最大长度 100
|
||||
*/
|
||||
public static final int MAX_FILE_NAME_LENGTH = 100;
|
||||
|
||||
public static final String[] ALLOWED_DOWNLOAD_EXTENSIONS = {
|
||||
// 图片
|
||||
"bmp", "gif", "jpg", "jpeg", "png",
|
||||
// word excel powerpoint
|
||||
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
|
||||
// 压缩文件
|
||||
"rar", "zip", "gz", "bz2",
|
||||
// 视频格式
|
||||
"mp4", "avi", "rmvb",
|
||||
// pdf
|
||||
"pdf"};
|
||||
|
||||
/**
|
||||
* 默认上传的地址
|
||||
*/
|
||||
private static String defaultBaseDir = AgileBootConfig.getProfile();
|
||||
|
||||
|
||||
public static String getDefaultBaseDir() {
|
||||
return defaultBaseDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以默认配置进行文件上传
|
||||
*
|
||||
* @param file 上传的文件
|
||||
* @return 文件名称
|
||||
*/
|
||||
public static String upload(MultipartFile file) throws IOException {
|
||||
try {
|
||||
return upload(getDefaultBaseDir(), file, ALLOWED_DOWNLOAD_EXTENSIONS);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件路径上传
|
||||
*
|
||||
* @param baseDir 相对应用的基目录
|
||||
* @param file 上传的文件
|
||||
* @return 文件名称
|
||||
*/
|
||||
public static String upload(String baseDir, MultipartFile file) throws IOException {
|
||||
try {
|
||||
return upload(baseDir, file, ALLOWED_DOWNLOAD_EXTENSIONS);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param baseDir 相对应用的基目录
|
||||
* @param file 上传的文件
|
||||
* @param allowedExtension 上传文件类型
|
||||
* @return 返回上传成功的文件名
|
||||
* @throws IOException 比如读写文件出错时
|
||||
*/
|
||||
public static String upload(String baseDir, MultipartFile file, String[] allowedExtension)
|
||||
throws IOException {
|
||||
|
||||
int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length();
|
||||
if (fileNameLength > FileUploadUtils.MAX_FILE_NAME_LENGTH) {
|
||||
throw new ApiException(ErrorCode.Business.UPLOAD_FILE_NAME_EXCEED_MAX_LENGTH, MAX_FILE_NAME_LENGTH);
|
||||
}
|
||||
|
||||
assertAllowed(file, allowedExtension);
|
||||
|
||||
String fileName = generateFilename(file);
|
||||
|
||||
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
|
||||
file.transferTo(Paths.get(absPath));
|
||||
return getPathFileName(baseDir, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码文件名
|
||||
*/
|
||||
public static String generateFilename(MultipartFile file) {
|
||||
return StrUtil.format("{}_{}_{}.{}", DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN),
|
||||
FilenameUtils.getBaseName(file.getOriginalFilename()), IdUtil.simpleUUID(), getExtension(file));
|
||||
}
|
||||
|
||||
public static File getAbsoluteFile(String uploadDir, String fileName) {
|
||||
File desc = new File(uploadDir + File.separator + fileName);
|
||||
if (!desc.exists()) {
|
||||
if (!desc.getParentFile().exists()) {
|
||||
desc.getParentFile().mkdirs();
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
public static String getPathFileName(String uploadDir, String fileName) {
|
||||
String currentDir = StrUtil.strip(uploadDir, AgileBootConfig.getProfile() + "/");
|
||||
return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件大小校验
|
||||
*
|
||||
* @param file 上传的文件
|
||||
*/
|
||||
public static void assertAllowed(MultipartFile file, String[] allowedExtension) {
|
||||
long size = file.getSize();
|
||||
if (size > MAX_FILE_SIZE) {
|
||||
throw new ApiException(ErrorCode.Business.UPLOAD_FILE_SIZE_EXCEED_MAX_SIZE, MAX_FILE_SIZE / Constants.MB);
|
||||
}
|
||||
|
||||
String extension = getExtension(file);
|
||||
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
|
||||
throw new ApiException(ErrorCode.Business.UPLOAD_FILE_TYPE_NOT_ALLOWED,
|
||||
StrUtil.join(",", (Object[]) allowedExtension));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断MIME类型是否是允许的MIME类型
|
||||
*/
|
||||
public static boolean isAllowedExtension(String extension, String[] allowedExtension) {
|
||||
return StrUtil.containsAnyIgnoreCase(extension, allowedExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名的后缀
|
||||
*
|
||||
* @param file 表单文件
|
||||
* @return 后缀名
|
||||
*/
|
||||
public static String getExtension(MultipartFile file) {
|
||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
||||
if (StrUtil.isEmpty(extension)) {
|
||||
MimeType mimeType = MimeTypeUtils.parseMimeType(Objects.requireNonNull(file.getContentType()));
|
||||
extension = mimeType.getSubtype();
|
||||
}
|
||||
return extension;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查文件是否可下载
|
||||
*
|
||||
* @param resource 需要下载的文件
|
||||
* @return true 正常 false 非法
|
||||
*/
|
||||
public static boolean isAllowDownload(String resource) {
|
||||
// 禁止目录上跳级别
|
||||
return !StrUtil.contains(resource, "..") &&
|
||||
// 检查允许下载的文件规则
|
||||
StrUtil.containsAnyIgnoreCase(FileNameUtil.getSuffix(resource), ALLOWED_DOWNLOAD_EXTENSIONS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下载文件名重新编码
|
||||
*
|
||||
* @param response 响应对象
|
||||
* @param realFileName 真实文件名
|
||||
*/
|
||||
public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) {
|
||||
String fileNameUrlEncoded = URLUtil.encode(realFileName, CharsetUtil.CHARSET_UTF_8);
|
||||
|
||||
String contentDisposition = String.format("attachment; filename=%s;filename*=utf-8''%s", fileNameUrlEncoded,
|
||||
fileNameUrlEncoded);
|
||||
|
||||
response.addHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "Content-Disposition,download-filename");
|
||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, contentDisposition);
|
||||
response.setHeader("download-filename", fileNameUrlEncoded);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.agileboot.common.utils.i18n;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
/**
|
||||
* 获取i18n资源文件
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class MessageUtils {
|
||||
|
||||
/**
|
||||
* 根据消息键和参数 获取消息 委托给spring messageSource
|
||||
*
|
||||
* @param code 消息键
|
||||
* @param args 参数
|
||||
* @return 获取国际化翻译值
|
||||
*/
|
||||
public static String message(String code, Object... args) {
|
||||
MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
|
||||
return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.agileboot.common.utils.ip;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@ToString
|
||||
public class IpRegion {
|
||||
private static final String UNKNOWN = "未知";
|
||||
private String country;
|
||||
private String region;
|
||||
private String province;
|
||||
private String city;
|
||||
private String isp;
|
||||
|
||||
public IpRegion(String province, String city) {
|
||||
this.province = province;
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String briefLocation() {
|
||||
return String.format("%s %s",
|
||||
CharSequenceUtil.nullToDefault(province, UNKNOWN),
|
||||
CharSequenceUtil.nullToDefault(city, UNKNOWN));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.agileboot.common.utils.ip;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
public class IpRegionUtil {
|
||||
|
||||
public static IpRegion getIpRegion(String ip) {
|
||||
IpRegion ipRegionOffline = OfflineIpRegionUtil.getIpRegion(ip);
|
||||
if (ipRegionOffline != null) {
|
||||
return ipRegionOffline;
|
||||
}
|
||||
|
||||
IpRegion ipRegionOnline = OnlineIpRegionUtil.getIpRegion(ip);
|
||||
if (ipRegionOnline != null) {
|
||||
return ipRegionOnline;
|
||||
}
|
||||
|
||||
return new IpRegion();
|
||||
}
|
||||
|
||||
public static String getBriefLocationByIp(String ip) {
|
||||
return getIpRegion(ip).briefLocation();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.agileboot.common.utils.ip;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.lionsoul.ip2region.xdb.Searcher;
|
||||
|
||||
@Slf4j
|
||||
public class OfflineIpRegionUtil {
|
||||
|
||||
private static Searcher searcher;
|
||||
|
||||
static {
|
||||
InputStream resourceAsStream = OfflineIpRegionUtil.class.getResourceAsStream("/ip2region.xdb");
|
||||
|
||||
byte[] bytes = null;
|
||||
try {
|
||||
bytes = new byte[resourceAsStream.available()];
|
||||
IOUtils.read(resourceAsStream, bytes);
|
||||
} catch (IOException e) {
|
||||
log.error("读取本地Ip文件失败", e);
|
||||
}
|
||||
|
||||
try {
|
||||
searcher = Searcher.newWithBuffer(bytes);
|
||||
} catch (Exception e) {
|
||||
log.error("构建本地Ip缓存失败", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static IpRegion getIpRegion(String ip) {
|
||||
try {
|
||||
|
||||
String rawRegion = searcher.search(ip);
|
||||
if (StrUtil.isNotEmpty(rawRegion)) {
|
||||
String[] split = rawRegion.split("\\|");
|
||||
return new IpRegion(split[0], split[1], split[2], split[3], split[4]);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.agileboot.common.utils.ip;
|
||||
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.agileboot.common.config.AgileBootConfig;
|
||||
import com.agileboot.common.utils.jackson.JacksonUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* query geography address from ip
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Slf4j
|
||||
public class OnlineIpRegionUtil {
|
||||
|
||||
/**
|
||||
* website for query geography address from ip
|
||||
*/
|
||||
public static final String ADDRESS_QUERY_SITE = "http://whois.pconline.com.cn/ipJson.jsp";
|
||||
|
||||
|
||||
public static IpRegion getIpRegion(String ip) {
|
||||
// no need to query address for inner ip
|
||||
if (NetUtil.isInnerIP(ip)) {
|
||||
return new IpRegion("internal", "IP");
|
||||
}
|
||||
if (AgileBootConfig.isAddressEnabled()) {
|
||||
try {
|
||||
String rspStr = HttpUtil.get(ADDRESS_QUERY_SITE + "ip=" + ip + "&json=true",
|
||||
CharsetUtil.CHARSET_GBK);
|
||||
if (StrUtil.isEmpty(rspStr)) {
|
||||
log.error("获取地理位置异常 {}", ip);
|
||||
return null;
|
||||
}
|
||||
|
||||
String province = JacksonUtil.getAsString(rspStr, "pro");
|
||||
String city = JacksonUtil.getAsString(rspStr, "city");
|
||||
return new IpRegion(province, city);
|
||||
} catch (Exception e) {
|
||||
log.error("获取地理位置异常 {}", ip);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.agileboot.common.utils.jackson;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
public class JacksonException extends RuntimeException {
|
||||
public JacksonException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public JacksonException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JacksonException(String message, Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
|
||||
public JacksonException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,679 @@
|
||||
package com.agileboot.common.utils.jackson;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.json.JsonReadFeature;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.fasterxml.jackson.databind.type.CollectionType;
|
||||
import com.fasterxml.jackson.databind.type.MapType;
|
||||
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URL;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* Jackson工具类 优势: 数据量高于百万的时候,速度和FastJson相差极小 API和注解支持最完善,可定制性最强
|
||||
* 支持的数据源最广泛(字符串,对象,文件、流、URL)
|
||||
* @author valarchie
|
||||
*/
|
||||
@Slf4j
|
||||
public class JacksonUtil {
|
||||
|
||||
private static ObjectMapper mapper;
|
||||
|
||||
private static final Set<JsonReadFeature> JSON_READ_FEATURES_ENABLED = CollUtil.newHashSet(
|
||||
//允许在JSON中使用Java注释
|
||||
JsonReadFeature.ALLOW_JAVA_COMMENTS,
|
||||
//允许 json 存在没用双引号括起来的 field
|
||||
JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES,
|
||||
//允许 json 存在使用单引号括起来的 field
|
||||
JsonReadFeature.ALLOW_SINGLE_QUOTES,
|
||||
//允许 json 存在没用引号括起来的 ascii 控制字符
|
||||
JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS,
|
||||
//允许 json number 类型的数存在前导 0 (例: 0001)
|
||||
JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS,
|
||||
//允许 json 存在 NaN, INF, -INF 作为 number 类型
|
||||
JsonReadFeature.ALLOW_NON_NUMERIC_NUMBERS,
|
||||
//允许 只有Key没有Value的情况
|
||||
JsonReadFeature.ALLOW_MISSING_VALUES,
|
||||
//允许数组json的结尾多逗号
|
||||
JsonReadFeature.ALLOW_TRAILING_COMMA
|
||||
);
|
||||
|
||||
static {
|
||||
try {
|
||||
//初始化
|
||||
mapper = initMapper();
|
||||
} catch (Exception e) {
|
||||
log.error("jackson config error", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static ObjectMapper initMapper() {
|
||||
JsonMapper.Builder builder = JsonMapper.builder()
|
||||
.enable(JSON_READ_FEATURES_ENABLED.toArray(new JsonReadFeature[0]));
|
||||
return initMapperConfig(builder.build());
|
||||
}
|
||||
|
||||
public static ObjectMapper initMapperConfig(ObjectMapper objectMapper) {
|
||||
String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
|
||||
objectMapper.setDateFormat(new SimpleDateFormat(dateTimeFormat));
|
||||
//配置序列化级别
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
//配置JSON缩进支持
|
||||
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, false);
|
||||
//允许单个数值当做数组处理
|
||||
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
|
||||
//禁止重复键, 抛出异常
|
||||
objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
|
||||
//禁止使用int代表Enum的order()來反序列化Enum, 抛出异常
|
||||
objectMapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);
|
||||
//有属性不能映射的时候不报错
|
||||
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
//对象为空时不抛异常
|
||||
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
|
||||
//时间格式
|
||||
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
//允许未知字段
|
||||
objectMapper.enable(JsonGenerator.Feature.IGNORE_UNKNOWN);
|
||||
//序列化BigDecimal时之间输出原始数字还是科学计数, 默认false, 即是否以toPlainString()科学计数方式来输出
|
||||
objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
|
||||
//识别Java8时间
|
||||
objectMapper.registerModule(new ParameterNamesModule());
|
||||
objectMapper.registerModule(new Jdk8Module());
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
javaTimeModule.addSerializer(LocalDateTime.class,
|
||||
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat)))
|
||||
.addDeserializer(LocalDateTime.class,
|
||||
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
|
||||
objectMapper.registerModule(javaTimeModule);
|
||||
// if we use guava, we can add this line of code: objectMapper.registerModule(new GuavaModule())
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
public static ObjectMapper getObjectMapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化
|
||||
*/
|
||||
public static <V> V from(URL url, Class<V> type) {
|
||||
try {
|
||||
return mapper.readValue(url, type);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson from error, url: {}, type: {}", url.getPath(), type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化
|
||||
*/
|
||||
public static <V> V from(URL url, TypeReference<V> type) {
|
||||
try {
|
||||
return mapper.readValue(url, type);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson from error, url: {}, type: {}", url.getPath(), type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化(List)
|
||||
*/
|
||||
public static <V> List<V> fromList(URL url, Class<V> type) {
|
||||
try {
|
||||
CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, type);
|
||||
return mapper.readValue(url, collectionType);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson from error, url: {}, type: {}", url.getPath(), type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化
|
||||
*/
|
||||
public static <V> V from(InputStream inputStream, Class<V> type) {
|
||||
try {
|
||||
return mapper.readValue(inputStream, type);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson from error, type: {}", type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化
|
||||
*/
|
||||
public static <V> V from(InputStream inputStream, TypeReference<V> type) {
|
||||
try {
|
||||
return mapper.readValue(inputStream, type);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson from error, type: {}", type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化(List)
|
||||
*/
|
||||
public static <V> List<V> fromList(InputStream inputStream, Class<V> type) {
|
||||
try {
|
||||
CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, type);
|
||||
return mapper.readValue(inputStream, collectionType);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson from error, type: {}", type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化
|
||||
*/
|
||||
public static <V> V from(File file, Class<V> type) {
|
||||
try {
|
||||
return mapper.readValue(file, type);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(
|
||||
StrUtil.format("jackson from error, file path: {}, type: {}", file.getPath(), type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化
|
||||
*/
|
||||
public static <V> V from(File file, TypeReference<V> type) {
|
||||
try {
|
||||
return mapper.readValue(file, type);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(
|
||||
StrUtil.format("jackson from error, file path: {}, type: {}", file.getPath(), type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化(List)
|
||||
*/
|
||||
public static <V> List<V> fromList(File file, Class<V> type) {
|
||||
try {
|
||||
CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, type);
|
||||
return mapper.readValue(file, collectionType);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(
|
||||
StrUtil.format("jackson from error, file path: {}, type: {}", file.getPath(), type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化
|
||||
*/
|
||||
public static <V> V from(String json, Class<V> type) {
|
||||
return from(json, (Type) type);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化
|
||||
*/
|
||||
public static <V> V from(String json, TypeReference<V> type) {
|
||||
return from(json, type.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化
|
||||
*/
|
||||
public static <V> V from(String json, Type type) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JavaType javaType = mapper.getTypeFactory().constructType(type);
|
||||
return mapper.readValue(json, javaType);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson from error, json: {}, type: {}", json, type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化(List)
|
||||
*/
|
||||
public static <V> List<V> fromList(String json, Class<V> type) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, type);
|
||||
return mapper.readValue(json, collectionType);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson from error, json: {}, type: {}", json, type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON反序列化(Map)
|
||||
*/
|
||||
public static Map<String, Object> fromMap(String json) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
MapType mapType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class);
|
||||
return mapper.readValue(json, mapType);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson from error, json: {}, type: {}", json), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化为JSON
|
||||
*/
|
||||
public static <V> String to(List<V> list) {
|
||||
try {
|
||||
return mapper.writeValueAsString(list);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson to error, data: {}", list), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化为JSON
|
||||
*/
|
||||
public static <V> String to(V v) {
|
||||
try {
|
||||
return mapper.writeValueAsString(v);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson to error, data: {}", v), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化为JSON
|
||||
*/
|
||||
public static <V> void toFile(String path, List<V> list) {
|
||||
try (Writer writer = new FileWriter(new File(path), true)) {
|
||||
mapper.writer().writeValues(writer).writeAll(list);
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(StrUtil.format("jackson to file error, path: {}, list: {}", path, list), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化为JSON
|
||||
*/
|
||||
public static <V> void toFile(String path, V v) {
|
||||
try (Writer writer = new FileWriter(new File(path), true)) {
|
||||
mapper.writer().writeValues(writer).write(v);
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(StrUtil.format("jackson to file error, path: {}, data: {}", path, v), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return String,默认为 null
|
||||
*/
|
||||
public static String getAsString(String json, String key) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = getAsJsonObject(json, key);
|
||||
if (null == jsonNode) {
|
||||
return null;
|
||||
}
|
||||
return getAsString(jsonNode);
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(StrUtil.format("jackson get string error, json: {}, key: {}", json, key), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getAsString(JsonNode jsonNode) {
|
||||
return jsonNode.isTextual() ? jsonNode.textValue() : jsonNode.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return int,默认为 0
|
||||
*/
|
||||
public static int getAsInt(String json, String key) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = getAsJsonObject(json, key);
|
||||
if (null == jsonNode) {
|
||||
return 0;
|
||||
}
|
||||
return jsonNode.isInt() ? jsonNode.intValue() : Integer.parseInt(getAsString(jsonNode));
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(StrUtil.format("jackson get int error, json: {}, key: {}", json, key), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return long,默认为 0
|
||||
*/
|
||||
public static long getAsLong(String json, String key) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return 0L;
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = getAsJsonObject(json, key);
|
||||
if (null == jsonNode) {
|
||||
return 0L;
|
||||
}
|
||||
return jsonNode.isLong() ? jsonNode.longValue() : Long.parseLong(getAsString(jsonNode));
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(StrUtil.format("jackson get long error, json: {}, key: {}", json, key), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return double,默认为 0.0
|
||||
*/
|
||||
public static double getAsDouble(String json, String key) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return 0.0;
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = getAsJsonObject(json, key);
|
||||
if (null == jsonNode) {
|
||||
return 0.0;
|
||||
}
|
||||
return jsonNode.isDouble() ? jsonNode.doubleValue() : Double.parseDouble(getAsString(jsonNode));
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(StrUtil.format("jackson get double error, json: {}, key: {}", json, key), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return BigInteger,默认为 0.0
|
||||
*/
|
||||
public static BigInteger getAsBigInteger(String json, String key) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return new BigInteger(String.valueOf(0.00));
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = getAsJsonObject(json, key);
|
||||
if (null == jsonNode) {
|
||||
return new BigInteger(String.valueOf(0.00));
|
||||
}
|
||||
return jsonNode.isBigInteger() ? jsonNode.bigIntegerValue() : new BigInteger(getAsString(jsonNode));
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(StrUtil.format("jackson get big integer error, json: {}, key: {}", json, key),
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return BigDecimal,默认为 0.00
|
||||
*/
|
||||
public static BigDecimal getAsBigDecimal(String json, String key) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return new BigDecimal("0.00");
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = getAsJsonObject(json, key);
|
||||
if (null == jsonNode) {
|
||||
return new BigDecimal("0.00");
|
||||
}
|
||||
return jsonNode.isBigDecimal() ? jsonNode.decimalValue() : new BigDecimal(getAsString(jsonNode));
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(StrUtil.format("jackson get big decimal error, json: {}, key: {}", json, key),
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return boolean, 默认为false
|
||||
*/
|
||||
public static boolean getAsBoolean(String json, String key) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = getAsJsonObject(json, key);
|
||||
if (null == jsonNode) {
|
||||
return false;
|
||||
}
|
||||
if (jsonNode.isBoolean()) {
|
||||
return jsonNode.booleanValue();
|
||||
} else {
|
||||
if (jsonNode.isTextual()) {
|
||||
String textValue = jsonNode.textValue();
|
||||
return Convert.toBool(textValue);
|
||||
} else {//number
|
||||
return BooleanUtils.toBoolean(jsonNode.intValue());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(StrUtil.format("jackson get boolean error, json: {}, key: {}", json, key), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return byte[], 默认为 null
|
||||
*/
|
||||
public static byte[] getAsBytes(String json, String key) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = getAsJsonObject(json, key);
|
||||
if (null == jsonNode) {
|
||||
return null;
|
||||
}
|
||||
return jsonNode.isBinary() ? jsonNode.binaryValue() : getAsString(jsonNode).getBytes();
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(StrUtil.format("jackson get byte error, json: {}, key: {}", json, key), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return object, 默认为 null
|
||||
*/
|
||||
public static <V> V getAsObject(String json, String key, Class<V> type) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = getAsJsonObject(json, key);
|
||||
if (null == jsonNode) {
|
||||
return null;
|
||||
}
|
||||
JavaType javaType = mapper.getTypeFactory().constructType(type);
|
||||
return from(getAsString(jsonNode), javaType);
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(
|
||||
StrUtil.format("jackson get list error, json: {}, key: {}, type: {}", json, key, type), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return list, 默认为 null
|
||||
*/
|
||||
public static <V> List<V> getAsList(String json, String key, Class<V> type) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = getAsJsonObject(json, key);
|
||||
if (null == jsonNode) {
|
||||
return null;
|
||||
}
|
||||
CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, type);
|
||||
return from(getAsString(jsonNode), collectionType);
|
||||
} catch (Exception e) {
|
||||
throw new JacksonException(
|
||||
StrUtil.format("jackson get list error, json: {}, key: {}, type: {}", json, key, type), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json串中获取某个字段
|
||||
*
|
||||
* @return JsonNode, 默认为 null
|
||||
*/
|
||||
public static JsonNode getAsJsonObject(String json, String key) {
|
||||
try {
|
||||
JsonNode node = mapper.readTree(json);
|
||||
if (null == node) {
|
||||
return null;
|
||||
}
|
||||
return node.get(key);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(
|
||||
StrUtil.format("jackson get object from json error, json: {}, key: {}", json, key), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向json中添加属性
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
public static <V> String add(String json, String key, V value) {
|
||||
try {
|
||||
JsonNode node = mapper.readTree(json);
|
||||
add(node, key, value);
|
||||
return node.toString();
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(
|
||||
StrUtil.format("jackson add error, json: {}, key: {}, value: {}", json, key, value), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向json中添加属性
|
||||
*/
|
||||
private static <V> void add(JsonNode jsonNode, String key, V value) {
|
||||
if (value instanceof String) {
|
||||
((ObjectNode) jsonNode).put(key, (String) value);
|
||||
} else if (value instanceof Short) {
|
||||
((ObjectNode) jsonNode).put(key, (Short) value);
|
||||
} else if (value instanceof Integer) {
|
||||
((ObjectNode) jsonNode).put(key, (Integer) value);
|
||||
} else if (value instanceof Long) {
|
||||
((ObjectNode) jsonNode).put(key, (Long) value);
|
||||
} else if (value instanceof Float) {
|
||||
((ObjectNode) jsonNode).put(key, (Float) value);
|
||||
} else if (value instanceof Double) {
|
||||
((ObjectNode) jsonNode).put(key, (Double) value);
|
||||
} else if (value instanceof BigDecimal) {
|
||||
((ObjectNode) jsonNode).put(key, (BigDecimal) value);
|
||||
} else if (value instanceof BigInteger) {
|
||||
((ObjectNode) jsonNode).put(key, (BigInteger) value);
|
||||
} else if (value instanceof Boolean) {
|
||||
((ObjectNode) jsonNode).put(key, (Boolean) value);
|
||||
} else if (value instanceof byte[]) {
|
||||
((ObjectNode) jsonNode).put(key, (byte[]) value);
|
||||
} else {
|
||||
((ObjectNode) jsonNode).put(key, to(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 除去json中的某个属性
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
public static String remove(String json, String key) {
|
||||
try {
|
||||
JsonNode node = mapper.readTree(json);
|
||||
((ObjectNode) node).remove(key);
|
||||
return node.toString();
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson remove error, json: {}, key: {}", json, key), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改json中的属性
|
||||
*/
|
||||
public static <V> String update(String json, String key, V value) {
|
||||
try {
|
||||
JsonNode node = mapper.readTree(json);
|
||||
((ObjectNode) node).remove(key);
|
||||
add(node, key, value);
|
||||
return node.toString();
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(
|
||||
StrUtil.format("jackson update error, json: {}, key: {}, value: {}", json, key, value), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化Json(美化)
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
public static String format(String json) {
|
||||
try {
|
||||
JsonNode node = mapper.readTree(json);
|
||||
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
|
||||
} catch (IOException e) {
|
||||
throw new JacksonException(StrUtil.format("jackson format json error, json: {}", json), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否是json
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
public static boolean isJson(String json) {
|
||||
try {
|
||||
mapper.readTree(json);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
package com.agileboot.common.utils.poi;
|
||||
|
||||
import cn.hutool.poi.excel.ExcelReader;
|
||||
import cn.hutool.poi.excel.ExcelUtil;
|
||||
import cn.hutool.poi.excel.ExcelWriter;
|
||||
import com.agileboot.common.annotation.ExcelColumn;
|
||||
import com.agileboot.common.annotation.ExcelSheet;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
public class CustomExcelUtil {
|
||||
|
||||
|
||||
public static void writeToResponse(List<?> list, Class clazz, HttpServletResponse response) {
|
||||
|
||||
// 通过工具类创建writer
|
||||
ExcelWriter writer = ExcelUtil.getWriter();
|
||||
|
||||
ExcelSheet sheetAnno = (ExcelSheet)clazz.getAnnotation(ExcelSheet.class);
|
||||
|
||||
if (sheetAnno != null) {
|
||||
// 默认的sheetName是 sheet1
|
||||
writer.renameSheet(sheetAnno.name());
|
||||
}
|
||||
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
|
||||
//自定义标题别名
|
||||
for (Field field : fields) {
|
||||
ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
|
||||
if (annotation != null) {
|
||||
writer.addHeaderAlias(field.getName(), annotation.name());
|
||||
}
|
||||
}
|
||||
|
||||
// 默认的,未添加alias的属性也会写出,如果想只写出加了别名的字段,可以调用此方法排除之
|
||||
writer.setOnlyAlias(true);
|
||||
|
||||
// 合并单元格后的标题行,使用默认标题样式
|
||||
// writer.merge(4, "一班成绩单");
|
||||
// 一次性写出内容,使用默认样式,强制输出标题
|
||||
writer.write(list, true);
|
||||
|
||||
try {
|
||||
writer.flush(response.getOutputStream(), true);
|
||||
} catch (IOException e) {
|
||||
writer.close();
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static List<?> readFromResponse(Class clazz, MultipartFile file) {
|
||||
|
||||
ExcelReader reader = null;
|
||||
try {
|
||||
reader = ExcelUtil.getReader(file.getInputStream());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
|
||||
//自定义标题别名
|
||||
if (fields != null) {
|
||||
for (Field field : fields) {
|
||||
ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
|
||||
if (annotation != null) {
|
||||
reader.addHeaderAlias(annotation.name(), field.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reader.read(0, 1, clazz);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.agileboot.common.utils.time;
|
||||
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import java.util.Date;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Slf4j
|
||||
public class DatePicker {
|
||||
|
||||
public static Date getBeginOfTheDay(Object date) {
|
||||
if (date == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
DateTime parse = DateUtil.parse(date.toString());
|
||||
return DateUtil.beginOfDay(parse);
|
||||
} catch (Exception e) {
|
||||
log.error("pick begin of day failed, due to: ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Date getEndOfTheDay(Object date) {
|
||||
if (date == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
DateTime parse = DateUtil.parse(date.toString());
|
||||
return DateUtil.endOfDay(parse);
|
||||
} catch (Exception e) {
|
||||
log.error("pick end of day failed, due to: ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
BIN
agileboot-common/src/main/resources/ip2region.xdb
Normal file
BIN
agileboot-common/src/main/resources/ip2region.xdb
Normal file
Binary file not shown.
@ -0,0 +1,24 @@
|
||||
package com.agileboot.common.core.exception;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ApiExceptionTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testVarargsWithArrayArgs() {
|
||||
String errorMsg = "these parameters are null: %s, %s, %s.";
|
||||
|
||||
Object[] array = new Object[] { "param1" , "param2" , "param3"};
|
||||
|
||||
String format1 = String.format(errorMsg, array);
|
||||
String format2 = String.format(errorMsg, "param1", "param2", "param3");
|
||||
|
||||
System.out.println(format1);
|
||||
System.out.println(format2);
|
||||
|
||||
Assert.assertEquals(format1, format2);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.agileboot.common.utils;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.agileboot.common.utils.jackson.JacksonUtil;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author duanxinyuan 2019/1/21 18:17
|
||||
*/
|
||||
public class JacksonUtilTest {
|
||||
|
||||
@Test
|
||||
public void testObjectToJson() {
|
||||
Person person = Person.newPerson();
|
||||
|
||||
String jacksonStr = JacksonUtil.to(person);
|
||||
Assert.assertEquals(DateUtil.formatDateTime(person.getDate()), JacksonUtil.getAsString(jacksonStr, "date"));
|
||||
Assert.assertEquals(DateUtil.formatLocalDateTime(person.getLocalDateTime()),
|
||||
JacksonUtil.getAsString(jacksonStr, "localDateTime"));
|
||||
Assert.assertEquals(person.getName(), JacksonUtil.getAsString(jacksonStr, "name"));
|
||||
Assert.assertEquals(person.getAge(), JacksonUtil.getAsInt(jacksonStr, "age"));
|
||||
Assert.assertEquals(person.isMan(), JacksonUtil.getAsBoolean(jacksonStr, "man"));
|
||||
Assert.assertEquals(person.getMoney(), JacksonUtil.getAsBigDecimal(jacksonStr, "money"));
|
||||
Assert.assertEquals(person.getTrait(), JacksonUtil.getAsList(jacksonStr, "trait", String.class));
|
||||
|
||||
Assert.assertNotNull(JacksonUtil.getAsString(jacksonStr, "name"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试兼容情况
|
||||
*/
|
||||
@Test
|
||||
public void testAllPrimitiveTypeToJson() {
|
||||
String json = "{\n"
|
||||
+ "\"code\": \"200\",\n"
|
||||
+ "\"id\": \"2001215464647687987\",\n"
|
||||
+ "\"message\": \"success\",\n"
|
||||
+ "\"amount\": \"1.12345\",\n"
|
||||
+ "\"amount1\": \"0.12345\",\n"
|
||||
+ "\"isSuccess\": \"true\",\n"
|
||||
+ "\"isSuccess1\": \"1\",\n"
|
||||
+ "\"key\": \"8209167202090377654857374178856064487200234961995543450245362822537162918731039965956758726661669012305745755921310000297396309887550627402157318910581311\"\n"
|
||||
+ "}";
|
||||
Assert.assertEquals(200, JacksonUtil.getAsInt(json, "code"));
|
||||
Assert.assertEquals(2001215464647687987L,JacksonUtil.getAsLong(json, "id"));
|
||||
Assert.assertEquals("success", JacksonUtil.getAsString(json, "message"));
|
||||
Assert.assertEquals(new BigDecimal("1.12345"), JacksonUtil.getAsBigDecimal(json, "amount"));
|
||||
Assert.assertEquals(new BigDecimal("0.12345"), JacksonUtil.getAsBigDecimal(json, "amount1"));
|
||||
Assert.assertEquals(1.12345d, JacksonUtil.getAsDouble(json, "amount"), 0.00001);
|
||||
Assert.assertEquals(0.12345d, JacksonUtil.getAsDouble(json, "amount1"), 0.00001);
|
||||
Assert.assertEquals(true, JacksonUtil.getAsBoolean(json, "isSuccess"));
|
||||
Assert.assertEquals(true, JacksonUtil.getAsBoolean(json, "isSuccess1"));
|
||||
Assert.assertEquals(new BigInteger(
|
||||
"8209167202090377654857374178856064487200234961995543450245362822537162918731039965956758726661669012305745755921310000297396309887550627402157318910581311"),
|
||||
JacksonUtil.getAsBigInteger(json, "key"));
|
||||
Assert.assertEquals("1", JacksonUtil.getAsString(json, "isSuccess1"));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.agileboot.common.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author duanxinyuan
|
||||
* 2018/6/29 14:17
|
||||
*/
|
||||
@Data
|
||||
public class Person {
|
||||
public String name;
|
||||
public Date date;
|
||||
public LocalDateTime localDateTime;
|
||||
public int age;
|
||||
public BigDecimal money;
|
||||
public boolean man;
|
||||
public ArrayList<String> trait;
|
||||
public HashMap<String, String> cards;
|
||||
|
||||
public static Person newPerson() {
|
||||
Person person = new Person();
|
||||
person.name = "张三";
|
||||
person.date = new Date();
|
||||
person.localDateTime = LocalDateTime.now();
|
||||
person.age = 100;
|
||||
person.money = BigDecimal.valueOf(500.21);
|
||||
person.man = true;
|
||||
person.trait = new ArrayList<>();
|
||||
person.trait.add("淡然");
|
||||
person.trait.add("温和");
|
||||
person.cards = new HashMap<>();
|
||||
person.cards.put("身份证", "4a6d456as");
|
||||
person.cards.put("建行卡", "649874545");
|
||||
return person;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.agileboot.common.utils.file;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FileUploadUtilsTest {
|
||||
|
||||
@Test
|
||||
public void isAllowedExtension() {
|
||||
String[] imageTypes = new String[]{"img", "gif"};
|
||||
boolean isAllow = FileUploadUtils.isAllowedExtension("img", imageTypes);
|
||||
boolean isNotAllow = FileUploadUtils.isAllowedExtension("png", imageTypes);
|
||||
Assert.assertTrue(isAllow);
|
||||
Assert.assertFalse(isNotAllow);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.agileboot.common.utils.ip;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class OfflineIpRegionUtilTest {
|
||||
|
||||
@Test
|
||||
public void getIpRegion() {
|
||||
IpRegion ipRegion = OfflineIpRegionUtil.getIpRegion("110.81.189.80");
|
||||
|
||||
Assert.assertEquals("中国", ipRegion.getCountry());
|
||||
Assert.assertEquals("福建省", ipRegion.getProvince());
|
||||
Assert.assertEquals("泉州市", ipRegion.getCity());
|
||||
}
|
||||
}
|
||||
47
agileboot-domain/pom.xml
Normal file
47
agileboot-domain/pom.xml
Normal file
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>agileboot</artifactId>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>agileboot-domain</artifactId>
|
||||
|
||||
<description>
|
||||
领域核心代码 放在这个包
|
||||
generator代码生成
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-orm</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-infrastructure</artifactId>
|
||||
</dependency>
|
||||
<!--
|
||||
<!– 核心模块–>
|
||||
<dependency>
|
||||
<groupId>com.agileboot</groupId>
|
||||
<artifactId>agileboot-infrastructure</artifactId>
|
||||
</dependency>-->
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,22 @@
|
||||
package com.agileboot.domain.common;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BulkOperationCommand<T> {
|
||||
|
||||
public BulkOperationCommand(List<T> idList) {
|
||||
if (CollUtil.isEmpty(idList)) {
|
||||
throw new ApiException(ErrorCode.Business.BULK_DELETE_IDS_IS_INVALID);
|
||||
}
|
||||
|
||||
this.ids = idList;
|
||||
}
|
||||
|
||||
private List<T> ids;
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.agileboot.domain.common;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class UploadFileDTO {
|
||||
|
||||
public UploadFileDTO(String imgUrl) {
|
||||
this.imgUrl = imgUrl;
|
||||
}
|
||||
|
||||
private String imgUrl;
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.agileboot.domain.system;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class TreeSelectedDTO {
|
||||
|
||||
private List<Long> checkedKeys;
|
||||
private List<Tree<Long>> menus;
|
||||
private List<Tree<Long>> depts;
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.agileboot.domain.system.config;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.orm.entity.SysConfigEntity;
|
||||
import com.agileboot.orm.enums.dictionary.CommonAnswerEnum;
|
||||
import com.agileboot.orm.enums.interfaces.BasicEnumUtil;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ConfigDTO {
|
||||
|
||||
public ConfigDTO(SysConfigEntity entity) {
|
||||
|
||||
if (entity != null) {
|
||||
configId = entity.getConfigId() + "";
|
||||
configName = entity.getConfigName();
|
||||
configKey = entity.getConfigKey();
|
||||
configValue = entity.getConfigValue();
|
||||
configOptions =
|
||||
JSONUtil.isTypeJSONArray(entity.getConfigOptions()) ? JSONUtil.toList(entity.getConfigOptions(),
|
||||
String.class) : ListUtil.empty();
|
||||
isAllowChange = Convert.toInt(entity.getIsAllowChange()) + "";
|
||||
isAllowChangeStr = BasicEnumUtil.getDescriptionByBool(CommonAnswerEnum.class, entity.getIsAllowChange());
|
||||
remark = entity.getRemark();
|
||||
createTime = entity.getCreateTime();
|
||||
}
|
||||
}
|
||||
|
||||
private String configId;
|
||||
private String configName;
|
||||
private String configKey;
|
||||
private String configValue;
|
||||
private List<String> configOptions;
|
||||
private String isAllowChange;
|
||||
private String isAllowChangeStr;
|
||||
private String remark;
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package com.agileboot.domain.system.config;
|
||||
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import com.agileboot.orm.entity.SysConfigEntity;
|
||||
import com.agileboot.orm.service.ISysConfigService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
public class ConfigDomainService {
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
public PageDTO getConfigList(ConfigQuery query) {
|
||||
Page<SysConfigEntity> page = configService.page(query.toPage(), query.toQueryWrapper());
|
||||
List<ConfigDTO> records = page.getRecords().stream().map(ConfigDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO(records, page.getTotal());
|
||||
}
|
||||
|
||||
|
||||
public ConfigDTO getConfigInfo(Long id) {
|
||||
SysConfigEntity byId = configService.getById(id);
|
||||
return new ConfigDTO(byId);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void updateConfig(ConfigUpdateCommand updateCommand, LoginUser loginUser) {
|
||||
ConfigModel configModel = getConfigModel(updateCommand.getConfigId());
|
||||
|
||||
configModel.setConfigValue(updateCommand.getConfigValue());
|
||||
configModel.checkCanBeEdit();
|
||||
|
||||
configModel.logUpdater(loginUser);
|
||||
configModel.updateById();
|
||||
}
|
||||
|
||||
public ConfigModel getConfigModel(Long id) {
|
||||
SysConfigEntity byId = configService.getById(id);
|
||||
|
||||
if (byId == null) {
|
||||
throw new ApiException(ErrorCode.Business.OBJECT_NOT_FOUND, id, "参数配置");
|
||||
}
|
||||
|
||||
return new ConfigModel(byId);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.agileboot.domain.system.config;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.orm.entity.SysConfigEntity;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ConfigModel extends SysConfigEntity {
|
||||
|
||||
private Set<String> configOptionSet;
|
||||
|
||||
public ConfigModel(SysConfigEntity entity) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
|
||||
List<String> options =
|
||||
JSONUtil.isTypeJSONArray(entity.getConfigOptions()) ? JSONUtil.toList(entity.getConfigOptions(),
|
||||
String.class) : ListUtil.empty();
|
||||
|
||||
this.configOptionSet = new HashSet<>(options);
|
||||
}
|
||||
|
||||
public void checkCanBeEdit() {
|
||||
if (StrUtil.isBlank(getConfigValue())) {
|
||||
throw new ApiException(ErrorCode.Business.CONFIG_VALUE_IS_NOT_ALLOW_TO_EMPTY);
|
||||
}
|
||||
|
||||
if(!configOptionSet.isEmpty()&& !configOptionSet.contains(getConfigValue())) {
|
||||
throw new ApiException(ErrorCode.Business.CONFIG_VALUE_IS_NOT_IN_OPTIONS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.agileboot.domain.system.config;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.orm.entity.SysConfigEntity;
|
||||
import com.agileboot.orm.query.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class ConfigQuery extends AbstractPageQuery {
|
||||
|
||||
private String configName;
|
||||
|
||||
private String configKey;
|
||||
|
||||
private Boolean isAllowChange;
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public QueryWrapper toQueryWrapper() {
|
||||
QueryWrapper<SysConfigEntity> sysNoticeWrapper = new QueryWrapper<>();
|
||||
sysNoticeWrapper.like(StrUtil.isNotEmpty(configName), "config_name", configName);
|
||||
sysNoticeWrapper.eq(StrUtil.isNotEmpty(configKey), "config_key", configKey);
|
||||
sysNoticeWrapper.eq(isAllowChange != null, "is_allow_change", isAllowChange);
|
||||
|
||||
addSortCondition(sysNoticeWrapper);
|
||||
addTimeCondition(sysNoticeWrapper, "create_time");
|
||||
|
||||
return sysNoticeWrapper;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.agileboot.domain.system.config;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Positive;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ConfigUpdateCommand {
|
||||
|
||||
@NotNull
|
||||
@Positive
|
||||
private Long configId;
|
||||
@NotNull
|
||||
@NotEmpty
|
||||
private String configValue;
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.agileboot.domain.system.dept;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AddDeptCommand {
|
||||
/**
|
||||
* 父部门ID
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 祖级列表
|
||||
*/
|
||||
private String ancestors;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@NotBlank(message = "部门名称不能为空")
|
||||
@Size(max = 30, message = "部门名称长度不能超过30个字符")
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer orderNum;
|
||||
|
||||
/**
|
||||
* 负责人
|
||||
*/
|
||||
private String leaderName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
@Size(max = 11, message = "联系电话长度不能超过11个字符")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@Email(message = "邮箱格式不正确")
|
||||
@Size(max = 50, message = "邮箱长度不能超过50个字符")
|
||||
private String email;
|
||||
|
||||
public DeptModel toModel() {
|
||||
DeptModel model = new DeptModel();
|
||||
|
||||
model.setParentId(parentId);
|
||||
model.setAncestors(ancestors);
|
||||
model.setDeptName(deptName);
|
||||
model.setOrderNum(orderNum);
|
||||
model.setLeaderName(leaderName);
|
||||
model.setPhone(phone);
|
||||
model.setEmail(email);
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.agileboot.domain.system.dept;
|
||||
|
||||
import com.agileboot.orm.entity.SysDeptEntity;
|
||||
import com.agileboot.orm.enums.dictionary.CommonStatusEnum;
|
||||
import com.agileboot.orm.enums.interfaces.BasicEnumUtil;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DeptDTO {
|
||||
|
||||
public DeptDTO(SysDeptEntity entity) {
|
||||
if (entity != null) {
|
||||
this.deptId = entity.getDeptId();
|
||||
this.parentId = entity.getParentId();
|
||||
this.deptName = entity.getDeptName();
|
||||
this.orderNum = entity.getOrderNum();
|
||||
this.leaderName = entity.getLeaderName();
|
||||
this.email = entity.getEmail();
|
||||
this.phone = entity.getPhone();
|
||||
this.status = entity.getStatus() + "";
|
||||
this.statusStr = BasicEnumUtil.getDescriptionByValue(CommonStatusEnum.class, entity.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Long deptId;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private String deptName;
|
||||
|
||||
private Integer orderNum;
|
||||
|
||||
private String leaderName;
|
||||
|
||||
private String phone;
|
||||
|
||||
private String email;
|
||||
|
||||
private String status;
|
||||
|
||||
private String statusStr;
|
||||
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
package com.agileboot.domain.system.dept;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.system.TreeSelectedDTO;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import com.agileboot.orm.entity.SysDeptEntity;
|
||||
import com.agileboot.orm.entity.SysRoleEntity;
|
||||
import com.agileboot.orm.service.ISysDeptService;
|
||||
import com.agileboot.orm.service.ISysRoleService;
|
||||
import com.agileboot.orm.service.ISysUserService;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@SuppressWarnings("AlibabaTransactionMustHaveRollback")
|
||||
@Service
|
||||
public class DeptDomainService {
|
||||
|
||||
@Autowired
|
||||
private ISysDeptService deptService;
|
||||
|
||||
@Autowired
|
||||
private ISysRoleService roleService;
|
||||
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
public List<DeptDTO> getDeptList(DeptQuery query) {
|
||||
List<SysDeptEntity> list = deptService.list(query.toQueryWrapper());
|
||||
return list.stream().map(DeptDTO::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public DeptDTO getDeptInfo(Long id) {
|
||||
SysDeptEntity byId = deptService.getById(id);
|
||||
return new DeptDTO(byId);
|
||||
}
|
||||
|
||||
public List<Tree<Long>> getDeptTree() {
|
||||
List<SysDeptEntity> list = deptService.list();
|
||||
|
||||
return TreeUtil.build(list, 0L, (dept, tree) -> {
|
||||
tree.setId(dept.getDeptId());
|
||||
tree.setParentId(dept.getParentId());
|
||||
tree.putExtra("label", dept.getDeptName());
|
||||
});
|
||||
}
|
||||
|
||||
public TreeSelectedDTO getDeptTreeForRole(Long roleId) {
|
||||
List<Long> checkedKeys = new ArrayList<>();
|
||||
SysRoleEntity role = roleService.getById(roleId);
|
||||
if (role != null && StrUtil.isNotEmpty(role.getDeptIdSet())) {
|
||||
checkedKeys = StrUtil.split(role.getDeptIdSet(), ",")
|
||||
.stream().map(Long::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
TreeSelectedDTO selectedDTO = new TreeSelectedDTO();
|
||||
selectedDTO.setDepts(getDeptTree());
|
||||
selectedDTO.setCheckedKeys(checkedKeys);
|
||||
|
||||
return selectedDTO;
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void addDept(AddDeptCommand addCommand, LoginUser loginUser) {
|
||||
DeptModel deptModel = addCommand.toModel();
|
||||
if (deptService.checkDeptNameUnique(deptModel.getDeptName(), null, deptModel.getParentId())) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_NAME_IS_NOT_UNIQUE, deptModel.getDeptName());
|
||||
}
|
||||
|
||||
deptModel.generateAncestors(deptService);
|
||||
deptModel.logCreator(loginUser);
|
||||
|
||||
deptModel.insert();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void updateDept(UpdateDeptCommand updateCommand, LoginUser loginUser) {
|
||||
// TODO 需要再调整一下
|
||||
getDeptModel(updateCommand.getDeptId());
|
||||
|
||||
DeptModel deptModel = updateCommand.toModel();
|
||||
if (deptService.checkDeptNameUnique(deptModel.getDeptName(), deptModel.getDeptId(), deptModel.getParentId())) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_NAME_IS_NOT_UNIQUE, deptModel.getDeptName());
|
||||
}
|
||||
|
||||
deptModel.checkParentId();
|
||||
deptModel.checkStatusAllowChange(deptService);
|
||||
deptModel.generateAncestors(deptService);
|
||||
|
||||
deptModel.logUpdater(loginUser);
|
||||
|
||||
deptModel.updateById();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void removeDept(Long deptId) {
|
||||
DeptModel deptModel = getDeptModel(deptId);
|
||||
|
||||
deptModel.checkExistChildDept(deptService);
|
||||
deptModel.checkExistLinkedUsers(userService);
|
||||
|
||||
deptService.removeById(deptId);
|
||||
}
|
||||
|
||||
public DeptModel getDeptModel(Long id) {
|
||||
SysDeptEntity byId = deptService.getById(id);
|
||||
|
||||
if (byId == null) {
|
||||
throw new ApiException(ErrorCode.Business.OBJECT_NOT_FOUND, id, "参数配置");
|
||||
}
|
||||
|
||||
return new DeptModel(byId);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
package com.agileboot.domain.system.dept;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.orm.entity.SysDeptEntity;
|
||||
import com.agileboot.orm.enums.dictionary.CommonStatusEnum;
|
||||
import com.agileboot.orm.enums.interfaces.BasicEnumUtil;
|
||||
import com.agileboot.orm.service.ISysDeptService;
|
||||
import com.agileboot.orm.service.ISysUserService;
|
||||
import java.util.Objects;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
public class DeptModel extends SysDeptEntity {
|
||||
|
||||
public DeptModel(SysDeptEntity entity) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkParentId() {
|
||||
if (Objects.equals(getParentId(), getDeptId())) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkExistChildDept(ISysDeptService deptService) {
|
||||
if (deptService.hasChildDeptById(getDeptId())) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkExistLinkedUsers(ISysUserService userService) {
|
||||
if (userService.checkDeptExistUser(getDeptId())) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
public void generateAncestors(ISysDeptService deptService) {
|
||||
SysDeptEntity parentDept = deptService.getById(getParentId());
|
||||
|
||||
if (parentDept == null || CommonStatusEnum.DISABLE.equals(
|
||||
BasicEnumUtil.fromValue(CommonStatusEnum.class, parentDept.getStatus()))) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED);
|
||||
}
|
||||
|
||||
setAncestors(parentDept.getAncestors() + "," + getParentId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DDD 有些阻抗 如果为了追求性能的话 还是得通过 数据库的方式来判断
|
||||
* @param deptService
|
||||
*/
|
||||
public void checkStatusAllowChange(ISysDeptService deptService) {
|
||||
if (CommonStatusEnum.DISABLE.getValue().equals(getStatus()) &&
|
||||
deptService.existChildrenDeptById(getDeptId(), true)) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.agileboot.domain.system.dept;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.orm.entity.SysDeptEntity;
|
||||
import com.agileboot.orm.query.AbstractQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class DeptQuery extends AbstractQuery {
|
||||
|
||||
private Long deptId;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private String deptName;
|
||||
|
||||
private boolean isExcludeCurrentDept;
|
||||
|
||||
@Override
|
||||
public QueryWrapper toQueryWrapper() {
|
||||
QueryWrapper<SysDeptEntity> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
queryWrapper.eq(status != null, "status", status)
|
||||
.eq(parentId != null, "parent_id", parentId)
|
||||
.like(StrUtil.isNotEmpty(deptName), "dept_name", deptName)
|
||||
.and(deptId != null && isExcludeCurrentDept, o ->
|
||||
o.ne("dept_id", deptId)
|
||||
.or()
|
||||
.apply("FIND_IN_SET ( dept_id , ancestors)")
|
||||
);
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.agileboot.domain.system.dept;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UpdateDeptCommand extends AddDeptCommand{
|
||||
|
||||
@NotNull
|
||||
@PositiveOrZero
|
||||
private Long deptId;
|
||||
|
||||
@PositiveOrZero
|
||||
private String status;
|
||||
|
||||
@Override
|
||||
public DeptModel toModel() {
|
||||
DeptModel deptModel = super.toModel();
|
||||
deptModel.setDeptId(this.deptId);
|
||||
deptModel.setStatus(Convert.toInt(status, 0));
|
||||
return deptModel;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.agileboot.domain.system.loginInfo;
|
||||
|
||||
import com.agileboot.common.annotation.ExcelColumn;
|
||||
import com.agileboot.common.annotation.ExcelSheet;
|
||||
import com.agileboot.orm.entity.SysLoginInfoEntity;
|
||||
import com.agileboot.orm.enums.LoginStatusEnum;
|
||||
import com.agileboot.orm.enums.interfaces.BasicEnumUtil;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@ExcelSheet(name = "登录日志")
|
||||
public class LoginInfoDTO {
|
||||
|
||||
public LoginInfoDTO(SysLoginInfoEntity entity) {
|
||||
if (entity != null) {
|
||||
infoId = entity.getInfoId() + "";
|
||||
username = entity.getUsername();
|
||||
ipAddress = entity.getIpAddress();
|
||||
loginLocation = entity.getLoginLocation();
|
||||
operationSystem = entity.getOperationSystem();
|
||||
browser = entity.getBrowser();
|
||||
status = entity.getStatus() + "";
|
||||
statusStr = BasicEnumUtil.getDescriptionByValue(LoginStatusEnum.class, entity.getStatus());
|
||||
msg = entity.getMsg();
|
||||
loginTime = entity.getLoginTime();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ExcelColumn(name = "ID")
|
||||
private String infoId;
|
||||
|
||||
@ExcelColumn(name = "用户名")
|
||||
private String username;
|
||||
|
||||
@ExcelColumn(name = "ip地址")
|
||||
private String ipAddress;
|
||||
|
||||
@ExcelColumn(name = "登录地点")
|
||||
private String loginLocation;
|
||||
|
||||
@ExcelColumn(name = "操作系统")
|
||||
private String operationSystem;
|
||||
|
||||
@ExcelColumn(name = "浏览器")
|
||||
private String browser;
|
||||
|
||||
private String status;
|
||||
|
||||
@ExcelColumn(name = "状态")
|
||||
private String statusStr;
|
||||
|
||||
@ExcelColumn(name = "描述")
|
||||
private String msg;
|
||||
|
||||
@ExcelColumn(name = "登录时间")
|
||||
private Date loginTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.agileboot.domain.system.loginInfo;
|
||||
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.BulkOperationCommand;
|
||||
import com.agileboot.orm.entity.SysLoginInfoEntity;
|
||||
import com.agileboot.orm.service.ISysLoginInfoService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
public class LoginInfoDomainService {
|
||||
|
||||
@Autowired
|
||||
private ISysLoginInfoService loginInfoService;
|
||||
|
||||
public PageDTO getLoginInfoList(LoginInfoQuery query) {
|
||||
Page<SysLoginInfoEntity> page = loginInfoService.page(query.toPage(), query.toQueryWrapper());
|
||||
List<LoginInfoDTO> records = page.getRecords().stream().map(LoginInfoDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO(records, page.getTotal());
|
||||
}
|
||||
|
||||
public void deleteLoginInfo(BulkOperationCommand<Long> deleteCommand) {
|
||||
QueryWrapper<SysLoginInfoEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.in("info_id", deleteCommand.getIds());
|
||||
loginInfoService.remove(queryWrapper);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.agileboot.domain.system.loginInfo;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.orm.entity.SysLoginInfoEntity;
|
||||
import com.agileboot.orm.query.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class LoginInfoQuery extends AbstractPageQuery {
|
||||
|
||||
private String ipaddr;
|
||||
private String status;
|
||||
private String username;
|
||||
|
||||
|
||||
@Override
|
||||
public QueryWrapper toQueryWrapper() {
|
||||
QueryWrapper<SysLoginInfoEntity> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
queryWrapper.like(StrUtil.isNotEmpty(ipaddr), "ip_address", ipaddr)
|
||||
.eq(StrUtil.isNotEmpty(status), "status", status)
|
||||
.like(StrUtil.isNotEmpty(username), "username", username);
|
||||
|
||||
addSortCondition(queryWrapper);
|
||||
addTimeCondition(queryWrapper, "login_time");
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.agileboot.domain.system.loginInfo;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.orm.query.AbstractPageQuery;
|
||||
import com.agileboot.orm.result.SearchUserDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SearchUserQuery extends AbstractPageQuery {
|
||||
|
||||
private Long userId;
|
||||
private String username;
|
||||
private Integer status;
|
||||
private String phoneNumber;
|
||||
private Long deptId;
|
||||
|
||||
@Override
|
||||
public QueryWrapper<SearchUserDO> toQueryWrapper() {
|
||||
QueryWrapper<SearchUserDO> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
queryWrapper.like(StrUtil.isNotEmpty(username), "username", username)
|
||||
.like(StrUtil.isNotEmpty(phoneNumber), "u.phone_number", phoneNumber)
|
||||
.eq(userId != null, "u.user_id", userId)
|
||||
.eq(status != null, "u.status", status)
|
||||
.eq("u.deleted", 0)
|
||||
.and(deptId != null, o ->
|
||||
o.eq("u.dept_id", deptId)
|
||||
.or()
|
||||
.apply("u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(" + deptId
|
||||
+ ", ancestors))"));
|
||||
|
||||
this.addTimeCondition(queryWrapper, "u.create_time");
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package com.agileboot.domain.system.menu;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AddMenuCommand {
|
||||
|
||||
@NotBlank(message = "菜单名称不能为空")
|
||||
@Size(max = 50, message = "菜单名称长度不能超过50个字符")
|
||||
private String menuName;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer orderNum;
|
||||
|
||||
@Size(max = 200, message = "路由地址不能超过200个字符")
|
||||
private String path;
|
||||
|
||||
@Size(max = 200, message = "组件路径不能超过255个字符")
|
||||
private String component;
|
||||
|
||||
private Integer isExternal;
|
||||
|
||||
private Integer isCache;
|
||||
|
||||
private Integer menuType;
|
||||
|
||||
private Integer isVisible;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String query;
|
||||
|
||||
@Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
|
||||
private String perms;
|
||||
|
||||
private String icon;
|
||||
|
||||
public MenuModel toModel() {
|
||||
MenuModel model = new MenuModel();
|
||||
BeanUtil.copyProperties(this, model);
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.agileboot.domain.system.menu;
|
||||
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import com.agileboot.orm.entity.SysMenuEntity;
|
||||
import com.agileboot.orm.enums.dictionary.CommonStatusEnum;
|
||||
import com.agileboot.orm.enums.interfaces.BasicEnumUtil;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MenuDTO {
|
||||
|
||||
public MenuDTO(SysMenuEntity entity) {
|
||||
if (entity != null) {
|
||||
this.menuId = entity.getMenuId();
|
||||
this.parentId = entity.getParentId();
|
||||
this.menuName = entity.getMenuName();
|
||||
this.menuType = entity.getMenuType() + "";
|
||||
this.icon = entity.getIcon();
|
||||
this.orderNum = entity.getOrderNum() + "";
|
||||
this.component = entity.getComponent();
|
||||
this.perms = entity.getPerms();
|
||||
this.path = entity.getPath();
|
||||
this.status = entity.getStatus() + "";
|
||||
this.statusStr = BasicEnumUtil.getDescriptionByValue(CommonStatusEnum.class, entity.getStatus());
|
||||
this.createTime = entity.getCreateTime();
|
||||
this.isExternal = BooleanUtil.toInt(entity.getIsExternal()) + "";
|
||||
this.isCache = BooleanUtil.toInt(entity.getIsCache()) + "";
|
||||
this.isVisible = BooleanUtil.toInt(entity.getIsVisible()) + "";
|
||||
this.query = entity.getQuery();
|
||||
}
|
||||
}
|
||||
|
||||
private Long menuId;
|
||||
private Long parentId;
|
||||
private String menuType;
|
||||
private String menuName;
|
||||
private String icon;
|
||||
private String orderNum;
|
||||
private String component;
|
||||
private String path;
|
||||
private String perms;
|
||||
private String status;
|
||||
private String statusStr;
|
||||
private Date createTime;
|
||||
private String isExternal;
|
||||
private String isCache;
|
||||
private String isVisible;
|
||||
private String query;
|
||||
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
package com.agileboot.domain.system.menu;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.system.TreeSelectedDTO;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import com.agileboot.infrastructure.web.util.AuthenticationUtils;
|
||||
import com.agileboot.orm.entity.SysMenuEntity;
|
||||
import com.agileboot.orm.service.ISysMenuService;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
public class MenuDomainService {
|
||||
|
||||
@Autowired
|
||||
private ISysMenuService menuService;
|
||||
|
||||
|
||||
public List<MenuDTO> getMenuList(MenuQuery query) {
|
||||
List<SysMenuEntity> list = menuService.list(query.toQueryWrapper());
|
||||
return list.stream().map(MenuDTO::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public MenuDTO getMenuInfo(Long menuId) {
|
||||
SysMenuEntity byId = menuService.getById(menuId);
|
||||
return new MenuDTO(byId);
|
||||
}
|
||||
|
||||
public List<Tree<Long>> getDropdownList(LoginUser loginUser) {
|
||||
List<SysMenuEntity> menuEntityList =
|
||||
loginUser.isAdmin() ? menuService.list() : menuService.selectMenuListByUserId(loginUser.getUserId());
|
||||
|
||||
return buildMenuTreeSelect(menuEntityList);
|
||||
}
|
||||
|
||||
|
||||
public TreeSelectedDTO getRoleDropdownList(LoginUser loginUser, Long roleId) {
|
||||
List<SysMenuEntity> menus = loginUser.isAdmin() ?
|
||||
menuService.list() : menuService.selectMenuListByUserId(loginUser.getUserId());
|
||||
|
||||
TreeSelectedDTO tree = new TreeSelectedDTO();
|
||||
tree.setMenus(buildMenuTreeSelect(menus));
|
||||
tree.setCheckedKeys(menuService.selectMenuListByRoleId(roleId));
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
||||
public void addMenu(AddMenuCommand addCommand, LoginUser loginUser) {
|
||||
MenuModel model = addCommand.toModel();
|
||||
|
||||
model.checkMenuNameUnique(menuService);
|
||||
model.checkExternalLink();
|
||||
|
||||
model.logCreator(loginUser);
|
||||
|
||||
model.insert();
|
||||
}
|
||||
|
||||
public void updateMenu(UpdateMenuCommand updateCommand, LoginUser loginUser) {
|
||||
MenuModel model = updateCommand.toModel();
|
||||
model.checkMenuNameUnique(menuService);
|
||||
model.checkExternalLink();
|
||||
model.checkParentId();
|
||||
|
||||
model.logUpdater(loginUser);
|
||||
|
||||
model.updateById();
|
||||
}
|
||||
|
||||
|
||||
public void remove(Long menuId) {
|
||||
MenuModel menuModel = getMenuModel(menuId);
|
||||
|
||||
menuModel.checkHasChildMenus(menuService);
|
||||
menuModel.checkMenuAlreadyAssignToRole(menuService);
|
||||
|
||||
menuModel.deleteById();
|
||||
}
|
||||
|
||||
|
||||
public MenuModel getMenuModel(Long menuId) {
|
||||
SysMenuEntity byId = menuService.getById(menuId);
|
||||
if (byId == null) {
|
||||
throw new ApiException(ErrorCode.Business.OBJECT_NOT_FOUND, menuId, "菜单");
|
||||
}
|
||||
return new MenuModel(byId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 构建前端所需要树结构
|
||||
*
|
||||
* @param menus 菜单列表
|
||||
* @return 树结构列表
|
||||
*/
|
||||
public List<Tree<Long>> buildMenuTreeSelect(List<SysMenuEntity> menus) {
|
||||
TreeNodeConfig config = new TreeNodeConfig();
|
||||
//默认为id可以不设置
|
||||
config.setIdKey("menuId");
|
||||
return TreeUtil.build(menus, 0L, config, (menu, tree) -> {
|
||||
// 也可以使用 tree.setId(dept.getId());等一些默认值
|
||||
tree.setId(menu.getMenuId());
|
||||
tree.setParentId(menu.getParentId());
|
||||
tree.putExtra("label", menu.getMenuName());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public List<Tree<Long>> buildMenuEntityTree(Long userId) {
|
||||
|
||||
List<SysMenuEntity> menus = null;
|
||||
if (AuthenticationUtils.isAdmin(userId)) {
|
||||
menus = menuService.listMenuListWithoutButton();
|
||||
} else {
|
||||
menus = menuService.listMenuListWithoutButtonByUserId(userId);
|
||||
}
|
||||
|
||||
TreeNodeConfig config = new TreeNodeConfig();
|
||||
//默认为id可以不设置
|
||||
config.setIdKey("menuId");
|
||||
|
||||
return TreeUtil.build(menus, 0L, config, (menu, tree) -> {
|
||||
// 也可以使用 tree.setId(dept.getId());等一些默认值
|
||||
tree.setId(menu.getMenuId());
|
||||
tree.setParentId(menu.getParentId());
|
||||
tree.putExtra("entity", menu);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
public List<RouterVo> buildRouterTree(List<Tree<Long>> trees) {
|
||||
List<RouterVo> routers = new LinkedList<RouterVo>();
|
||||
if (CollUtil.isNotEmpty(trees)) {
|
||||
for (Tree<Long> tree : trees) {
|
||||
RouterVo routerVo = null;
|
||||
|
||||
Object entity = tree.get("entity");
|
||||
|
||||
if (entity != null) {
|
||||
RouterModel model = new RouterModel();
|
||||
BeanUtil.copyProperties(entity, model, true);
|
||||
|
||||
routerVo = model.produceDefaultRouterVO();
|
||||
|
||||
if(model.isMultipleLevelMenu(tree)) {
|
||||
routerVo = model.produceDirectoryRouterVO(buildRouterTree(tree.getChildren()));
|
||||
}
|
||||
|
||||
if(model.isSingleLevelMenu()) {
|
||||
routerVo = model.produceMenuFrameRouterVO();
|
||||
}
|
||||
|
||||
if(model.getParentId() == 0L && model.isInnerLink()) {
|
||||
routerVo = model.produceInnerLinkRouterVO();
|
||||
}
|
||||
|
||||
routers.add(routerVo);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return routers;
|
||||
}
|
||||
|
||||
|
||||
public List<RouterVo> getRouterTree(Long userId) {
|
||||
List<Tree<Long>> trees = buildMenuEntityTree(userId);
|
||||
return buildRouterTree(trees);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package com.agileboot.domain.system.menu;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.orm.entity.SysMenuEntity;
|
||||
import com.agileboot.orm.service.ISysMenuService;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
public class MenuModel extends SysMenuEntity {
|
||||
|
||||
public MenuModel(SysMenuEntity entity) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkMenuNameUnique(ISysMenuService menuService) {
|
||||
if (menuService.checkMenuNameUnique(getMenuName(), getMenuId(), getParentId())) {
|
||||
throw new ApiException(ErrorCode.Business.MENU_NAME_IS_NOT_UNIQUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkExternalLink() {
|
||||
if (getIsExternal() && !HttpUtil.isHttp(getPath()) && !HttpUtil.isHttps(getPath())) {
|
||||
throw new ApiException(ErrorCode.Business.MENU_EXTERNAL_LINK_MUST_BE_HTTP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkParentId() {
|
||||
if (getMenuId().equals(getParentId())) {
|
||||
throw new ApiException(ErrorCode.Business.MENU_PARENT_ID_NOT_ALLOW_SELF);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkHasChildMenus(ISysMenuService menuService) {
|
||||
if (menuService.hasChildByMenuId(getMenuId())) {
|
||||
throw new ApiException(ErrorCode.Business.MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkMenuAlreadyAssignToRole(ISysMenuService menuService) {
|
||||
if (menuService.checkMenuExistRole(getMenuId())) {
|
||||
throw new ApiException(ErrorCode.Business.MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.agileboot.domain.system.menu;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.orm.entity.SysMenuEntity;
|
||||
import com.agileboot.orm.query.AbstractQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import java.util.Arrays;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MenuQuery extends AbstractQuery {
|
||||
|
||||
private String menuName;
|
||||
private Boolean isVisible;
|
||||
private Integer status;
|
||||
|
||||
|
||||
@Override
|
||||
public QueryWrapper<SysMenuEntity> toQueryWrapper() {
|
||||
|
||||
QueryWrapper<SysMenuEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.like(StrUtil.isNotEmpty(menuName), columnName("menu_name"), menuName)
|
||||
.eq(isVisible!=null, "is_visible", isVisible)
|
||||
.eq(status!=null, "status", status);
|
||||
|
||||
queryWrapper.orderBy(true, true, Arrays.asList("parent_id", "order_num"));
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.agileboot.domain.system.menu;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 路由显示信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class MetaVo {
|
||||
|
||||
/**
|
||||
* 设置该路由在侧边栏和面包屑中展示的名字
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 设置该路由的图标,对应路径src/assets/icons/svg
|
||||
*/
|
||||
private String icon;
|
||||
|
||||
/**
|
||||
* 设置为true,则不会被 <keep-alive>缓存
|
||||
*/
|
||||
private boolean noCache;
|
||||
|
||||
/**
|
||||
* 内链地址(http(s)://开头)
|
||||
*/
|
||||
private String link;
|
||||
|
||||
public MetaVo(String title, String icon) {
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
|
||||
public MetaVo(String title, String icon, String link) {
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
if (HttpUtil.isHttp(link)) {
|
||||
this.link = link;
|
||||
}
|
||||
}
|
||||
|
||||
public MetaVo(String title, String icon, boolean noCache, String link) {
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.noCache = noCache;
|
||||
if (HttpUtil.isHttp(link)) {
|
||||
this.link = link;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,197 @@
|
||||
package com.agileboot.domain.system.menu;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.agileboot.common.constant.Constants;
|
||||
import com.agileboot.orm.entity.SysMenuEntity;
|
||||
import com.agileboot.orm.enums.MenuComponentEnum;
|
||||
import com.agileboot.orm.enums.MenuTypeEnum;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class RouterModel extends SysMenuEntity {
|
||||
|
||||
|
||||
public RouterVo produceDirectoryRouterVO(List<RouterVo> children) {
|
||||
|
||||
RouterVo router = produceDefaultRouterVO();
|
||||
|
||||
if (CollUtil.isNotEmpty(children) && Objects.equals(MenuTypeEnum.DIRECTORY.getValue(), getMenuType())) {
|
||||
router.setAlwaysShow(true);
|
||||
router.setRedirect("noRedirect");
|
||||
router.setChildren(children);
|
||||
}
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
|
||||
public RouterVo produceMenuFrameRouterVO() {
|
||||
RouterVo router = new RouterVo();
|
||||
|
||||
router.setMeta(null);
|
||||
List<RouterVo> childrenList = new ArrayList<>();
|
||||
RouterVo children = new RouterVo();
|
||||
children.setPath(getPath());
|
||||
children.setComponent(getComponent());
|
||||
children.setName(StrUtil.upperFirst(getPath()));
|
||||
children.setMeta(new MetaVo(getMenuName(), getIcon(), !getIsCache(), getPath()));
|
||||
children.setQuery(getQuery());
|
||||
childrenList.add(children);
|
||||
router.setChildren(childrenList);
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
|
||||
public RouterVo produceInnerLinkRouterVO() {
|
||||
|
||||
RouterVo router = new RouterVo();
|
||||
|
||||
router.setMeta(new MetaVo(getMenuName(), getIcon()));
|
||||
router.setPath("/");
|
||||
List<RouterVo> childrenList = new ArrayList<>();
|
||||
RouterVo children = new RouterVo();
|
||||
String routerPath = trimHttpPrefixForInnerLink(getPath());
|
||||
children.setPath(routerPath);
|
||||
children.setComponent(MenuComponentEnum.INNER_LINK.description());
|
||||
children.setName(StrUtil.upperFirst(routerPath));
|
||||
children.setMeta(new MetaVo(getMenuName(), getIcon(), getPath()));
|
||||
childrenList.add(children);
|
||||
router.setChildren(childrenList);
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
public RouterVo produceDefaultRouterVO() {
|
||||
RouterVo router = new RouterVo();
|
||||
router.setHidden(!getIsVisible());
|
||||
router.setName(getRouteName());
|
||||
router.setPath(getRouterPath());
|
||||
router.setComponent(getComponentTypeForFrontEnd());
|
||||
router.setQuery(getQuery());
|
||||
router.setMeta(new MetaVo(getMenuName(), getIcon(), !getIsCache(), getPath()));
|
||||
return router;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取路由名称
|
||||
* @return 路由名称
|
||||
*/
|
||||
public String getRouteName() {
|
||||
String routerName = StrUtil.upperFirst(getPath());
|
||||
// 非外链并且是一级目录(类型为目录)
|
||||
if (isSingleLevelMenu()) {
|
||||
routerName = StrUtil.EMPTY;
|
||||
}
|
||||
return routerName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 是否为单个一级菜单
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public boolean isSingleLevelMenu() {
|
||||
return getParentId().intValue() == 0
|
||||
&& MenuTypeEnum.MENU.getValue().equals(getMenuType())
|
||||
&& !getIsExternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 是否为菜单内部跳转
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public boolean isMultipleLevelMenu(Tree<Long> tree) {
|
||||
return MenuTypeEnum.DIRECTORY.getValue().equals(getMenuType()) && tree.hasChild();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取路由地址
|
||||
* @return 路由地址
|
||||
*/
|
||||
public String getRouterPath() {
|
||||
String routerPath = getPath();
|
||||
// 内链打开外网方式
|
||||
if (getParentId().intValue() != 0 && isInnerLink()) {
|
||||
routerPath = trimHttpPrefixForInnerLink(routerPath);
|
||||
}
|
||||
// 非外链并且是一级目录(类型为目录)
|
||||
if (0L == getParentId() && Objects.equals(MenuTypeEnum.DIRECTORY.getValue(), getMenuType()) && !getIsExternal()) {
|
||||
routerPath = "/" + getPath();
|
||||
// 非外链并且是一级目录(类型为菜单)
|
||||
} else if (isSingleLevelMenu()) {
|
||||
routerPath = "/";
|
||||
}
|
||||
return routerPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为内链组件
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public boolean isInnerLink() {
|
||||
return !getIsExternal() && (HttpUtil.isHttp(getPath()) || HttpUtil.isHttps(getPath()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 内链域名特殊字符替换
|
||||
*/
|
||||
public String trimHttpPrefixForInnerLink(String path) {
|
||||
if (HttpUtil.isHttp(path)) {
|
||||
return StrUtil.stripIgnoreCase(path, Constants.HTTP, "");
|
||||
}
|
||||
if (HttpUtil.isHttps(path)) {
|
||||
return StrUtil.stripIgnoreCase(path, Constants.HTTPS, "");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件信息
|
||||
*
|
||||
* @return 组件信息
|
||||
*/
|
||||
public String getComponentTypeForFrontEnd() {
|
||||
String component = MenuComponentEnum.LAYOUT.description();
|
||||
if (StrUtil.isNotEmpty(getComponent()) && !isSingleLevelMenu()) {
|
||||
component = getComponent();
|
||||
} else if (isInnerLinkView()) {
|
||||
component = MenuComponentEnum.INNER_LINK.description();
|
||||
} else if (isParentView()) {
|
||||
component = MenuComponentEnum.PARENT_VIEW.description();
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为inner_link_view组件
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public boolean isInnerLinkView() {
|
||||
return StrUtil.isEmpty(getComponent()) && getParentId().intValue() != 0 && isInnerLink();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 是否为parent_view组件
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public boolean isParentView() {
|
||||
return StrUtil.isEmpty(getComponent()) && getParentId().intValue() != 0 && MenuTypeEnum.DIRECTORY.getValue() == getMenuType();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
package com.agileboot.domain.system.menu;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 路由配置信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
@Data
|
||||
public class RouterVo {
|
||||
|
||||
/**
|
||||
* 路由名字
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 路由地址
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现
|
||||
*/
|
||||
private boolean hidden;
|
||||
|
||||
/**
|
||||
* 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
|
||||
*/
|
||||
private String redirect;
|
||||
|
||||
/**
|
||||
* 组件地址
|
||||
*/
|
||||
private String component;
|
||||
|
||||
/**
|
||||
* 路由参数:如 {"id": 1, "name": "agileBoot"}
|
||||
*/
|
||||
private String query;
|
||||
|
||||
/**
|
||||
* 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
|
||||
*/
|
||||
private Boolean alwaysShow;
|
||||
|
||||
/**
|
||||
* 其他元素
|
||||
*/
|
||||
private MetaVo meta;
|
||||
|
||||
/**
|
||||
* 子路由
|
||||
*/
|
||||
private List<RouterVo> children;
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.agileboot.domain.system.menu;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UpdateMenuCommand extends AddMenuCommand{
|
||||
|
||||
@NotNull
|
||||
private Long menuId;
|
||||
|
||||
@Override
|
||||
public MenuModel toModel() {
|
||||
MenuModel model = super.toModel();
|
||||
model.setMenuId(menuId);
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,124 @@
|
||||
package com.agileboot.domain.system.monitor;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.agileboot.domain.system.monitor.dto.RedisCacheInfoDTO;
|
||||
import com.agileboot.domain.system.monitor.dto.RedisCacheInfoDTO.CommonStatusDTO;
|
||||
import com.agileboot.infrastructure.cache.RedisUtil;
|
||||
import com.agileboot.infrastructure.cache.guava.GuavaCacheService;
|
||||
import com.agileboot.infrastructure.cache.redis.CacheKeyEnum;
|
||||
import com.agileboot.infrastructure.cache.redis.RedisCacheService;
|
||||
import com.agileboot.infrastructure.web.domain.OnlineUser;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import com.agileboot.infrastructure.web.domain.server.ServerInfo;
|
||||
import com.agileboot.orm.entity.SysDeptEntity;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.connection.RedisServerCommands;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MonitorDomainService {
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@Autowired
|
||||
private RedisCacheService redisCacheService;
|
||||
|
||||
|
||||
public RedisCacheInfoDTO getRedisCacheInfo() {
|
||||
|
||||
Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::info);
|
||||
Properties commandStats = (Properties) redisTemplate.execute(
|
||||
(RedisCallback<Object>) connection -> connection.info("commandstats"));
|
||||
Object dbSize = redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::dbSize);
|
||||
|
||||
if(commandStats == null) {
|
||||
throw new RuntimeException("找不到对应的redis信息。");
|
||||
}
|
||||
|
||||
RedisCacheInfoDTO cacheInfo = new RedisCacheInfoDTO();
|
||||
|
||||
cacheInfo.setInfo(info);
|
||||
cacheInfo.setDbSize(dbSize);
|
||||
cacheInfo.setCommandStats(new ArrayList<>());
|
||||
|
||||
commandStats.stringPropertyNames().forEach(key -> {
|
||||
String property = commandStats.getProperty(key);
|
||||
|
||||
RedisCacheInfoDTO.CommonStatusDTO commonStatus = new CommonStatusDTO();
|
||||
commonStatus.setName(StrUtil.removePrefix(key, "cmdstat_"));
|
||||
commonStatus.setValue(StrUtil.subBetween(property, "calls=", ",usec"));
|
||||
|
||||
cacheInfo.getCommandStats().add(commonStatus);
|
||||
});
|
||||
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
public List<OnlineUser> getOnlineUserList(String userName, String ipaddr) {
|
||||
Collection<String> keys = redisUtil.keys(CacheKeyEnum.LOGIN_USER_KEY.key() + "*");
|
||||
|
||||
List<OnlineUser> allOnlineUsers = keys.stream().map(
|
||||
o -> mapLoginUserToUserOnline(redisCacheService.loginUserCache.getCachedObjectByKey(o)))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<OnlineUser> filteredOnlineUsers = allOnlineUsers.stream()
|
||||
.filter(o ->
|
||||
StrUtil.isEmpty(userName) || userName.equals(o.getUserName())
|
||||
).filter( o ->
|
||||
StrUtil.isEmpty(ipaddr) || ipaddr.equals(o.getIpaddr())
|
||||
).collect(Collectors.toList());
|
||||
|
||||
Collections.reverse(filteredOnlineUsers);
|
||||
return filteredOnlineUsers;
|
||||
}
|
||||
|
||||
public ServerInfo getServerInfo() {
|
||||
return ServerInfo.fillInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置在线用户信息
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @return 在线用户
|
||||
*/
|
||||
public OnlineUser mapLoginUserToUserOnline(LoginUser user) {
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
OnlineUser onlineUser = new OnlineUser();
|
||||
onlineUser.setTokenId(user.getToken());
|
||||
onlineUser.setUserName(user.getUsername());
|
||||
onlineUser.setIpaddr(user.getLoginInfo().getIpAddress());
|
||||
onlineUser.setLoginLocation(user.getLoginInfo().getLocation());
|
||||
onlineUser.setBrowser(user.getLoginInfo().getBrowser());
|
||||
onlineUser.setOs(user.getLoginInfo().getOperationSystem());
|
||||
onlineUser.setLoginTime(user.getLoginTime());
|
||||
|
||||
GuavaCacheService cacheService = SpringUtil.getBean(GuavaCacheService.class);
|
||||
|
||||
SysDeptEntity deptEntity = cacheService.deptCache.get(user.getDeptId() + "");
|
||||
|
||||
if (deptEntity != null) {
|
||||
onlineUser.setDeptName(deptEntity.getDeptName());
|
||||
}
|
||||
|
||||
return onlineUser;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.agileboot.domain.system.monitor.dto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class RedisCacheInfoDTO {
|
||||
|
||||
private Properties info;
|
||||
private Object dbSize;
|
||||
private List<CommonStatusDTO> commandStats;
|
||||
|
||||
@Data
|
||||
public static class CommonStatusDTO {
|
||||
private String name;
|
||||
private String value;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.agileboot.domain.system.notice;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class NoticeAddCommand {
|
||||
|
||||
@NotBlank(message = "公告标题不能为空")
|
||||
@Size(max = 50, message = "公告标题不能超过50个字符")
|
||||
protected String noticeTitle;
|
||||
|
||||
protected String noticeType;
|
||||
|
||||
@NotBlank
|
||||
protected String noticeContent;
|
||||
|
||||
protected String status;
|
||||
|
||||
public NoticeModel toModel() {
|
||||
NoticeModel model = new NoticeModel();
|
||||
|
||||
model.setNoticeTitle(noticeTitle);
|
||||
model.setNoticeType(Convert.toInt(noticeType));
|
||||
model.setNoticeContent(noticeContent);
|
||||
model.setStatus(Convert.toInt(status));
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.agileboot.domain.system.notice;
|
||||
|
||||
import com.agileboot.orm.entity.SysNoticeEntity;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class NoticeDTO {
|
||||
|
||||
public NoticeDTO(SysNoticeEntity entity) {
|
||||
if (entity != null) {
|
||||
this.noticeId = entity.getNoticeId() + "";
|
||||
this.noticeTitle = entity.getNoticeTitle() + "";
|
||||
this.noticeType = entity.getNoticeType() + "";
|
||||
this.noticeContent = entity.getNoticeContent();
|
||||
this.status = entity.getStatus() + "";
|
||||
this.createTime = entity.getCreateTime();
|
||||
this.creatorName = entity.getCreatorName();
|
||||
}
|
||||
}
|
||||
|
||||
private String noticeId;
|
||||
|
||||
private String noticeTitle;
|
||||
|
||||
private String noticeType;
|
||||
|
||||
private String noticeContent;
|
||||
|
||||
private String status;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private String creatorName;
|
||||
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
package com.agileboot.domain.system.notice;
|
||||
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.common.BulkOperationCommand;
|
||||
import com.agileboot.infrastructure.web.domain.login.LoginUser;
|
||||
import com.agileboot.orm.entity.SysNoticeEntity;
|
||||
import com.agileboot.orm.service.ISysNoticeService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
public class NoticeDomainService {
|
||||
|
||||
@Autowired
|
||||
private ISysNoticeService noticeService;
|
||||
|
||||
public PageDTO getNoticeList(NoticeQuery query) {
|
||||
Page<SysNoticeEntity> page = noticeService.page(query.toPage(), query.toQueryWrapper());
|
||||
List<NoticeDTO> records = page.getRecords().stream().map(NoticeDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO(records, page.getTotal());
|
||||
}
|
||||
|
||||
|
||||
public NoticeDTO getNoticeInfo(Long id) {
|
||||
SysNoticeEntity byId = noticeService.getById(id);
|
||||
return new NoticeDTO(byId);
|
||||
}
|
||||
|
||||
|
||||
public void addNotice(NoticeAddCommand addCommand, LoginUser loginUser) {
|
||||
NoticeModel noticeModel = addCommand.toModel();
|
||||
|
||||
noticeModel.checkFields();
|
||||
|
||||
noticeModel.logCreator(loginUser);
|
||||
|
||||
noticeModel.insert();
|
||||
}
|
||||
|
||||
|
||||
public void updateNotice(NoticeUpdateCommand updateCommand, LoginUser loginUser) {
|
||||
SysNoticeEntity byId = noticeService.getById(updateCommand.getNoticeId());
|
||||
|
||||
if (byId == null) {
|
||||
throw new ApiException(ErrorCode.Business.OBJECT_NOT_FOUND, updateCommand.getNoticeId(), "通知公告");
|
||||
}
|
||||
|
||||
NoticeModel noticeModel = updateCommand.toModel();
|
||||
|
||||
noticeModel.checkFields();
|
||||
|
||||
noticeModel.logUpdater(loginUser);
|
||||
|
||||
noticeModel.updateById();
|
||||
}
|
||||
|
||||
public void deleteNotice(BulkOperationCommand<Long> deleteCommand) {
|
||||
noticeService.removeBatchByIds(deleteCommand.getIds());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.agileboot.domain.system.notice;
|
||||
|
||||
import com.agileboot.orm.entity.SysNoticeEntity;
|
||||
import com.agileboot.orm.enums.dictionary.CommonStatusEnum;
|
||||
import com.agileboot.orm.enums.dictionary.NoticeTypeEnum;
|
||||
import com.agileboot.orm.enums.interfaces.BasicEnumUtil;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class NoticeModel extends SysNoticeEntity {
|
||||
|
||||
|
||||
public void checkFields() {
|
||||
|
||||
Integer noticeType = this.getNoticeType();
|
||||
BasicEnumUtil.fromValue(NoticeTypeEnum.class, noticeType);
|
||||
|
||||
Integer status = this.getStatus();
|
||||
BasicEnumUtil.fromValue(CommonStatusEnum.class, status);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.agileboot.domain.system.notice;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.orm.entity.SysNoticeEntity;
|
||||
import com.agileboot.orm.query.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class NoticeQuery extends AbstractPageQuery {
|
||||
|
||||
private String noticeType;
|
||||
|
||||
private String noticeTitle;
|
||||
|
||||
private String creatorName;
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public QueryWrapper toQueryWrapper() {
|
||||
QueryWrapper<SysNoticeEntity> sysNoticeWrapper = new QueryWrapper<>();
|
||||
sysNoticeWrapper.like(StrUtil.isNotEmpty(noticeTitle), "notice_title", noticeTitle)
|
||||
.eq(noticeType != null, "notice_type", noticeType)
|
||||
.like(StrUtil.isNotEmpty(creatorName), "creator_name", creatorName);
|
||||
|
||||
return sysNoticeWrapper;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.agileboot.domain.system.notice;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Positive;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class NoticeUpdateCommand extends NoticeAddCommand{
|
||||
|
||||
@NotNull
|
||||
@Positive
|
||||
protected String noticeId;
|
||||
|
||||
|
||||
@Override
|
||||
public NoticeModel toModel() {
|
||||
NoticeModel noticeModel = super.toModel();
|
||||
noticeModel.setNoticeId(Convert.toInt(noticeId));
|
||||
return noticeModel;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
package com.agileboot.domain.system.operationLog;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.annotation.ExcelColumn;
|
||||
import com.agileboot.common.annotation.ExcelSheet;
|
||||
import com.agileboot.orm.entity.SysOperationLogEntity;
|
||||
import com.agileboot.orm.enums.OperatorTypeEnum;
|
||||
import com.agileboot.orm.enums.RequestMethodEnum;
|
||||
import com.agileboot.orm.enums.dictionary.BusinessTypeEnum;
|
||||
import com.agileboot.orm.enums.dictionary.OperationStatusEnum;
|
||||
import com.agileboot.orm.enums.interfaces.BasicEnumUtil;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@ExcelSheet(name = "操作日志")
|
||||
public class OperationLogDTO {
|
||||
|
||||
public OperationLogDTO(SysOperationLogEntity entity) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
this.requestMethod = BasicEnumUtil.getDescriptionByValue(RequestMethodEnum.class,
|
||||
entity.getRequestMethod());
|
||||
this.statusStr = BasicEnumUtil.getDescriptionByValue(OperationStatusEnum.class, entity.getStatus());
|
||||
businessTypeStr = BasicEnumUtil.getDescriptionByValue(BusinessTypeEnum.class, entity.getBusinessType());
|
||||
operatorTypeStr = BasicEnumUtil.getDescriptionByValue(OperatorTypeEnum.class, entity.getOperatorType());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ExcelColumn(name = "ID")
|
||||
private Long operationId;
|
||||
|
||||
private Integer businessType;
|
||||
|
||||
@ExcelColumn(name = "操作类型")
|
||||
private String businessTypeStr;
|
||||
|
||||
@ExcelColumn(name = "操作类型")
|
||||
private String requestMethod;
|
||||
|
||||
@ExcelColumn(name = "操作类型")
|
||||
private String requestModule;
|
||||
|
||||
@ExcelColumn(name = "操作类型")
|
||||
private String requestUrl;
|
||||
|
||||
@ExcelColumn(name = "操作类型")
|
||||
private String calledMethod;
|
||||
|
||||
private Integer operatorType;
|
||||
|
||||
@ExcelColumn(name = "操作人类型")
|
||||
private String operatorTypeStr;
|
||||
|
||||
@ExcelColumn(name = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@ExcelColumn(name = "用户名")
|
||||
private String username;
|
||||
|
||||
@ExcelColumn(name = "ip地址")
|
||||
private String operatorIp;
|
||||
|
||||
@ExcelColumn(name = "ip地点")
|
||||
private String operatorLocation;
|
||||
|
||||
@ExcelColumn(name = "部门ID")
|
||||
private Long deptId;
|
||||
|
||||
@ExcelColumn(name = "部门")
|
||||
private String deptName;
|
||||
|
||||
@ExcelColumn(name = "操作参数")
|
||||
private String operationParam;
|
||||
|
||||
@ExcelColumn(name = "操作结果")
|
||||
private String operationResult;
|
||||
|
||||
private Integer status;
|
||||
|
||||
@ExcelColumn(name = "状态")
|
||||
private String statusStr;
|
||||
|
||||
@ExcelColumn(name = "错误堆栈")
|
||||
private String errorStack;
|
||||
|
||||
@ExcelColumn(name = "操作时间")
|
||||
private Date operationTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.agileboot.domain.system.operationLog;
|
||||
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.BulkOperationCommand;
|
||||
import com.agileboot.orm.entity.SysOperationLogEntity;
|
||||
import com.agileboot.orm.service.ISysOperationLogService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
public class OperationLogDomainService {
|
||||
|
||||
@Autowired
|
||||
private ISysOperationLogService operationLogService;
|
||||
|
||||
public PageDTO getOperationLogList(OperationLogQuery query) {
|
||||
Page<SysOperationLogEntity> page = operationLogService.page(query.toPage(), query.toQueryWrapper());
|
||||
List<OperationLogDTO> records = page.getRecords().stream().map(OperationLogDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO(records, page.getTotal());
|
||||
}
|
||||
|
||||
public void deleteOperationLog(BulkOperationCommand<Long> deleteCommand) {
|
||||
operationLogService.removeBatchByIds(deleteCommand.getIds());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.agileboot.domain.system.operationLog;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.orm.entity.SysLoginInfoEntity;
|
||||
import com.agileboot.orm.query.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class OperationLogQuery extends AbstractPageQuery {
|
||||
|
||||
private String businessType;
|
||||
private String status;
|
||||
private String username;
|
||||
private String requestModule;
|
||||
|
||||
|
||||
@Override
|
||||
public QueryWrapper toQueryWrapper() {
|
||||
QueryWrapper<SysLoginInfoEntity> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
queryWrapper.like(businessType!=null, "business_type", businessType)
|
||||
.eq(status != null, "status", status)
|
||||
.like(StrUtil.isNotEmpty(username), "username", username)
|
||||
.like(StrUtil.isNotEmpty(requestModule), "request_module", requestModule);
|
||||
|
||||
addSortCondition(queryWrapper);
|
||||
addTimeCondition(queryWrapper, "operation_time");
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.agileboot.domain.system.post;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AddPostCommand {
|
||||
|
||||
@NotBlank(message = "岗位编码不能为空")
|
||||
@Size(max = 64, message = "岗位编码长度不能超过64个字符")
|
||||
protected String postCode;
|
||||
|
||||
/**
|
||||
* 岗位名称
|
||||
*/
|
||||
@NotBlank(message = "岗位名称不能为空")
|
||||
@Size(max = 64, message = "岗位名称长度不能超过64个字符")
|
||||
protected String postName;
|
||||
|
||||
/**
|
||||
* 岗位排序
|
||||
*/
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
protected Integer postSort;
|
||||
|
||||
protected String remark;
|
||||
|
||||
@PositiveOrZero
|
||||
protected String status;
|
||||
|
||||
public PostModel toModel() {
|
||||
PostModel model = new PostModel();
|
||||
|
||||
model.setPostCode(postCode);
|
||||
model.setPostName(postName);
|
||||
model.setPostSort(postSort);
|
||||
model.setRemark(remark);
|
||||
model.setStatus(Convert.toInt(status));
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.agileboot.domain.system.post;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.annotation.ExcelColumn;
|
||||
import com.agileboot.orm.entity.SysPostEntity;
|
||||
import com.agileboot.orm.enums.dictionary.CommonStatusEnum;
|
||||
import com.agileboot.orm.enums.interfaces.BasicEnumUtil;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PostDTO {
|
||||
|
||||
public PostDTO(SysPostEntity entity) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
statusStr = BasicEnumUtil.getDescriptionByValue(CommonStatusEnum.class, entity.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@ExcelColumn(name = "岗位ID")
|
||||
private Long postId;
|
||||
|
||||
|
||||
@ExcelColumn(name = "岗位编码")
|
||||
private String postCode;
|
||||
|
||||
@ExcelColumn(name = "岗位名称")
|
||||
private String postName;
|
||||
|
||||
|
||||
@ExcelColumn(name = "岗位排序")
|
||||
private String postSort;
|
||||
|
||||
@ExcelColumn(name = "备注")
|
||||
private String remark;
|
||||
|
||||
private String status;
|
||||
|
||||
@ExcelColumn(name = "状态")
|
||||
private String statusStr;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user