first commit

This commit is contained in:
root 2025-01-10 14:16:18 +08:00
parent 04ac5d8f68
commit 4b4124df36
923 changed files with 231475 additions and 0 deletions

279
java/filesmanagesystem.iml Normal file
View File

@ -0,0 +1,279 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
<facet type="web" name="Web">
<configuration>
<webroots />
<sourceRoots>
<root url="file://$MODULE_DIR$/src/main/java" />
<root url="file://$MODULE_DIR$/src/main/resources" />
<root url="file://$MODULE_DIR$/target/generated-sources/annotations" />
</sourceRoots>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/target/generated-sources/annotations" isTestSource="false" generated="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.7.3" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.11" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.11" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.17.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.17.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.36" level="project" />
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.30" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.7.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.3.22" level="project" />
<orderEntry type="library" name="Maven: com.google.zxing:core:3.5.0" level="project" />
<orderEntry type="library" name="Maven: com.google.zxing:javase:3.5.0" level="project" />
<orderEntry type="library" name="Maven: com.beust:jcommander:1.82" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.github.jai-imageio:jai-imageio-core:1.4.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.pdfbox:pdfbox:2.0.21" level="project" />
<orderEntry type="library" name="Maven: org.apache.pdfbox:fontbox:2.0.21" level="project" />
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-security:2.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-config:5.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.3.22" level="project" />
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:6.1.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport-native-unix-common:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.4.22" level="project" />
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-websocket:2.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-messaging:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-websocket:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-cache:2.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-webflux:2.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-reactor-netty:2.7.3" level="project" />
<orderEntry type="library" name="Maven: io.projectreactor.netty:reactor-netty-http:1.0.22" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec-http:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec-http2:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver-dns:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec-dns:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver-dns-native-macos:osx-x86_64:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver-dns-classes-macos:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport-native-epoll:linux-x86_64:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport-classes-epoll:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.projectreactor.netty:reactor-netty-core:1.0.22" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler-proxy:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec-socks:4.1.79.Final" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-webflux:5.3.22" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.7.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.7.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.7.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.7.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.4.8" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:2.4.8" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.ow2.asm:asm:9.1" level="project" />
<orderEntry type="library" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3" level="project" />
<orderEntry type="library" name="Maven: jakarta.activation:jakarta.activation-api:1.2.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.22.0" level="project" />
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest:2.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter:5.8.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.8.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.8.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.1.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-params:5.8.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.8.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-engine:1.8.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:4.5.1" level="project" />
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.12.13" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.12.13" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:3.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-junit-jupiter:4.5.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.22" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.3.22" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.9.0" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:30.0-jre" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:failureaccess:1.0.1" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava" level="project" />
<orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:3.0.2" level="project" />
<orderEntry type="library" name="Maven: org.checkerframework:checker-qual:3.5.0" level="project" />
<orderEntry type="library" name="Maven: com.google.errorprone:error_prone_annotations:2.3.4" level="project" />
<orderEntry type="library" name="Maven: com.google.j2objc:j2objc-annotations:1.3" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.7.3" level="project" />
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.65" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.65" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.65" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-quartz:2.7.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.3.22" level="project" />
<orderEntry type="library" name="Maven: org.quartz-scheduler:quartz:2.3.2" level="project" />
<orderEntry type="library" name="Maven: com.mchange:mchange-commons-java:0.2.15" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.2.2" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.5.9" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:2.0.7" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:druid:1.2.3" level="project" />
<orderEntry type="library" name="Maven: javax.annotation:javax.annotation-api:1.3.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.7.3" level="project" />
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:4.0.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.3.22" level="project" />
<orderEntry type="library" name="Maven: com.deepoove:poi-tl:1.10.0" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.36" level="project" />
<orderEntry type="library" name="Maven: com.deepoove:poi-ooxml-schemas-extra:4.1.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-transcoder:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-anim:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-css:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-ext:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-parser:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-svg-dom:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-awt-util:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:xmlgraphics-commons:2.6" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:1.3.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-bridge:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-script:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-dom:1.14" level="project" />
<orderEntry type="library" name="Maven: xalan:xalan:2.7.2" level="project" />
<orderEntry type="library" name="Maven: xalan:serializer:2.7.2" level="project" />
<orderEntry type="library" name="Maven: xml-apis:xml-apis:1.4.01" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-gvt:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-shared-resources:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-svggen:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-util:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-constants:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-i18n:1.14" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-xml:1.14" level="project" />
<orderEntry type="library" name="Maven: xml-apis:xml-apis-ext:1.3.04" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-codec:1.14" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.1.22" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.7.3" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: mysql:mysql-connector-java:8.0.30" level="project" />
<orderEntry type="library" name="Maven: org.xerial:sqlite-jdbc:3.32.3.2" level="project" />
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-boot-starter:3.4.3" level="project" />
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus:3.4.3" level="project" />
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-generator:3.4.1" level="project" />
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-extension:3.4.1" level="project" />
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-core:3.4.1" level="project" />
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-annotation:3.4.1" level="project" />
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:3.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" />
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.24" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.7.3" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.7" level="project" />
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.8.8" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi:4.1.2" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.15" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-math3:3.6.1" level="project" />
<orderEntry type="library" name="Maven: com.zaxxer:SparseBitSet:1.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml:4.1.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml-schemas:4.1.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlbeans:xmlbeans:3.1.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.19" level="project" />
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" />
<orderEntry type="library" name="Maven: org.jfree:jfreechart:1.5.3" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:fastjson:1.2.70" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2:2.0.29" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-boot-starter:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-oas:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.swagger.core.v3:swagger-annotations:2.1.2" level="project" />
<orderEntry type="library" name="Maven: io.swagger.core.v3:swagger-models:2.1.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-core:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.github.classgraph:classgraph:4.8.83" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-webmvc:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-webflux:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:3.0.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.mapstruct:mapstruct:1.3.1.Final" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-data-rest:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-bean-validators:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:3.0.0" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.20" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.20" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-ui:3.0.0" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:2.0.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-boot-starter:3.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-boot-autoconfigure:3.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring:3.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-annotations:3.0.2" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-core:3.0.2" level="project" />
<orderEntry type="library" name="Maven: org.javassist:javassist:3.25.0-GA" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-core:1.5.22" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.3" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-ui:3.0.2" level="project" />
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.28" level="project" />
<orderEntry type="library" name="Maven: org.jsoup:jsoup:1.11.3" level="project" />
<orderEntry type="library" name="Maven: com.github.ulisesbocchio:jasypt-spring-boot-starter:1.16" level="project" />
<orderEntry type="library" name="Maven: com.github.ulisesbocchio:jasypt-spring-boot:1.16" level="project" />
<orderEntry type="library" name="Maven: org.jasypt:jasypt:1.9.2" level="project" />
<orderEntry type="library" name="Maven: org.lionsoul:ip2region:1.7.2" level="project" />
<orderEntry type="library" name="Maven: com.github.whvcse:easy-captcha:1.6.2" level="project" />
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" />
<orderEntry type="library" name="Maven: com.upyun:java-sdk:4.2.3" level="project" />
<orderEntry type="library" name="Maven: junit:junit:4.13.2" level="project" />
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest-core:2.2" level="project" />
<orderEntry type="library" name="Maven: org.json:json:20160212" level="project" />
<orderEntry type="library" name="Maven: com.squareup.okhttp3:okhttp:4.9.3" level="project" />
<orderEntry type="library" name="Maven: com.squareup.okio:okio:2.8.0" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-common:1.6.21" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib:1.6.21" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains:annotations:13.0" level="project" />
<orderEntry type="library" name="Maven: com.amazonaws:aws-java-sdk-s3:1.12.470" level="project" />
<orderEntry type="library" name="Maven: com.amazonaws:aws-java-sdk-kms:1.12.470" level="project" />
<orderEntry type="library" name="Maven: com.amazonaws:aws-java-sdk-core:1.12.470" level="project" />
<orderEntry type="library" name="Maven: software.amazon.ion:ion-java:1.0.2" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.13.3" level="project" />
<orderEntry type="library" name="Maven: joda-time:joda-time:2.8.1" level="project" />
<orderEntry type="library" name="Maven: com.amazonaws:jmespath-java:1.12.470" level="project" />
<orderEntry type="library" name="Maven: com.qiniu:qiniu-java-sdk:7.12.1" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.google.code.gson:gson:2.9.1" level="project" />
<orderEntry type="library" name="Maven: com.jcraft:jsch:0.1.55" level="project" />
<orderEntry type="library" name="Maven: com.github.lookfirst:sardine:5.10" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.13" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.15" level="project" />
<orderEntry type="library" name="Maven: org.glassfish.jaxb:jaxb-runtime:2.3.6" level="project" />
<orderEntry type="library" name="Maven: org.glassfish.jaxb:txw2:2.3.6" level="project" />
<orderEntry type="library" name="Maven: com.sun.istack:istack-commons-runtime:3.0.12" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.sun.activation:jakarta.activation:1.2.2" level="project" />
<orderEntry type="library" name="Maven: commons-chain:commons-chain:1.2" level="project" />
</component>
</module>

371
java/pom.xml Normal file
View File

@ -0,0 +1,371 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<groupId>com.yfd</groupId>
<artifactId>filesmanagesystem</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>filesmanagesystem</name>
<description>文件管理系统</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- spring-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 生成二维码 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.5.0</version>
</dependency>
<!-- 生成pdf文件 -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.21</version>
</dependency>
<!-- spring-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--Spring boot Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- WebSocket依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--Spring 缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Guava是一种基于开源的Java库高性能数据缓存-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.0-jre</version>
</dependency>
<!-- spring-内置Tomcat-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- spring-quartz任务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!-- spring-elasticsearch搜素-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-elasticsearch</artifactId>-->
<!-- </dependency>-->
<!-- spring-Mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!-- druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.3</version>
</dependency>
<!--数据库连接-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--poi-tl 生成word -->
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.10.0</version>
</dependency>
<!-- druid相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
<!-- mysql数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- sqlite-jdbc数据库 -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.32.3.2</version>
</dependency>
<!-- mybatis-plus 数据库扩展插件-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!--apache.commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!--lombok bean注解 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 日志相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 胡图工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.8</version>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.jfree</groupId>
<artifactId>jfreechart</artifactId>
<version>1.5.3</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.29</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
<!-- 数据库密码加密 -->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>1.16</version>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
<!-- Java图形验证码 -->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
<!-- 解析客户端操作系统、浏览器信息 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.21</version>
</dependency>
<!-- 存储策略相关 API, 对象存储、FTP、 Rest API-->
<dependency>
<groupId>com.upyun</groupId>
<artifactId>java-sdk</artifactId>
<version>4.2.3</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.12.470</version>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.12.1</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<dependency>
<groupId>com.github.lookfirst</groupId>
<artifactId>sardine</artifactId>
<version>5.10</version>
</dependency>
<!-- 过滤器链 -->
<dependency>
<groupId>commons-chain</groupId>
<artifactId>commons-chain</artifactId>
<version>1.2</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.mapstruct</groupId>-->
<!-- <artifactId>mapstruct</artifactId>-->
<!-- <version>1.5.3.Final</version>-->
<!-- </dependency>-->
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.*</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.8</version>
<executions>
<execution>
<id>generate-docs</id>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html</backend>
<doctype>book</doctype>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,54 @@
package com.yfd.platform;
import com.yfd.platform.annotation.rest.AnonymousGetMapping;
import com.yfd.platform.datasource.DynamicDataSourceConfig;
import com.yfd.platform.utils.SpringContextHolder;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
//@SpringBootApplication
@RestController
@EnableTransactionManagement
@ServletComponentScan("com.yfd.platform.config")
@MapperScan(basePackages = "com.yfd.platform.modules.*.convert.impl,com.yfd.platform.modules.*.mapper,com.yfd.platform.*.mapper")
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@Import({DynamicDataSourceConfig.class})
@EnableCaching
@EnableScheduling
@EnableAsync
public class PlatformApplication {
public static void main(String[] args) {
SpringApplication.run(PlatformApplication.class, args);
}
@Bean
public SpringContextHolder springContextHolder() {
return new SpringContextHolder();
}
@Bean
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
/**
* 访问首页提示
*
* @return /
*/
@AnonymousGetMapping("/")
public String index() {
return "Backend service started successfully";
}
}

View File

@ -0,0 +1,13 @@
package com.yfd.platform;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(PlatformApplication.class);
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.annotation;
import java.lang.annotation.*;
/**
* @author jacky
* 用于标记匿名访问方法
*/
@Inherited
@Documented
@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonymousAccess {
}

View File

@ -0,0 +1,20 @@
package com.yfd.platform.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author LiMengNan
* @date 2018-11-24
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
String module() default "";
}

View File

@ -0,0 +1,80 @@
package com.yfd.platform.annotation;
import com.yfd.platform.modules.storage.model.enums.StorageParamTypeEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标记存储类型参数名称
*
* @author zhengsl
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface StorageParamItem {
/**
* 字段显示排序值, 值越小, 越靠前. 默认为 99
*/
int order() default 99;
/**
* 参数键, 如果为空, 则使用字段名称.
*/
String key() default "";
/**
* 参数名称, 用于网页上显示名称.
*/
String name();
/**
* 字段类型, 默认为 input, 可选值为: input, select, switch.
*/
StorageParamTypeEnum type() default StorageParamTypeEnum.INPUT;
/**
* {@link #type} select , 选项的值.
*/
StorageParamSelectOption[] options() default {};
/**
* {@link #type} select , 选项的值. 通过 {@link StorageParamSelect#getOptions)} 方法获取选项值.
*/
Class<? extends StorageParamSelect> optionsClass() default StorageParamSelect.class;
/**
* 参数值是否可以为空. 如不为空则抛出异常.
*/
boolean required() default true;
/**
* 如果填写值为空则给予默认值.
* 支持 ${xxx} 变量, 会读取配置文件中的值, 如获取失败, 会默认为空.
*/
String defaultValue() default "";
/**
* 参数描述信息, 用户在用户填写时, 进行提示.
*/
String description() default "";
/**
* 参数下方的提示链接, 如果为空, 则不显示.
*/
String link() default "";
/**
* 参数下方的提示链接文件信息, 如果为空, 则默认为链接地址.
*/
String linkName() default "";
/**
* 是否忽略参数不传递给前端.
*/
boolean ignoreInput() default false;
}

View File

@ -0,0 +1,28 @@
package com.yfd.platform.annotation;
import com.yfd.platform.modules.storage.model.bo.StorageSourceParamDef;
import com.yfd.platform.modules.storage.model.param.IStorageParam;
import java.util.List;
/**
* 存储源参数下拉值接口.
*
* @author zhengsl
*/
public interface StorageParamSelect {
/**
* 获取存储源参数下拉选项列表.
*
* @param storageParamItem
* 存储源下拉参数定义
*
* @param targetParam
* 存储源参数
*
* @return 存储源参数下拉选项列表
*/
List<StorageSourceParamDef.Options> getOptions(StorageParamItem storageParamItem, IStorageParam targetParam);
}

View File

@ -0,0 +1,27 @@
package com.yfd.platform.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标记存储类型参数类型为 select , 数据的下拉值.
*
* @author zhengsl
*/
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface StorageParamSelectOption {
/**
* 选项显示值
*/
String label();
/**
* 选项存储值
*/
String value();
}

View File

@ -0,0 +1,32 @@
package com.yfd.platform.annotation.impl;
import com.yfd.platform.annotation.StorageParamItem;
import com.yfd.platform.annotation.StorageParamSelect;
import com.yfd.platform.modules.storage.model.bo.StorageSourceParamDef;
import com.yfd.platform.modules.storage.model.param.IStorageParam;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* 编码格式动态参数.
*
* @author zhengsl
*/
public class EncodingStorageParamSelect implements StorageParamSelect {
@Override
public List<StorageSourceParamDef.Options> getOptions(StorageParamItem storageParamItem, IStorageParam targetParam) {
List<StorageSourceParamDef.Options> options = new ArrayList<>();
for (String name : Charset.availableCharsets().keySet()) {
StorageSourceParamDef.Options option = new StorageSourceParamDef.Options(name);
options.add(option);
}
return options;
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.annotation.rest;
import com.yfd.platform.annotation.AnonymousAccess;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.annotation.*;
/**
* Annotation for mapping HTTP {@code GET} requests onto specific handler
* methods.
* <p>
* 支持匿名访问 GetMapping
*
* @author liaojinlong
* @see RequestMapping
*/
@AnonymousAccess
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface AnonymousGetMapping {
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class)
String name() default "";
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] headers() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*
* @since 4.3.5
*/
@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] produces() default {};
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.aspect;
import com.yfd.platform.system.domain.SysLog;
import com.yfd.platform.system.mapper.SysUserMapper;
import com.yfd.platform.system.service.ISysLogService;
import com.yfd.platform.system.service.IUserService;
import com.yfd.platform.utils.RequestHolder;
import com.yfd.platform.utils.SecurityUtils;
import com.yfd.platform.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* @author
* @date 2018-11-24
*/
@Component
@Aspect
@Slf4j
public class LogAspect {
@Resource
private final ISysLogService sysLogService;
@Resource
private IUserService userService;
ThreadLocal<Long> currentTime = new ThreadLocal<>();
public LogAspect(ISysLogService sysLogService) {
this.sysLogService = sysLogService;
}
/**
* 配置切入点
*/
@Pointcut("@annotation(com.yfd.platform.annotation.Log)")
public void logPointcut() {
// 该方法无方法体,主要为了让同类中其他方法使用此切入点
}
/**
* 配置环绕通知,使用在方法logPointcut()上注册的切入点
*
* @param joinPoint join point for advice
*/
@Around("logPointcut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result;
currentTime.set(System.currentTimeMillis());
result = joinPoint.proceed();
SysLog log = new SysLog("INFO");
currentTime.remove();
HttpServletRequest request = RequestHolder.getHttpServletRequest();
Map<String, String> nameInfo = userService.getNameInfo();
String nickname = nameInfo.get("nickname");
String username = nameInfo.get("username");
sysLogService.save(nickname, username, StringUtils.getBrowser(request),
StringUtils.getIp(request), joinPoint, log);
return result;
}
public String getUsername() {
try {
return SecurityUtils.getCurrentUsername();
} catch (Exception e) {
return "";
}
}
}

View File

@ -0,0 +1,147 @@
package com.yfd.platform.component;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/**
* @author Huhailong
* SSE Server send Event 服务器推送服务
*/
@Slf4j
public class ServerSendEventServer {
/**
* 当前连接数
*/
private static AtomicInteger count = new AtomicInteger(0);
private static Map<String, SseEmitter> sseEmitterMap =
new ConcurrentHashMap<>();
public static SseEmitter connect(String userId) {
//设置超时时间0表示不过期默认是30秒超过时间未完成会抛出异常
SseEmitter sseEmitter = new SseEmitter(0L);
//SseEmitter sseEmitter = new SseEmitter();
//注册回调
sseEmitter.onCompletion(completionCallBack(userId));
sseEmitter.onError(errorCallBack(userId));
sseEmitter.onTimeout(timeOutCallBack(userId));
sseEmitterMap.put(userId, sseEmitter);
//数量+1
count.getAndIncrement();
log.info("create new sse connect ,current user:{}", userId);
return sseEmitter;
}
/**
* 给指定用户发消息
*/
public static void sendMessage(String userId, String message) {
if (sseEmitterMap.containsKey(userId)) {
try {
sseEmitterMap.get(userId).send(message);
} catch (IOException e) {
log.error("user id:{}, send message error:{}", userId,
e.getMessage());
e.printStackTrace();
}
}
}
/**
* 给所有用户发消息
*/
public static void sendMessage(String message) {
if (sseEmitterMap != null && !sseEmitterMap.isEmpty()) {
sseEmitterMap.forEach((k, v) -> {
// 发送消息
sendMessage(k, message);
});
}
}
/**
* 想多人发送消息组播
*/
public static void groupSendMessage(String groupId, String message) {
if (sseEmitterMap != null && !sseEmitterMap.isEmpty()) {
sseEmitterMap.forEach((k, v) -> {
try {
if (k.startsWith(groupId)) {
v.send(message, MediaType.APPLICATION_JSON);
}
} catch (IOException e) {
log.error("user id:{}, send message error:{}", groupId,
message);
removeUser(k);
}
});
}
}
public static void batchSendMessage(String message) {
sseEmitterMap.forEach((k, v) -> {
try {
v.send(message, MediaType.APPLICATION_JSON);
} catch (IOException e) {
log.error("user id:{}, send message error:{}", k,
e.getMessage());
removeUser(k);
}
});
}
/**
* 群发消息
*/
public static void batchSendMessage(String message, Set<String> userIds) {
userIds.forEach(userId -> sendMessage(userId, message));
}
public static void removeUser(String userId) {
sseEmitterMap.remove(userId);
//数量-1
count.getAndDecrement();
log.info("remove user id:{}", userId);
}
public static List<String> getIds() {
return new ArrayList<>(sseEmitterMap.keySet());
}
public static int getUserCount() {
return count.intValue();
}
private static Runnable completionCallBack(String userId) {
return () -> {
log.info("结束连接,{}", userId);
removeUser(userId);
};
}
private static Runnable timeOutCallBack(String userId) {
return () -> {
log.info("连接超时,{}", userId);
removeUser(userId);
};
}
private static Consumer<Throwable> errorCallBack(String userId) {
return throwable -> {
log.error("连接异常,{}", userId);
removeUser(userId);
};
}
}

View File

@ -0,0 +1,106 @@
package com.yfd.platform.component;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;
@ServerEndpoint("/websocket/{token}")
@Component
public class WebSocketServer {
private static int onlineCount=0;//在线人数
private static CopyOnWriteArrayList<WebSocketServer> webSocketSet=new CopyOnWriteArrayList<WebSocketServer>();//在线用户集合
private Session session;//与某个客户端的连接会话
private String currentUser;
@OnOpen
public void onOpen(@PathParam("token") String token, Session session){
this.currentUser = token;
this.session=session;
webSocketSet.add(this);//加入set中
addOnlineCount();
System.out.println("有新连接加入!当前在线人数为"+getOnlineCount());
allCurrentOnline();
}
@OnClose
public void onClose(){
webSocketSet.remove(this);
subOnlineCount();
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
allCurrentOnline();
}
@OnMessage
public void onMessage(String message, Session session){
System.out.println("来自客户端的消息:"+message);
for (WebSocketServer item:webSocketSet){
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
continue;
}
}
}
@OnError
public void onError(Session session, Throwable throwable){
System.out.println("发生错误!");
throwable.printStackTrace();
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 获取当前所有在线用户名
*/
public static void allCurrentOnline(){
for (WebSocketServer item : webSocketSet) {
System.out.println(item.currentUser);
}
}
/**
* 发送给指定用户
*/
public static void sendMessageTo(String message,String token) throws IOException {
for (WebSocketServer item : webSocketSet) {
if(item.currentUser.equals(token)){
item.session.getBasicRemote().sendText(message);
}
}
}
/**
* 群发自定义消息
*/
public static void sendInfo(String message) throws IOException {
System.out.println(message);
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount(){
return onlineCount;
}
public static synchronized void addOnlineCount(){
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount(){
WebSocketServer.onlineCount--;
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "file")
public class FileProperties {
/** 文件大小限制 */
private Long maxSize;
/** 头像大小限制 */
private Long avatarMaxSize;
private ElPath mac;
private ElPath linux;
private ElPath windows;
public ElPath getPath(){
String os = System.getProperty("os.name");
if(os.toLowerCase().startsWith("win")) {
return windows;
} else if(os.toLowerCase().startsWith("mac")){
return mac;
}
return linux;
}
@Data
public static class ElPath{
private String path;
private String avatar;
}
}

View File

@ -0,0 +1,24 @@
package com.yfd.platform.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author LiMengNan
* @Date: 2023/3/27 18:07
* @Description:
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(value = Throwable.class)
public ResponseResult handleException(Throwable e) {
log.error("message:{}", e.getMessage());
return ResponseResult.error(e.getMessage());
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.system.domain.QuartzJob;
import com.yfd.platform.system.mapper.QuartzJobMapper;
import com.yfd.platform.utils.QuartzManage;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author
* @date 2019-01-07
*/
@Component
@RequiredArgsConstructor
public class JobRunner implements ApplicationRunner {
private static final Logger log = LoggerFactory.getLogger(JobRunner.class);
private final QuartzJobMapper quartzJobMapper;
private final QuartzManage quartzManage;
/**
* 项目启动时重新激活启用的定时任务
*
* @param applicationArguments /
*/
@Override
public void run(ApplicationArguments applicationArguments) {
log.info("--------------------注入定时任务---------------------");
List<QuartzJob> quartzJobs =
quartzJobMapper.selectList(new LambdaQueryWrapper<QuartzJob>().eq(QuartzJob::getStatus, "1"));
quartzJobs.forEach(quartzManage::addJob);
log.info("--------------------定时任务注入完成---------------------");
}
}

View File

@ -0,0 +1,76 @@
package com.yfd.platform.config;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.component.ServerSendEventServer;
import com.yfd.platform.constant.Constant;
import com.yfd.platform.system.domain.LoginUser;
import com.yfd.platform.system.domain.Message;
import com.yfd.platform.system.service.IMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private WebConfig webConfig;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
FilterChain filterChain) throws ServletException, IOException {
//获取token
String uri = httpServletRequest.getRequestURI();
String token = httpServletRequest.getHeader("token");
if (StrUtil.isEmpty(token) || "/user/login".equals(uri)) {
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
//解析token
boolean isok = JWTUtil.verify(token, "12345678".getBytes());
String userid = "";
if (isok) {
final JWT jwt = JWTUtil.parseToken(token);
userid = jwt.getPayload("userid").toString();
long expire_time = (Long) jwt.getPayload("expire_time");
if (System.currentTimeMillis() > expire_time) {
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Token超过期限");
return;
}
}
//从cachekey中获取用户信息
String cachekey = "login:" + userid;
String jsonstr = webConfig.loginuserCache().get(cachekey);
LoginUser loginUser = JSON.parseObject(jsonstr, LoginUser.class);
if (ObjectUtil.isEmpty(loginUser)) {
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN,
"登录用户已失效!");
return;
}
//存入SecurityContextHolder
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginUser, null,
loginUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
webConfig.loginuserCache().put(Constant.TOKEN + userid, token);
//放行过滤器
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}

View File

@ -0,0 +1,50 @@
package com.yfd.platform.config;
import cn.hutool.cache.Cache;
import cn.hutool.cache.impl.CacheObj;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.component.ServerSendEventServer;
import com.yfd.platform.constant.Constant;
import com.yfd.platform.system.domain.Message;
import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.service.IMessageService;
import com.yfd.platform.system.service.IUserService;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Iterator;
/**
* @author LiMengNan
* @Date: 2023/3/24 15:56
* @Description:
*/
@Component
public class MessageConfig {
@Resource
private IMessageService messageService;
@Resource
private IUserService userService;
@Resource
private WebConfig webConfig;
public void sendMessage() {
long count =
messageService.count(new LambdaQueryWrapper<Message>().eq(Message::getStatus, "1"));
String userId = userService.getUserInfo().getId();
String token = webConfig.loginuserCache().get(Constant.TOKEN + userId);
ServerSendEventServer.sendMessage(token, count + "");
}
public void addMessage(Message message) {
messageService.save(message);
long count =
messageService.count(new LambdaQueryWrapper<Message>().eq(Message::getStatus, "1"));
ServerSendEventServer.sendMessage(count + "");
}
}

View File

@ -0,0 +1,174 @@
/*
* Copyright (c) 2011-2022, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.yfd.platform.utils.TypeUtils;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaClass;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.invoker.Invoker;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/**
* 自定义枚举属性转换器
*
* @author hubin
* @since 2017-10-11
*/
public class MybatisEnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {
private static final Map<String, String> TABLE_METHOD_OF_ENUM_TYPES = new ConcurrentHashMap<>();
private static final ReflectorFactory REFLECTOR_FACTORY = new DefaultReflectorFactory();
private final Class<E> enumClassType;
private final Class<?> propertyType;
private final Invoker getInvoker;
public MybatisEnumTypeHandler(Class<E> enumClassType) {
if (enumClassType == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.enumClassType = enumClassType;
MetaClass metaClass = MetaClass.forClass(enumClassType, REFLECTOR_FACTORY);
String name = "value";
if (!IEnum.class.isAssignableFrom(enumClassType)) {
name = findEnumValueFieldName(this.enumClassType).orElseThrow(() -> new IllegalArgumentException(String.format("Could not find @EnumValue in Class: %s.", this.enumClassType.getName())));
}
this.propertyType = TypeUtils.resolvePrimitiveIfNecessary(metaClass.getGetterType(name));
this.getInvoker = metaClass.getGetInvoker(name);
}
/**
* 查找标记标记EnumValue字段
*
* @param clazz class
* @return EnumValue字段
* @since 3.3.1
*/
public static Optional<String> findEnumValueFieldName(Class<?> clazz) {
if (clazz != null && clazz.isEnum()) {
String className = clazz.getName();
return Optional.ofNullable(CollectionUtils.computeIfAbsent(TABLE_METHOD_OF_ENUM_TYPES, className, key -> {
Optional<Field> fieldOptional = findEnumValueAnnotationField(clazz);
return fieldOptional.map(Field::getName).orElse(null);
}));
}
return Optional.empty();
}
private static Optional<Field> findEnumValueAnnotationField(Class<?> clazz) {
return Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(EnumValue.class)).findFirst();
}
/**
* 判断是否为MP枚举处理
*
* @param clazz class
* @return 是否为MP枚举处理
* @since 3.3.1
*/
public static boolean isMpEnums(Class<?> clazz) {
return clazz != null && clazz.isEnum() && (IEnum.class.isAssignableFrom(clazz) || findEnumValueFieldName(clazz).isPresent());
}
@SuppressWarnings("Duplicates")
@Override
public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType)
throws SQLException {
if (jdbcType == null) {
ps.setObject(i, this.getValue(parameter));
} else {
// see r3589
ps.setObject(i, this.getValue(parameter), jdbcType.TYPE_CODE);
}
}
@Override
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
Object value = rs.getObject(columnName);
if (null == value && rs.wasNull()) {
return null;
}
return this.valueOf(value);
}
@Override
public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
Object value = rs.getObject(columnIndex, this.propertyType);
if (null == value && rs.wasNull()) {
return null;
}
return this.valueOf(value);
}
@Override
public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
Object value = cs.getObject(columnIndex, this.propertyType);
if (null == value && cs.wasNull()) {
return null;
}
return this.valueOf(value);
}
private E valueOf(Object value) {
E[] es = this.enumClassType.getEnumConstants();
return Arrays.stream(es).filter((e) -> equalsValue(value, getValue(e))).findAny().orElse(null);
}
/**
* 值比较
*
* @param sourceValue 数据库字段值
* @param targetValue 当前枚举属性值
* @return 是否匹配
* @since 3.3.0
*/
protected boolean equalsValue(Object sourceValue, Object targetValue) {
String sValue = StringUtils.toStringTrim(sourceValue);
String tValue = StringUtils.toStringTrim(targetValue);
if (sourceValue instanceof Number && targetValue instanceof Number
&& new BigDecimal(sValue).compareTo(new BigDecimal(tValue)) == 0) {
return true;
}
return Objects.equals(sValue, tValue);
}
private Object getValue(Object object) {
try {
return this.getInvoker.invoke(object, new Object[0]);
} catch (ReflectiveOperationException e) {
throw ExceptionUtils.mpe(e);
}
}
}

View File

@ -0,0 +1,26 @@
package com.yfd.platform.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/******************************
* 用途说明:
* 作者姓名: pcj
* 创建时间: 2022/10/24 10:50
******************************/
@Configuration
public class MybitsPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config;
import org.quartz.Scheduler;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* 定时任务配置
*
* @author /
* @date 2019-01-07
*/
@Configuration
public class QuartzConfig {
/**
* 解决Job中注入Spring Bean为null的问题
*/
@Component("quartzJobFactory")
public static class QuartzJobFactory extends AdaptableJobFactory {
private final AutowireCapableBeanFactory capableBeanFactory;
public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) {
this.capableBeanFactory = capableBeanFactory;
}
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
/**
* 注入scheduler到spring
*
* @param quartzJobFactory /
* @return Scheduler
* @throws Exception /
*/
@Bean(name = "scheduler")
public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {
SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
factoryBean.setJobFactory(quartzJobFactory);
factoryBean.afterPropertiesSet();
Scheduler scheduler = factoryBean.getScheduler();
scheduler.start();
return scheduler;
}
}

View File

@ -0,0 +1,65 @@
package com.yfd.platform.config;
import java.util.HashMap;
public class ResponseResult extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
// 未登录状态码
public static final String CODE_NOT_LOGIN = "401";
// 成功状态码
public static final String CODE_SUCCESS = "0";
// 错误状态码
public static final String CODE_ERROR = "1";
public ResponseResult() {
}
public static ResponseResult unlogin() {
return message(CODE_NOT_LOGIN, "未登录");
}
public static ResponseResult error() {
return error("操作失败");
}
public static ResponseResult success() {
return success("操作成功");
}
public static ResponseResult error(String msg) {
ResponseResult json = new ResponseResult();
json.put("code", CODE_ERROR);
json.put("msg", msg);
return json;
}
public static ResponseResult message(String code, String msg) {
ResponseResult json = new ResponseResult();
json.put("code", code);
json.put("msg", msg);
return json;
}
public static ResponseResult success(String msg) {
ResponseResult json = new ResponseResult();
json.put("code", CODE_SUCCESS);
json.put("msg", msg);
return json;
}
public static ResponseResult successData(Object obj) {
ResponseResult json = new ResponseResult();
json.put("code", CODE_SUCCESS);
json.put("msg", "操作成功");
json.put("data", obj);
return json;
}
public ResponseResult put(String key, Object value) {
super.put(key, value);
return this;
}
}

View File

@ -0,0 +1,111 @@
package com.yfd.platform.config;
import com.yfd.platform.config.bean.LoginProperties;
import com.yfd.platform.exception.AccessDeniedHandExcetion;
import com.yfd.platform.exception.AuthenticationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
// 注入了加密算法
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@ConfigurationProperties(prefix = "login", ignoreUnknownFields = true)
public LoginProperties loginProperties() {
return new LoginProperties();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception{
return super.authenticationManagerBean();
}
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Autowired
private AuthenticationException authenticationException;
@Autowired
private AccessDeniedHandExcetion accessDeniedHandExcetion;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// 关闭 CSRF
.csrf().disable()
//不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
//对于登录接口允许匿名访问
.authorizeRequests()
.antMatchers("/user/login").anonymous()
.antMatchers("/user/code").permitAll()
.antMatchers("/app/app-doctor/*").permitAll()//医生登录
.antMatchers("/app/app-user/*").permitAll() //家长登录
.and()
.authorizeRequests()
// 放行静态资源
.antMatchers(
HttpMethod.GET,
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/webSocket/**"
).permitAll()
// 放行 swagger 文档
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").permitAll()
// 放行 图片预览
.antMatchers("/report/**").permitAll()
.antMatchers("/images/**").permitAll()
.antMatchers("/pageimage/**").permitAll()
.antMatchers("/avatar/**").permitAll()
.antMatchers("/systemurl/**").permitAll()
.antMatchers("/api/imageserver/upload").permitAll()
.antMatchers("/activity/**").permitAll()
.antMatchers("/appnews/**").permitAll()
.antMatchers("/QRcode/**").permitAll()
.antMatchers("/template/**").permitAll()
.antMatchers("/tempword/**").permitAll()
.antMatchers("/tempzip/**").permitAll()
//测试放行所有访问
.antMatchers("/**/**").permitAll()
//除上面外的所有请求全部需要签权认证
.anyRequest().authenticated();
//允许跨域
httpSecurity.cors();
//将jwt过来器加入到httpSecurity过滤器链中
httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
//配置异常处理器
httpSecurity.exceptionHandling()
.authenticationEntryPoint(authenticationException)
.accessDeniedHandler(accessDeniedHandExcetion);
}
}

View File

@ -0,0 +1,79 @@
package com.yfd.platform.config;
import io.swagger.models.auth.In;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.RequestParameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
import java.util.List;
/**
* swagger配置
*/
@Configuration
public class SwaggerConfig {
Boolean swaggerEnabled = true;
@Bean
public Docket createRestGBApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
// .globalRequestParameters(generateRequestParameters())
.groupName("1. 系统管理")
.select()
.apis(RequestHandlerSelectors.basePackage("com.yfd.platform.system.controller"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.enable(swaggerEnabled);
}
@Bean
public Docket createRestStorageApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
// .globalRequestParameters(generateRequestParameters())
.groupName("2. 文件存储管理")
.select()
.apis(RequestHandlerSelectors.basePackage("com.yfd.platform.modules.storage.controller"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.enable(swaggerEnabled);
}
/**
* 获取通用的全局参数
*
* @return 全局参数列表
*/
private List<RequestParameter> generateRequestParameters(){
RequestParameterBuilder token = new RequestParameterBuilder();
List<RequestParameter> parameters = new ArrayList<>();
token.name("token").description("token").in(In.HEADER.toValue()).required(true).build();
parameters.add(token.build());
return parameters;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("项目API 接口文档")
.description("")
.contact(new Contact("郑顺利", "郑顺利", "13910913995@163.com"))
.version("3.0")
.build();
}
}

View File

@ -0,0 +1,86 @@
package com.yfd.platform.config;
import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.servlet.ServletContext;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Value("${file-space.system}")
private String systempath;
private final ServletContext servletContext;
public WebConfig(ServletContext servletContext) {
this.servletContext = servletContext;
}
@Bean
public Cache<String, String> loginuserCache() {
return CacheUtil.newLRUCache(200);//用户登录缓存数 缺省200
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setMaxAge(3600L);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
private boolean isTomcatEnvironment() {
// 在此处可以根据不同的条件来判断当前运行环境
// 例如可以检查System.getProperty("catalina.home")是否存在
// 或者检查是否存在某个特定的系统属性来区分环境
// return System.getProperty("catalina.home") != null;
return false;
}
@SneakyThrows
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (isTomcatEnvironment()) {
// Tomcat部署环境
String appRoot = servletContext.getRealPath("/");
String iconPath = appRoot + "WEB-INF/classes/static/icon/";
registry.addResourceHandler("/menu/**")
.addResourceLocations("file:" + iconPath)
.setCachePeriod(0);
} else {
// IDEA开发环境
registry.addResourceHandler("/menu/**")
.addResourceLocations("classpath:/static/icon/")
.setCachePeriod(0);
registry.addResourceHandler("swagger-ui.html").addResourceLocations(
"classpath:/META-INF/resources/");
}
String menuUrl = "file:" + systempath + "menu/";
registry.addResourceHandler("/menu/**").addResourceLocations(menuUrl).setCachePeriod(0);
String systemUrl = "file:" + systempath + "user/";
registry.addResourceHandler("/avatar/**").addResourceLocations(systemUrl).setCachePeriod(0);
}
}

View File

@ -0,0 +1,16 @@
package com.yfd.platform.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.bean;
import lombok.Data;
/**
* 登录验证码配置信息
*
* @author: liaojinlong
* @date: 2020/6/10 18:53
*/
@Data
public class LoginCode {
/**
* 验证码配置
*/
private LoginCodeEnum codeType;
/**
* 验证码有效期 分钟
*/
private Long expiration = 2L;
/**
* 验证码内容长度
*/
private int length = 2;
/**
* 验证码宽度
*/
private int width = 111;
/**
* 验证码高度
*/
private int height = 36;
/**
* 验证码字体
*/
private String fontName;
/**
* 字体大小
*/
private int fontSize = 25;
public LoginCodeEnum getCodeType() {
return codeType;
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.bean;
/**
* 验证码配置枚举
*
* @author: liaojinlong
* @date: 2020/6/10 17:40
*/
public enum LoginCodeEnum {
/**
* 算数
*/
arithmetic,
/**
* 中文
*/
chinese,
/**
* 中文闪图
*/
chinese_gif,
/**
* 闪图
*/
gif,
spec
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version loginCode.length.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-loginCode.length.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.bean;
import cn.hutool.core.util.StrUtil;
import com.wf.captcha.*;
import com.wf.captcha.base.Captcha;
import com.yfd.platform.exception.BadConfigurationException;
import lombok.Data;
import java.awt.*;
import java.util.Objects;
/**
* 配置文件读取
*
* @author liaojinlong
* @date loginCode.length0loginCode.length0/6/10 17:loginCode.length6
*/
@Data
public class LoginProperties {
/**
* 账号单用户 登录
*/
private boolean singleLogin = false;
private LoginCode loginCode;
/**
* 用户登录信息缓存
*/
private boolean cacheEnable;
public boolean isSingleLogin() {
return singleLogin;
}
public boolean isCacheEnable() {
return cacheEnable;
}
/**
* 获取验证码生产类
*
* @return /
*/
public Captcha getCaptcha() {
if (Objects.isNull(loginCode)) {
loginCode = new LoginCode();
if (Objects.isNull(loginCode.getCodeType())) {
loginCode.setCodeType(LoginCodeEnum.arithmetic);
}
}
return switchCaptcha(loginCode);
}
/**
* 依据配置信息生产验证码
*
* @param loginCode 验证码配置信息
* @return /
*/
private Captcha switchCaptcha(LoginCode loginCode) {
Captcha captcha;
synchronized (this) {
switch (loginCode.getCodeType()) {
case arithmetic:
// 算术类型 https://gitee.com/whvse/EasyCaptcha
captcha = new ArithmeticCaptcha(loginCode.getWidth(), loginCode.getHeight());
// 几位数运算默认是两位
captcha.setLen(loginCode.getLength());
break;
case chinese:
captcha = new ChineseCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case chinese_gif:
captcha = new ChineseGifCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case gif:
captcha = new GifCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case spec:
captcha = new SpecCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
default:
throw new BadConfigurationException("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
}
}
if(StrUtil.isNotBlank(loginCode.getFontName())){
captcha.setFont(new Font(loginCode.getFontName(), Font.PLAIN, loginCode.getFontSize()));
}
return captcha;
}
}

View File

@ -0,0 +1,31 @@
package com.yfd.platform.config.thread;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "asyncExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数处理器数量
executor.setCorePoolSize(16);
// 最大线程数
executor.setMaxPoolSize(64);
// 队列容量
executor.setQueueCapacity(100);
// 线程名前缀
executor.setThreadNamePrefix("AsyncThread-");
// 线程池任务拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.thread;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 异步任务线程池装配类
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
* @date 2019年10月31日15:06:18
*/
@Slf4j
@Configuration
public class AsyncTaskExecutePool implements AsyncConfigurer {
/** 注入配置类 */
private final AsyncTaskProperties config;
public AsyncTaskExecutePool(AsyncTaskProperties config) {
this.config = config;
}
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(config.getCorePoolSize());
//最大线程数
executor.setMaxPoolSize(config.getMaxPoolSize());
//队列容量
executor.setQueueCapacity(config.getQueueCapacity());
//活跃时间
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
//线程名字前缀
executor.setThreadNamePrefix("el-async-");
// setRejectedExecutionHandler当pool已经达到max size的时候如何处理新任务
// CallerRunsPolicy不在新线程中执行任务而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (throwable, method, objects) -> {
log.error("===="+throwable.getMessage()+"====", throwable);
log.error("exception method:"+method.getName());
};
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.thread;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 线程池配置属性类
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
* @date 2019年10月31日14:58:18
*/
@Data
@Component
@ConfigurationProperties(prefix = "task.pool")
public class AsyncTaskProperties {
private int corePoolSize;
private int maxPoolSize;
private int keepAliveSeconds;
private int queueCapacity;
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.thread;
import org.springframework.stereotype.Component;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 自定义线程名称
* @author
* @date 2019年10月31日17:49:55
*/
@Component
public class TheadFactoryName implements ThreadFactory {
private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public TheadFactoryName() {
this("el-pool");
}
private TheadFactoryName(String name){
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
//此时namePrefix就是 name + 第几个用这个工厂创建线程池的
this.namePrefix = name +
POOL_NUMBER.getAndIncrement();
}
@Override
public Thread newThread(Runnable r) {
//此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程
Thread t = new Thread(group, r,
namePrefix + "-thread-"+threadNumber.getAndIncrement(),
0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.config.thread;
import com.yfd.platform.utils.SpringContextHolder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 用于获取自定义线程池
* @author
* @date 2019年10月31日18:16:47
*/
public class ThreadPoolExecutorUtil {
public static ThreadPoolExecutor getPoll(){
AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class);
return new ThreadPoolExecutor(
properties.getCorePoolSize(),
properties.getMaxPoolSize(),
properties.getKeepAliveSeconds(),
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(properties.getQueueCapacity()),
new TheadFactoryName()
);
}
}

View File

@ -0,0 +1,48 @@
package com.yfd.platform.constant;
import java.util.Arrays;
import java.util.List;
/**
* @author LiMengNan
* @Date: 2023/3/3 17:40
* @Description: 常量类
*/
public class Constant {
public static final String LOGIN = "login:";
public static final String TOKEN = "token:";
public static final String USER_ID = "userid";
public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String CODE_KEY = "code-key-";
public static final long CODE_EXPIRATION_TIME = 1000 * 60;
/**
* 用于IP定位转换
*/
public static final String REGION = "内网IP|内网IP";
/**
* win 系统
*/
public static final String WIN = "win";
/**
* mac 系统
*/
public static final String MAC = "mac";
/**
* 常用接口
*/
public static class Url {
// IP归属地查询
// public static final String IP_URL = "http://whois.pconline.com
// .cn/ipJson.jsp?ip=%s&json=true";
public static final String IP_URL = "http://whois.pconline.com" +
".cn/ipJson.jsp?ip=%s&json=true";
}
public final static List<String> GRADE_NAMES = Arrays.asList("小班", "中班", "大班", "大大班", "小学一年级", "小学二年级", "小学三年级", "小学四年级", "小学五年级", "小学六年级",
"初中一年级", "初中二年级", "初中三年级", "初中四年级",
"高中一年级", "高中二年级", "高中三年级", "高中四年级", "高中五年级", "高中六年级", "高中七年级");
}

View File

@ -0,0 +1,16 @@
package com.yfd.platform.constant;
/**
* Slf4j mdc 常量
*
* @author zhengsl
*/
public class MdcConstant {
public static final String TRACE_ID = "traceId";
public static final String IP = "ip";
public static final String USER = "user";
}

View File

@ -0,0 +1,13 @@
package com.yfd.platform.constant;
/**
* 系统设置字段常量.
*
* @author zhengsl
*/
public class SystemConfigConstant {
public static final String RSA_HEX_KEY = "rsaHexKey";
}

View File

@ -0,0 +1,29 @@
package com.yfd.platform.constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* ZFile 常量
*
* @author zhengsl
*/
@Configuration
public class ZFileConstant {
public static final Character PATH_SEPARATOR_CHAR = '/';
public static final String PATH_SEPARATOR = "/";
/**
* 最大支持文本文件大小为 ? KB 的文件内容.
*/
public static Long TEXT_MAX_FILE_SIZE_KB = 100L;
@Autowired(required = false)
public void setTextMaxFileSizeMb(@Value("${file-system.preview.text.maxFileSizeKb}") Long maxFileSizeKb) {
ZFileConstant.TEXT_MAX_FILE_SIZE_KB = maxFileSizeKb;
}
}

View File

@ -0,0 +1,17 @@
package com.yfd.platform.datasource;
import java.lang.annotation.*;
/******************************
* 用途说明:
* 作者姓名: wxy
* 创建时间: 2022/9/23 17:48
******************************/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String name() default "";
}

View File

@ -0,0 +1,55 @@
package com.yfd.platform.datasource;
import cn.hutool.core.util.StrUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/******************************
* 用途说明:
* 作者姓名: wxy
* 创建时间: 2022/9/23 17:50
******************************/
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("@annotation(com.yfd.platform.datasource.DataSource)")
public void dataSourcePointCut() {
}
private String DataBaseName;
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
if (StrUtil.isNotBlank(DataBaseName)){
DynamicDataSource.setDataSource(DataBaseName);
}else {
DynamicDataSource.setDataSource("master");
}
try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSource();
}
}
public String getDataBase(Integer type){
if (type == 1){
DataBaseName="master";
}else {
DataBaseName="slave";
}
return DataBaseName;
}
}

View File

@ -0,0 +1,40 @@
package com.yfd.platform.datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
/******************************
* 用途说明:
* 作者姓名: wxy
* 创建时间: 2022/9/23 17:47
******************************/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}

View File

@ -0,0 +1,39 @@
package com.yfd.platform.datasource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/******************************
* 用途说明:
* 作者姓名: wxy
* 创建时间: 2022/9/23 17:45
******************************/
@Configuration
@Component
public class DynamicDataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.druid.master")
public DataSource wglMasterDataSource(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DynamicDataSource dataSource(DataSource wglMasterDataSource, DataSource wglSlaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master",wglMasterDataSource);
return new DynamicDataSource(wglMasterDataSource, targetDataSources);
}
}

View File

@ -0,0 +1,27 @@
package com.yfd.platform.exception;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AccessDeniedHandExcetion implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
JSONObject jobj=new JSONObject();
jobj.putOnce("status","403");
jobj.putOnce("msg","用户权限不足,不能访问");
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().println(JSONUtil.toJsonStr(jobj));
}
}

View File

@ -0,0 +1,32 @@
package com.yfd.platform.exception;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yfd.platform.config.ResponseResult;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AuthenticationException implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.AuthenticationException authException) throws IOException, ServletException {
JSONObject jobj=new JSONObject();
if(authException.getMessage().equals("用户账号不存在!")){
jobj.putOnce("code","401");
jobj.putOnce("msg","用户账号不存在/密码错误,登录失败!");
}else{
jobj.putOnce("code","401");
jobj.putOnce("msg","用户Token失效请重新登录");
}
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().println(JSONUtil.toJsonStr(jobj));
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.exception;
/**
* 统一关于错误配置信息 异常
*
* @author: liaojinlong
* @date: 2020/6/10 18:06
*/
public class BadConfigurationException extends RuntimeException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public BadConfigurationException() {
super();
}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public BadConfigurationException(String message) {
super(message);
}
/**
* Constructs a new runtime exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public BadConfigurationException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new runtime exception with the specified cause and a
* detail message of {@code (cause==null ? null : cause.toString())}
* (which typically contains the class and detail message of
* {@code cause}). This constructor is useful for runtime exceptions
* that are little more than wrappers for other throwables.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public BadConfigurationException(Throwable cause) {
super(cause);
}
/**
* Constructs a new runtime exception with the specified detail
* message, cause, suppression enabled or disabled, and writable
* stack trace enabled or disabled.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @param enableSuppression whether or not suppression is enabled
* or disabled
* @param writableStackTrace whether or not the stack trace should
* be writable
* @since 1.7
*/
protected BadConfigurationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.exception;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
/**
* @author
* @date 2018-11-23
* 统一异常处理
*/
@Getter
public class BadRequestException extends RuntimeException{
private Integer status = BAD_REQUEST.value();
public BadRequestException(String msg){
super(msg);
}
public BadRequestException(HttpStatus status, String msg){
super(msg);
this.status = status.value();
}
}

View File

@ -0,0 +1,20 @@
package com.yfd.platform.exception;
import org.springframework.util.StringUtils;
/**
* @Author pcj
* @Date 2021/1/26 9:07
* @Version 1.0
*/
public class ChildrenExistException extends RuntimeException{
public ChildrenExistException(Class clazz, String field, String val) {
super(ChildrenExistException.generateMessage(clazz.getSimpleName(), field, val));
}
private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity)
+ " with " + field + " "+ val + " Children Exist";
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.exception;
import org.springframework.util.StringUtils;
/**
* @author
* @date 2018-11-23
*/
public class EntityExistException extends RuntimeException {
public EntityExistException(Class clazz, String field, String val) {
super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val));
}
private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity)
+ " with " + field + " "+ val + " existed";
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yfd.platform.exception;
import org.springframework.util.StringUtils;
/**
* @author
* @date 2018-11-23
*/
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(Class clazz, String field, String val) {
super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val));
}
private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity)
+ " with " + field + " "+ val + " does not exist";
}
}

View File

@ -0,0 +1,42 @@
package com.yfd.platform.exception;
import com.yfd.platform.utils.CodeMsg;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* Service 层异常
* 所有 message 均为系统日志打印输出, CodeMsg 中的消息才是返回给客户端的消息.
*
* @author zhengsl
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class ServiceException extends RuntimeException {
private CodeMsg codeMsg;
public ServiceException(CodeMsg codeMsg) {
this.codeMsg = codeMsg;
}
public ServiceException(String message, CodeMsg codeMsg) {
super(message);
this.codeMsg = codeMsg;
}
public ServiceException(String message, Throwable cause, CodeMsg codeMsg) {
super(message, cause);
this.codeMsg = codeMsg;
}
public ServiceException(Throwable cause, CodeMsg codeMsg) {
super(cause);
this.codeMsg = codeMsg;
}
public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, CodeMsg codeMsg) {
super(message, cause, enableSuppression, writableStackTrace);
this.codeMsg = codeMsg;
}
}

View File

@ -0,0 +1,21 @@
package com.yfd.platform.exception;
import com.yfd.platform.modules.storage.model.param.IStorageParam;
import lombok.Getter;
/**
* 存储源自动设置 cors 异常
*
* @author zhengsl
*/
@Getter
public class StorageSourceAutoConfigCorsException extends RuntimeException {
private final IStorageParam iStorageParam;
public StorageSourceAutoConfigCorsException(String message, Throwable cause, IStorageParam iStorageParam) {
super(message, cause);
this.iStorageParam = iStorageParam;
}
}

View File

@ -0,0 +1,60 @@
package com.yfd.platform.exception;
import com.yfd.platform.utils.CodeMsg;
import lombok.EqualsAndHashCode;
import lombok.Getter;
/**
* 存储源异常
*
* @author zhengsl
*/
@EqualsAndHashCode(callSuper = true)
@Getter
public class StorageSourceException extends ServiceException {
/**
* 是否使用异常消息进行接口返回如果是则取异常的 message, 否则取 CodeMsg 中的 message
*/
private boolean responseExceptionMessage;
/**
* 存储源 ID
*/
private final Integer storageId;
public StorageSourceException(CodeMsg codeMsg, Integer storageId, String message) {
super(message, codeMsg);
this.storageId = storageId;
}
public StorageSourceException(CodeMsg codeMsg, Integer storageId, String message, Throwable cause) {
super(message, cause, codeMsg);
this.storageId = storageId;
}
/**
* 根据 responseExceptionMessage 判断使用异常消息进行接口返回如果是则取异常的 message, 否则取 CodeMsg 中的 message
*
* @return 异常消息
*/
public String getResultMessage() {
return responseExceptionMessage ? super.getMessage() : super.getCodeMsg().getMsg();
}
/**
* 设置值是否使用异常消息进行接口返回
*
* @param responseExceptionMessage
* 是否使用异常消息进行接口返回
*
* @return 当前对象
*/
public StorageSourceException setResponseExceptionMessage(boolean responseExceptionMessage) {
this.responseExceptionMessage = responseExceptionMessage;
return this;
}
}

View File

@ -0,0 +1,22 @@
package com.yfd.platform.exception;
import lombok.Getter;
/**
* @author zhengsl
*/
@Getter
public class StorageSourceRefreshTokenException extends RuntimeException {
private final Integer storageId;
public StorageSourceRefreshTokenException(String message, Integer storageId) {
super(message);
this.storageId = storageId;
}
public StorageSourceRefreshTokenException(String message, Throwable cause, Integer storageId) {
super(message, cause);
this.storageId = storageId;
}
}

View File

@ -0,0 +1,25 @@
package com.yfd.platform.exception.file;
import com.yfd.platform.exception.StorageSourceException;
import com.yfd.platform.utils.CodeMsg;
/**
* 无效的存储源异常
*
* @author zhengsl
*/
public class InvalidStorageSourceException extends StorageSourceException {
public InvalidStorageSourceException(String message) {
super(CodeMsg.STORAGE_SOURCE_NOT_FOUND, null, message);
}
public InvalidStorageSourceException(Integer storageId) {
super(CodeMsg.STORAGE_SOURCE_NOT_FOUND, storageId, CodeMsg.STORAGE_SOURCE_NOT_FOUND.getMsg());
}
public InvalidStorageSourceException(Integer storageId, String message) {
super(CodeMsg.STORAGE_SOURCE_NOT_FOUND, storageId, message);
}
}

View File

@ -0,0 +1,21 @@
package com.yfd.platform.exception.init;
import com.yfd.platform.exception.StorageSourceException;
import com.yfd.platform.utils.CodeMsg;
/**
* 存储源初始化异常
*
* @author zhengsl
*/
public class InitializeStorageSourceException extends StorageSourceException {
public InitializeStorageSourceException(CodeMsg codeMsg, Integer storageId, String message) {
super(codeMsg, storageId, message);
}
public InitializeStorageSourceException(CodeMsg codeMsg, Integer storageId, String message, Throwable cause) {
super(codeMsg, storageId, message, cause);
}
}

View File

@ -0,0 +1,20 @@
package com.yfd.platform.modules.config.event;
import com.yfd.platform.modules.config.model.entity.SystemConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author zhengsl
*/
@Slf4j
@Component
public class DirectLinkPrefixModifyHandler implements ISystemConfigModifyHandler {
@Override
public boolean matches(String name) {
return SystemConfig.DIRECT_LINK_PREFIX_NAME.equals(name);
}
}

View File

@ -0,0 +1,21 @@
package com.yfd.platform.modules.config.event;
/**
* 系统设置修改事件
*
* @author zhengsl
*/
public interface ISystemConfigModifyHandler {
/**
* 判断是否匹配当前处理器
*
* @param name
* 配置项名称
*
* @return 是否匹配
*/
boolean matches(String name);
}

View File

@ -0,0 +1,23 @@
package com.yfd.platform.modules.config.event;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* @author zhengsl
*/
@Component
public class SystemConfigModifyHandler implements ISystemConfigModifyHandler {
@Resource
private List<ISystemConfigModifyHandler> handlers;
@Override
public boolean matches(String name) {
return true;
}
}

View File

@ -0,0 +1,48 @@
package com.yfd.platform.modules.config.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.modules.config.model.entity.SystemConfig;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 系统配置 Mapper 接口
*
* @author zhengsl
*/
@Mapper
public interface SystemConfigMapper extends BaseMapper<SystemConfig> {
/**
* 获取所有系统设置
*
* @return 系统设置列表
*/
List<SystemConfig> findAll();
/**
* 根据系统设置名称获取设置信息
*
* @param name
* 系统设置名称
*
* @return 系统设置信息
*/
SystemConfig findByName(@Param("name") String name);
/**
* 批量保存系统设置
*
* @param list
* 系统设置列表
*
* @return 保存记录数
*/
int saveAll(@Param("list") List<SystemConfig> list);
}

View File

@ -0,0 +1,167 @@
package com.yfd.platform.modules.config.model.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 系统设置传输类
*
* @author zhengsl
*/
@Data
@ApiModel(description = "系统设置类")
public class SystemConfigDTO {
@JsonIgnore
@ApiModelProperty(value = "ID", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "站点名称", example = "ZFile Site Name")
private String siteName;
@ApiModelProperty(value = "用户名", example = "admin")
private String username;
@ApiModelProperty(value = "头像地址", example = "https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png")
private String avatar;
@ApiModelProperty(value = "备案号", example = "冀ICP备12345678号-1")
private String icp;
@JsonIgnore
private String password;
@ApiModelProperty(value = "站点域名", example = "https://zfile.vip")
private String domain;
@ApiModelProperty(value = "自定义 JS")
private String customJs;
@ApiModelProperty(value = "自定义 CSS")
private String customCss;
@ApiModelProperty(value = "列表尺寸", notes = "large:大,default:中,small:小", example = "default")
private String tableSize;
@ApiModelProperty(value = "是否显示文档区", example = "true")
private Boolean showDocument;
@ApiModelProperty(value = "网站公告", example = "ZFile 网站公告")
private String announcement;
@ApiModelProperty(value = "是否显示网站公告", example = "true")
private Boolean showAnnouncement;
@ApiModelProperty(value = "页面布局", notes = "full:全屏,center:居中", example = "full")
private String layout;
@ApiModelProperty(value = "是否显示生成直链功能(含直链和路径短链)", example = "true")
private Boolean showLinkBtn;
@ApiModelProperty(value = "是否显示生成短链功能", example = "true")
private Boolean showShortLink;
@ApiModelProperty(value = "是否显示生成路径链接功能", example = "true")
private Boolean showPathLink;
@ApiModelProperty(value = "是否已初始化", example = "true")
private Boolean installed;
@ApiModelProperty(value = "自定义视频文件后缀格式")
private String customVideoSuffix;
@ApiModelProperty(value = "自定义图像文件后缀格式")
private String customImageSuffix;
@ApiModelProperty(value = "自定义音频文件后缀格式")
private String customAudioSuffix;
@ApiModelProperty(value = "自定义文本文件后缀格式")
private String customTextSuffix;
@ApiModelProperty(value = "直链地址前缀")
private String directLinkPrefix;
@ApiModelProperty(value = "直链 Referer 防盗链类型")
private String refererType;
@ApiModelProperty(value = "是否记录下载日志", example = "true")
private Boolean recordDownloadLog;
@ApiModelProperty(value = "直链 Referer 是否允许为空")
private Boolean refererAllowEmpty;
@ApiModelProperty(value = "直链 Referer 值")
private String refererValue;
@ApiModelProperty(value = "登陆验证方式,支持验证码和 2FA 认证")
private String loginVerifyMode;
@ApiModelProperty(value = "登陆验证 Secret")
private String loginVerifySecret;
@ApiModelProperty(value = "根目录是否显示所有存储源", notes = "根目录是否显示所有存储源, 如果为 true, 则根目录显示所有存储源列表, 如果为 false, 则会自动跳转到第一个存储源.", example = "true", required = true)
private Boolean rootShowStorage;
@ApiModelProperty(value = "前端域名", notes = "前端域名,前后端分离情况下需要配置.", example = "http://xxx.example.com")
private String frontDomain;
@ApiModelProperty(value = "是否在前台显示登陆按钮", example = "true")
private Boolean showLogin;
@ApiModelProperty(value = "RAS Hex Key", example = "r2HKbzc1DfvOs5uHhLn7pA==")
private String rsaHexKey;
@ApiModelProperty(value = "默认文件点击习惯", example = "click")
private String fileClickMode;
@ApiModelProperty(value = "最大同时上传文件数", example = "5")
private Integer maxFileUploads;
@ApiModelProperty(value = "onlyOffice 在线预览地址", example = "http://office.zfile.vip")
private String onlyOfficeUrl;
@ApiModelProperty(value = "是否允许路径直链可直接访问", example = "true", required = true)
private Boolean allowPathLinkAnonAccess;
@ApiModelProperty(value = "默认最大显示文件数", example = "1000")
private Integer maxShowSize;
@ApiModelProperty(value = "每次加载更多文件数", example = "50")
private Integer loadMoreSize;
@ApiModelProperty(value = "默认排序字段", example = "name")
private String defaultSortField;
@ApiModelProperty(value = "默认排序方向", example = "asc")
private String defaultSortOrder;
@ApiModelProperty(value = "站点 Home 名称", example = "xxx 的小站")
private String siteHomeName;
@ApiModelProperty(value = "站点 Home Logo", example = "true")
private String siteHomeLogo;
@ApiModelProperty(value = "站点 Logo 点击后链接", example = "https://www.zfile.vip")
private String siteHomeLogoLink;
@ApiModelProperty(value = "站点 Logo 链接打开方式", example = "_blank")
private String siteHomeLogoTargetMode;
@ApiModelProperty(value = "限制直链下载秒数", example = "_blank")
private Integer linkLimitSecond;
@ApiModelProperty(value = "限制直链下载次数", example = "_blank")
private Integer linkDownloadLimit;
@ApiModelProperty(value = "网站 favicon 图标地址", example = "https://www.example.com/favicon.ico")
private String faviconUrl;
@ApiModelProperty(value = "短链过期时间设置", example = "[{value: 1, unit: \"day\"}, {value: 1, unit: \"week\"}, {value: 1, unit: \"month\"}, {value: 1, unit: \"year\"}]")
private String linkExpireTimes;
@ApiModelProperty(value = "是否默认记住密码", example = "true")
private Boolean defaultSavePwd;
}

View File

@ -0,0 +1,46 @@
package com.yfd.platform.modules.config.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 系统设置 entity
*
* @author zhengsl
*/
@Data
@ApiModel(description = "系统设置")
@TableName(value = "fi_system_config")
public class SystemConfig implements Serializable {
public static final String DIRECT_LINK_PREFIX_NAME = "directLinkPrefix";
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty(value = "ID, 新增无需填写", example = "1")
private Integer id;
@TableField(value = "name")
@ApiModelProperty(value = "系统设置名称", example = "siteName")
private String name;
@TableField(value = "`value`")
@ApiModelProperty(value = "系统设置值", example = "ZFile 演示站")
private String value;
@TableField(value = "title")
@ApiModelProperty(value = "系统设置描述", example = "站点名称")
private String title;
}

View File

@ -0,0 +1,33 @@
package com.yfd.platform.modules.config.model.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 复制存储源请求参数
*
* @author zhaojun
*/
@Data
@ApiModel(description = "复制存储源请求请求类")
public class CopyStorageSourceRequest {
@ApiModelProperty(value = "存储源 ID", required = true, example = "1")
@NotNull(message = "存储源 id 不能为空")
private Integer fromId;
@ApiModelProperty(value = "复制后存储源名称", required = true, example = "1")
@NotBlank(message = "复制后存储源名称不能为空")
private String toName;
@ApiModelProperty(value = "复制后存储源别名", required = true, example = "1")
@NotBlank(message = "复制后存储源别名不能为空")
private String toKey;
}

View File

@ -0,0 +1,52 @@
package com.yfd.platform.modules.config.model.request;
import cn.hutool.core.util.StrUtil;
import com.yfd.platform.utils.StringUtils;
import com.yfd.platform.validation.StringListValue;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 获取文件夹下文件列表请求参数
*
* @author zhengsl
*/
@Data
@ApiModel(description = "获取文件夹下文件列表请求类")
public class FileListRequest {
@ApiModelProperty(value = "存储源 key", required = true, example = "local")
@NotBlank(message = "存储源 key 不能为空")
private String storageKey;
@ApiModelProperty(value = "请求路径", example = "/")
private String path;
@ApiModelProperty(value = "文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码", example = "123456")
private String password;
@StringListValue(message = "排序字段参数异常,只能是 name、size、time", vals = {"name", "size", "time"})
private String orderBy;
@StringListValue(message = "排序顺序参数异常,只能是 asc 或 desc", vals = {"asc", "desc"})
private String orderDirection;
public void handleDefaultValue() {
if (StrUtil.isEmpty(path)) {
path = "/";
}
if (StrUtil.isEmpty(orderBy)) {
orderBy = "name";
}
if (StrUtil.isEmpty(orderDirection)) {
orderDirection = "asc";
}
// 自动补全路径, a 补全为 /a/
path = StringUtils.concat(path);
}
}

View File

@ -0,0 +1,28 @@
package com.yfd.platform.modules.config.model.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 系统初始化请求参数
*
* @author zhengsl
*/
@Data
@ApiModel(description = "系统初始化请求类")
public class InstallSystemRequest {
@ApiModelProperty(value = "站点名称", example = "ZFile Site Name")
private String siteName;
@ApiModelProperty(value = "用户名", example = "admin")
private String username;
@ApiModelProperty(value = "密码", example = "123456")
private String password;
@ApiModelProperty(value = "站点域名", example = "https://zfile.vip")
private String domain;
}

View File

@ -0,0 +1,72 @@
package com.yfd.platform.modules.config.model.request;
import com.baomidou.mybatisplus.annotation.TableField;
import com.yfd.platform.modules.storage.model.dto.StorageSourceAllParamDTO;
import com.yfd.platform.modules.storage.model.enums.SearchModeEnum;
import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 保存存储源信息请求类
*
* @author zhengsl
*/
@Data
@ApiModel(description = "存储源基本参数")
public class SaveStorageSourceRequest {
@ApiModelProperty(value = "ID, 新增无需填写", example = "1")
private Integer id;
@ApiModelProperty(value = "存储源名称", example = "阿里云 OSS 存储")
private String name;
@ApiModelProperty(value = "存储源别名", example = "存储源别名,用于 URL 中展示, 如 http://ip:port/{存储源别名}")
private String key;
@ApiModelProperty(value = "存储源备注", example = "这是一个备注信息, 用于管理员区分不同的存储源, 此字段仅管理员可见")
private String remark;
@ApiModelProperty(value = "存储源类型", example = "ftp")
private StorageTypeEnum type;
@ApiModelProperty(value = "是否启用", example = "true")
private Boolean enable;
@ApiModelProperty(value = "是否启用文件操作功能", example = "true", notes = "是否启用文件上传,编辑,删除等操作.")
private Boolean enableFileOperator;
@ApiModelProperty(value = "是否允许匿名进行文件操作", example = "true", notes = "是否允许匿名进行文件上传,编辑,删除等操作.")
private Boolean enableFileAnnoOperator;
@ApiModelProperty(value = "是否开启缓存", example = "true")
private boolean enableCache;
@ApiModelProperty(value = "是否开启缓存自动刷新", example = "true")
private boolean autoRefreshCache;
@ApiModelProperty(value = "是否开启搜索", example = "true")
private boolean searchEnable;
@ApiModelProperty(value = "搜索是否忽略大小写", example = "true")
private boolean searchIgnoreCase;
@TableField(value = "`search_mode`")
@ApiModelProperty(value = "搜索模式", example = "SEARCH_CACHE", notes = "仅从缓存中搜索或直接全量搜索")
private SearchModeEnum searchMode;
@ApiModelProperty(value = "排序值", example = "1")
private Integer orderNum;
@ApiModelProperty(value = "存储源拓展属性")
private StorageSourceAllParamDTO storageSourceAllParam;
@ApiModelProperty(value = "是否默认开启图片模式", example = "true")
private boolean defaultSwitchToImgMode;
@ApiModelProperty(value = "兼容 readme 模式", example = "true", notes = "兼容模式, 目录文档读取 readme.md 文件")
private boolean compatibilityReadme;
}

View File

@ -0,0 +1,12 @@
package com.yfd.platform.modules.config.model.request;
import lombok.Data;
@Data
public class TestAntPathMatcherRequest {
private String antPath;
private String testPath;
}

View File

@ -0,0 +1,53 @@
package com.yfd.platform.modules.config.model.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 站点设置请求参数类
*
* @author zhengsl
*/
@Data
@ApiModel(description = "站点设置请求参数类")
public class UpdateSiteSettingRequest {
@ApiModelProperty(value = "站点名称", required = true, example = "ZFile Site Name")
@NotBlank(message = "站点名称不能为空")
private String siteName;
@ApiModelProperty(value = "站点域名", required = true, example = "https://zfile.vip")
@NotBlank(message = "站点域名不能为空")
private String domain;
@ApiModelProperty(value = "前端域名", notes = "前端域名,前后端分离情况下需要配置.", example = "http://xxx.example.com")
private String frontDomain;
@ApiModelProperty(value = "头像地址", example = "https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png")
private String avatar;
@ApiModelProperty(value = "备案号", example = "冀ICP备12345678号-1")
private String icp;
@ApiModelProperty(value = "最大同时上传文件数", example = "5")
private Integer maxFileUploads;
@ApiModelProperty(value = "站点 Home 名称", example = "xxx 的小站")
private String siteHomeName;
@ApiModelProperty(value = "站点 Home Logo", example = "true")
private String siteHomeLogo;
@ApiModelProperty(value = "站点 Logo 点击后链接", example = "https://www.zfile.vip")
private String siteHomeLogoLink;
@ApiModelProperty(value = "站点 Logo 链接打开方式", example = "_blank")
private String siteHomeLogoTargetMode;
@ApiModelProperty(value = "网站 favicon 图标地址", example = "https://www.example.com/favicon.ico")
private String faviconUrl;
}

View File

@ -0,0 +1,27 @@
package com.yfd.platform.modules.config.model.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 更新存储源排序值请求参数
*
* @author zhaojun
*/
@Data
@ApiModel(description = "更新存储源排序值请求类")
public class UpdateStorageSortRequest {
@ApiModelProperty(value = "存储源 ID", required = true, example = "1")
@NotBlank(message = "存储源 id 不能为空")
private Integer id;
@ApiModelProperty(value = "排序值,值越小越靠前", required = true, example = "5")
@NotBlank(message = "排序值不能为空")
private Integer orderNum;
}

View File

@ -0,0 +1 @@
package com.yfd.platform.modules.config.model.request; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotBlank; /** * 用户修改密码请求参数类 * * @author zhengsl */ @Data @ApiModel(description = "用户修改密码请求参数类") public class UpdateUserNameAndPasswordRequest { @ApiModelProperty(value = "用户名", required = true, example = "admin") @NotBlank(message = "用户名不能为空") private String username; @ApiModelProperty(value = "密码", required = true, example = "123456") @NotBlank(message = "密码不能为空") private String password; }

View File

@ -0,0 +1,73 @@
package com.yfd.platform.modules.config.model.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 显示设置请求参数类
*
* @author zhengsl
*/
@Data
@ApiModel(description = "显示设置请求参数类")
public class UpdateViewSettingRequest {
@ApiModelProperty(value = "根目录是否显示所有存储源", notes = "根目录是否显示所有存储源, 如果为 true, 则根目录显示所有存储源列表, 如果为 false, 则会自动跳转到第一个存储源.", example = "true", required = true)
private Boolean rootShowStorage;
@ApiModelProperty(value = "页面布局", notes = "full:全屏,center:居中", example = "full", required = true)
private String layout;
@ApiModelProperty(value = "列表尺寸", notes = "large:大,default:中,small:小", example = "default", required = true)
private String tableSize;
@ApiModelProperty(value = "自定义视频文件后缀格式")
private String customVideoSuffix;
@ApiModelProperty(value = "自定义图像文件后缀格式")
private String customImageSuffix;
@ApiModelProperty(value = "自定义音频文件后缀格式")
private String customAudioSuffix;
@ApiModelProperty(value = "自定义文本文件后缀格式")
private String customTextSuffix;
@ApiModelProperty(value = "是否显示文档区", example = "true", required = true)
private Boolean showDocument;
@ApiModelProperty(value = "是否显示网站公告", example = "true", required = true)
private Boolean showAnnouncement;
@ApiModelProperty(value = "网站公告", example = "ZFile 网站公告")
private String announcement;
@ApiModelProperty(value = "自定义 CSS")
private String customCss;
@ApiModelProperty(value = "自定义 JS")
private String customJs;
@ApiModelProperty(value = "默认文件点击习惯", example = "click")
private String fileClickMode;
@ApiModelProperty(value = "onlyOffice 在线预览地址", example = "http://office.zfile.vip")
private String onlyOfficeUrl;
@ApiModelProperty(value = "默认最大显示文件数", example = "1000")
private Integer maxShowSize;
@ApiModelProperty(value = "每次加载更多文件数", example = "50")
private Integer loadMoreSize;
@ApiModelProperty(value = "默认排序字段", example = "name")
private String defaultSortField;
@ApiModelProperty(value = "默认排序方向", example = "asc")
private String defaultSortOrder;
@ApiModelProperty(value = "是否默认记住密码", example = "true")
private Boolean defaultSavePwd;
}

View File

@ -0,0 +1,26 @@
package com.yfd.platform.modules.config.model.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author zhengsl
*/
@Data
@ApiModel(description = "WebDAV 设置请求参数类")
public class UpdateWebDAVRequest {
@ApiModelProperty(value = "启用 WebDAV", example = "true")
private Boolean webdavEnable;
@ApiModelProperty(value = "WebDAV 服务器中转下载", example = "true")
private Boolean webdavProxy;
@ApiModelProperty(value = "WebDAV 账号", example = "admin")
private String webdavUsername;
@ApiModelProperty(value = "WebDAV 密码", example = "123456")
private String webdavPassword;
}

View File

@ -0,0 +1,173 @@
package com.yfd.platform.modules.config.service;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import com.yfd.platform.constant.SystemConfigConstant;
import com.yfd.platform.modules.config.event.ISystemConfigModifyHandler;
import com.yfd.platform.modules.config.mapper.SystemConfigMapper;
import com.yfd.platform.modules.config.model.dto.SystemConfigDTO;
import com.yfd.platform.modules.config.model.entity.SystemConfig;
import com.yfd.platform.utils.EnumConvertUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Optional;
/**
* 系统设置 Service
*
* @author zhengsl
*/
@Slf4j
@Service
@CacheConfig(cacheNames = "systemConfig")
public class SystemConfigService {
public static final String CACHE_NAME = "systemConfig";
private static final String DEFAULT_USERNAME = "admin";
private static final String DEFAULT_PASSWORD = "123456";
// private static final String CACHE_NAME = "systemConfig";
@Resource
private SystemConfigMapper systemConfigMapper;
// @Resource
// private SystemConfigService systemConfigService;
@Resource
private CacheManager cacheManager;
@Resource
private ISystemConfigModifyHandler systemConfigModifyHandler;
private final Class<SystemConfigDTO> systemConfigClazz = SystemConfigDTO.class;
/**
* 获取系统设置, 如果缓存中有, 则去缓存取, 没有则查询数据库并写入到缓存中.
*
* @return 系统设置
*/
@Cacheable(key = "'dto'")
public SystemConfigDTO getSystemConfig() {
SystemConfigDTO systemConfigDTO = new SystemConfigDTO();
List<SystemConfig> systemConfigList = systemConfigMapper.findAll();
for (SystemConfig systemConfig : systemConfigList) {
String key = systemConfig.getName();
try {
Field field = systemConfigClazz.getDeclaredField(key);
field.setAccessible(true);
String strVal = systemConfig.getValue();
Class<?> fieldType = field.getType();
Object convertVal;
if (EnumUtil.isEnum(fieldType)) {
convertVal = EnumConvertUtils.convertStrToEnum(fieldType, strVal);
} else {
convertVal = Convert.convert(fieldType, strVal);
}
field.set(systemConfigDTO, convertVal);
} catch (NoSuchFieldException | IllegalAccessException | ConvertException e) {
log.error("通过反射, 将字段 {} 注入 SystemConfigDTO 时出现异常:", key, e);
}
}
return systemConfigDTO;
}
/**
* 获取 RSA Hex 格式密钥
*
* @return RSA Hex 格式密钥
*/
public synchronized String getRsaHexKeyOrGenerate() {
SystemConfigDTO systemConfigDTO = this.getSystemConfig();
String rsaHexKey = systemConfigDTO.getRsaHexKey();
if (StrUtil.isEmpty(rsaHexKey)) {
byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded();
rsaHexKey = HexUtil.encodeHexStr(key);
SystemConfig loginVerifyModeConfig = systemConfigMapper.findByName(SystemConfigConstant.RSA_HEX_KEY);
loginVerifyModeConfig.setValue(rsaHexKey);
systemConfigMapper.updateById(loginVerifyModeConfig);
systemConfigDTO.setRsaHexKey(rsaHexKey);
Cache cache = cacheManager.getCache(CACHE_NAME);
Optional.ofNullable(cache).ifPresent(cache1 -> cache1.put("dto", systemConfigDTO));
}
return rsaHexKey;
}
/**
* 获取系统是否已初始化
*
* @return 管理员名称
*/
public Boolean getSystemIsInstalled() {
return this.getSystemConfig().getInstalled();
}
/**
* 获取后端站点域名
*
* @return 后端站点域名
*/
public String getDomain() {
SystemConfigDTO systemConfigDTO = this.getSystemConfig();
return systemConfigDTO.getDomain();
}
/**
* 获取前端站点域名
*
* @return 前端站点域名
*/
public String getFrontDomain() {
SystemConfigDTO systemConfigDTO = this.getSystemConfig();
return systemConfigDTO.getFrontDomain();
}
/**
* 获取实际的前端站点域名
*
* @return 实际的前端站点域名
*/
public String getRealFrontDomain() {
SystemConfigDTO systemConfigDTO = this.getSystemConfig();
return StrUtil.firstNonNull(systemConfigDTO.getFrontDomain(), systemConfigDTO.getDomain());
}
/**
* 获取前端地址下的 403 页面地址.
*
* @return 前端地址下的 403 页面地址.
*
*/
public String getForbiddenUrl() {
return getRealFrontDomain() + "/403";
}
}

View File

@ -0,0 +1,56 @@
package com.yfd.platform.modules.readme.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* readme 文档配置 entity
*
* @author zhengsl
*/
@Data
@ApiModel(value="readme 文档配置")
@TableName(value = "`fi_readme_config`")
public class ReadmeConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.INPUT)
@ApiModelProperty(value = "ID, 新增无需填写", example = "1")
@JsonIgnore
private Integer id;
@TableField(value = "`storage_id`")
@ApiModelProperty(value="存储源 ID")
private Integer storageId;
@TableField(value = "`description`")
@ApiModelProperty(value = "表达式描述", required = true, example = "用来辅助记忆表达式")
private String description;
@TableField(value = "`expression`")
@ApiModelProperty(value="路径表达式")
private String expression;
@TableField(value = "`readme_text`")
@ApiModelProperty(value="readme 文本内容, 支持 md 语法.")
private String readmeText;
@TableField(value = "`display_mode`")
@ApiModelProperty(value = "显示模式", required = true, example = "readme 显示模式,支持顶部显示: top, 底部显示:bottom, 弹窗显示: dialog")
private String displayMode;
}

View File

@ -0,0 +1,59 @@
package com.yfd.platform.modules.storage.chain;
import com.yfd.platform.modules.storage.chain.command.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.chain.impl.ChainBase;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* 文件处理责任链定义
*
* @author zhengsl
*/
@Service
@Slf4j
public class FileChain extends ChainBase {
@Resource
private FileAccessPermissionVerifyCommand fileAccessPermissionVerifyCommand;
@Resource
private FolderPasswordVerifyCommand folderPasswordVerifyCommand;
@Resource
private FileHiddenCommand fileHiddenCommand;
@Resource
private FileSortCommand fileSortCommand;
@Resource
private FileUrlAddVersionCommand fileUrlAddVersionCommand;
/**
* 初始化责任链
*/
@PostConstruct
public void init() {
this.addCommand(fileAccessPermissionVerifyCommand);
this.addCommand(folderPasswordVerifyCommand);
this.addCommand(fileHiddenCommand);
this.addCommand(fileSortCommand);
this.addCommand(fileUrlAddVersionCommand);
}
/**
* 执行文件处理责任链
*
* @param content
* 文件上下文
*
* @return 是否执行成功
*/
public FileContext execute(FileContext content) throws Exception {
super.execute(content);
return content;
}
}

View File

@ -0,0 +1,45 @@
package com.yfd.platform.modules.storage.chain;
import com.yfd.platform.modules.config.model.request.FileListRequest;
import com.yfd.platform.modules.storage.model.result.FileItemResult;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.chain.impl.ContextBase;
import java.util.List;
/**
* 文件处理责任链上下文
*
* @author zhengsl
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@Builder
public class FileContext extends ContextBase {
/**
* 存储源 id
*/
private Integer storageId;
/**
* 存储源请求
*/
private FileListRequest fileListRequest;
/**
* 根据存储源请求获取到的文件列表
*/
private List<FileItemResult> fileItemList;
/**
* 当前目录密码路径表达式
*/
private String passwordPattern;
}

View File

@ -0,0 +1,50 @@
package com.yfd.platform.modules.storage.chain.command;
import cn.hutool.core.util.StrUtil;
import com.yfd.platform.exception.StorageSourceException;
import com.yfd.platform.modules.config.model.request.FileListRequest;
import com.yfd.platform.modules.storage.chain.FileContext;
import com.yfd.platform.utils.CodeMsg;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 目录访问权限责任链 command 命令
* 检查请求的目录是否有访问权限
*
* @author zhengsl
*/
@Service
public class FileAccessPermissionVerifyCommand implements Command {
// @Resource
// private FilterConfigService filterConfigService;
/**
* 校验是否有权限访问此目录
*
* @param context 文件处理责任链上下文
* @return 是否停止执行责任链, true: 停止执行责任链, false: 继续执行责任链
*/
@Override
public boolean execute(Context context) throws Exception {
FileContext fileContext = (FileContext) context;
Integer storageId = fileContext.getStorageId();
FileListRequest fileListRequest = fileContext.getFileListRequest();
// 检查文件目录是否是不可访问的, 如果是则抛出异常
// boolean isInaccessible = filterConfigService.checkFileIsInaccessible(storageId, fileListRequest
// .getPath());
boolean isInaccessible = false;
if (isInaccessible) {
String errorMsg = StrUtil.format("文件目录 [{}] 无访问权限", fileListRequest.getPath());
throw new StorageSourceException(CodeMsg.STORAGE_SOURCE_FILE_FORBIDDEN, storageId, errorMsg);
}
return false;
}
}

View File

@ -0,0 +1,53 @@
package com.yfd.platform.modules.storage.chain.command;
import cn.hutool.core.collection.CollUtil;
import com.yfd.platform.modules.storage.chain.FileContext;
import com.yfd.platform.modules.storage.model.result.FileItemResult;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* 文件隐藏责任链 command 命令
* 过滤此存储源通过规则隐藏的文件.
*
* @author zhengsl
*/
@Service
public class FileHiddenCommand implements Command {
// @Resource
// private FilterConfigService filterConfigService;
/**
* 隐藏存储源规律规则匹配到的文件.
*
* @param context
* 文件处理责任链上下文
*
* @return 是否停止执行责任链, true: 停止执行责任链, false: 继续执行责任链
*/
@Override
public boolean execute(Context context) throws Exception {
FileContext fileContext = (FileContext) context;
Integer storageId = fileContext.getStorageId();
List<FileItemResult> fileItemList = fileContext.getFileItemList();
if (CollUtil.isEmpty(fileItemList)) {
return false;
}
// List<FileItemResult> result = fileItemList.stream()
// .filter(fileItem -> !filterConfigService.checkFileIsHidden(storageId, fileItem.getFullPath()))
// .collect(Collectors.toList());
//
// fileContext.setFileItemList(result);
fileContext.setFileItemList(fileItemList);
return false;
}
}

View File

@ -0,0 +1,52 @@
package com.yfd.platform.modules.storage.chain.command;
import com.yfd.platform.modules.config.model.request.FileListRequest;
import com.yfd.platform.modules.storage.chain.FileContext;
import com.yfd.platform.modules.storage.model.result.FileItemResult;
import com.yfd.platform.utils.FileComparator;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 文件排序责任链 command 命令
* 根据请求类中的排序参数进行文件排序.
*
* @author zhengsl
*/
@Service
public class FileSortCommand implements Command {
/**
* 按照请求的排序字段和方向进行文件排序.
*
* @param context
* 文件处理责任链上下文
*
* @return 是否停止执行责任链, true: 停止执行责任链, false: 继续执行责任链
*/
@Override
public boolean execute(Context context) throws Exception {
FileContext fileContext = (FileContext) context;
List<FileItemResult> fileItemList = fileContext.getFileItemList();
FileListRequest fileListRequest = fileContext.getFileListRequest();
if (fileListRequest.getOrderBy() == null || fileListRequest.getOrderDirection() == null) {
return false;
}
// 创建副本, 防止排序和过滤对原数据产生影响
List<FileItemResult> copyList = new ArrayList<>(fileItemList);
// 按照自然排序
copyList.sort(new FileComparator(fileListRequest.getOrderBy(), fileListRequest.getOrderDirection()));
fileContext.setFileItemList(copyList);
return false;
}
}

View File

@ -0,0 +1,45 @@
package com.yfd.platform.modules.storage.chain.command;
import cn.hutool.core.date.DateUtil;
import com.yfd.platform.modules.storage.chain.FileContext;
import com.yfd.platform.modules.storage.model.result.FileItemResult;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 处理文件 url, 给直链增加版本号原始链接不添加防止浏览器缓存.
*
* @author zhengsl
*/
@Service
public class FileUrlAddVersionCommand implements Command {
/**
* 处理文件 url, 给直链增加版本号防止浏览器缓存.
*
* @param context
* 文件处理责任链上下文
*
* @return 是否停止执行责任链, true: 停止执行责任链, false: 继续执行责任链
*/
@Override
public boolean execute(Context context) throws Exception {
FileContext fileContext = (FileContext) context;
List<FileItemResult> fileItemList = fileContext.getFileItemList();
long version = DateUtil.currentSeconds();
// fileItemList.forEach((item) -> {
// // url 中不包含 ? 才添加此参数否则可能会影响正常下载.
// if (!StrUtil.contains(item.getUrl(), '?')) {
// item.setUrl(item.getUrl() + "?v=" + version);
// }
//
// });
return false;
}
}

View File

@ -0,0 +1,51 @@
package com.yfd.platform.modules.storage.chain.command;
import com.yfd.platform.modules.config.model.request.FileListRequest;
import com.yfd.platform.modules.storage.chain.FileContext;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 校验文件夹密码责任链 command 命令
* 校验当前请求的文件夹是否需要密码校验如果需求则校验密码密码不正确则抛出异常
*
* @author zhengsl
*/
@Service
public class FolderPasswordVerifyCommand implements Command {
// @Resource
// private PasswordConfigService passwordConfigService;
/**
* 校验当前文件是否需要密码.
*
* @param context
* 文件处理责任链上下文
*
* @return 是否停止执行责任链, true: 停止执行责任链, false: 继续执行责任链
*/
@Override
public boolean execute(Context context) throws Exception {
FileContext fileContext = (FileContext) context;
Integer storageId = fileContext.getStorageId();
FileListRequest fileListRequest = fileContext.getFileListRequest();
String path = fileListRequest.getPath();
String password = fileListRequest.getPassword();
// 校验密码, 如果校验不通过, 则返回错误消息
// VerifyResultDTO verifyResultDTO = passwordConfigService.verifyPassword(storageId, path, password);
// if (!verifyResultDTO.isPassed()) {
// throw new PasswordVerifyException(verifyResultDTO.getCode(), verifyResultDTO.getMsg());
// }
// 设置当前文件夹所对应的文件夹路径表达式.
// fileContext.setPasswordPattern(verifyResultDTO.getPattern());;
return false;
}
}

View File

@ -0,0 +1,275 @@
package com.yfd.platform.modules.storage.context;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.yfd.platform.annotation.StorageParamItem;
import com.yfd.platform.exception.file.InvalidStorageSourceException;
import com.yfd.platform.exception.init.InitializeStorageSourceException;
import com.yfd.platform.modules.storage.mapper.StorageSourceConfigMapper;
import com.yfd.platform.modules.storage.mapper.StorageSourceMapper;
import com.yfd.platform.modules.storage.model.bo.StorageSourceParamDef;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig;
import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum;
import com.yfd.platform.modules.storage.model.param.IStorageParam;
import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import com.yfd.platform.modules.storage.support.StorageSourceSupport;
import com.yfd.platform.utils.ClassUtils;
import com.yfd.platform.utils.CodeMsg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 每个存储源对应一个 Service, 其中初始化好了与对象存储的配置信息.
* 此存储源上下文环境用户缓存每个 Service, 避免重复初始化.
* <br>
*
* @author zhengsl
*/
@Component
@Order(0)
@Slf4j
public class StorageSourceContext {
/**
* Map<Integer, AbstractBaseFileService>
* Map<存储源 ID, 存储源 Service>
*/
private static final Map<Integer, AbstractBaseFileService<IStorageParam>> DRIVES_SERVICE_MAP = new ConcurrentHashMap<>();
/**
* Map<存储源类型, 存储源 Service>
*/
private static Map<String, AbstractBaseFileService> storageTypeEnumFileServiceMap;
/**
* 缓存每个存储源参数的字段列表.
*/
private final Map<Class<?>, Map<String, Field>> PARAM_CLASS_FIELD_NAME_MAP_CACHE = new HashMap<>();
@Resource
private StorageSourceMapper storageSourceMapper;
@Resource
private StorageSourceConfigMapper storageSourceConfigMapper;
/**
* 项目启动时, 自动调用数据库已存储的所有存储源进行初始化.
*/
// @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
storageTypeEnumFileServiceMap = applicationContext.getBeansOfType(AbstractBaseFileService.class);
List<StorageSource> list = storageSourceMapper.findAllOrderByOrderNum();
for (StorageSource storageSource : list) {
try {
init(storageSource);
log.info("启动时初始化存储源成功, 存储源 id: [{}], 存储源类型: [{}], 存储源名称: [{}]",
storageSource.getId(), storageSource.getType().getDescription(), storageSource.getName());
} catch (Exception e) {
log.error("启动时初始化存储源失败, 存储源 id: {}, 存储源类型: {}, 存储源名称: {}",
storageSource.getId(), storageSource.getType().getDescription(), storageSource.getName(), e);
}
}
}
/**
* 根据存储源 id 获取对应的 Service.
*
* @param storageId
* 存储源 ID
*
* @return 存储源对应的 Service
*/
public AbstractBaseFileService<IStorageParam> getByStorageId(Integer storageId) {
AbstractBaseFileService<IStorageParam> abstractBaseFileService = DRIVES_SERVICE_MAP.get(storageId);
if (abstractBaseFileService == null) {
throw new InvalidStorageSourceException(storageId);
}
return abstractBaseFileService;
}
/**
* 根据存储源 key 获取对应的 Service.
*
* @param key
* 存储源 key
*
* @return 存储源对应的 Service
*/
public AbstractBaseFileService<?> getByStorageKey(String key) {
Integer storageId = storageSourceMapper.findIdByStorageKey(key);
if (storageId == null) {
return null;
}
return getByStorageId(storageId);
}
/**
* 根据存储类型获取对应的存储源的参数列表.
*
* @param type
* 存储类型: {@link StorageTypeEnum}
*
* @return 指定类型存储源的参数列表. {@link StorageSourceSupport#getStorageSourceParamList(AbstractBaseFileService)} )}}
*/
public static List<StorageSourceParamDef> getStorageSourceParamListByType(StorageTypeEnum type) {
return storageTypeEnumFileServiceMap.values().stream()
// 根据存储源类型找到第一个匹配的 Service
.filter(fileService -> fileService.getStorageTypeEnum() == type)
.findFirst()
// 获取该 Service 的参数列表
.map(StorageSourceSupport::getStorageSourceParamList)
// 如果没有找到, 则返回空列表
.orElse(Collections.emptyList());
}
/**
* 初始化指定存储源的 Service, 添加到上下文环境中.
*
* @param storageSource
* 存储源对象
*/
public void init(StorageSource storageSource) {
Integer storageId = storageSource.getId();
String storageName = storageSource.getName();
AbstractBaseFileService<IStorageParam> baseFileService = getInitStorageBeanByStorageId(storageId);
if (baseFileService == null) {
throw new InvalidStorageSourceException(storageId);
}
// 填充初始化参数
IStorageParam initParam = getInitParam(storageId, baseFileService);
// 进行初始化并测试连接
baseFileService.init(storageName, storageId, initParam);
baseFileService.testConnection();
DRIVES_SERVICE_MAP.put(storageId, baseFileService);
}
/**
* 获取指定存储源初始状态的 Service.
*
* @param storageId
* 存储源 ID
*
* @return 存储源对应未初始化的 Service
*/
private AbstractBaseFileService<IStorageParam> getInitStorageBeanByStorageId(Integer storageId) {
String keyById = storageSourceMapper.findKeyById(storageId);
StorageTypeEnum storageTypeEnum = Optional.ofNullable(storageSourceMapper.findByStorageKey(keyById)).map(StorageSource::getType).orElse(null);
for (AbstractBaseFileService<?> value : storageTypeEnumFileServiceMap.values()) {
if (Objects.equals(value.getStorageTypeEnum(), storageTypeEnum)) {
return SpringUtil.getBean(value.getClass());
}
}
return null;
}
/**
* 获取指定存储源的初始化参数.
*
* @param storageId
* 存储源 ID
*
* @return 存储源初始化参数
*/
private IStorageParam getInitParam(Integer storageId, AbstractBaseFileService<?> baseFileService) {
// 获取存储源实现类的实际 Class
Class<?> beanTargetClass = AopUtils.getTargetClass(baseFileService);
// 获取存储源实现类的实际 Class 的泛型参数类型
Class<?> paramClass = ClassUtils.getClassFirstGenericsParam(beanTargetClass);
// 获取存储器参数 key -> 存储器 field 对照关系如果缓存中有则从缓存中取.
Map<String, Field> fieldMap = new HashMap<>();
if (PARAM_CLASS_FIELD_NAME_MAP_CACHE.containsKey(paramClass)) {
fieldMap = PARAM_CLASS_FIELD_NAME_MAP_CACHE.get(paramClass);
} else {
Field[] fields = ReflectUtil.getFieldsDirectly(paramClass, true);
List<String> ignoreFieldNameList = new ArrayList<>();
for (Field field : fields) {
String key;
StorageParamItem storageParamItem = field.getDeclaredAnnotation(StorageParamItem.class);
// 没有注解或注解中没有配置 key 则使用字段名.
if (storageParamItem == null || StrUtil.isEmpty(storageParamItem.key())) {
key = field.getName();
} else {
key = storageParamItem.key();
}
if (storageParamItem.ignoreInput()) {
ignoreFieldNameList.add(key);
}
// 如果 map 中包含此 key, 则是父类的, 跳过.
if (fieldMap.containsKey(key)) {
continue;
}
if (!ignoreFieldNameList.contains(key)) {
fieldMap.put(key, field);
}
}
PARAM_CLASS_FIELD_NAME_MAP_CACHE.put(paramClass, fieldMap);
}
// 实例化参数对象
IStorageParam iStorageParam = ReflectUtil.newInstance(paramClass.getName());
// 给所有字段填充值
List<StorageSourceConfig> storageSourceConfigList = storageSourceConfigMapper.findByStorageIdOrderById(storageId);
for (StorageSourceConfig storageSourceConfig : storageSourceConfigList) {
String name = storageSourceConfig.getName();
String value = storageSourceConfig.getValue();
try {
Field field = fieldMap.get(name);
ReflectUtil.setFieldValue(iStorageParam, field, value);
} catch (Exception e) {
String errMsg = StrUtil.format("为字段 {} 初始化值 {} 失败", name, value);
throw new InitializeStorageSourceException(CodeMsg.STORAGE_SOURCE_INIT_STORAGE_PARAM_FIELD_FAIL, storageId, errMsg, e).setResponseExceptionMessage(true);
}
}
return iStorageParam;
}
/**
* 销毁指定存储源的 Service.
*
* @param storageId
* 存储源 ID
*/
public void destroy(Integer storageId) {
log.info("清理存储源上下文对象, storageId: {}", storageId);
DRIVES_SERVICE_MAP.remove(storageId);
}
}

View File

@ -0,0 +1,138 @@
package com.yfd.platform.modules.storage.controller.base;
import cn.hutool.core.bean.BeanUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest;
import com.yfd.platform.modules.config.model.request.UpdateStorageSortRequest;
import com.yfd.platform.modules.storage.convert.StorageSourceConvert;
import com.yfd.platform.modules.storage.model.dto.StorageSourceDTO;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.result.StorageSourceAdminResult;
import com.yfd.platform.modules.storage.service.StorageSourceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* 存储源基础设置模块接口
*
* @author zhaojun
*/
@Api(tags = "存储源模块-基础")
@ApiSort(3)
@RestController
@RequestMapping("/admin")
public class StorageSourceController {
@Resource
private StorageSourceService storageSourceService;
@Resource
private StorageSourceConvert storageSourceConvert;
@ApiOperationSupport(order = 1)
@ApiOperation(value = "获取所有存储源列表", notes = "获取所有添加的存储源列表,按照排序值由小到大排序")
@GetMapping("/storages")
public ResponseResult storageList() {
List<StorageSource> list = storageSourceService.findAllOrderByOrderNum();
List<StorageSourceAdminResult> storageSourceAdminResults = storageSourceConvert.entityToAdminResultList(list);
return ResponseResult.successData(storageSourceAdminResults);
}
@ApiOperationSupport(order = 2)
@ApiOperation(value = "获取指定存储源参数", notes = "获取指定存储源基本信息及其参数")
@ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class)
@GetMapping("/storage/{storageId}")
public ResponseResult storageItem(@PathVariable Integer storageId) {
StorageSourceDTO storageSourceDTO = storageSourceService.findDTOById(storageId);
return ResponseResult.successData(storageSourceDTO);
}
@ApiOperationSupport(order = 3)
@ApiOperation(value = "保存存储源参数", notes = "保存存储源的所有参数")
@PostMapping("/storage")
public ResponseResult saveStorageItem(@RequestBody SaveStorageSourceRequest saveStorageSourceRequest) {
Integer id = storageSourceService.saveStorageSource(saveStorageSourceRequest);
return ResponseResult.successData(id);
}
@ApiOperationSupport(order = 4)
@ApiOperation(value = "删除存储源", notes = "删除存储源基本设置和拓展设置")
@ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class)
@DeleteMapping("/storage/{storageId}")
public ResponseResult deleteStorageItem(@PathVariable Integer storageId) {
storageSourceService.deleteById(storageId);
return ResponseResult.success();
}
@ApiOperationSupport(order = 5)
@ApiOperation(value = "启用存储源", notes = "开启存储源后可在前台显示")
@ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class)
@PostMapping("/storage/{storageId}/enable")
public ResponseResult enable(@PathVariable Integer storageId) {
StorageSource storageSource = storageSourceService.findById(storageId);
storageSource.setEnable(true);
storageSourceService.updateById(storageSource);
return ResponseResult.success();
}
@ApiOperationSupport(order = 6)
@ApiOperation(value = "停止存储源", notes = "停用存储源后不在前台显示")
@ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class)
@PostMapping("/storage/{storageId}/disable")
public ResponseResult disable(@PathVariable Integer storageId) {
StorageSource storageSource = storageSourceService.findById(storageId);
storageSource.setEnable(false);
storageSourceService.updateById(storageSource);
return ResponseResult.success();
}
@ApiOperationSupport(order = 7)
@ApiOperation(value = "更新存储源顺序")
@PostMapping("/storage/sort")
public ResponseResult updateStorageSort(@RequestBody List<UpdateStorageSortRequest> updateStorageSortRequestList) {
storageSourceService.updateStorageSort(updateStorageSortRequestList);
return ResponseResult.success();
}
@ApiOperationSupport(order = 8)
@ApiOperation(value = "校验存储源 key 是否重复")
@ApiImplicitParam(paramType = "query", name = "storageKey", value = "存储源 key", required = true, dataTypeClass = String.class)
@GetMapping("/storage/exist/key")
public ResponseResult existKey(String storageKey) {
boolean exist = storageSourceService.existByStorageKey(storageKey);
return ResponseResult.successData(exist);
}
@ApiOperationSupport(order = 9)
@ApiOperation(value = "修改 readme 兼容模式", notes = "修改 readme 兼容模式是否启用")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(paramType = "path", name = "status", value = "存储源兼容模式状态", required = true, dataTypeClass = Boolean.class)
})
@PostMapping("/storage/{storageId}/compatibility_readme/{status}")
public ResponseResult changeCompatibilityReadme(@PathVariable Integer storageId, @PathVariable Boolean status) {
StorageSource storageSource = storageSourceService.findById(storageId);
storageSource.setCompatibilityReadme(status);
storageSourceService.updateById(storageSource);
return ResponseResult.success();
}
}

View File

@ -0,0 +1 @@
package com.yfd.platform.modules.storage.controller.file; import cn.hutool.core.bean.BeanUtil; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; import com.yfd.platform.config.ResponseResult; import com.yfd.platform.exception.file.InvalidStorageSourceException; import com.yfd.platform.modules.config.model.request.FileListRequest; import com.yfd.platform.modules.storage.chain.FileChain; import com.yfd.platform.modules.storage.chain.FileContext; import com.yfd.platform.modules.storage.context.StorageSourceContext; import com.yfd.platform.modules.storage.convert.StorageSourceConvert; import com.yfd.platform.modules.storage.model.entity.StorageSource; import com.yfd.platform.modules.storage.model.result.FileInfoResult; import com.yfd.platform.modules.storage.model.result.FileItemResult; import com.yfd.platform.modules.storage.model.result.StorageSourceResult; import com.yfd.platform.modules.storage.service.StorageSourceService; import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; import java.util.List; import java.util.stream.Collectors; /** * 文件列表相关接口, 如展示存储源列表, 展示文件列表, 搜索文件列表等. * * @author zhengsl */ @Api(tags = "文件列表模块") @ApiSort(2) @Slf4j @RequestMapping("/api/storage") @RestController public class FileController { @Resource private StorageSourceContext storageSourceContext; @Resource private StorageSourceService storageSourceService; @Resource private FileChain fileChain; @Resource private StorageSourceConvert storageSourceConvert; @ApiOperationSupport(order = 1) @ApiOperation(value = "获取存储源列表", notes = "获取所有已启用的存储源, 并且按照后台顺序排序") @GetMapping("/list") public ResponseResult storageList() { List<StorageSource> storageList = storageSourceService.findAllEnableOrderByOrderNum(); List<StorageSourceResult> storageSourceResultList = storageSourceConvert.entityToResultList (storageList); return ResponseResult.successData(storageSourceResultList); } @ApiOperationSupport(order = 2) @ApiOperation(value = "获取文件列表", notes = "获取某个存储源下, 指定路径的文件&文件夹列表") @PostMapping("/files") public ResponseResult list(@Valid @RequestBody FileListRequest fileListRequest) throws Exception { String storageKey = fileListRequest.getStorageKey(); Integer storageId = storageSourceService.findIdByKey(storageKey); if (storageId == null) { throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey); } // 处理请求参数默认值 fileListRequest.handleDefaultValue(); // 获取文件列表 AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageId(storageId); List<FileItemResult> fileItemList = fileService.fileList(fileListRequest.getPath()); // 执行责任链 FileContext fileContext = FileContext.builder() .storageId(storageId) .fileListRequest(fileListRequest) .fileItemList(fileItemList).build(); fileChain.execute(fileContext); return ResponseResult.successData(new FileInfoResult(fileContext.getFileItemList(), fileContext.getPasswordPattern())); } }

View File

@ -0,0 +1,190 @@
package com.yfd.platform.modules.storage.controller.file;
import cn.hutool.core.collection.CollUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.storage.context.StorageSourceContext;
import com.yfd.platform.modules.storage.model.enums.FileTypeEnum;
import com.yfd.platform.modules.storage.model.request.*;
import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
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;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
/**
* 文件操作相关接口, 如新建文件夹, 上传文件, 删除文件, 移动文件等.
*
* @author zhengsl
*/
@Api(tags = "文件操作模块")
@ApiSort(3)
@Slf4j
@RestController
@RequestMapping("/api/file/operator")
public class FileOperatorController {
@Resource
private StorageSourceContext storageSourceContext;
@ApiOperationSupport(order = 1)
@ApiOperation(value = "创建文件夹")
@PostMapping("/mkdir")
public ResponseResult mkdir(@Valid @RequestBody NewFolderRequest newFolderRequest) {
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey());
boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName());
if (flag) {
return ResponseResult.success("创建成功");
} else {
return ResponseResult.error("创建失败");
}
}
@ApiOperationSupport(order = 2)
@ApiOperation(value = "批量删除文件/文件夹")
@PostMapping("/delete/batch")
public ResponseResult deleteFile(@Valid @RequestBody BatchDeleteRequest batchDeleteRequest) {
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey());
List<BatchDeleteRequest.DeleteItem> deleteItems = batchDeleteRequest.getDeleteItems();
int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItems);
for (BatchDeleteRequest.DeleteItem deleteItem : deleteItems) {
boolean flag = false;
try {
if (deleteItem.getType() == FileTypeEnum.FILE) {
flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName());
} else if (deleteItem.getType() == FileTypeEnum.FOLDER) {
flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName());
}
if (flag) {
deleteSuccessCount++;
} else {
deleteFailCount++;
}
} catch (Exception e) {
log.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e);
deleteFailCount++;
}
}
if (totalCount > 1) {
return ResponseResult.success("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个.");
} else {
return totalCount == deleteSuccessCount ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
}
}
@ApiOperationSupport(order = 3)
@ApiOperation(value = "重命名文件")
@PostMapping("/rename/file")
public ResponseResult rename(@Valid @RequestBody RenameFileRequest renameFileRequest) {
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(renameFileRequest.getStorageKey());
boolean flag = fileService.renameFile(renameFileRequest.getPath(), renameFileRequest.getName(), renameFileRequest.getNewName());
if (flag) {
return ResponseResult.success("重命名成功");
} else {
return ResponseResult.error("重命名失败");
}
}
@ApiOperationSupport(order = 4)
@ApiOperation(value = "重命名文件夹")
@PostMapping("/rename/folder")
public ResponseResult deleteFile(@Valid @RequestBody RenameFolderRequest renameFolderRequest) {
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(renameFolderRequest.getStorageKey());
boolean flag = fileService.renameFolder(renameFolderRequest.getPath(), renameFolderRequest.getName(), renameFolderRequest.getNewName());
if (flag) {
return ResponseResult.success("重命名成功");
} else {
return ResponseResult.error("重命名失败");
}
}
@ApiOperationSupport(order = 5)
@ApiOperation(value = "上传文件")
@PostMapping("/upload/file")
public ResponseResult getUploadFileUrl(@Valid @RequestBody UploadFileRequest uploadFileRequest) {
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(uploadFileRequest.getStorageKey());
String uploadUrl = fileService.getUploadUrl(uploadFileRequest.getPath(),
uploadFileRequest.getName(), uploadFileRequest.getSize());
return ResponseResult.successData(uploadUrl);
}
//@ApiOperationSupport(order = 6)
//@ApiOperation(value = "移动文件")
//@PostMapping("/move/file")
//@CheckPassword(storageKeyFieldExpression = "[0].storageKey",
// pathFieldExpression = "[0].path",
// passwordFieldExpression = "[0].password")
//public AjaxJson<?> moveFile(@Valid @RequestBody MoveFileRequest moveFileRequest) {
// AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(moveFileRequest.getStorageKey());
// boolean flag = fileService.moveFile(moveFileRequest.getPath(), moveFileRequest.getName(), moveFileRequest.getTargetPath(), moveFileRequest.getTargetName());
// if (flag) {
// return AjaxJson.getSuccess("移动成功");
// } else {
// return AjaxJson.getError("移动失败");
// }
//}
//
//@ApiOperationSupport(order = 7)
//@ApiOperation(value = "移动文件夹")
//@PostMapping("/move/folder")
//@CheckPassword(storageKeyFieldExpression = "[0].storageKey",
// pathFieldExpression = "[0].path",
// passwordFieldExpression = "[0].password")
//public AjaxJson<?> moveFolder(@Valid @RequestBody MoveFolderRequest moveFolderRequest) {
// AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(moveFolderRequest.getStorageKey());
// boolean flag = fileService.moveFolder(moveFolderRequest.getPath(), moveFolderRequest.getName(), moveFolderRequest.getTargetPath(), moveFolderRequest.getTargetName());
// if (flag) {
// return AjaxJson.getSuccess("移动成功");
// } else {
// return AjaxJson.getError("移动失败");
// }
//}
//
//@ApiOperationSupport(order = 8)
//@ApiOperation(value = "复制文件")
//@PostMapping("/copy/file")
//@CheckPassword(storageKeyFieldExpression = "[0].storageKey",
// pathFieldExpression = "[0].path",
// passwordFieldExpression = "[0].password")
//public AjaxJson<?> copyFile(@Valid @RequestBody CopyFileRequest copyFileRequest) {
// AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(copyFileRequest.getStorageKey());
// boolean flag = fileService.copyFile(copyFileRequest.getPath(), copyFileRequest.getName(), copyFileRequest.getTargetPath(), copyFileRequest.getTargetName());
// if (flag) {
// return AjaxJson.getSuccess("复制成功");
// } else {
// return AjaxJson.getError("复制失败");
// }
//}
//
//@ApiOperationSupport(order = 9)
//@ApiOperation(value = "复制文件夹")
//@PostMapping("/copy/folder")
//@CheckPassword(storageKeyFieldExpression = "[0].storageKey",
// pathFieldExpression = "[0].path",
// passwordFieldExpression = "[0].password")
//public AjaxJson<?> copyFolder(@Valid @RequestBody CopyFolderRequest copyFolderRequest) {
// AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey(copyFolderRequest.getStorageKey());
// boolean flag = fileService.copyFolder(copyFolderRequest.getPath(), copyFolderRequest.getName(), copyFolderRequest.getTargetPath(), copyFolderRequest.getTargetName());
// if (flag) {
// return AjaxJson.getSuccess("复制成功");
// } else {
// return AjaxJson.getError("复制失败");
// }
//}
}

View File

@ -0,0 +1,80 @@
package com.yfd.platform.modules.storage.controller.proxy;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.yfd.platform.modules.storage.context.StorageSourceContext;
import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import com.yfd.platform.modules.storage.service.base.AbstractProxyTransferService;
import com.yfd.platform.utils.ProxyDownloadUrlUtils;
import com.yfd.platform.utils.SpringMvcUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.beans.Beans;
import java.io.IOException;
/**
* 服务端代理下载 Controller
*
* @author zhengsl
*/
@Api(tags = "服务端代理下载")
@ApiSort(6)
@Controller
public class ProxyDownloadController {
@Resource
private StorageSourceContext storageSourceContext;
@Resource
private HttpServletRequest httpServletRequest;
@GetMapping("/pd/{storageKey}/**")
@ApiOperationSupport(order = 1)
@ApiOperation(value = "下载本地存储源的文件", notes = "因第三方存储源都有下载地址,本接口提供本地存储的下载地址的处理, 返回文件流进行下载.")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "path", name = "storageKey", value = "存储源 key", dataTypeClass = String.class),
@ApiImplicitParam(paramType = "query", name = "type",
value = "下载类型: download(不论什么格式的文件都进行下载操作), " +
"default(使用浏览器默认处理,浏览器支持预览的格式,则进行预览,不支持的则进行下载)",
example = "download", dataTypeClass = String.class)
})
@ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> downAttachment(@PathVariable("storageKey") String storageKey, String signature) throws IOException {
// 获取下载文件路径
String filePath = SpringMvcUtils.getExtractPathWithinPattern();
AbstractBaseFileService<?> storageServiceByKey = storageSourceContext.getByStorageKey(storageKey);
// 如果不是 ProxyTransferService, 则返回错误信息.
if (!Beans.isInstanceOf(storageServiceByKey, AbstractProxyTransferService.class)) {
throw new RuntimeException("存储类型异常,不支持上传.");
}
// 进行上传.
AbstractProxyTransferService<?> proxyDownloadService = (AbstractProxyTransferService<?>) storageServiceByKey;
// 如果是私有空间才校验签名.
boolean privateStorage = proxyDownloadService.getParam().isPrivate();
if (privateStorage) {
Integer storageId = proxyDownloadService.getStorageId();
boolean valid = ProxyDownloadUrlUtils.validSignatureExpired(storageId, filePath, signature);
if (!valid) {
throw new IllegalArgumentException("签名无效或下载地址已过期.");
}
}
return proxyDownloadService.downloadToStream(filePath);
}
}

View File

@ -0,0 +1,57 @@
package com.yfd.platform.modules.storage.controller.proxy;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.storage.context.StorageSourceContext;
import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import com.yfd.platform.modules.storage.service.base.AbstractProxyTransferService;
import com.yfd.platform.utils.SpringMvcUtils;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.beans.Beans;
import java.io.IOException;
/**
* 服务端代理上传 Controller
*
* @author zhengsl
*/
@Api(tags = "服务端代理上传")
@RestController
public class ProxyUploadController {
@Resource
private StorageSourceContext storageSourceContext;
@Resource
private HttpServletRequest httpServletRequest;
@PostMapping("/file/upload/{storageKey}/**")
@ResponseBody
public ResponseResult upload(@RequestParam MultipartFile file, @PathVariable("storageKey") String storageKey) throws IOException {
if (file == null) {
throw new RuntimeException("空文件不能为空");
}
// 获取上传路径
String filePath = SpringMvcUtils.getExtractPathWithinPattern();
AbstractBaseFileService<?> storageServiceByKey = storageSourceContext.getByStorageKey(storageKey);
// 如果不是 ProxyTransferService, 则返回错误信息.
if (!Beans.isInstanceOf(storageServiceByKey, AbstractProxyTransferService.class)) {
return ResponseResult.error("存储类型异常,不支持上传.");
}
// 进行上传.
AbstractProxyTransferService<?> proxyUploadService = (AbstractProxyTransferService<?>) storageServiceByKey;
proxyUploadService.uploadFile(filePath, file.getInputStream());
return ResponseResult.success();
}
}

View File

@ -0,0 +1,71 @@
package com.yfd.platform.modules.storage.convert;
import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest;
import com.yfd.platform.modules.readme.model.entity.ReadmeConfig;
import com.yfd.platform.modules.storage.model.dto.StorageSourceAllParamDTO;
import com.yfd.platform.modules.storage.model.dto.StorageSourceDTO;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.result.StorageSourceAdminResult;
import com.yfd.platform.modules.storage.model.result.StorageSourceConfigResult;
import com.yfd.platform.modules.storage.model.result.StorageSourceResult;
import java.util.List;
/**
* StorageSource 转换器
*
* @author zhengsl
*/
public interface StorageSourceConvert {
/**
* StorageSource 转换为 StorageSourceResult
*
* @param list
* StorageSource 列表
*
* @return StorageSourceResult 列表
*/
List<StorageSourceResult> entityToResultList(List<StorageSource> list);
/**
* StorageSource 转换为 StorageSourceConfigResult
*
* @param storageSource
* StorageSource 实体
*
* @return StorageSourceConfigResult 实体
*/
// @Mapping(source = "readmeConfig.displayMode", target = "readmeDisplayMode")
// @Mapping(source = "storageSource.allowOperator", target = "enableFileOperator")
StorageSourceConfigResult entityToConfigResult(StorageSource storageSource, ReadmeConfig readmeConfig);
/**
* StorageSource 转换为 StorageSourceAdminResult
*
* @param list
* StorageSource 列表
*
* @return StorageSourceAdminResult 列表
*/
List<StorageSourceAdminResult> entityToAdminResultList(List<StorageSource> list);
StorageSourceDTO entityToDTO(StorageSource storageSource, StorageSourceAllParamDTO storageSourceAllParam);
/**
* SaveStorageSourceRequest 转换为 StorageSource
*
* @param saveStorageSourceRequest
* SaveStorageSourceRequest 实体
*
* @return StorageSource 实体
*/
StorageSource saveRequestToEntity(SaveStorageSourceRequest saveStorageSourceRequest);
}

View File

@ -0,0 +1,184 @@
package com.yfd.platform.modules.storage.convert.impl;
import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest;
import com.yfd.platform.modules.readme.model.entity.ReadmeConfig;
import com.yfd.platform.modules.storage.convert.StorageSourceConvert;
import com.yfd.platform.modules.storage.model.dto.StorageSourceAllParamDTO;
import com.yfd.platform.modules.storage.model.dto.StorageSourceDTO;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.result.StorageSourceAdminResult;
import com.yfd.platform.modules.storage.model.result.StorageSourceConfigResult;
import com.yfd.platform.modules.storage.model.result.StorageSourceResult;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* @Date: 2025/1/10 12:44
* @Description:
*/
@Service
public class StorageSourceConvertImpl implements StorageSourceConvert {
@Override
public List<StorageSourceResult> entityToResultList(List<StorageSource> list) {
if ( list == null ) {
return null;
}
List<StorageSourceResult> list1 = new ArrayList<StorageSourceResult>( list.size() );
for ( StorageSource storageSource : list ) {
list1.add( storageSourceToStorageSourceResult( storageSource ) );
}
return list1;
}
@Override
public StorageSourceConfigResult entityToConfigResult(StorageSource storageSource, ReadmeConfig readmeConfig) {
if ( storageSource == null && readmeConfig == null ) {
return null;
}
StorageSourceConfigResult storageSourceConfigResult = new StorageSourceConfigResult();
if ( storageSource != null ) {
storageSourceConfigResult.setEnableFileOperator( storageSource.getEnableFileOperator() );
storageSourceConfigResult.setDefaultSwitchToImgMode( storageSource.getDefaultSwitchToImgMode() );
}
if ( readmeConfig != null ) {
storageSourceConfigResult.setReadmeDisplayMode( readmeConfig.getDisplayMode() );
storageSourceConfigResult.setReadmeText( readmeConfig.getReadmeText() );
}
return storageSourceConfigResult;
}
@Override
public List<StorageSourceAdminResult> entityToAdminResultList(List<StorageSource> list) {
if ( list == null ) {
return null;
}
List<StorageSourceAdminResult> list1 = new ArrayList<StorageSourceAdminResult>( list.size() );
for ( StorageSource storageSource : list ) {
list1.add( storageSourceToStorageSourceAdminResult( storageSource ) );
}
return list1;
}
@Override
public StorageSourceDTO entityToDTO(StorageSource storageSource, StorageSourceAllParamDTO storageSourceAllParam) {
if ( storageSource == null && storageSourceAllParam == null ) {
return null;
}
StorageSourceDTO storageSourceDTO = new StorageSourceDTO();
if ( storageSource != null ) {
storageSourceDTO.setId( storageSource.getId() );
storageSourceDTO.setName( storageSource.getName() );
storageSourceDTO.setKey( storageSource.getKey() );
storageSourceDTO.setRemark( storageSource.getRemark() );
storageSourceDTO.setType( storageSource.getType() );
if ( storageSource.getEnable() != null ) {
storageSourceDTO.setEnable( storageSource.getEnable() );
}
storageSourceDTO.setEnableFileOperator( storageSource.getEnableFileOperator() );
storageSourceDTO.setEnableFileAnnoOperator( storageSource.getEnableFileAnnoOperator() );
if ( storageSource.getEnableCache() != null ) {
storageSourceDTO.setEnableCache( storageSource.getEnableCache() );
}
if ( storageSource.getAutoRefreshCache() != null ) {
storageSourceDTO.setAutoRefreshCache( storageSource.getAutoRefreshCache() );
}
if ( storageSource.getSearchEnable() != null ) {
storageSourceDTO.setSearchEnable( storageSource.getSearchEnable() );
}
if ( storageSource.getSearchIgnoreCase() != null ) {
storageSourceDTO.setSearchIgnoreCase( storageSource.getSearchIgnoreCase() );
}
storageSourceDTO.setOrderNum( storageSource.getOrderNum() );
if ( storageSource.getDefaultSwitchToImgMode() != null ) {
storageSourceDTO.setDefaultSwitchToImgMode( storageSource.getDefaultSwitchToImgMode() );
}
storageSourceDTO.setCompatibilityReadme( storageSource.getCompatibilityReadme() );
}
storageSourceDTO.setStorageSourceAllParam( storageSourceAllParam );
return storageSourceDTO;
}
@Override
public StorageSource saveRequestToEntity(SaveStorageSourceRequest saveStorageSourceRequest) {
if ( saveStorageSourceRequest == null ) {
return null;
}
StorageSource storageSource = new StorageSource();
storageSource.setId( saveStorageSourceRequest.getId() );
storageSource.setEnable( saveStorageSourceRequest.getEnable() );
storageSource.setEnableFileOperator( saveStorageSourceRequest.getEnableFileOperator() );
storageSource.setEnableFileAnnoOperator( saveStorageSourceRequest.getEnableFileAnnoOperator() );
storageSource.setEnableCache( saveStorageSourceRequest.isEnableCache() );
storageSource.setName( saveStorageSourceRequest.getName() );
storageSource.setKey( saveStorageSourceRequest.getKey() );
storageSource.setRemark( saveStorageSourceRequest.getRemark() );
storageSource.setAutoRefreshCache( saveStorageSourceRequest.isAutoRefreshCache() );
storageSource.setType( saveStorageSourceRequest.getType() );
storageSource.setSearchEnable( saveStorageSourceRequest.isSearchEnable() );
storageSource.setSearchIgnoreCase( saveStorageSourceRequest.isSearchIgnoreCase() );
storageSource.setSearchMode( saveStorageSourceRequest.getSearchMode() );
storageSource.setOrderNum( saveStorageSourceRequest.getOrderNum() );
storageSource.setDefaultSwitchToImgMode( saveStorageSourceRequest.isDefaultSwitchToImgMode() );
storageSource.setCompatibilityReadme( saveStorageSourceRequest.isCompatibilityReadme() );
return storageSource;
}
protected StorageSourceResult storageSourceToStorageSourceResult(StorageSource storageSource) {
if ( storageSource == null ) {
return null;
}
StorageSourceResult storageSourceResult = new StorageSourceResult();
storageSourceResult.setName( storageSource.getName() );
storageSourceResult.setKey( storageSource.getKey() );
storageSourceResult.setType( storageSource.getType() );
storageSourceResult.setSearchEnable( storageSource.getSearchEnable() );
storageSourceResult.setDefaultSwitchToImgMode( storageSource.getDefaultSwitchToImgMode() );
return storageSourceResult;
}
protected StorageSourceAdminResult storageSourceToStorageSourceAdminResult(StorageSource storageSource) {
if ( storageSource == null ) {
return null;
}
StorageSourceAdminResult storageSourceAdminResult = new StorageSourceAdminResult();
storageSourceAdminResult.setId( storageSource.getId() );
storageSourceAdminResult.setEnable( storageSource.getEnable() );
storageSourceAdminResult.setEnableFileOperator( storageSource.getEnableFileOperator() );
storageSourceAdminResult.setEnableFileAnnoOperator( storageSource.getEnableFileAnnoOperator() );
storageSourceAdminResult.setEnableCache( storageSource.getEnableCache() );
storageSourceAdminResult.setName( storageSource.getName() );
storageSourceAdminResult.setKey( storageSource.getKey() );
storageSourceAdminResult.setRemark( storageSource.getRemark() );
storageSourceAdminResult.setAutoRefreshCache( storageSource.getAutoRefreshCache() );
storageSourceAdminResult.setType( storageSource.getType() );
storageSourceAdminResult.setSearchEnable( storageSource.getSearchEnable() );
storageSourceAdminResult.setSearchIgnoreCase( storageSource.getSearchIgnoreCase() );
storageSourceAdminResult.setSearchMode( storageSource.getSearchMode() );
storageSourceAdminResult.setOrderNum( storageSource.getOrderNum() );
storageSourceAdminResult.setDefaultSwitchToImgMode( storageSource.getDefaultSwitchToImgMode() );
storageSourceAdminResult.setCompatibilityReadme( storageSource.getCompatibilityReadme() );
return storageSourceAdminResult;
}
}

View File

@ -0,0 +1,50 @@
package com.yfd.platform.modules.storage.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 存储源拓展设置 Mapper 接口
*
* @author zhengsl
*/
@Mapper
public interface StorageSourceConfigMapper extends BaseMapper<StorageSourceConfig> {
/**
* 根据存储源 ID 查询存储源拓展配置, 并按照存储源 id 排序
*
* @param storageId
* 存储源 ID
*
* @return 存储源拓展配置列表
*/
List<StorageSourceConfig> findByStorageIdOrderById(@Param("storageId") Integer storageId);
/**
* 根据存储源 ID 删除存储源拓展配置
*
* @param storageId
* 存储源 ID
*
* @return 删除记录数
*/
int deleteByStorageId(@Param("storageId") Integer storageId);
/**
* 批量插入存储源拓展配置
*
* @param list
* 存储源拓展配置列表
*
* @return 插入记录数
*/
int insertList(@Param("list") List<StorageSourceConfig> list);
}

View File

@ -0,0 +1,99 @@
package com.yfd.platform.modules.storage.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.modules.storage.model.entity.StorageSource;
import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 存储源基本配置 Mapper 接口
*
* @author zhengsl
*/
@Mapper
public interface StorageSourceMapper extends BaseMapper<StorageSource> {
/**
* 获取所有已启用的存储源, 并按照存储源排序值排序
*
* @return 存储源列表
*/
List<StorageSource> findListByEnableOrderByOrderNum();
/**
* 获取所有存储源, 并按照存储源排序值排序
*
* @return 存储源列表
*/
List<StorageSource> findAllOrderByOrderNum();
/**
* 获取存储源 ID 最大值
*
* @return 存储源 ID 最大值
*/
Integer selectMaxId();
/**
* 根据存储源类型获取存储源列表
*
* @param type
* 存储源类型
*
* @return 存储源列表
*/
List<StorageSource> findByType(@Param("type") StorageTypeEnum type);
/**
* 根据存储源 ID 设置排序值
*
* @param orderNum
* 排序值
*
* @param id
* 存储源 ID
*/
void updateSetOrderNumById(@Param("orderNum") int orderNum, @Param("id") Integer id);
/**
* 根据存储源 key 获取存储源
*
* @param storageKey
* 存储源 key
*
* @return 存储源信息
*/
StorageSource findByStorageKey(@Param("storageKey") String storageKey);
/**
* 根据存储源 key 获取存储源 id
*
* @param storageKey
* 存储源 key
*
* @return 存储源 id
*/
Integer findIdByStorageKey(@Param("storageKey") String storageKey);
/**
* 根据存储源 id 获取存储源 key
*
* @param id
* 存储源 id
*
* @return 存储源 key
*/
String findKeyById(@Param("id") Integer id);
}

View File

@ -0,0 +1,95 @@
package com.yfd.platform.modules.storage.model.bo;
import com.yfd.platform.annotation.StorageParamSelectOption;
import com.yfd.platform.modules.storage.model.enums.StorageParamTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import java.util.List;
/**
* 存储源参数定义, 包含参数名称描述必填默认值等信息.
*
* @author zhengsl
*/
@Data
@AllArgsConstructor
@Builder
public class StorageSourceParamDef {
/**
* 字段显示排序值, 值越小, 越靠前.
*/
private int order;
/**
* 参数 key
*/
private String key;
/**
* 参数名称
*/
private String name;
/**
* 参数描述
*/
private String description;
/**
* 是否必填
*/
private boolean required;
/**
* 默认值
*/
private String defaultValue;
/**
* 链接地址
*/
private String link;
/**
* 链接名称
*/
private String linkName;
/**
* 字段类型, 默认为 input, 可选值为: input, select, switch.
*/
private StorageParamTypeEnum type;
/**
* {@link #type} select , 选项的值.
*/
private List<Options> options;
@Getter
public static class Options {
private final String label;
private final String value;
public Options(String value) {
this.label = value;
this.value = value;
}
public Options(String label, String value) {
this.label = label;
this.value = value;
}
public Options(StorageParamSelectOption storageParamSelectOption) {
this.label = storageParamSelectOption.label();
this.value = storageParamSelectOption.value();
}
}
}

View File

@ -0,0 +1,117 @@
package com.yfd.platform.modules.storage.model.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 所有存储源的全部参数
*
* @author zhengsl
*/
@Data
@ApiModel(description = "存储源所有拓展参数")
public class StorageSourceAllParamDTO implements Serializable {
@ApiModelProperty(value = "Endpoint 接入点", example = "oss-cn-beijing.aliyuncs.com")
private String endPoint;
@ApiModelProperty(value = "路径风格", example = "path-style")
private String pathStyle;
@ApiModelProperty(value = "是否是私有空间", example = "true")
private Boolean isPrivate;
@ApiModelProperty(value = "accessKey", example = "LTAI4FjfXqXxQZQZ")
private String accessKey;
@ApiModelProperty(value = "secretKey", example = "QJIO19ASJIKL10ZL")
private String secretKey;
@ApiModelProperty(value = "bucket 名称", example = "zfile-test")
private String bucketName;
@ApiModelProperty(value = "原 bucket 名称", example = "zfile-test")
private String originBucketName;
@ApiModelProperty(value = "域名或 IP", example = "127.0.0.1")
private String host;
@ApiModelProperty(value = "端口", example = "8080")
private String port;
@ApiModelProperty(value = "访问令牌", example = "2.a6b7dbd428f731035f771b8d15063f61.86400.12929220")
private String accessToken;
@ApiModelProperty(value = "刷新令牌", example = "15063f61.86400.1292922000-2346678-1243281asd-1asa")
private String refreshToken;
@ApiModelProperty(value = "secretId", example = "LTAI4FjfXqXxQZQZ")
private String secretId;
@ApiModelProperty(value = "文件路径", example = "/root/")
private String filePath;
@ApiModelProperty(value = "用户名", example = "admin")
private String username;
@ApiModelProperty(value = "密码", example = "123456")
private String password;
@ApiModelProperty(value = "域名", example = "http://zfile-test.oss-cn-beijing.aliyuncs.com")
private String domain;
@ApiModelProperty(value = "基路径", example = "/root/")
private String basePath;
@ApiModelProperty(value = "token", example = "12e34awsde12")
private String token;
@ApiModelProperty(value = "token 有效期", example = "1800")
private Integer tokenTime;
@ApiModelProperty(value = "siteId", example = "ltzx124yu54z")
private String siteId;
@ApiModelProperty(value = "listId", example = "nbmyuoya12sz")
private String listId;
@ApiModelProperty(value = "站点名称", example = "test")
private String siteName;
@ApiModelProperty(value = "站点类型", example = "sites")
private String siteType;
@ApiModelProperty(value = "下载反代域名", example = "http://zfile-oroxy.zfile.vip")
private String proxyDomain;
@ApiModelProperty(value = "下载链接类型", example = "basic")
private String downloadLinkType;
@ApiModelProperty(value = "clientId", example = "4a72d927-1917-418d-9eb2-1b365c53c1c5")
private String clientId;
@ApiModelProperty(value = "clientSecret", example = "l:zI-_yrW75lV8M61K@z.I2K@B/On6Q1a")
private String clientSecret;
@ApiModelProperty(value = "回调地址", example = "https://zfile.jun6.net/onedrive/callback")
private String redirectUri;
@ApiModelProperty(value = "区域", example = "cn-beijing")
private String region;
@ApiModelProperty(value = "url", example = "url 链接")
private String url;
@ApiModelProperty(value = "是否自动配置 cors 规则", example = "true")
private Boolean autoConfigCors;
@ApiModelProperty(value = "编码格式", example = "UTF-8")
private String encoding;
@ApiModelProperty(value = "存储源 ID", example = "0AGrY0xF1D7PEUk9PV2")
private String driveId;
}

View File

@ -0,0 +1,69 @@
package com.yfd.platform.modules.storage.model.dto;
import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* @author zhengsl
*/
@Data
@ApiModel(description = "存储源基本参数")
public class StorageSourceDTO implements Serializable {
@ApiModelProperty(value = "ID, 新增无需填写", example = "1")
private Integer id;
@ApiModelProperty(value = "存储源名称", example = "阿里云 OSS 存储")
private String name;
@ApiModelProperty(value = "存储源别名", example = "存储源别名,用于 URL 中展示, 如 http://ip:port/{存储源别名}")
private String key;
@ApiModelProperty(value = "存储源备注", example = "这是一个备注信息, 用于管理员区分不同的存储源, 此字段仅管理员可见")
private String remark;
@ApiModelProperty(value = "存储源类型", example = "ftp")
private StorageTypeEnum type;
@ApiModelProperty(value = "是否启用", example = "true")
private boolean enable;
@ApiModelProperty(value = "是否启用文件操作功能", example = "true", notes = "是否启用文件上传,编辑,删除等操作.")
private Boolean enableFileOperator;
@ApiModelProperty(value = "是否允许匿名进行文件操作", example = "true", notes = "是否允许匿名进行文件上传,编辑,删除等操作.")
private Boolean enableFileAnnoOperator;
@ApiModelProperty(value = "是否开启缓存", example = "true")
private boolean enableCache;
@ApiModelProperty(value = "是否开启缓存自动刷新", example = "true")
private boolean autoRefreshCache;
@ApiModelProperty(value = "是否开启搜索", example = "true")
private boolean searchEnable;
@ApiModelProperty(value = "搜索是否忽略大小写", example = "true")
private boolean searchIgnoreCase;
// @TableField(value = "`search_mode`")
// @ApiModelProperty(value = "搜索模式", example = "SEARCH_CACHE", notes = "仅从缓存中搜索或直接全量搜索")
// private SearchModeEnum searchMode;
@ApiModelProperty(value = "排序值", example = "1")
private Integer orderNum;
@ApiModelProperty(value = "存储源拓展属性")
private StorageSourceAllParamDTO storageSourceAllParam;
@ApiModelProperty(value = "是否默认开启图片模式", example = "true")
private boolean defaultSwitchToImgMode;
@ApiModelProperty(value = "兼容 readme 模式", example = "true", notes = "兼容模式, 目录文档读取 readme.md 文件")
private Boolean compatibilityReadme;
}

View File

@ -0,0 +1,106 @@
package com.yfd.platform.modules.storage.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yfd.platform.modules.storage.model.enums.SearchModeEnum;
import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 存储源基本属性 entity
*
* @author zhengsl
*/
@Data
@ApiModel(description = "存储源基本属性")
@TableName(value = "fi_storage_source")
public class StorageSource implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty(value = "ID, 新增无需填写", example = "1")
private Integer id;
@TableField(value = "`enable`")
@ApiModelProperty(value = "是否启用", example = "true")
private Boolean enable;
@TableField(value = "`enable_file_operator`")
@ApiModelProperty(value = "是否启用文件操作功能", example = "true", notes = "是否启用文件上传,编辑,删除等操作.")
private Boolean enableFileOperator;
@TableField(value = "`enable_file_anno_operator`")
@ApiModelProperty(value = "是否允许匿名进行文件操作", example = "true", notes = "是否允许匿名进行文件上传,编辑,删除等操作.")
private Boolean enableFileAnnoOperator;
@TableField(value = "`enable_cache`")
@ApiModelProperty(value = "是否开启缓存", example = "true")
private Boolean enableCache;
@TableField(value = "`name`")
@ApiModelProperty(value = "存储源名称", example = "阿里云 OSS 存储")
private String name;
@TableField(value = "`key`")
@ApiModelProperty(value = "存储源别名", example = "存储源别名,用于 URL 中展示, 如 http://ip:port/{存储源别名}")
private String key;
@TableField(value = "`remark`")
@ApiModelProperty(value = "存储源备注", example = "这是一个备注信息, 用于管理员区分不同的存储源, 此字段仅管理员可见")
private String remark;
@TableField(value = "auto_refresh_cache")
@ApiModelProperty(value = "是否开启缓存自动刷新", example = "true")
private Boolean autoRefreshCache;
@TableField(value = "`type`")
@ApiModelProperty(value = "存储源类型")
private StorageTypeEnum type;
@TableField(value = "search_enable")
@ApiModelProperty(value = "是否开启搜索", example = "true")
private Boolean searchEnable;
@TableField(value = "search_ignore_case")
@ApiModelProperty(value = "搜索是否忽略大小写", example = "true")
private Boolean searchIgnoreCase;
@TableField(value = "`search_mode`")
@ApiModelProperty(value = "搜索模式", example = "SEARCH_CACHE", notes = "仅从缓存中搜索或直接全量搜索")
private SearchModeEnum searchMode;
@TableField(value = "order_num")
@ApiModelProperty(value = "排序值", example = "1")
private Integer orderNum;
@TableField(value = "default_switch_to_img_mode")
@ApiModelProperty(value = "是否默认开启图片模式", example = "true")
private Boolean defaultSwitchToImgMode;
@TableField(value = "compatibility_readme")
@ApiModelProperty(value = "兼容 readme 模式", example = "true", notes = "兼容模式, 目录文档读取 readme.md 文件")
private Boolean compatibilityReadme;
}

View File

@ -0,0 +1,55 @@
package com.yfd.platform.modules.storage.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 存储源拓展属性 entity
*
* @author zhengsl
*/
@Data
@ApiModel(description = "存储源拓展属性")
@TableName(value = "fi_storage_source_config")
public class StorageSourceConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty(value = "ID, 新增无需填写", example = "1")
private Integer id;
@TableField(value = "`name`")
@ApiModelProperty(value = "存储源属性名称 name", example = "bucketName")
private String name;
@TableField(value = "`type`")
@ApiModelProperty(value = "存储源类型")
private StorageTypeEnum type;
@TableField(value = "title")
@ApiModelProperty(value = "存储源属性名称", example = "Bucket 名称")
private String title;
@TableField(value = "storage_id")
@ApiModelProperty(value = "存储源 id", example = "1")
private Integer storageId;
@TableField(value = "`value`")
@ApiModelProperty(value = "存储源对应的值", example = "my-bucket")
private String value;
}

View File

@ -0,0 +1,31 @@
package com.yfd.platform.modules.storage.model.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 文件类型枚举
*
* @author zhengsl
*/
@Getter
@AllArgsConstructor
public enum FileTypeEnum {
/**
* 文件
*/
FILE("FILE"),
/**
* 文件夹
*/
FOLDER("FOLDER");
@EnumValue
@JsonValue
private final String value;
}

View File

@ -0,0 +1,31 @@
package com.yfd.platform.modules.storage.model.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 文件搜索模式枚举
*
* @author zhengsl
*/
@Getter
@AllArgsConstructor
public enum SearchModeEnum {
/**
* 仅搜索缓存
*/
SEARCH_CACHE_MODE("SEARCH_CACHE"),
/**
* 搜索全部
*/
SEARCH_ALL_MODE("SEARCH_ALL");
@EnumValue
@JsonValue
private final String value;
}

View File

@ -0,0 +1,36 @@
package com.yfd.platform.modules.storage.model.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 存储源参数类型枚举
*
* @author zhengsl
*/
@Getter
@AllArgsConstructor
public enum StorageParamTypeEnum {
/**
* 输入框
*/
INPUT("input"),
/**
* 下拉框
*/
SELECT("select"),
/**
* 开关
*/
SWITCH("switch");
@EnumValue
@JsonValue
private final String value;
}

View File

@ -0,0 +1,73 @@
package com.yfd.platform.modules.storage.model.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import java.util.HashMap;
import java.util.Map;
/**
* 存储源类型枚举
*
* @author zhengsl
*/
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum StorageTypeEnum implements IEnum {
/**
* 当前系统支持的所有存储源类型
*/
LOCAL("local", "本地存储"),
ALIYUN("aliyun", "阿里云 OSS"),
WEBDAV("webdav", "WebDAV"),
TENCENT("tencent", "腾讯云 COS"),
UPYUN("upyun", "又拍云 USS"),
FTP("ftp", "FTP"),
SFTP("sftp", "SFTP"),
HUAWEI("huawei", "华为云 OBS"),
MINIO("minio", "MINIO"),
S3("s3", "S3通用协议"),
ONE_DRIVE("onedrive", "OneDrive"),
ONE_DRIVE_CHINA("onedrive-china", "OneDrive 世纪互联"),
SHAREPOINT_DRIVE("sharepoint", "SharePoint"),
SHAREPOINT_DRIVE_CHINA("sharepoint-china", "SharePoint 世纪互联"),
GOOGLE_DRIVE("google-drive", "Google Drive"),
QINIU("qiniu", "七牛云 KODO"),
DOGE_CLOUD("doge-cloud", "多吉云");
private static final Map<String, StorageTypeEnum> ENUM_MAP = new HashMap<>();
static {
for (StorageTypeEnum type : StorageTypeEnum.values()) {
ENUM_MAP.put(type.getKey(), type);
}
}
@ApiModelProperty(value = "存储源类型枚举 Key", example = "aliyun")
@EnumValue
private final String key;
@ApiModelProperty(value = "存储源类型枚举描述", example = "阿里云 OSS")
private final String description;
StorageTypeEnum(String key, String description) {
this.key = key;
this.description = description;
}
public String getKey() {
return key;
}
public String getDescription() {
return description;
}
@JsonIgnore
public String getValue() {
return key;
}
}

Some files were not shown because too many files have changed in this diff Show More