Commit 150ccda62aa35cee64d38b9cca06a701b26ec68c
0 parents
assistant project init
Showing
95 changed files
with
4741 additions
and
0 deletions
Too many changes to show.
To preserve performance only 95 of 181 files are displayed.
.gitignore
0 → 100644
1 | +++ a/.gitignore | ||
1 | +# Compiled class file | ||
2 | +*.class | ||
3 | + | ||
4 | +# Log file | ||
5 | +*.log | ||
6 | + | ||
7 | +# BlueJ files | ||
8 | +*.ctxt | ||
9 | + | ||
10 | +# Mobile Tools for Java (J2ME) | ||
11 | +.mtj.tmp/ | ||
12 | + | ||
13 | +# Package Files # | ||
14 | +*.war | ||
15 | +*.nar | ||
16 | +*.ear | ||
17 | +*.zip | ||
18 | +*.tar.gz | ||
19 | +*.rar | ||
20 | + | ||
21 | +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml | ||
22 | +hs_err_pid* | ||
23 | +replay_pid* |
README.md
0 → 100644
1 | +++ a/README.md | ||
1 | +dili-uap | ||
2 | + uap-shared 基础设施和共享模块(解决循环依赖问题,工具类引入,中间件服务mq/redis/mysql等配置,第三方框架的封装和配置,全局异常拦截配置) | ||
3 | + uap-rpc 远程调用模块(openfeign集成,访问其他平台服务) | ||
4 | + uap-boss 管理模块,维护用户/角色/权限等 | ||
5 | + uap-auth 用户认证授权模块,用于用户登陆和权限控制,集成uap-security权限框架 | ||
6 | + uap-security 参考spring-security自研的一套权限验证框架,用于uap及其他子系统进行用户认证授权,类似于uap sdk | ||
7 | + uap-boot 父工程(springboot打包,系统对外提供开放接口) | ||
8 | + | ||
9 | +项目依赖 | ||
10 | +uap-shared -> etrade-rpc -> uap-boss -> uap-auth -> uap-boot | ||
11 | +uap-security | ||
12 | + | ||
13 | +项目结构 | ||
14 | + com.diligrp.uap.xxxx - 模块spring配置xxxxConfiguration(Spring组件扫描配置/MybatisMapper扫描配置)ErrorCode Constants | ||
15 | + com.diligrp.uap.xxxx.controller - 后台接口 | ||
16 | + com.diligrp.uap.xxxx.api - 移动端接口 | ||
17 | + com.diligrp.uap.xxxx.service | ||
18 | + com.diligrp.uap.xxxx.dao | ||
19 | + com.diligrp.uap.xxxx.exception | ||
20 | + com.diligrp.uap.xxxx.domain | ||
21 | + com.diligrp.uap.xxxx.model | ||
22 | + com.diligrp.uap.xxxx.type | ||
23 | + com.diligrp.uap.xxxx.util | ||
24 | + resource/com.diligrp.uap.dao.mapper - mybatis mapper文件 | ||
25 | + | ||
26 | + 系统对第三方系统提供接口通过uap-boot controller包 | ||
27 | + 所有数据模型类放入com.diligrp.uap.xxxx.model下,所有域模型类(VO DTO)放入com.diligrp.uap.xxxx.domain下 | ||
28 | + 所有数据模型类须继承BaseDo类,进一步规范数据表设计:需包含id version created_time modified_time | ||
29 | + 所有枚举类型放入com.diligrp.uap.xxxx.type下,枚举类定义请提供code/name属性,参见com.diligrp.uap.shared.type.Gender | ||
30 | + 所有自定义工具类放入com.diligrp.uap.xxxx.util下,如果大家都能公用请放uap-shared模块下 | ||
31 | + 所有异常类继承PlatformServiceException(提供了错误码和是否打印异常栈信息功能),并放入com.diligrp.uap.xxxx.exception下 | ||
32 | + 每个模块的常量类请放在模块根目录下,如通用常量请放入uap-shared模块下 | ||
33 | + 错误码为6位,每个模块的错误类ErrorCode且放入模块根目录,错误码应唯一且独特如前三位为模块标识,公共错误码参见com.diligrp.uap.shared.ErrorCode | ||
34 | + | ||
35 | +工具类 | ||
36 | + 参见:com.diligrp.uap.shared.util.* com.diligrp.uap.shared.security.* | ||
37 | + 包括:JsonUtils CurrencyUtils DateUtils RandomUtils AssertUtils HexUtils AesCipher RsaCipher ShaCipher KeyStoreUtils等等 | ||
38 | + | ||
39 | +技术要求 | ||
40 | + JDK17 SpringCould SpringBoot 3版本 | ||
41 | + 编译工具:gradle | ||
42 | + 第三方库尽量使用springboot默认推荐,如:Jackson Lettuce;springboot工具集中没有推荐的第三方库,引入时请在合适模块中进行 | ||
43 | + 已在uap-shared中完成Jackson配置,包括Spring DataBinding,且额外提供了Jackson工具类JsonUtils | ||
44 | + 已在uap-shared中已完成Redis基础配置Lettuce,可直接使用StringRedisTemplate,如需进行进一步封装配置请在合适的模块中配置,如需Redis分布式锁,可考虑引入Redission | ||
45 | + 已在uap-shared中已完成Mybatis基础配置,使用MapperScan完成mapper文件的扫描,不用plus,可用mybatis分页插件 | ||
46 | + 已在uap-shared中完成MQ基础配置RabbitMQ,可直接进行使用RabbitTemplate且可进行Queue Exchange和消息监听器的配置 | ||
47 | + 外部第三方jar放入dili-uap/libs | ||
48 | + 新技术框架的引入不以个人熟悉为重点考量标准,以技术框架的通用型和稳定性为考量标准 | ||
49 | + | ||
50 | +数据库脚本要求 | ||
51 | + 维护全量(dili-uap/scripts)和增量脚本(scripts/upgrade) | ||
52 | + 维护增量脚本,需同时修改权量脚本 | ||
53 | + 所有建表SQL,每个字段需填写备注 | ||
54 | + 通常情况下,每个表都需要包含三个字段id,version,created_time,modified_time | ||
55 | + 每个模块的数据表,建议统一的前缀uap_**** | ||
0 | \ No newline at end of file | 56 | \ No newline at end of file |
assistant-boot/build.gradle
0 → 100644
1 | +++ a/assistant-boot/build.gradle | ||
1 | +group = 'com.diligrp' | ||
2 | +archivesBaseName = 'assistant-boot' | ||
3 | + | ||
4 | +jar.enabled = false | ||
5 | +bootJar { | ||
6 | + enabled = true | ||
7 | + archiveBaseName = 'assistant-boot' | ||
8 | +} | ||
9 | + | ||
10 | +dependencies { | ||
11 | + implementation project(':assistant-dfs') | ||
12 | + implementation project(':assistant-sms') | ||
13 | + implementation project(':assistant-data') | ||
14 | + implementation project(':assistant-product') | ||
15 | + implementation project(':assistant-logging') | ||
16 | + implementation project(':assistant-uid') | ||
17 | + implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2022.0.0.0-RC2' | ||
18 | + implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config:2022.0.0.0-RC2' | ||
19 | +} | ||
0 | \ No newline at end of file | 20 | \ No newline at end of file |
assistant-boot/src/main/java/com/diligrp/assistant/boot/AssistantServiceBootstrap.java
0 → 100644
1 | +++ a/assistant-boot/src/main/java/com/diligrp/assistant/boot/AssistantServiceBootstrap.java | ||
1 | +package com.diligrp.assistant.boot; | ||
2 | + | ||
3 | +import com.diligrp.assistant.data.DataConfiguration; | ||
4 | +import com.diligrp.assistant.dfs.DfsConfiguration; | ||
5 | +import com.diligrp.assistant.logging.LoggingConfiguration; | ||
6 | +import com.diligrp.assistant.product.ProductConfiguration; | ||
7 | +import com.diligrp.assistant.shared.SharedConfiguration; | ||
8 | +import com.diligrp.assistant.sms.SmsConfiguration; | ||
9 | +import com.diligrp.assistant.uid.UidConfiguration; | ||
10 | +import org.springframework.boot.SpringApplication; | ||
11 | +import org.springframework.boot.SpringBootConfiguration; | ||
12 | +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | ||
13 | +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | ||
14 | +import org.springframework.context.annotation.Import; | ||
15 | + | ||
16 | +@SpringBootConfiguration | ||
17 | +@EnableAutoConfiguration | ||
18 | +@Import({BootConfiguration.class, SharedConfiguration.class, DfsConfiguration.class, SmsConfiguration.class, | ||
19 | + DataConfiguration.class, ProductConfiguration.class, LoggingConfiguration.class, UidConfiguration.class}) | ||
20 | +@EnableDiscoveryClient | ||
21 | +public class AssistantServiceBootstrap { | ||
22 | + public static void main(String[] args) { | ||
23 | + SpringApplication.run(AssistantServiceBootstrap.class, args); | ||
24 | + } | ||
25 | +} | ||
0 | \ No newline at end of file | 26 | \ No newline at end of file |
assistant-boot/src/main/java/com/diligrp/assistant/boot/BootConfiguration.java
0 → 100644
1 | +++ a/assistant-boot/src/main/java/com/diligrp/assistant/boot/BootConfiguration.java | ||
1 | +package com.diligrp.assistant.boot; | ||
2 | + | ||
3 | +import org.springframework.context.annotation.ComponentScan; | ||
4 | +import org.springframework.context.annotation.Configuration; | ||
5 | + | ||
6 | +@Configuration | ||
7 | +@ComponentScan("com.diligrp.assistant.boot") | ||
8 | +public class BootConfiguration { | ||
9 | +} |
assistant-boot/src/main/java/com/diligrp/assistant/boot/controller/TestOpenApiController.java
0 → 100644
1 | +++ a/assistant-boot/src/main/java/com/diligrp/assistant/boot/controller/TestOpenApiController.java | ||
1 | +package com.diligrp.assistant.boot.controller; | ||
2 | + | ||
3 | +import jakarta.servlet.http.HttpServletRequest; | ||
4 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
5 | +import org.springframework.web.bind.annotation.RestController; | ||
6 | + | ||
7 | +@RestController | ||
8 | +@RequestMapping(value = "/assistant") | ||
9 | +public class TestOpenApiController { | ||
10 | + @RequestMapping(value = "/test.do") | ||
11 | + public String staticTest(HttpServletRequest request) { | ||
12 | + return "I'm test url"; | ||
13 | + } | ||
14 | +} |
assistant-boot/src/main/resources/application.properties
0 → 100644
1 | +++ a/assistant-boot/src/main/resources/application.properties | ||
1 | +#Logback configuration | ||
2 | +logging.config=classpath:logback-spring.xml | ||
3 | + | ||
4 | +#Mybatis configuration | ||
5 | +mybatis.configuration.cache-enabled=true | ||
6 | +mybatis.configuration.multiple-result-sets-enabled=true | ||
7 | +mybatis.configuration.map-underscore-to-camel-case=true | ||
8 | +mybatis.configuration.use-column-label=true | ||
9 | +mybatis.configuration.default-statement-timeout=25000 | ||
10 | +mybatis.mapper-locations=classpath*:com/diligrp/assistant/dao/mapper/**/*.xml | ||
11 | +mybatis.configuration.default-enum-type-handler=com.diligrp.assistant.shared.mybatis.GenericEnumTypeHandler | ||
12 | + | ||
13 | +#Datasource configuration | ||
14 | +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver | ||
15 | +spring.datasource.url=jdbc:mysql://mysql.diligrp.com:3306/dili_assistant?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT%2B8 | ||
16 | +spring.datasource.username=root | ||
17 | +spring.datasource.password=123456 | ||
18 | +spring.datasource.type=com.zaxxer.hikari.HikariDataSource | ||
19 | +spring.datasource.hikari.pool-name=AssistantHikariPool | ||
20 | +spring.datasource.hikari.minimum-idle=4 | ||
21 | +spring.datasource.hikari.maximum-pool-size=60 | ||
22 | +spring.datasource.hikari.idle-timeout=120000 | ||
23 | +spring.datasource.hikari.max-lifetime=900000 | ||
24 | +spring.datasource.hikari.connection-timeout=15000 | ||
25 | +spring.datasource.hikari.connection-test-query=SELECT 1 | ||
26 | + | ||
27 | +#Redis configuration | ||
28 | +spring.data.redis.host=redis.diligrp.com | ||
29 | +spring.data.redis.port=6379 | ||
30 | +spring.data.redis.database=8 | ||
31 | +#spring.data.redis.username= | ||
32 | +#spring.data.redis.password= | ||
33 | +spring.data.redis.connect-timeout=15000 | ||
34 | +spring.data.redis.timeout=30000 | ||
35 | +#spring.data.redis.lettuce.pool.enabled=false | ||
36 | + | ||
37 | +#RabbitMQ configuration | ||
38 | +spring.rabbitmq.host=rabbitmq.diligrp.com | ||
39 | +spring.rabbitmq.port=5672 | ||
40 | +spring.rabbitmq.username=admin | ||
41 | +spring.rabbitmq.password=123456 | ||
42 | +spring.rabbitmq.virtual-host=/ | ||
43 | + | ||
44 | +#DFS configuration | ||
45 | +spring.servlet.multipart.max-file-size=40MB | ||
46 | +spring.servlet.multipart.max-request-size=100MB | ||
47 | +spring.servlet.multipart.file-size-threshold=20MB | ||
48 | +dfs.private-key=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAvRtBBrQX5di1jQPbUh+Lu5pMwrg6/H9/XX7qBU7dsGA/yygQAH7AYb/fpHQ1GQDolU3LVgYt3IE43QacLo09MwIDAQABAkAJ8U5kb8e0U2J+CmIJedRZO0GtX+MeD1uX51iCNJqYvbI/tKAgqd9ulc07it7tW0vGhDDj+WaVLp1R5D7bgRcpAiEA6Vc1xjoMYmT+OL+DZfipOeMTUwEePCg0Eq8DnVtalgsCIQDPeGSQ+lVijjNTEF7swM6rH5Ofa1E+ry5VRAw1ywI2eQIgdNFuYIErNg9tnqdydxiYUBy4zfNfWaqe90ObQao8naUCIQComhNIClgXZq5pA3XQ+wM458llFaaJxX1mx40QrjDXKQIgB+x7Fz2MT/GdIUhN6s1Rpfb5IIAR51ztiVEJlJ+wpdo= | ||
49 | +dfs.public-key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL0bQQa0F+XYtY0D21Ifi7uaTMK4Ovx/f11+6gVO3bBgP8soEAB+wGG/36R0NRkA6JVNy1YGLdyBON0GnC6NPTMCAwEAAQ== | ||
50 | +dfs.oss.uri=https://oss-cn-hangzhou.aliyuncs.com | ||
51 | +dfs.oss.access-key-id=LTAI5tS2xUrriUfti9pvDTwM | ||
52 | +dfs.oss.access-key-secret=NIa9FQMDc5zSAtvfOeOK4J1dp7aotg | ||
53 | + | ||
54 | +#Sms configuration | ||
55 | +sms.private-key=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAvRtBBrQX5di1jQPbUh+Lu5pMwrg6/H9/XX7qBU7dsGA/yygQAH7AYb/fpHQ1GQDolU3LVgYt3IE43QacLo09MwIDAQABAkAJ8U5kb8e0U2J+CmIJedRZO0GtX+MeD1uX51iCNJqYvbI/tKAgqd9ulc07it7tW0vGhDDj+WaVLp1R5D7bgRcpAiEA6Vc1xjoMYmT+OL+DZfipOeMTUwEePCg0Eq8DnVtalgsCIQDPeGSQ+lVijjNTEF7swM6rH5Ofa1E+ry5VRAw1ywI2eQIgdNFuYIErNg9tnqdydxiYUBy4zfNfWaqe90ObQao8naUCIQComhNIClgXZq5pA3XQ+wM458llFaaJxX1mx40QrjDXKQIgB+x7Fz2MT/GdIUhN6s1Rpfb5IIAR51ztiVEJlJ+wpdo= | ||
56 | +sms.public-key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL0bQQa0F+XYtY0D21Ifi7uaTMK4Ovx/f11+6gVO3bBgP8soEAB+wGG/36R0NRkA6JVNy1YGLdyBON0GnC6NPTMCAwEAAQ== | ||
57 | +sms.smschinese.uri=http://utf8.api.smschinese.cn | ||
58 | +sms.smschinese.uid=zhuxuegang@diligrp.com | ||
59 | +sms.smschinese.secret-key=c0978121c3893cf9ddbc | ||
0 | \ No newline at end of file | 60 | \ No newline at end of file |
assistant-boot/src/main/resources/bootstrap.properties
0 → 100644
1 | +++ a/assistant-boot/src/main/resources/bootstrap.properties | ||
1 | +server.port=8080 | ||
2 | +server.servlet.context-path=/ | ||
3 | +server.servlet.encoding.charset=UTF-8 | ||
4 | +server.servlet.encoding.force=true | ||
5 | + | ||
6 | +spring.profiles.active=dev | ||
7 | +spring.application.name=uap-service | ||
8 | + | ||
9 | +spring.cloud.nacos.discovery.enabled=true | ||
10 | +spring.cloud.nacos.discovery.group=WEB_APPLICATION | ||
11 | +spring.cloud.nacos.discovery.server-addr=nacos.diligrp.com:8848 | ||
12 | +spring.cloud.nacos.discovery.namespace=54c39cfe-d1c4-4022-a94b-a3486c5927fc | ||
13 | + | ||
14 | +spring.cloud.nacos.config.enabled=true | ||
15 | +spring.cloud.nacos.config.group=WEB_APPLICATION | ||
16 | +spring.cloud.nacos.config.server-addr=nacos.diligrp.com:8848 | ||
17 | +spring.cloud.nacos.config.namespace=54c39cfe-d1c4-4022-a94b-a3486c5927fc | ||
0 | \ No newline at end of file | 18 | \ No newline at end of file |
assistant-boot/src/main/resources/logback-spring.xml
0 → 100644
1 | +++ a/assistant-boot/src/main/resources/logback-spring.xml | ||
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<configuration> | ||
3 | + <!-- 日志名称 --> | ||
4 | + <property name="LOG_NAME" value="uap-boot" /> | ||
5 | + <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 --> | ||
6 | + <property name="LOG_HOME" value="logs" /> | ||
7 | + | ||
8 | + <!-- springProperty读取springboot配置属性 --> | ||
9 | + <springProperty scope="context" name="build.profile.id" source="spring.profiles.active" /> | ||
10 | + | ||
11 | + <statusListener class="ch.qos.logback.core.status.NopStatusListener" /> | ||
12 | + | ||
13 | + <!-- 日志控制台输出 --> | ||
14 | + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> | ||
15 | + <encoder> | ||
16 | + <pattern>%d %-5level [${LOG_NAME}-${build.profile.id}] [%t] [%c:%L] -| %msg%n</pattern> | ||
17 | + </encoder> | ||
18 | + </appender> | ||
19 | + | ||
20 | + <!-- 日志文件输出 --> | ||
21 | + <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||
22 | + <file>${LOG_HOME}/${LOG_NAME}.log</file> | ||
23 | + <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | ||
24 | + <!--日志文件输出的文件名 --> | ||
25 | + <fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/${LOG_NAME}_%i.log.zip</fileNamePattern> | ||
26 | + <!--日志文件保留天数(FileNamePattern中的%d 格式有关,如果yyyy-MM-dd 则是天数) --> | ||
27 | + <maxHistory>10</maxHistory> | ||
28 | + <!--日志文件最大的大小 --> | ||
29 | + <maxFileSize>10MB</maxFileSize> | ||
30 | + </rollingPolicy> | ||
31 | + <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> | ||
32 | + <pattern>%d %-5level [${LOG_NAME}-${build.profile.id}] [%t] [%c:%L]-| %msg%n</pattern> | ||
33 | + </encoder> | ||
34 | + </appender> | ||
35 | + | ||
36 | + <!-- 开发环境 --> | ||
37 | + <springProfile name="dev"> | ||
38 | + <root level="INFO"> | ||
39 | + <appender-ref ref="CONSOLE" /> | ||
40 | + </root> | ||
41 | + | ||
42 | + <logger name="com.diligrp.assistant" level="DEBUG" additivity="false"> | ||
43 | + <appender-ref ref="CONSOLE" /> | ||
44 | + </logger> | ||
45 | + | ||
46 | + <logger name="com.alibaba" level="ERROR" additivity="false"> | ||
47 | + <appender-ref ref="CONSOLE" /> | ||
48 | + </logger> | ||
49 | + </springProfile> | ||
50 | + | ||
51 | + <!-- 测试环境 --> | ||
52 | + <springProfile name="test"> | ||
53 | + <root level="INFO"> | ||
54 | + <appender-ref ref="CONSOLE" /> | ||
55 | + </root> | ||
56 | + | ||
57 | + <logger name="com.diligrp.assistant" level="DEBUG"> | ||
58 | + <appender-ref ref="FILE" /> | ||
59 | + </logger> | ||
60 | + | ||
61 | + <logger name="com.alibaba" level="ERROR" additivity="false"> | ||
62 | + <appender-ref ref="CONSOLE" /> | ||
63 | + <appender-ref ref="FILE" /> | ||
64 | + </logger> | ||
65 | + </springProfile> | ||
66 | + | ||
67 | + <!-- 灰度、生产环境 --> | ||
68 | + <springProfile name="pre,prod"> | ||
69 | + <root level="INFO"> | ||
70 | + <appender-ref ref="CONSOLE" /> | ||
71 | + </root> | ||
72 | + | ||
73 | + <logger name="com.diligrp.assistant" level="DEBUG"> | ||
74 | + <appender-ref ref="FILE" /> | ||
75 | + </logger> | ||
76 | + | ||
77 | + <logger name="com.alibaba" level="ERROR" additivity="false"> | ||
78 | + <appender-ref ref="CONSOLE" /> | ||
79 | + <appender-ref ref="FILE" /> | ||
80 | + </logger> | ||
81 | + | ||
82 | + <!-- 单独给子模块指定日志配置时,请注意additivity的使用 | ||
83 | + <logger name="com.diligrp.assistant.boss" level="debug" additivity="false"> | ||
84 | + <appender-ref ref="CONSOLE" /> | ||
85 | + <appender-ref ref="FILE" /> | ||
86 | + </logger> | ||
87 | + --> | ||
88 | + </springProfile> | ||
89 | +</configuration> | ||
0 | \ No newline at end of file | 90 | \ No newline at end of file |
assistant-data/build.gradle
0 → 100644
assistant-data/src/main/java/com/diligrp/assistant/data/DataConfiguration.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/DataConfiguration.java | ||
1 | +package com.diligrp.assistant.data; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.mybatis.MybatisMapperSupport; | ||
4 | +import org.mybatis.spring.annotation.MapperScan; | ||
5 | +import org.springframework.context.annotation.ComponentScan; | ||
6 | +import org.springframework.context.annotation.Configuration; | ||
7 | + | ||
8 | +@Configuration | ||
9 | +@ComponentScan("com.diligrp.assistant.data") | ||
10 | +@MapperScan(basePackages = {"com.diligrp.assistant.data.dao"}, markerInterface = MybatisMapperSupport.class) | ||
11 | +public class DataConfiguration { | ||
12 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/controller/DataDictionaryController.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/controller/DataDictionaryController.java | ||
1 | +package com.diligrp.assistant.data.controller; | ||
2 | + | ||
3 | +import com.diligrp.assistant.data.domain.DataDictionaryDTO; | ||
4 | +import com.diligrp.assistant.data.model.DataDictionary; | ||
5 | +import com.diligrp.assistant.data.service.DataDictionaryService; | ||
6 | +import com.diligrp.assistant.shared.domain.Message; | ||
7 | +import com.diligrp.assistant.shared.util.AssertUtils; | ||
8 | +import jakarta.annotation.Resource; | ||
9 | +import org.springframework.web.bind.annotation.RequestBody; | ||
10 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
11 | +import org.springframework.web.bind.annotation.RestController; | ||
12 | + | ||
13 | +import java.time.LocalDateTime; | ||
14 | +import java.util.List; | ||
15 | +import java.util.stream.Collectors; | ||
16 | + | ||
17 | +@RestController | ||
18 | +@RequestMapping(value = "/dictionary") | ||
19 | +public class DataDictionaryController { | ||
20 | + | ||
21 | + @Resource | ||
22 | + private DataDictionaryService dataDictionaryService; | ||
23 | + | ||
24 | + @RequestMapping(value = "/save.do") | ||
25 | + public Message save(@RequestBody DataDictionaryDTO request) { | ||
26 | + AssertUtils.notNull(request.getType(), "type missed"); | ||
27 | + AssertUtils.notEmpty(request.getGroupCode(), "groupCode missed"); | ||
28 | + AssertUtils.notEmpty(request.getCode(), "code missed"); | ||
29 | + AssertUtils.notEmpty(request.getValue(), "value missed"); | ||
30 | + | ||
31 | + LocalDateTime now = LocalDateTime.now(); | ||
32 | + DataDictionary.Builder dictionary = DataDictionary.builder(); | ||
33 | + dictionary.type(request.getType()).groupCode(request.getGroupCode()).code(request.getCode()) | ||
34 | + .name(request.getName()).value(request.getValue()).description(request.getDescription()) | ||
35 | + .createdTime(now).modifiedTime(now); | ||
36 | + dataDictionaryService.insertDataDictionary(dictionary.build()); | ||
37 | + return Message.success(); | ||
38 | + } | ||
39 | + | ||
40 | + @RequestMapping(value = "/findByCode.do") | ||
41 | + public Message<DataDictionaryDTO> findByCode(@RequestBody DataDictionaryDTO request) { | ||
42 | + AssertUtils.notEmpty(request.getGroupCode(), "groupCode missed"); | ||
43 | + AssertUtils.notEmpty(request.getCode(), "code missed"); | ||
44 | + | ||
45 | + DataDictionary dictionary = dataDictionaryService.findDataDictionaryByCode(request.getGroupCode(), request.getCode()); | ||
46 | + return Message.success(DataDictionaryDTO.from(dictionary.getType(), dictionary.getGroupCode(), | ||
47 | + dictionary.getCode(), dictionary.getName(), dictionary.getValue(), dictionary.getDescription())); | ||
48 | + } | ||
49 | + | ||
50 | + @RequestMapping(value = "/findByGroupCode.do") | ||
51 | + public Message<List<DataDictionaryDTO>> findByGroupCode(@RequestBody DataDictionaryDTO request) { | ||
52 | + AssertUtils.notEmpty(request.getGroupCode(), "groupCode missed"); | ||
53 | + | ||
54 | + List<DataDictionary> dictionaries = dataDictionaryService.findDataDictionaries(request.getGroupCode()); | ||
55 | + List<DataDictionaryDTO> data = dictionaries.stream().map(dictionary -> DataDictionaryDTO.from(dictionary.getType(), | ||
56 | + dictionary.getGroupCode(), dictionary.getCode(), dictionary.getName(), dictionary.getValue(), | ||
57 | + dictionary.getDescription())).collect(Collectors.toList()); | ||
58 | + | ||
59 | + return Message.success(data); | ||
60 | + } | ||
61 | + | ||
62 | + @RequestMapping(value = "/update.do") | ||
63 | + public Message update(@RequestBody DataDictionaryDTO request) { | ||
64 | + AssertUtils.notEmpty(request.getGroupCode(), "groupCode missed"); | ||
65 | + AssertUtils.notEmpty(request.getCode(), "code missed"); | ||
66 | + AssertUtils.notEmpty(request.getValue(), "value missed"); | ||
67 | + | ||
68 | + DataDictionary.Builder dictionary = DataDictionary.builder().groupCode(request.getGroupCode()) | ||
69 | + .code(request.getCode()).name(request.getName()).value(request.getValue()) | ||
70 | + .description(request.getDescription()).modifiedTime(LocalDateTime.now()); | ||
71 | + dataDictionaryService.updateDataDictionary(dictionary.build()); | ||
72 | + | ||
73 | + return Message.success(); | ||
74 | + } | ||
75 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/controller/DataDistrictController.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/controller/DataDistrictController.java | ||
1 | +package com.diligrp.assistant.data.controller; | ||
2 | + | ||
3 | +import com.diligrp.assistant.data.domain.DataDistrictDTO; | ||
4 | +import com.diligrp.assistant.data.domain.DistrictPageQuery; | ||
5 | +import com.diligrp.assistant.data.domain.ListDataDistrict; | ||
6 | +import com.diligrp.assistant.data.model.DataDistrict; | ||
7 | +import com.diligrp.assistant.data.service.DataDistrictService; | ||
8 | +import com.diligrp.assistant.shared.domain.Message; | ||
9 | +import com.diligrp.assistant.shared.util.AssertUtils; | ||
10 | +import jakarta.annotation.Resource; | ||
11 | +import org.springframework.web.bind.annotation.RequestBody; | ||
12 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
13 | +import org.springframework.web.bind.annotation.RequestParam; | ||
14 | +import org.springframework.web.bind.annotation.RestController; | ||
15 | + | ||
16 | +import java.util.List; | ||
17 | +import java.util.stream.Collectors; | ||
18 | + | ||
19 | +@RestController | ||
20 | +@RequestMapping(value = "/api/district") | ||
21 | +public class DataDistrictController { | ||
22 | + | ||
23 | + @Resource | ||
24 | + private DataDistrictService dataDistrictService; | ||
25 | + | ||
26 | + @RequestMapping(value = "/findById.do") | ||
27 | + public Message<DataDistrictDTO> findById(@RequestParam("id") Long id) { | ||
28 | + DataDistrict district = dataDistrictService.findDataDistrictById(id); | ||
29 | + return Message.success(DataDistrictDTO.of(district.getId(), district.getParentId(), | ||
30 | + district.getName(), district.getLevel(), district.getFullName(), district.getPath())); | ||
31 | + } | ||
32 | + | ||
33 | + @RequestMapping(value = "/findParentById.do") | ||
34 | + public Message<DataDistrictDTO> findParentById(@RequestParam("id") Long id) { | ||
35 | + DataDistrict district = dataDistrictService.findParentDistrictById(id); | ||
36 | + return Message.success(DataDistrictDTO.of(district.getId(), district.getParentId(), | ||
37 | + district.getName(), district.getLevel(), district.getFullName(), district.getPath())); | ||
38 | + } | ||
39 | + | ||
40 | + @RequestMapping(value = "/listParentsById.do") | ||
41 | + public Message<List<DataDistrictDTO>> listParentsById(@RequestParam("id") Long id) { | ||
42 | + List<DataDistrictDTO> districts = dataDistrictService.listParentsById(id).stream().map(d -> | ||
43 | + DataDistrictDTO.of(d.getId(), d.getParentId(), d.getName(), d.getLevel(), d.getFullName(), d.getPath())) | ||
44 | + .collect(Collectors.toList()); | ||
45 | + return Message.success(districts); | ||
46 | + } | ||
47 | + | ||
48 | + @RequestMapping(value = "/listChildrenById.do") | ||
49 | + public Message<List<DataDistrictDTO>> listChildrenById(@RequestBody ListDataDistrict request) { | ||
50 | + AssertUtils.notNull(request.getId(), "id missed"); | ||
51 | + AssertUtils.notNull(request.getPageNo(), "pageNo missed"); | ||
52 | + AssertUtils.notNull(request.getPageSize(), "pageSize missed"); | ||
53 | + | ||
54 | + DistrictPageQuery query = new DistrictPageQuery(); | ||
55 | + query.setId(request.getId()); | ||
56 | + query.from(request.getPageNo(), request.getPageSize()); | ||
57 | + | ||
58 | + List<DataDistrictDTO> districts = dataDistrictService.listChildrenById(query).stream().map(d -> | ||
59 | + DataDistrictDTO.of(d.getId(), d.getParentId(), d.getName(), d.getLevel(), d.getFullName(), d.getPath())) | ||
60 | + .collect(Collectors.toList()); | ||
61 | + return Message.success(districts); | ||
62 | + } | ||
63 | + | ||
64 | + @RequestMapping(value = "/listByLevel.do") | ||
65 | + public Message<List<DataDistrictDTO>> listByLevel(@RequestBody ListDataDistrict request) { | ||
66 | + AssertUtils.notNull(request.getLevel(), "level missed"); | ||
67 | + AssertUtils.notNull(request.getPageNo(), "pageNo missed"); | ||
68 | + AssertUtils.notNull(request.getPageSize(), "pageSize missed"); | ||
69 | + | ||
70 | + DistrictPageQuery query = new DistrictPageQuery(); | ||
71 | + query.setLevel(request.getLevel()); | ||
72 | + query.from(request.getPageNo(), request.getPageSize()); | ||
73 | + | ||
74 | + List<DataDistrictDTO> districts = dataDistrictService.listDataDistrictsByLevel(query).stream().map(d -> | ||
75 | + DataDistrictDTO.of(d.getId(), d.getParentId(), d.getName(), d.getLevel(), d.getFullName(), d.getPath())) | ||
76 | + .collect(Collectors.toList()); | ||
77 | + return Message.success(districts); | ||
78 | + } | ||
79 | + | ||
80 | + @RequestMapping(value = "/listByDistance.do") | ||
81 | + public Message<List<DataDistrictDTO>> listByDistance(@RequestBody ListDataDistrict request) { | ||
82 | + AssertUtils.notEmpty(request.getLongitude(), "longitude missed"); | ||
83 | + AssertUtils.notEmpty(request.getLatitude(), "latitude missed"); | ||
84 | + AssertUtils.notNull(request.getPageNo(), "pageNo missed"); | ||
85 | + AssertUtils.notNull(request.getPageSize(), "pageSize missed"); | ||
86 | + | ||
87 | + DistrictPageQuery query = new DistrictPageQuery(); | ||
88 | + query.setLongitude(request.getLongitude()); | ||
89 | + query.setLatitude(request.getLatitude()); | ||
90 | + query.from(request.getPageNo(), request.getPageSize()); | ||
91 | + | ||
92 | + List<DataDistrictDTO> districts = dataDistrictService.listDataDistrictsByDistance(query).stream().map(d -> | ||
93 | + DataDistrictDTO.of(d.getId(), d.getParentId(), d.getName(), d.getLevel(), d.getFullName(), d.getPath())) | ||
94 | + .collect(Collectors.toList()); | ||
95 | + return Message.success(districts); | ||
96 | + } | ||
97 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/dao/DataDictionaryDao.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/dao/DataDictionaryDao.java | ||
1 | +package com.diligrp.assistant.data.dao; | ||
2 | + | ||
3 | +import com.diligrp.assistant.data.model.DataDictionary; | ||
4 | +import com.diligrp.assistant.shared.mybatis.MybatisMapperSupport; | ||
5 | +import org.apache.ibatis.annotations.Param; | ||
6 | +import org.springframework.stereotype.Repository; | ||
7 | + | ||
8 | +import java.util.List; | ||
9 | +import java.util.Optional; | ||
10 | + | ||
11 | +/** | ||
12 | + * 数据字典设计:参数配置唯一约束:code + group_code, 允许出现重复code的配置参数;但不允许 | ||
13 | + * 在某个参数分组中(group_code)重复出现code的配置参数,这样设计的目的是允许不同商户下某个参数 | ||
14 | + * 配置有不同的值; 根据业务场景使用不同的数据字典API(返回一条还是多条字典配置) | ||
15 | + */ | ||
16 | +@Repository("dataDictionaryDao") | ||
17 | +public interface DataDictionaryDao extends MybatisMapperSupport { | ||
18 | + /** | ||
19 | + * 新增数据字典配置 | ||
20 | + * | ||
21 | + * @param dictionary - 数据字典 | ||
22 | + */ | ||
23 | + void insertDataDictionary(DataDictionary dictionary); | ||
24 | + | ||
25 | + /** | ||
26 | + * 根据编码(groupCode和Code)查询数据字典配置 | ||
27 | + * | ||
28 | + * @param groupCode - 分组编码,必填 | ||
29 | + * @param code - 参数编码,必填 | ||
30 | + * @return DataDictionary - 查询结果大于一条记录将抛出异常 | ||
31 | + */ | ||
32 | + Optional<DataDictionary> findDataDictionaryByCode(@Param("groupCode") String groupCode, @Param("code") String code); | ||
33 | + | ||
34 | + /** | ||
35 | + * 根据编码查询数据字典列表 | ||
36 | + * | ||
37 | + * @param groupCode - 分组编码,非必填 | ||
38 | + * @return List<DataDictionary> - 数据字典列表 | ||
39 | + */ | ||
40 | + List<DataDictionary> findDataDictionaries(@Param("groupCode") String groupCode); | ||
41 | + | ||
42 | + /** | ||
43 | + * 根据编码(groupCode和Code)修改数据字典配置 | ||
44 | + * | ||
45 | + * @param dictionary - 数据字典 | ||
46 | + * @return int - 更新条数 | ||
47 | + */ | ||
48 | + int updateDataDictionary(DataDictionary dictionary); | ||
49 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/dao/DataDistrictDao.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/dao/DataDistrictDao.java | ||
1 | +package com.diligrp.assistant.data.dao; | ||
2 | + | ||
3 | +import com.diligrp.assistant.data.domain.DistrictPageQuery; | ||
4 | +import com.diligrp.assistant.data.model.DataDistrict; | ||
5 | +import com.diligrp.assistant.shared.mybatis.MybatisMapperSupport; | ||
6 | +import org.springframework.stereotype.Repository; | ||
7 | + | ||
8 | +import java.util.List; | ||
9 | +import java.util.Optional; | ||
10 | + | ||
11 | +@Repository("dataDistrictDao") | ||
12 | +public interface DataDistrictDao extends MybatisMapperSupport { | ||
13 | + Optional<DataDistrict> findDataDistrictById(Long id); | ||
14 | + | ||
15 | + Optional<DataDistrict> findParentDistrictById(Long id); | ||
16 | + | ||
17 | + List<DataDistrict> findDataDistrictsByIds(List<Long> ids); | ||
18 | + | ||
19 | + List<DataDistrict> listChildrenById(DistrictPageQuery query); | ||
20 | + | ||
21 | + List<DataDistrict> listDataDistrictsByLevel(DistrictPageQuery query); | ||
22 | + | ||
23 | + List<DataDistrict> listDataDistrictsByDistance(DistrictPageQuery query); | ||
24 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/domain/DataDictionaryDTO.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/domain/DataDictionaryDTO.java | ||
1 | +package com.diligrp.assistant.data.domain; | ||
2 | + | ||
3 | +public class DataDictionaryDTO { | ||
4 | + // 类型 | ||
5 | + private Integer type; | ||
6 | + // 分组编码 | ||
7 | + private String groupCode; | ||
8 | + // 编码 | ||
9 | + private String code; | ||
10 | + // 名称 | ||
11 | + private String name; | ||
12 | + // 字典值 | ||
13 | + private String value; | ||
14 | + // 描述 | ||
15 | + private String description; | ||
16 | + | ||
17 | + public static DataDictionaryDTO from(Integer type, String groupCode, String code, String name, | ||
18 | + String value, String description) { | ||
19 | + DataDictionaryDTO dictionary = new DataDictionaryDTO(); | ||
20 | + dictionary.type = type; | ||
21 | + dictionary.groupCode = groupCode; | ||
22 | + dictionary.code = code; | ||
23 | + dictionary.name = name; | ||
24 | + dictionary.value = value; | ||
25 | + dictionary.description = description; | ||
26 | + return dictionary; | ||
27 | + } | ||
28 | + | ||
29 | + public Integer getType() { | ||
30 | + return type; | ||
31 | + } | ||
32 | + | ||
33 | + public void setType(Integer type) { | ||
34 | + this.type = type; | ||
35 | + } | ||
36 | + | ||
37 | + public String getGroupCode() { | ||
38 | + return groupCode; | ||
39 | + } | ||
40 | + | ||
41 | + public void setGroupCode(String groupCode) { | ||
42 | + this.groupCode = groupCode; | ||
43 | + } | ||
44 | + | ||
45 | + public String getCode() { | ||
46 | + return code; | ||
47 | + } | ||
48 | + | ||
49 | + public void setCode(String code) { | ||
50 | + this.code = code; | ||
51 | + } | ||
52 | + | ||
53 | + public String getName() { | ||
54 | + return name; | ||
55 | + } | ||
56 | + | ||
57 | + public void setName(String name) { | ||
58 | + this.name = name; | ||
59 | + } | ||
60 | + | ||
61 | + public String getValue() { | ||
62 | + return value; | ||
63 | + } | ||
64 | + | ||
65 | + public void setValue(String value) { | ||
66 | + this.value = value; | ||
67 | + } | ||
68 | + | ||
69 | + public String getDescription() { | ||
70 | + return description; | ||
71 | + } | ||
72 | + | ||
73 | + public void setDescription(String description) { | ||
74 | + this.description = description; | ||
75 | + } | ||
76 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/domain/DataDistrictDTO.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/domain/DataDistrictDTO.java | ||
1 | +package com.diligrp.assistant.data.domain; | ||
2 | + | ||
3 | +public class DataDistrictDTO { | ||
4 | + // ID | ||
5 | + private Long id; | ||
6 | + // 父区域ID | ||
7 | + private Long parentId; | ||
8 | + // 名称 | ||
9 | + private String name; | ||
10 | + // 级别 | ||
11 | + private Integer level; | ||
12 | + // 全称 | ||
13 | + private String fullName; | ||
14 | + // 路径 | ||
15 | + private String path; | ||
16 | + | ||
17 | + public static DataDistrictDTO of(Long id, Long parentId, String name, Integer level, String fullName, String path) { | ||
18 | + DataDistrictDTO district = new DataDistrictDTO(); | ||
19 | + district.id = id; | ||
20 | + district.parentId = parentId; | ||
21 | + district.name = name; | ||
22 | + district.level = level; | ||
23 | + district.fullName = fullName; | ||
24 | + district.path = path; | ||
25 | + | ||
26 | + return district; | ||
27 | + } | ||
28 | + | ||
29 | + public Long getId() { | ||
30 | + return id; | ||
31 | + } | ||
32 | + | ||
33 | + public void setId(Long id) { | ||
34 | + this.id = id; | ||
35 | + } | ||
36 | + | ||
37 | + public Long getParentId() { | ||
38 | + return parentId; | ||
39 | + } | ||
40 | + | ||
41 | + public void setParentId(Long parentId) { | ||
42 | + this.parentId = parentId; | ||
43 | + } | ||
44 | + | ||
45 | + public String getName() { | ||
46 | + return name; | ||
47 | + } | ||
48 | + | ||
49 | + public void setName(String name) { | ||
50 | + this.name = name; | ||
51 | + } | ||
52 | + | ||
53 | + public Integer getLevel() { | ||
54 | + return level; | ||
55 | + } | ||
56 | + | ||
57 | + public void setLevel(Integer level) { | ||
58 | + this.level = level; | ||
59 | + } | ||
60 | + | ||
61 | + public String getFullName() { | ||
62 | + return fullName; | ||
63 | + } | ||
64 | + | ||
65 | + public void setFullName(String fullName) { | ||
66 | + this.fullName = fullName; | ||
67 | + } | ||
68 | + | ||
69 | + public String getPath() { | ||
70 | + return path; | ||
71 | + } | ||
72 | + | ||
73 | + public void setPath(String path) { | ||
74 | + this.path = path; | ||
75 | + } | ||
76 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/domain/DistrictPageQuery.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/domain/DistrictPageQuery.java | ||
1 | +package com.diligrp.assistant.data.domain; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.domain.PageQuery; | ||
4 | + | ||
5 | +public class DistrictPageQuery extends PageQuery { | ||
6 | + // 区域ID | ||
7 | + private Long id; | ||
8 | + // 区域级别 | ||
9 | + private Integer level; | ||
10 | + // 经度 | ||
11 | + private String longitude; | ||
12 | + // 纬度 | ||
13 | + private String latitude; | ||
14 | + | ||
15 | + public Long getId() { | ||
16 | + return id; | ||
17 | + } | ||
18 | + | ||
19 | + public void setId(Long id) { | ||
20 | + this.id = id; | ||
21 | + } | ||
22 | + | ||
23 | + public Integer getLevel() { | ||
24 | + return level; | ||
25 | + } | ||
26 | + | ||
27 | + public void setLevel(Integer level) { | ||
28 | + this.level = level; | ||
29 | + } | ||
30 | + | ||
31 | + public String getLongitude() { | ||
32 | + return longitude; | ||
33 | + } | ||
34 | + | ||
35 | + public void setLongitude(String longitude) { | ||
36 | + this.longitude = longitude; | ||
37 | + } | ||
38 | + | ||
39 | + public String getLatitude() { | ||
40 | + return latitude; | ||
41 | + } | ||
42 | + | ||
43 | + public void setLatitude(String latitude) { | ||
44 | + this.latitude = latitude; | ||
45 | + } | ||
46 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/domain/ListDataDistrict.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/domain/ListDataDistrict.java | ||
1 | +package com.diligrp.assistant.data.domain; | ||
2 | + | ||
3 | +public class ListDataDistrict { | ||
4 | + // 页号 | ||
5 | + private Integer pageNo = 1; | ||
6 | + // 每页记录数 | ||
7 | + private Integer pageSize = 20; | ||
8 | + | ||
9 | + // 区域ID | ||
10 | + private Long id; | ||
11 | + // 区域级别 | ||
12 | + private Integer level; | ||
13 | + // 经度 | ||
14 | + private String longitude; | ||
15 | + // 纬度 | ||
16 | + private String latitude; | ||
17 | + | ||
18 | + public Integer getPageNo() { | ||
19 | + return pageNo; | ||
20 | + } | ||
21 | + | ||
22 | + public void setPageNo(Integer pageNo) { | ||
23 | + this.pageNo = pageNo; | ||
24 | + } | ||
25 | + | ||
26 | + public Integer getPageSize() { | ||
27 | + return pageSize; | ||
28 | + } | ||
29 | + | ||
30 | + public void setPageSize(Integer pageSize) { | ||
31 | + this.pageSize = pageSize; | ||
32 | + } | ||
33 | + | ||
34 | + public Long getId() { | ||
35 | + return id; | ||
36 | + } | ||
37 | + | ||
38 | + public void setId(Long id) { | ||
39 | + this.id = id; | ||
40 | + } | ||
41 | + | ||
42 | + public Integer getLevel() { | ||
43 | + return level; | ||
44 | + } | ||
45 | + | ||
46 | + public void setLevel(Integer level) { | ||
47 | + this.level = level; | ||
48 | + } | ||
49 | + | ||
50 | + public String getLongitude() { | ||
51 | + return longitude; | ||
52 | + } | ||
53 | + | ||
54 | + public void setLongitude(String longitude) { | ||
55 | + this.longitude = longitude; | ||
56 | + } | ||
57 | + | ||
58 | + public String getLatitude() { | ||
59 | + return latitude; | ||
60 | + } | ||
61 | + | ||
62 | + public void setLatitude(String latitude) { | ||
63 | + this.latitude = latitude; | ||
64 | + } | ||
65 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/exception/DataAccessException.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/exception/DataAccessException.java | ||
1 | +package com.diligrp.assistant.data.exception; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.exception.PlatformServiceException; | ||
4 | + | ||
5 | +public class DataAccessException extends PlatformServiceException { | ||
6 | + public DataAccessException(String message) { | ||
7 | + super(message); | ||
8 | + } | ||
9 | + | ||
10 | + public DataAccessException(int code, String message) { | ||
11 | + super(code, message); | ||
12 | + } | ||
13 | + | ||
14 | + public DataAccessException(String message, Throwable ex) { | ||
15 | + super(message, ex); | ||
16 | + } | ||
17 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/model/DataDictionary.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/model/DataDictionary.java | ||
1 | +package com.diligrp.assistant.data.model; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.domain.BaseDo; | ||
4 | + | ||
5 | +import java.time.LocalDateTime; | ||
6 | + | ||
7 | +public class DataDictionary extends BaseDo { | ||
8 | + // 类型 | ||
9 | + private Integer type; | ||
10 | + // 分组编码 | ||
11 | + private String groupCode; | ||
12 | + // 编码 | ||
13 | + private String code; | ||
14 | + // 名称 | ||
15 | + private String name; | ||
16 | + // 字典值 | ||
17 | + private String value; | ||
18 | + // 描述 | ||
19 | + private String description; | ||
20 | + | ||
21 | + public Integer getType() { | ||
22 | + return type; | ||
23 | + } | ||
24 | + | ||
25 | + public void setType(Integer type) { | ||
26 | + this.type = type; | ||
27 | + } | ||
28 | + | ||
29 | + public String getGroupCode() { | ||
30 | + return groupCode; | ||
31 | + } | ||
32 | + | ||
33 | + public void setGroupCode(String groupCode) { | ||
34 | + this.groupCode = groupCode; | ||
35 | + } | ||
36 | + | ||
37 | + public String getCode() { | ||
38 | + return code; | ||
39 | + } | ||
40 | + | ||
41 | + public void setCode(String code) { | ||
42 | + this.code = code; | ||
43 | + } | ||
44 | + | ||
45 | + public String getName() { | ||
46 | + return name; | ||
47 | + } | ||
48 | + | ||
49 | + public void setName(String name) { | ||
50 | + this.name = name; | ||
51 | + } | ||
52 | + | ||
53 | + public String getValue() { | ||
54 | + return value; | ||
55 | + } | ||
56 | + | ||
57 | + public void setValue(String value) { | ||
58 | + this.value = value; | ||
59 | + } | ||
60 | + | ||
61 | + public String getDescription() { | ||
62 | + return description; | ||
63 | + } | ||
64 | + | ||
65 | + public void setDescription(String description) { | ||
66 | + this.description = description; | ||
67 | + } | ||
68 | + | ||
69 | + public LocalDateTime getCreatedTime() { | ||
70 | + return createdTime; | ||
71 | + } | ||
72 | + | ||
73 | + public void setCreatedTime(LocalDateTime createdTime) { | ||
74 | + this.createdTime = createdTime; | ||
75 | + } | ||
76 | + | ||
77 | + public LocalDateTime getModifiedTime() { | ||
78 | + return modifiedTime; | ||
79 | + } | ||
80 | + | ||
81 | + public void setModifiedTime(LocalDateTime modifiedTime) { | ||
82 | + this.modifiedTime = modifiedTime; | ||
83 | + } | ||
84 | + | ||
85 | + public static Builder builder() { | ||
86 | + return new DataDictionary().new Builder(); | ||
87 | + } | ||
88 | + | ||
89 | + public class Builder { | ||
90 | + public Builder type(int type) { | ||
91 | + DataDictionary.this.type = type; | ||
92 | + return this; | ||
93 | + } | ||
94 | + | ||
95 | + public Builder groupCode(String groupCode) { | ||
96 | + DataDictionary.this.groupCode = groupCode; | ||
97 | + return this; | ||
98 | + } | ||
99 | + | ||
100 | + public Builder code(String code) { | ||
101 | + DataDictionary.this.code = code; | ||
102 | + return this; | ||
103 | + } | ||
104 | + | ||
105 | + public Builder name(String name) { | ||
106 | + DataDictionary.this.name = name; | ||
107 | + return this; | ||
108 | + } | ||
109 | + | ||
110 | + public Builder value(String value) { | ||
111 | + DataDictionary.this.value = value; | ||
112 | + return this; | ||
113 | + } | ||
114 | + | ||
115 | + public Builder description(String description) { | ||
116 | + DataDictionary.this.description = description; | ||
117 | + return this; | ||
118 | + } | ||
119 | + | ||
120 | + public Builder createdTime(LocalDateTime createdTime) { | ||
121 | + DataDictionary.this.createdTime = createdTime; | ||
122 | + return this; | ||
123 | + } | ||
124 | + | ||
125 | + public Builder modifiedTime(LocalDateTime modifiedTime) { | ||
126 | + DataDictionary.this.modifiedTime = modifiedTime; | ||
127 | + return this; | ||
128 | + } | ||
129 | + | ||
130 | + public DataDictionary build() { | ||
131 | + return DataDictionary.this; | ||
132 | + } | ||
133 | + } | ||
134 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/model/DataDistrict.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/model/DataDistrict.java | ||
1 | +package com.diligrp.assistant.data.model; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.domain.BaseDo; | ||
4 | + | ||
5 | +public class DataDistrict extends BaseDo { | ||
6 | + // 父区域ID | ||
7 | + private Long parentId; | ||
8 | + // 名称 | ||
9 | + private String name; | ||
10 | + // 简称 | ||
11 | + private String shortName; | ||
12 | + // 级别 | ||
13 | + private Integer level; | ||
14 | + // 全称 | ||
15 | + private String fullName; | ||
16 | + // 区号 | ||
17 | + private String areaCode; | ||
18 | + // 拼音 | ||
19 | + private String pyCode; | ||
20 | + // 简拼 | ||
21 | + private String shortPy; | ||
22 | + // 路径 | ||
23 | + private String path; | ||
24 | + // 路径名称 | ||
25 | + private String pathName; | ||
26 | + // 经度 | ||
27 | + private String longitude; | ||
28 | + // 纬度 | ||
29 | + private String latitude; | ||
30 | + // 状态 | ||
31 | + private Integer state; | ||
32 | + | ||
33 | + public Long getParentId() { | ||
34 | + return parentId; | ||
35 | + } | ||
36 | + | ||
37 | + public void setParentId(Long parentId) { | ||
38 | + this.parentId = parentId; | ||
39 | + } | ||
40 | + | ||
41 | + public String getName() { | ||
42 | + return name; | ||
43 | + } | ||
44 | + | ||
45 | + public void setName(String name) { | ||
46 | + this.name = name; | ||
47 | + } | ||
48 | + | ||
49 | + public String getShortName() { | ||
50 | + return shortName; | ||
51 | + } | ||
52 | + | ||
53 | + public void setShortName(String shortName) { | ||
54 | + this.shortName = shortName; | ||
55 | + } | ||
56 | + | ||
57 | + public Integer getLevel() { | ||
58 | + return level; | ||
59 | + } | ||
60 | + | ||
61 | + public void setLevel(Integer level) { | ||
62 | + this.level = level; | ||
63 | + } | ||
64 | + | ||
65 | + public String getFullName() { | ||
66 | + return fullName; | ||
67 | + } | ||
68 | + | ||
69 | + public void setFullName(String fullName) { | ||
70 | + this.fullName = fullName; | ||
71 | + } | ||
72 | + | ||
73 | + public String getAreaCode() { | ||
74 | + return areaCode; | ||
75 | + } | ||
76 | + | ||
77 | + public void setAreaCode(String areaCode) { | ||
78 | + this.areaCode = areaCode; | ||
79 | + } | ||
80 | + | ||
81 | + public String getPyCode() { | ||
82 | + return pyCode; | ||
83 | + } | ||
84 | + | ||
85 | + public void setPyCode(String pyCode) { | ||
86 | + this.pyCode = pyCode; | ||
87 | + } | ||
88 | + | ||
89 | + public String getShortPy() { | ||
90 | + return shortPy; | ||
91 | + } | ||
92 | + | ||
93 | + public void setShortPy(String shortPy) { | ||
94 | + this.shortPy = shortPy; | ||
95 | + } | ||
96 | + | ||
97 | + public String getPath() { | ||
98 | + return path; | ||
99 | + } | ||
100 | + | ||
101 | + public void setPath(String path) { | ||
102 | + this.path = path; | ||
103 | + } | ||
104 | + | ||
105 | + public String getPathName() { | ||
106 | + return pathName; | ||
107 | + } | ||
108 | + | ||
109 | + public void setPathName(String pathName) { | ||
110 | + this.pathName = pathName; | ||
111 | + } | ||
112 | + | ||
113 | + public String getLongitude() { | ||
114 | + return longitude; | ||
115 | + } | ||
116 | + | ||
117 | + public void setLongitude(String longitude) { | ||
118 | + this.longitude = longitude; | ||
119 | + } | ||
120 | + | ||
121 | + public String getLatitude() { | ||
122 | + return latitude; | ||
123 | + } | ||
124 | + | ||
125 | + public void setLatitude(String latitude) { | ||
126 | + this.latitude = latitude; | ||
127 | + } | ||
128 | + | ||
129 | + public Integer getState() { | ||
130 | + return state; | ||
131 | + } | ||
132 | + | ||
133 | + public void setState(Integer state) { | ||
134 | + this.state = state; | ||
135 | + } | ||
136 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/service/DataDictionaryService.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/service/DataDictionaryService.java | ||
1 | +package com.diligrp.assistant.data.service; | ||
2 | + | ||
3 | +import com.diligrp.assistant.data.model.DataDictionary; | ||
4 | +import org.apache.ibatis.annotations.Param; | ||
5 | + | ||
6 | +import java.util.List; | ||
7 | + | ||
8 | +public interface DataDictionaryService { | ||
9 | + /** | ||
10 | + * 新增数据字典配置 | ||
11 | + * | ||
12 | + * @param dictionary - 数据字典 | ||
13 | + */ | ||
14 | + void insertDataDictionary(DataDictionary dictionary); | ||
15 | + | ||
16 | + /** | ||
17 | + * 根据编码(groupCode和Code)查询数据字典配置 | ||
18 | + * | ||
19 | + * @param groupCode - 分组编码,必填 | ||
20 | + * @param code - 参数编码,必填 | ||
21 | + * @return DataDictionary - 查询结果大于一条记录将抛出异常 | ||
22 | + */ | ||
23 | + DataDictionary findDataDictionaryByCode(@Param("groupCode") String groupCode, @Param("code") String code); | ||
24 | + | ||
25 | + /** | ||
26 | + * 根据编码查询数据字典列表 | ||
27 | + * | ||
28 | + * @param groupCode - 分组编码,非必填 | ||
29 | + * @return List<DataDictionary> - 数据字典列表 | ||
30 | + */ | ||
31 | + List<DataDictionary> findDataDictionaries(@Param("groupCode") String groupCode); | ||
32 | + | ||
33 | + /** | ||
34 | + * 根据编码(groupCode和Code)修改数据字典配置 | ||
35 | + * | ||
36 | + * @param dictionary - 数据字典 | ||
37 | + * @return int - 更新条数 | ||
38 | + */ | ||
39 | + void updateDataDictionary(DataDictionary dictionary); | ||
40 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/service/DataDistrictService.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/service/DataDistrictService.java | ||
1 | +package com.diligrp.assistant.data.service; | ||
2 | + | ||
3 | +import com.diligrp.assistant.data.domain.DistrictPageQuery; | ||
4 | +import com.diligrp.assistant.data.model.DataDistrict; | ||
5 | + | ||
6 | +import java.util.List; | ||
7 | + | ||
8 | +public interface DataDistrictService { | ||
9 | + /** | ||
10 | + * 根据ID查询区域 | ||
11 | + * | ||
12 | + * @param id - 区域ID | ||
13 | + * @return 区域 | ||
14 | + */ | ||
15 | + DataDistrict findDataDistrictById(Long id); | ||
16 | + | ||
17 | + /** | ||
18 | + * 根据ID查询父级区域 | ||
19 | + * | ||
20 | + * @param id - 区域ID | ||
21 | + * @return 父级区域 | ||
22 | + */ | ||
23 | + DataDistrict findParentDistrictById(Long id); | ||
24 | + | ||
25 | + /** | ||
26 | + * 根据ID查询所有的祖先区域,查询结果包含自身且按照等级降序排序 | ||
27 | + * | ||
28 | + * @param id - 区域ID | ||
29 | + * @return 祖先区域 | ||
30 | + */ | ||
31 | + List<DataDistrict> listParentsById(Long id); | ||
32 | + | ||
33 | + /** | ||
34 | + * 根据父区域ID分页查询子区域 | ||
35 | + * | ||
36 | + * @param query 查询条件 | ||
37 | + * @return 子区域 | ||
38 | + */ | ||
39 | + List<DataDistrict> listChildrenById(DistrictPageQuery query); | ||
40 | + | ||
41 | + /** | ||
42 | + * 根据区域级别分页查询区域 | ||
43 | + * | ||
44 | + * @param query 查询条件 | ||
45 | + * @return 区域 | ||
46 | + */ | ||
47 | + List<DataDistrict> listDataDistrictsByLevel(DistrictPageQuery query); | ||
48 | + | ||
49 | + /** | ||
50 | + * 根据经纬度坐标分页查询区域,距离由近到远排序 | ||
51 | + * | ||
52 | + * @param query 查询条件 | ||
53 | + * @return 区域 | ||
54 | + */ | ||
55 | + List<DataDistrict> listDataDistrictsByDistance(DistrictPageQuery query); | ||
56 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/service/impl/DataDictionaryServiceImpl.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/service/impl/DataDictionaryServiceImpl.java | ||
1 | +package com.diligrp.assistant.data.service.impl; | ||
2 | + | ||
3 | +import com.diligrp.assistant.data.dao.DataDictionaryDao; | ||
4 | +import com.diligrp.assistant.data.exception.DataAccessException; | ||
5 | +import com.diligrp.assistant.data.model.DataDictionary; | ||
6 | +import com.diligrp.assistant.data.service.DataDictionaryService; | ||
7 | +import com.diligrp.assistant.shared.ErrorCode; | ||
8 | +import jakarta.annotation.Resource; | ||
9 | +import org.springframework.stereotype.Service; | ||
10 | +import org.springframework.transaction.annotation.Transactional; | ||
11 | + | ||
12 | +import java.util.List; | ||
13 | +import java.util.Optional; | ||
14 | + | ||
15 | +@Service("dataDictionaryService") | ||
16 | +public class DataDictionaryServiceImpl implements DataDictionaryService { | ||
17 | + | ||
18 | + @Resource | ||
19 | + private DataDictionaryDao dataDictionaryDao; | ||
20 | + | ||
21 | + @Override | ||
22 | + @Transactional(rollbackFor = Exception.class) | ||
23 | + public void insertDataDictionary(DataDictionary dictionary) { | ||
24 | + dataDictionaryDao.insertDataDictionary(dictionary); | ||
25 | + } | ||
26 | + | ||
27 | + @Override | ||
28 | + public DataDictionary findDataDictionaryByCode(String groupCode, String code) { | ||
29 | + //TODO: Use redis or local cache? | ||
30 | + Optional<DataDictionary> optional = dataDictionaryDao.findDataDictionaryByCode(groupCode, code); | ||
31 | + return optional.orElseThrow(() -> new DataAccessException(ErrorCode.OBJECT_NOT_FOUND, "数据字典不存在")); | ||
32 | + } | ||
33 | + | ||
34 | + @Override | ||
35 | + public List<DataDictionary> findDataDictionaries(String groupCode) { | ||
36 | + return dataDictionaryDao.findDataDictionaries(groupCode); | ||
37 | + } | ||
38 | + | ||
39 | + @Override | ||
40 | + @Transactional(rollbackFor = Exception.class) | ||
41 | + public void updateDataDictionary(DataDictionary dictionary) { | ||
42 | + int result = dataDictionaryDao.updateDataDictionary(dictionary); | ||
43 | + if (result == 0) { | ||
44 | + throw new DataAccessException(ErrorCode.OBJECT_NOT_FOUND, "数据字典不存在"); | ||
45 | + } | ||
46 | + } | ||
47 | +} |
assistant-data/src/main/java/com/diligrp/assistant/data/service/impl/DataDistrictServiceImpl.java
0 → 100644
1 | +++ a/assistant-data/src/main/java/com/diligrp/assistant/data/service/impl/DataDistrictServiceImpl.java | ||
1 | +package com.diligrp.assistant.data.service.impl; | ||
2 | + | ||
3 | +import com.diligrp.assistant.data.dao.DataDistrictDao; | ||
4 | +import com.diligrp.assistant.data.domain.DistrictPageQuery; | ||
5 | +import com.diligrp.assistant.data.exception.DataAccessException; | ||
6 | +import com.diligrp.assistant.data.model.DataDistrict; | ||
7 | +import com.diligrp.assistant.data.service.DataDistrictService; | ||
8 | +import com.diligrp.assistant.shared.ErrorCode; | ||
9 | +import jakarta.annotation.Resource; | ||
10 | +import org.springframework.stereotype.Service; | ||
11 | + | ||
12 | +import java.util.*; | ||
13 | + | ||
14 | +@Service("dataDistrictService") | ||
15 | +public class DataDistrictServiceImpl implements DataDistrictService { | ||
16 | + | ||
17 | + @Resource | ||
18 | + private DataDistrictDao dataDistrictDao; | ||
19 | + | ||
20 | + @Override | ||
21 | + public DataDistrict findDataDistrictById(Long id) { | ||
22 | + return dataDistrictDao.findDataDistrictById(id).orElseThrow(() -> | ||
23 | + new DataAccessException(ErrorCode.OBJECT_NOT_FOUND, "区域不存在")); | ||
24 | + } | ||
25 | + | ||
26 | + @Override | ||
27 | + public DataDistrict findParentDistrictById(Long id) { | ||
28 | + return dataDistrictDao.findParentDistrictById(id).orElseThrow(() -> | ||
29 | + new DataAccessException(ErrorCode.OBJECT_NOT_FOUND, "区域不存在")); | ||
30 | + } | ||
31 | + | ||
32 | + @Override | ||
33 | + public List<DataDistrict> listParentsById(Long id) { | ||
34 | + DataDistrict self = findDataDistrictById(id); | ||
35 | + String path = self.getPath(); | ||
36 | + | ||
37 | + if (Objects.nonNull(path)) { | ||
38 | + List<Long> ids = new ArrayList<>(); | ||
39 | + StringTokenizer tokenizer = new StringTokenizer(path, ","); | ||
40 | + | ||
41 | + while (tokenizer.hasMoreTokens()) { | ||
42 | + ids.add(Long.parseLong(tokenizer.nextToken())); | ||
43 | + } | ||
44 | + if (ids.isEmpty()) { | ||
45 | + ids.add(id); | ||
46 | + } | ||
47 | + | ||
48 | + return dataDistrictDao.findDataDistrictsByIds(ids); | ||
49 | + } else { | ||
50 | + return Collections.singletonList(self); | ||
51 | + } | ||
52 | + } | ||
53 | + | ||
54 | + @Override | ||
55 | + public List<DataDistrict> listChildrenById(DistrictPageQuery query) { | ||
56 | + return dataDistrictDao.listChildrenById(query); | ||
57 | + } | ||
58 | + | ||
59 | + @Override | ||
60 | + public List<DataDistrict> listDataDistrictsByLevel(DistrictPageQuery query) { | ||
61 | + return dataDistrictDao.listDataDistrictsByLevel(query); | ||
62 | + } | ||
63 | + | ||
64 | + @Override | ||
65 | + public List<DataDistrict> listDataDistrictsByDistance(DistrictPageQuery query) { | ||
66 | + return dataDistrictDao.listDataDistrictsByDistance(query); | ||
67 | + } | ||
68 | +} |
assistant-data/src/main/resources/com/diligrp/assistant/dao/mapper/DataDictionaryDao.xml
0 → 100644
1 | +++ a/assistant-data/src/main/resources/com/diligrp/assistant/dao/mapper/DataDictionaryDao.xml | ||
1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||
3 | + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
4 | + | ||
5 | +<mapper namespace="com.diligrp.assistant.data.dao.DataDictionaryDao"> | ||
6 | + <resultMap id="DataDictionaryMap" type="com.diligrp.assistant.data.model.DataDictionary"> | ||
7 | + <id column="id" property="id"/> | ||
8 | + <result column="type" property="type"/> | ||
9 | + <result column="group_code" property="groupCode"/> | ||
10 | + <result column="code" property="code"/> | ||
11 | + <result column="name" property="name"/> | ||
12 | + <result column="value" property="value"/> | ||
13 | + <result column="description" property="description"/> | ||
14 | + <result column="created_time" property="createdTime"/> | ||
15 | + <result column="modified_time" property="modifiedTime"/> | ||
16 | + </resultMap> | ||
17 | + | ||
18 | + <insert id="insertDataDictionary" parameterType="com.diligrp.assistant.data.model.DataDictionary"> | ||
19 | + INSERT INTO data_dictionary | ||
20 | + (type, group_code, code, name, value, description, created_time, modified_time) | ||
21 | + VALUES | ||
22 | + (#{type}, #{groupCode}, #{code}, #{name}, #{value}, #{description}, #{createdTime}, #{modifiedTime}) | ||
23 | + </insert> | ||
24 | + | ||
25 | + <select id="findDataDictionaryByCode" resultMap="DataDictionaryMap"> | ||
26 | + SELECT * FROM data_dictionary WHERE group_code = #{groupCode} AND code = #{code} | ||
27 | + </select> | ||
28 | + | ||
29 | + <select id="findDataDictionaries" resultMap="DataDictionaryMap"> | ||
30 | + SELECT * FROM data_dictionary WHERE group_code = #{groupCode} | ||
31 | + ORDER BY id | ||
32 | + </select> | ||
33 | + | ||
34 | + <update id="updateDataDictionary"> | ||
35 | + UPDATE data_dictionary SET value = #{value}, modified_time = #{modifiedTime} | ||
36 | + <if test="name != null"> | ||
37 | + , name = #{name} | ||
38 | + </if> | ||
39 | + <if test="description != null"> | ||
40 | + , description = #{description} | ||
41 | + </if> | ||
42 | + WHERE group_code = #{groupCode} AND code = #{code} | ||
43 | + </update> | ||
44 | +</mapper> |
assistant-data/src/main/resources/com/diligrp/assistant/dao/mapper/DataDistrictDao.xml
0 → 100644
1 | +++ a/assistant-data/src/main/resources/com/diligrp/assistant/dao/mapper/DataDistrictDao.xml | ||
1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||
3 | + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
4 | + | ||
5 | +<mapper namespace="com.diligrp.assistant.data.dao.DataDistrictDao"> | ||
6 | + <resultMap id="DataDistrictMap" type="com.diligrp.assistant.data.model.DataDistrict"> | ||
7 | + <id column="id" property="id"/> | ||
8 | + <result column="parent_id" property="parentId"/> | ||
9 | + <result column="name" property="name"/> | ||
10 | + <result column="short_name" property="shortName"/> | ||
11 | + <result column="level" property="level"/> | ||
12 | + <result column="full_name" property="fullName"/> | ||
13 | + <result column="area_code" property="areaCode"/> | ||
14 | + <result column="py_code" property="pyCode"/> | ||
15 | + <result column="short_py" property="shortPy"/> | ||
16 | + <result column="path" property="path"/> | ||
17 | + <result column="path_name" property="pathName"/> | ||
18 | + <result column="longitude" property="longitude"/> | ||
19 | + <result column="latitude" property="latitude"/> | ||
20 | + <result column="state" property="state"/> | ||
21 | + <result column="created_time" property="createdTime"/> | ||
22 | + </resultMap> | ||
23 | + | ||
24 | + <select id="findDataDistrictById" parameterType="long" resultMap="DataDistrictMap"> | ||
25 | + SELECT * FROM data_district WHERE id = #{id} AND state > 0 | ||
26 | + </select> | ||
27 | + | ||
28 | + <select id="findParentDistrictById" parameterType="long" resultMap="DataDistrictMap"> | ||
29 | + SELECT | ||
30 | + parent.* | ||
31 | + FROM data_district self | ||
32 | + INNER JOIN data_district parent ON self.parent_id = parent.id | ||
33 | + WHERE self.id = #{id} AND self.state > 0 | ||
34 | + </select> | ||
35 | + | ||
36 | + <select id="findDataDistrictsByIds" resultMap="DataDistrictMap"> | ||
37 | + SELECT * FROM data_district WHERE id IN | ||
38 | + <foreach item="id" collection="list" open="(" separator="," close=")"> | ||
39 | + #{id} | ||
40 | + </foreach> | ||
41 | + AND state > 0 ORDER BY level DESC, id | ||
42 | + </select> | ||
43 | + | ||
44 | + <select id="listChildrenById" parameterType="com.diligrp.assistant.data.domain.DistrictPageQuery" resultMap="DataDistrictMap"> | ||
45 | + SELECT * FROM data_district WHERE parent_Id = #{id} AND state > 0 | ||
46 | + ORDER BY ID LIMIT #{start}, #{limit} | ||
47 | + </select> | ||
48 | + | ||
49 | + <select id="listDataDistrictsByLevel" parameterType="com.diligrp.assistant.data.domain.DistrictPageQuery" resultMap="DataDistrictMap"> | ||
50 | + SELECT * FROM data_district WHERE level = #{level} AND state > 0 | ||
51 | + ORDER BY ID LIMIT #{start}, #{limit} | ||
52 | + </select> | ||
53 | + | ||
54 | + <select id="listDataDistrictsByDistance" parameterType="com.diligrp.assistant.data.domain.DistrictPageQuery" resultMap="DataDistrictMap"> | ||
55 | + SELECT * FROM data_district | ||
56 | + WHERE longitude IS NOT NULL AND latitude IS NOT NULL AND state > 0 | ||
57 | + ORDER BY ST_Distance(ST_GeomFromText('POINT(${longitude} ${latitude})'), ST_GeomFromText(CONCAT('POINT(', longitude, ' ', latitude, ')'))) | ||
58 | + LIMIT #{start}, #{limit} | ||
59 | + </select> | ||
60 | +</mapper> |
assistant-dfs/build.gradle
0 → 100644
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/Constants.java
0 → 100644
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/DfsConfiguration.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/DfsConfiguration.java | ||
1 | +package com.diligrp.assistant.dfs; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.pipeline.DefaultDfsPipelineManager; | ||
4 | +import com.diligrp.assistant.dfs.pipeline.DfsPipeline; | ||
5 | +import com.diligrp.assistant.dfs.pipeline.DfsPipelineManager; | ||
6 | +import com.diligrp.assistant.dfs.pipeline.OssPipeline; | ||
7 | +import com.diligrp.assistant.shared.mybatis.MybatisMapperSupport; | ||
8 | +import org.mybatis.spring.annotation.MapperScan; | ||
9 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
10 | +import org.springframework.context.annotation.Bean; | ||
11 | +import org.springframework.context.annotation.ComponentScan; | ||
12 | +import org.springframework.context.annotation.Configuration; | ||
13 | + | ||
14 | +@Configuration | ||
15 | +@ComponentScan("com.diligrp.assistant.dfs") | ||
16 | +@MapperScan(basePackages = {"com.diligrp.assistant.dfs.dao"}, markerInterface = MybatisMapperSupport.class) | ||
17 | +public class DfsConfiguration { | ||
18 | + | ||
19 | + @Bean | ||
20 | + @ConfigurationProperties("dfs") | ||
21 | + public DfsProperties dfsProperties() { | ||
22 | + return new DfsProperties(); | ||
23 | + } | ||
24 | + | ||
25 | + @Bean | ||
26 | + public DfsPipelineManager dfsPipelineManager(DfsProperties properties) { | ||
27 | + DfsPipelineManager pipelineManager = new DefaultDfsPipelineManager(); | ||
28 | + DfsProperties.Oss oss = properties.getOss(); | ||
29 | + if (oss != null) { | ||
30 | + // 可利用数据库进行通道配置, 前期并没有必要 | ||
31 | + DfsPipeline pipeline = new OssPipeline(1, "OSS文件存储服务", oss.getUri(), | ||
32 | + oss.getAccessKeyId(), oss.getAccessKeySecret()); | ||
33 | + pipelineManager.registerPipeline(pipeline); | ||
34 | + } | ||
35 | + return pipelineManager; | ||
36 | + } | ||
37 | +} | ||
0 | \ No newline at end of file | 38 | \ No newline at end of file |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/DfsProperties.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/DfsProperties.java | ||
1 | +package com.diligrp.assistant.dfs; | ||
2 | + | ||
3 | +import java.security.PrivateKey; | ||
4 | +import java.security.PublicKey; | ||
5 | + | ||
6 | +public class DfsProperties { | ||
7 | + // 私钥 | ||
8 | + private PrivateKey privateKey; | ||
9 | + // 公钥 | ||
10 | + private PublicKey publicKey; | ||
11 | + // OSS配置 | ||
12 | + private Oss oss; | ||
13 | + | ||
14 | + public PrivateKey getPrivateKey() { | ||
15 | + return privateKey; | ||
16 | + } | ||
17 | + | ||
18 | + public void setPrivateKey(PrivateKey privateKey) { | ||
19 | + this.privateKey = privateKey; | ||
20 | + } | ||
21 | + | ||
22 | + public PublicKey getPublicKey() { | ||
23 | + return publicKey; | ||
24 | + } | ||
25 | + | ||
26 | + public void setPublicKey(PublicKey publicKey) { | ||
27 | + this.publicKey = publicKey; | ||
28 | + } | ||
29 | + | ||
30 | + public Oss getOss() { | ||
31 | + return oss; | ||
32 | + } | ||
33 | + | ||
34 | + public void setOss(Oss oss) { | ||
35 | + this.oss = oss; | ||
36 | + } | ||
37 | + | ||
38 | + public static class Oss { | ||
39 | + private String uri; | ||
40 | + private String accessKeyId; | ||
41 | + private String accessKeySecret; | ||
42 | + | ||
43 | + public String getUri() { | ||
44 | + return uri; | ||
45 | + } | ||
46 | + | ||
47 | + public void setUri(String uri) { | ||
48 | + this.uri = uri; | ||
49 | + } | ||
50 | + | ||
51 | + public String getAccessKeyId() { | ||
52 | + return accessKeyId; | ||
53 | + } | ||
54 | + | ||
55 | + public void setAccessKeyId(String accessKeyId) { | ||
56 | + this.accessKeyId = accessKeyId; | ||
57 | + } | ||
58 | + | ||
59 | + public String getAccessKeySecret() { | ||
60 | + return accessKeySecret; | ||
61 | + } | ||
62 | + | ||
63 | + public void setAccessKeySecret(String accessKeySecret) { | ||
64 | + this.accessKeySecret = accessKeySecret; | ||
65 | + } | ||
66 | + } | ||
67 | +} | ||
0 | \ No newline at end of file | 68 | \ No newline at end of file |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/client/FileRepositoryClient.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/client/FileRepositoryClient.java | ||
1 | +package com.diligrp.assistant.dfs.client; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.domain.DfsFile; | ||
4 | + | ||
5 | +public interface FileRepositoryClient { | ||
6 | + /** | ||
7 | + * 创建文件仓库,并返回仓库唯一标识:名称 | ||
8 | + * | ||
9 | + * @param repositoryId - 仓库ID | ||
10 | + * @return 仓库名称,同仓库ID | ||
11 | + */ | ||
12 | + String createFileRepository(String repositoryId); | ||
13 | + | ||
14 | + /** | ||
15 | + * 删除文件仓库 - 空仓库才允许删除 | ||
16 | + * | ||
17 | + * @param repositoryId - 仓库ID | ||
18 | + * @return true/false | ||
19 | + */ | ||
20 | + boolean deleteFileRepository(String repositoryId); | ||
21 | + | ||
22 | + /** | ||
23 | + * 存放文件到仓库 | ||
24 | + * | ||
25 | + * @param repositoryId - 仓库ID | ||
26 | + * @param file - 文件 | ||
27 | + */ | ||
28 | + void putFile(String repositoryId, DfsFile file); | ||
29 | + | ||
30 | + /** | ||
31 | + * 从文件仓库中获取文件 | ||
32 | + * | ||
33 | + * @param repositoryId - 仓库ID | ||
34 | + * @param fileId - 文件标识 | ||
35 | + * @param style - 图片处理参数, 参见https://help.aliyun.com/zh/oss/user-guide/adjust-image-quality?spm=a2c4g.11186623.0.0.1c2d2759lemWct | ||
36 | + * @return - 文件 | ||
37 | + */ | ||
38 | + DfsFile getFile(String repositoryId, String fileId, String style); | ||
39 | + | ||
40 | + /** | ||
41 | + * 从文件仓库中删除文件 | ||
42 | + * | ||
43 | + * @param repositoryId - 仓库ID | ||
44 | + * @param fileId - 文件标识 | ||
45 | + * @return - true/false | ||
46 | + */ | ||
47 | + boolean deleteFile(String repositoryId, String fileId); | ||
48 | + | ||
49 | + void destroy(); | ||
50 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/client/OssFileRepositoryClient.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/client/OssFileRepositoryClient.java | ||
1 | +package com.diligrp.assistant.dfs.client; | ||
2 | + | ||
3 | +import com.aliyun.oss.ClientBuilderConfiguration; | ||
4 | +import com.aliyun.oss.OSS; | ||
5 | +import com.aliyun.oss.OSSClientBuilder; | ||
6 | +import com.aliyun.oss.OSSException; | ||
7 | +import com.aliyun.oss.common.auth.CredentialsProvider; | ||
8 | +import com.aliyun.oss.common.auth.DefaultCredentialProvider; | ||
9 | +import com.aliyun.oss.model.*; | ||
10 | +import com.diligrp.assistant.dfs.Constants; | ||
11 | +import com.diligrp.assistant.dfs.domain.DfsFile; | ||
12 | +import com.diligrp.assistant.dfs.domain.FileMetadata; | ||
13 | +import com.diligrp.assistant.dfs.exception.DfsServiceException; | ||
14 | +import com.diligrp.assistant.shared.ErrorCode; | ||
15 | +import org.slf4j.Logger; | ||
16 | +import org.slf4j.LoggerFactory; | ||
17 | + | ||
18 | +import java.nio.charset.StandardCharsets; | ||
19 | +import java.util.Base64; | ||
20 | + | ||
21 | +public class OssFileRepositoryClient implements FileRepositoryClient { | ||
22 | + private final static Logger LOGGER = LoggerFactory.getLogger(OssFileRepositoryClient.class); | ||
23 | + | ||
24 | + private OSS client; | ||
25 | + | ||
26 | + public OssFileRepositoryClient(String uri, String accessKeyId, String accessKeySecret) { | ||
27 | + CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret); | ||
28 | + ClientBuilderConfiguration conf = new ClientBuilderConfiguration(); | ||
29 | + // 设置OSSClient允许打开的最大HTTP连接数,默认为1024个。 | ||
30 | + conf.setMaxConnections(200); | ||
31 | + // 设置Socket层传输数据的超时时间,默认为50000毫秒。 | ||
32 | + conf.setSocketTimeout(20000); | ||
33 | + // 设置建立连接的超时时间,默认为50000毫秒。 | ||
34 | + conf.setConnectionTimeout(10000); | ||
35 | + // 设置从连接池中获取连接的超时时间(单位:毫秒),默认不超时。 | ||
36 | + conf.setConnectionRequestTimeout(15000); | ||
37 | + // 设置连接空闲超时时间。超时则关闭连接,默认为60000毫秒。 | ||
38 | + conf.setIdleConnectionTime(30000); | ||
39 | + // 设置失败请求重试次数,默认为3次。 | ||
40 | + conf.setMaxErrorRetry(5); | ||
41 | + client = new OSSClientBuilder().build(uri, credentialsProvider, conf); | ||
42 | + } | ||
43 | + | ||
44 | + @Override | ||
45 | + public String createFileRepository(String repositoryId) { | ||
46 | + CreateBucketRequest request = new CreateBucketRequest(repositoryId); | ||
47 | + try { | ||
48 | + Bucket bucket = client.createBucket(request); | ||
49 | + return bucket.getName(); | ||
50 | + } catch (OSSException oex) { | ||
51 | + LOGGER.error("Failed to create oss bucket", oex); | ||
52 | + throw new DfsServiceException(ErrorCode.SERVICE_ACCESS_ERROR, "创建存储空间失败: " + oex.getErrorMessage()); | ||
53 | + } catch (Exception ex) { | ||
54 | + LOGGER.error("Failed to create oss bucket", ex); | ||
55 | + throw new DfsServiceException(ErrorCode.SERVICE_ACCESS_ERROR, "创建存储空间失败: " + ex.getMessage()); | ||
56 | + } | ||
57 | + } | ||
58 | + | ||
59 | + @Override | ||
60 | + public boolean deleteFileRepository(String repositoryId) { | ||
61 | + try { | ||
62 | + client.deleteBucket(repositoryId); | ||
63 | + return true; | ||
64 | + } catch (OSSException oex) { | ||
65 | + LOGGER.error("Failed to delete oss bucket", oex); | ||
66 | + throw new DfsServiceException(ErrorCode.SERVICE_ACCESS_ERROR, "文件仓库删除失败: " + oex.getErrorMessage()); | ||
67 | + } catch (Exception ex) { | ||
68 | + LOGGER.error("Failed to delete oss bucket", ex); | ||
69 | + throw new DfsServiceException(ErrorCode.SERVICE_ACCESS_ERROR, "文件仓库删除失败: " + ex.getMessage()); | ||
70 | + } | ||
71 | + } | ||
72 | + | ||
73 | + @Override | ||
74 | + public void putFile(String repositoryId, DfsFile file) { | ||
75 | + FileMetadata option = file.getMetadata(); | ||
76 | + ObjectMetadata metadata = new ObjectMetadata(); | ||
77 | + metadata.setContentType(option.getMimeType()); | ||
78 | + // 处理中文名称无法验证签名导致无法完成文件上传 | ||
79 | + String encodedFileName = Base64.getEncoder().encodeToString(file.getName().getBytes(StandardCharsets.UTF_8)); | ||
80 | + metadata.addUserMetadata(Constants.FILE_METADATA_NAME, encodedFileName); | ||
81 | + PutObjectRequest request = new PutObjectRequest(repositoryId, file.getId(), file.getStream(), metadata); | ||
82 | + | ||
83 | + try { | ||
84 | + client.putObject(request); | ||
85 | + } catch (OSSException oex) { | ||
86 | + LOGGER.error("Failed to put file into bucket", oex); | ||
87 | + throw new DfsServiceException(ErrorCode.SERVICE_ACCESS_ERROR, "文件上传失败: " + oex.getErrorMessage()); | ||
88 | + } catch (Exception ex) { | ||
89 | + LOGGER.error("Failed to put file into bucket", ex); | ||
90 | + throw new DfsServiceException(ErrorCode.SERVICE_ACCESS_ERROR, "文件上传失败: " + ex.getMessage()); | ||
91 | + } | ||
92 | + } | ||
93 | + | ||
94 | + @Override | ||
95 | + public DfsFile getFile(String repositoryId, String fileId, String style) { | ||
96 | + GetObjectRequest request = new GetObjectRequest(repositoryId, fileId); | ||
97 | + if (style != null) { | ||
98 | + request.setProcess(style); | ||
99 | + } | ||
100 | + OSSObject ossObject; | ||
101 | + | ||
102 | + try { | ||
103 | + ossObject = client.getObject(request); | ||
104 | + ObjectMetadata metadata = ossObject.getObjectMetadata(); | ||
105 | + String encodedFileName = metadata.getUserMetadata().get(Constants.FILE_METADATA_NAME); | ||
106 | + String fileName = new String(Base64.getDecoder().decode(encodedFileName), StandardCharsets.UTF_8); | ||
107 | + | ||
108 | + FileMetadata fileMetadata = new FileMetadata(metadata.getContentType()); | ||
109 | + return new DfsFile(fileId, fileName, ossObject.getObjectContent(), fileMetadata); | ||
110 | + } catch (OSSException oex) { | ||
111 | + LOGGER.error("Failed to get file from bucket", oex); | ||
112 | + throw new DfsServiceException(ErrorCode.SERVICE_ACCESS_ERROR, "文件下载失败: " + oex.getErrorMessage()); | ||
113 | + } catch (Exception ex) { | ||
114 | + LOGGER.error("Failed to get file from bucket", ex); | ||
115 | + throw new DfsServiceException(ErrorCode.SERVICE_ACCESS_ERROR, "文件下载失败: " + ex.getMessage()); | ||
116 | + } | ||
117 | + } | ||
118 | + | ||
119 | + @Override | ||
120 | + public boolean deleteFile(String repositoryId, String fileId) { | ||
121 | + try { | ||
122 | + client.deleteObject(repositoryId, fileId); | ||
123 | + return true; | ||
124 | + } catch (OSSException oex) { | ||
125 | + LOGGER.error("Failed to delete file from bucket", oex); | ||
126 | + throw new DfsServiceException(ErrorCode.SERVICE_ACCESS_ERROR, "文件删除失败: " + oex.getErrorMessage()); | ||
127 | + } catch (Exception ex) { | ||
128 | + LOGGER.error("Failed to delete file from bucket", ex); | ||
129 | + throw new DfsServiceException(ErrorCode.SERVICE_ACCESS_ERROR, "文件删除失败: " + ex.getMessage()); | ||
130 | + } | ||
131 | + } | ||
132 | + | ||
133 | + @Override | ||
134 | + public void destroy() { | ||
135 | + client.shutdown(); | ||
136 | + } | ||
137 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/controller/FileObjectController.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/controller/FileObjectController.java | ||
1 | +package com.diligrp.assistant.dfs.controller; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.Constants; | ||
4 | +import com.diligrp.assistant.dfs.DfsProperties; | ||
5 | +import com.diligrp.assistant.dfs.domain.DfsAccessToken; | ||
6 | +import com.diligrp.assistant.dfs.domain.DfsFile; | ||
7 | +import com.diligrp.assistant.dfs.domain.FileMetadata; | ||
8 | +import com.diligrp.assistant.dfs.exception.DfsServiceException; | ||
9 | +import com.diligrp.assistant.dfs.service.FileRepositoryService; | ||
10 | +import com.diligrp.assistant.shared.ErrorCode; | ||
11 | +import com.diligrp.assistant.shared.domain.Message; | ||
12 | +import com.diligrp.assistant.shared.util.ObjectUtils; | ||
13 | +import jakarta.annotation.Resource; | ||
14 | +import jakarta.servlet.http.HttpServletResponse; | ||
15 | +import org.apache.commons.io.IOUtils; | ||
16 | +import org.springframework.http.MediaType; | ||
17 | +import org.springframework.http.MediaTypeFactory; | ||
18 | +import org.springframework.util.MimeType; | ||
19 | +import org.springframework.web.bind.annotation.*; | ||
20 | +import org.springframework.web.multipart.MultipartFile; | ||
21 | + | ||
22 | +import java.io.ByteArrayInputStream; | ||
23 | +import java.io.IOException; | ||
24 | +import java.io.InputStream; | ||
25 | +import java.net.URLDecoder; | ||
26 | +import java.net.URLEncoder; | ||
27 | +import java.nio.charset.StandardCharsets; | ||
28 | +import java.util.ArrayList; | ||
29 | +import java.util.Base64; | ||
30 | +import java.util.List; | ||
31 | +import java.util.Optional; | ||
32 | + | ||
33 | +@RestController | ||
34 | +@RequestMapping(value = "/dfs") | ||
35 | +public class FileObjectController { | ||
36 | + | ||
37 | + @Resource | ||
38 | + private DfsProperties dfsProperties; | ||
39 | + | ||
40 | + @Resource | ||
41 | + private FileRepositoryService fileRepositoryService; | ||
42 | + | ||
43 | + @RequestMapping(value = "/file/upload.do") | ||
44 | + public Message<?> fileUpload(@RequestPart("file") MultipartFile file, | ||
45 | + @RequestHeader(Constants.HEADER_AUTHORIZATION) String authorization) throws IOException { | ||
46 | + DfsAccessToken accessToken = accessAuthorization(authorization); | ||
47 | + | ||
48 | + Optional<MediaType> optional = MediaTypeFactory.getMediaType(file.getOriginalFilename()); | ||
49 | + MimeType mimeType = optional.orElse(MediaType.APPLICATION_OCTET_STREAM); | ||
50 | + FileMetadata metadata = new FileMetadata(mimeType.toString()); | ||
51 | + | ||
52 | + String fileName = ObjectUtils.isNotEmpty(file.getOriginalFilename()) ? file.getOriginalFilename() : "unknown"; | ||
53 | + DfsFile fileObject = new DfsFile(fileName, file.getInputStream(), metadata); | ||
54 | + String fileId = fileRepositoryService.uploadFile(accessToken, fileObject); | ||
55 | + return Message.success(fileId); | ||
56 | + } | ||
57 | + | ||
58 | + @RequestMapping(value = "/files/upload.do") | ||
59 | + public Message<?> fileUploads(@RequestPart(value = "files") MultipartFile[] files, | ||
60 | + @RequestHeader(Constants.HEADER_AUTHORIZATION) String authorization) throws IOException { | ||
61 | + DfsAccessToken accessToken = accessAuthorization(authorization); | ||
62 | + | ||
63 | + List<String> fileIds = new ArrayList<>(); | ||
64 | + for (MultipartFile file : files) { | ||
65 | + Optional<MediaType> optional = MediaTypeFactory.getMediaType(file.getOriginalFilename()); | ||
66 | + MimeType mimeType = optional.orElse(MediaType.APPLICATION_OCTET_STREAM); | ||
67 | + FileMetadata metadata = new FileMetadata(mimeType.toString()); | ||
68 | + | ||
69 | + DfsFile fileObject = new DfsFile(file.getOriginalFilename(), file.getInputStream(), metadata); | ||
70 | + String fileId = fileRepositoryService.uploadFile(accessToken, fileObject); | ||
71 | + fileIds.add(fileId); | ||
72 | + } | ||
73 | + | ||
74 | + return Message.success(fileIds); | ||
75 | + } | ||
76 | + | ||
77 | + @RequestMapping(value = "/file/uploadByBase64.do") | ||
78 | + public Message<?> uploadByBase64(@RequestParam("file") String file, @RequestParam(value = "name") String name, | ||
79 | + @RequestHeader(Constants.HEADER_AUTHORIZATION) String authorization) { | ||
80 | + DfsAccessToken accessToken = accessAuthorization(authorization); | ||
81 | + | ||
82 | + Optional<MediaType> optional = MediaTypeFactory.getMediaType(name); | ||
83 | + MimeType mimeType = optional.orElse(MediaType.APPLICATION_OCTET_STREAM); | ||
84 | + FileMetadata metadata = new FileMetadata(mimeType.toString()); | ||
85 | + | ||
86 | + ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(file)); | ||
87 | + DfsFile fileObject = new DfsFile(name, inputStream, metadata); | ||
88 | + String fileId = fileRepositoryService.uploadFile(accessToken, fileObject); | ||
89 | + return Message.success(fileId); | ||
90 | + } | ||
91 | + | ||
92 | + @RequestMapping(value = "/file/preview.do") | ||
93 | + public void preview(@RequestParam("fileId") String fileId, @RequestParam(name = "style", required = false) String style, | ||
94 | + @RequestHeader(Constants.HEADER_AUTHORIZATION) String authorization, HttpServletResponse response) throws IOException { | ||
95 | + // style参数为oss图片处理设置,比如:image/resize,m_fixed,h_300,w_300 | ||
96 | + DfsAccessToken accessToken = accessAuthorization(authorization); | ||
97 | + DfsFile file = fileRepositoryService.downloadFile(accessToken, fileId, style); | ||
98 | + InputStream fileStream = file.getStream(); | ||
99 | + response.setContentType(file.getMetadata().getMimeType()); | ||
100 | + // oss sdk存在bug, fileStream.available()和真实字节数存在差异 | ||
101 | + // response.setContentLength(fileStream.available()); | ||
102 | + try { | ||
103 | + IOUtils.copy(fileStream, response.getOutputStream()); | ||
104 | + } finally { | ||
105 | + IOUtils.closeQuietly(fileStream); | ||
106 | + } | ||
107 | + response.flushBuffer(); | ||
108 | + } | ||
109 | + | ||
110 | + @RequestMapping(value = "/file/download.do") | ||
111 | + public void download(@RequestParam("fileId") String fileId, @RequestHeader(Constants.HEADER_AUTHORIZATION) String authorization, | ||
112 | + HttpServletResponse response) throws IOException { | ||
113 | + DfsAccessToken accessToken = accessAuthorization(authorization); | ||
114 | + DfsFile file = fileRepositoryService.downloadFile(accessToken, fileId, null); | ||
115 | + InputStream fileStream = file.getStream(); | ||
116 | + response.setContentType(file.getMetadata().getMimeType()); | ||
117 | + // oss sdk存在bug, fileStream.available()和真实字节数存在差异 | ||
118 | + // response.setContentLength(fileStream.available()); | ||
119 | + System.out.println(file.getName()); | ||
120 | + String fileName = URLEncoder.encode(file.getName(), StandardCharsets.UTF_8); | ||
121 | + System.out.println(URLDecoder.decode(fileName, StandardCharsets.UTF_8)); | ||
122 | + response.addHeader("Content-Disposition", "attachment; filename*=UTF-8''" + fileName); | ||
123 | + try { | ||
124 | + IOUtils.copy(fileStream, response.getOutputStream()); | ||
125 | + } finally { | ||
126 | + IOUtils.closeQuietly(fileStream); | ||
127 | + } | ||
128 | + response.flushBuffer(); | ||
129 | + } | ||
130 | + | ||
131 | + @RequestMapping(value = "/file/delete.do") | ||
132 | + public Message<?> deleteFile(@RequestParam("fileId") String fileId, @RequestHeader(Constants.HEADER_AUTHORIZATION) String authorization) { | ||
133 | + DfsAccessToken accessToken = accessAuthorization(authorization); | ||
134 | + fileRepositoryService.deleteFile(accessToken, fileId); | ||
135 | + return Message.success(); | ||
136 | + } | ||
137 | + | ||
138 | + private DfsAccessToken accessAuthorization(String authorization) { | ||
139 | + if (authorization == null) { | ||
140 | + throw new DfsServiceException(ErrorCode.UNAUTHORIZED_ACCESS_ERROR, ErrorCode.MESSAGE_ACCESS_DENIED); | ||
141 | + } | ||
142 | + return DfsAccessToken.of(authorization, dfsProperties.getPublicKey()); | ||
143 | + } | ||
144 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/controller/FileRepositoryController.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/controller/FileRepositoryController.java | ||
1 | +package com.diligrp.assistant.dfs.controller; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.Constants; | ||
4 | +import com.diligrp.assistant.dfs.DfsProperties; | ||
5 | +import com.diligrp.assistant.dfs.domain.DfsAccessToken; | ||
6 | +import com.diligrp.assistant.dfs.domain.FileRepositoryDTO; | ||
7 | +import com.diligrp.assistant.dfs.exception.DfsServiceException; | ||
8 | +import com.diligrp.assistant.dfs.model.FileRepository; | ||
9 | +import com.diligrp.assistant.dfs.service.FileRepositoryService; | ||
10 | +import com.diligrp.assistant.shared.ErrorCode; | ||
11 | +import com.diligrp.assistant.shared.domain.Message; | ||
12 | +import com.diligrp.assistant.shared.util.AssertUtils; | ||
13 | +import com.diligrp.assistant.shared.util.RandomUtils; | ||
14 | +import jakarta.annotation.Resource; | ||
15 | +import org.springframework.web.bind.annotation.RequestBody; | ||
16 | +import org.springframework.web.bind.annotation.RequestHeader; | ||
17 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
18 | +import org.springframework.web.bind.annotation.RestController; | ||
19 | + | ||
20 | +@RestController | ||
21 | +@RequestMapping(value = "/dfs") | ||
22 | +public class FileRepositoryController { | ||
23 | + | ||
24 | + @Resource | ||
25 | + private DfsProperties dfsProperties; | ||
26 | + | ||
27 | + @Resource | ||
28 | + private FileRepositoryService fileRepositoryService; | ||
29 | + | ||
30 | + @RequestMapping(value = "/repository/create.do") | ||
31 | + public Message<?> create(@RequestBody FileRepositoryDTO request) { | ||
32 | + AssertUtils.notEmpty(request.getName(), "name missed"); | ||
33 | + AssertUtils.notNull(request.getPipeline(), "pipeline missed"); | ||
34 | + | ||
35 | + DfsAccessToken accessToken = new DfsAccessToken(request.getPipeline(), RandomUtils.randomUUID(false)); | ||
36 | + FileRepository repository = FileRepository.builder().repositoryId(accessToken.getRepositoryId()) | ||
37 | + .name(request.getName()).pipeline(request.getPipeline()).description(request.getDescription()).build(); | ||
38 | + fileRepositoryService.createFileRepository(accessToken, repository); | ||
39 | + return Message.success(accessToken.toString(dfsProperties.getPrivateKey())); | ||
40 | + } | ||
41 | + | ||
42 | + @RequestMapping(value = "/repository/delete.do") | ||
43 | + public Message<?> deleteRepository(@RequestHeader(Constants.HEADER_AUTHORIZATION) String authorization) { | ||
44 | + DfsAccessToken accessToken = accessAuthorization(authorization); | ||
45 | + fileRepositoryService.deleteFileRepository(accessToken); | ||
46 | + return Message.success(); | ||
47 | + } | ||
48 | + | ||
49 | + private DfsAccessToken accessAuthorization(String authorization) { | ||
50 | + if (authorization == null) { | ||
51 | + throw new DfsServiceException(ErrorCode.UNAUTHORIZED_ACCESS_ERROR, ErrorCode.MESSAGE_ACCESS_DENIED); | ||
52 | + } | ||
53 | + return DfsAccessToken.of(authorization, dfsProperties.getPublicKey()); | ||
54 | + } | ||
55 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/dao/FileObjectDao.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/dao/FileObjectDao.java | ||
1 | +package com.diligrp.assistant.dfs.dao; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.model.FileObject; | ||
4 | +import com.diligrp.assistant.shared.mybatis.MybatisMapperSupport; | ||
5 | +import org.apache.ibatis.annotations.Param; | ||
6 | +import org.springframework.stereotype.Repository; | ||
7 | + | ||
8 | +import java.time.LocalDateTime; | ||
9 | + | ||
10 | +@Repository("fileObjectDao") | ||
11 | +public interface FileObjectDao extends MybatisMapperSupport { | ||
12 | + void insertFileObject(FileObject file); | ||
13 | + | ||
14 | + int hitFileObject(@Param("fileId") String fileId, @Param("modifiedTime") LocalDateTime modifiedTime); | ||
15 | + | ||
16 | + int deleteFileObject(String fileId); | ||
17 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/dao/FileRepositoryDao.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/dao/FileRepositoryDao.java | ||
1 | +package com.diligrp.assistant.dfs.dao; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.model.FileRepository; | ||
4 | +import com.diligrp.assistant.shared.mybatis.MybatisMapperSupport; | ||
5 | +import org.springframework.stereotype.Repository; | ||
6 | + | ||
7 | +import java.util.Optional; | ||
8 | + | ||
9 | +@Repository("fileRepositoryDao") | ||
10 | +public interface FileRepositoryDao extends MybatisMapperSupport { | ||
11 | + void insertFileRepository(FileRepository repository); | ||
12 | + | ||
13 | + Optional<FileRepository> findFileRepositoryById(String repositoryId); | ||
14 | + | ||
15 | + int deleteFileRepository(String repositoryId); | ||
16 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/domain/DfsAccessToken.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/domain/DfsAccessToken.java | ||
1 | +package com.diligrp.assistant.dfs.domain; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.exception.DfsServiceException; | ||
4 | +import com.diligrp.assistant.shared.Constants; | ||
5 | +import com.diligrp.assistant.shared.ErrorCode; | ||
6 | +import com.diligrp.assistant.shared.codec.StringCodec; | ||
7 | + | ||
8 | +import java.io.Serializable; | ||
9 | +import java.nio.ByteBuffer; | ||
10 | +import java.security.PrivateKey; | ||
11 | +import java.security.PublicKey; | ||
12 | +import java.security.SecureRandom; | ||
13 | +import java.security.Signature; | ||
14 | +import java.util.Base64; | ||
15 | +import java.util.StringTokenizer; | ||
16 | + | ||
17 | +public class DfsAccessToken implements Serializable { | ||
18 | + // 文件存储通道 | ||
19 | + private int pipeline; | ||
20 | + // 文件仓库ID | ||
21 | + private String repositoryId; | ||
22 | + | ||
23 | + public DfsAccessToken(int pipeline, String repositoryId) { | ||
24 | + this.repositoryId = repositoryId; | ||
25 | + this.pipeline = pipeline; | ||
26 | + } | ||
27 | + | ||
28 | + public int getPipeline() { | ||
29 | + return pipeline; | ||
30 | + } | ||
31 | + | ||
32 | + public String getRepositoryId() { | ||
33 | + return repositoryId; | ||
34 | + } | ||
35 | + | ||
36 | + public String toString(PrivateKey privateKey) { | ||
37 | + try { | ||
38 | + byte[] bytes = StringCodec.getEncoder().encode(repositoryId); | ||
39 | + ByteBuffer packet = ByteBuffer.allocate(bytes.length + Integer.BYTES); | ||
40 | + packet.putInt(pipeline); | ||
41 | + packet.put(bytes); | ||
42 | + | ||
43 | + Signature signature = Signature.getInstance(Constants.SIGN_ALGORITHM); | ||
44 | + signature.initSign(privateKey, new SecureRandom()); | ||
45 | + signature.update(packet.array()); | ||
46 | + byte[] sign = signature.sign(); | ||
47 | + return String.format("%s.%s", Base64.getEncoder().encodeToString(packet.array()), Base64.getEncoder().encodeToString(sign)); | ||
48 | + } catch (Exception ex) { | ||
49 | + throw new DfsServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "accessToken sign failed"); | ||
50 | + } | ||
51 | + } | ||
52 | + | ||
53 | + public static DfsAccessToken of(String authorization, PublicKey publicKey) { | ||
54 | + StringTokenizer tokenizer = new StringTokenizer(authorization, "."); | ||
55 | + if (tokenizer.countTokens() != 2) { | ||
56 | + throw new DfsServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "Invalid accessToken format"); | ||
57 | + } | ||
58 | + byte[] data = Base64.getDecoder().decode(tokenizer.nextToken()); | ||
59 | + byte[] sign = Base64.getDecoder().decode(tokenizer.nextToken()); | ||
60 | + | ||
61 | + try { | ||
62 | + Signature signature = Signature.getInstance(Constants.SIGN_ALGORITHM); | ||
63 | + signature.initVerify(publicKey); | ||
64 | + signature.update(data); | ||
65 | + boolean result = signature.verify(sign); | ||
66 | + if (!result) { | ||
67 | + throw new DfsServiceException(ErrorCode.UNAUTHORIZED_ACCESS_ERROR, ErrorCode.MESSAGE_ACCESS_DENIED); | ||
68 | + } | ||
69 | + | ||
70 | + ByteBuffer packet = ByteBuffer.wrap(data); | ||
71 | + int pipeline = packet.getInt(); | ||
72 | + byte[] bytes = new byte[packet.remaining()]; | ||
73 | + for (int i = 0; packet.hasRemaining(); i++) { | ||
74 | + bytes[i] = packet.get(); | ||
75 | + } | ||
76 | + String repositoryId = StringCodec.getDecoder().decode(bytes); | ||
77 | + return new DfsAccessToken(pipeline, repositoryId); | ||
78 | + } catch (Exception ex) { | ||
79 | + throw new DfsServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "Invalid accessToken data"); | ||
80 | + } | ||
81 | + } | ||
82 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/domain/DfsFile.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/domain/DfsFile.java | ||
1 | +package com.diligrp.assistant.dfs.domain; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.util.RandomUtils; | ||
4 | + | ||
5 | +import java.io.InputStream; | ||
6 | + | ||
7 | +public class DfsFile { | ||
8 | + // 文件唯一标识 | ||
9 | + private String id; | ||
10 | + // 文件名称 | ||
11 | + private String name; | ||
12 | + // 文件流 | ||
13 | + private InputStream stream; | ||
14 | + // option参数 | ||
15 | + private FileMetadata metadata; | ||
16 | + | ||
17 | + public DfsFile(String name, InputStream stream, FileMetadata metadata) { | ||
18 | + this(RandomUtils.randomUUID(false), name, stream, metadata); | ||
19 | + } | ||
20 | + | ||
21 | + public DfsFile(String id, String name, InputStream stream, FileMetadata metadata) { | ||
22 | + this.id = id; | ||
23 | + this.name = name; | ||
24 | + this.stream = stream; | ||
25 | + this.metadata = metadata; | ||
26 | + } | ||
27 | + | ||
28 | + public String getId() { | ||
29 | + return id; | ||
30 | + } | ||
31 | + | ||
32 | + public String getName() { | ||
33 | + return name; | ||
34 | + } | ||
35 | + | ||
36 | + public InputStream getStream() { | ||
37 | + return stream; | ||
38 | + } | ||
39 | + | ||
40 | + public FileMetadata getMetadata() { | ||
41 | + return metadata; | ||
42 | + } | ||
43 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/domain/FileMetadata.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/domain/FileMetadata.java | ||
1 | +package com.diligrp.assistant.dfs.domain; | ||
2 | + | ||
3 | +public class FileMetadata { | ||
4 | + // MimeType or MediaType | ||
5 | + private String mimeType; | ||
6 | + | ||
7 | + public FileMetadata(String mimeType) { | ||
8 | + this.mimeType = mimeType; | ||
9 | + } | ||
10 | + | ||
11 | + public String getMimeType() { | ||
12 | + return mimeType; | ||
13 | + } | ||
14 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/domain/FileRepositoryDTO.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/domain/FileRepositoryDTO.java | ||
1 | +package com.diligrp.assistant.dfs.domain; | ||
2 | + | ||
3 | +public class FileRepositoryDTO { | ||
4 | + // 名称 | ||
5 | + private String name; | ||
6 | + // 文件存储通道 | ||
7 | + private Integer pipeline; | ||
8 | + // 描述 | ||
9 | + private String description; | ||
10 | + | ||
11 | + public String getName() { | ||
12 | + return name; | ||
13 | + } | ||
14 | + | ||
15 | + public void setName(String name) { | ||
16 | + this.name = name; | ||
17 | + } | ||
18 | + | ||
19 | + public Integer getPipeline() { | ||
20 | + return pipeline; | ||
21 | + } | ||
22 | + | ||
23 | + public void setPipeline(Integer pipeline) { | ||
24 | + this.pipeline = pipeline; | ||
25 | + } | ||
26 | + | ||
27 | + public String getDescription() { | ||
28 | + return description; | ||
29 | + } | ||
30 | + | ||
31 | + public void setDescription(String description) { | ||
32 | + this.description = description; | ||
33 | + } | ||
34 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/exception/DfsServiceException.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/exception/DfsServiceException.java | ||
1 | +package com.diligrp.assistant.dfs.exception; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.exception.PlatformServiceException; | ||
4 | + | ||
5 | +public class DfsServiceException extends PlatformServiceException { | ||
6 | + public DfsServiceException(String message) { | ||
7 | + super(message); | ||
8 | + } | ||
9 | + | ||
10 | + public DfsServiceException(int code, String message) { | ||
11 | + super(code, message); | ||
12 | + } | ||
13 | + | ||
14 | + public DfsServiceException(String message, Throwable ex) { | ||
15 | + super(message, ex); | ||
16 | + } | ||
17 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/model/FileObject.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/model/FileObject.java | ||
1 | +package com.diligrp.assistant.dfs.model; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.domain.BaseDo; | ||
4 | + | ||
5 | +import java.time.LocalDateTime; | ||
6 | + | ||
7 | +public class FileObject extends BaseDo { | ||
8 | + // 仓库ID | ||
9 | + private String repositoryId; | ||
10 | + // 服务通道 | ||
11 | + private Integer pipeline; | ||
12 | + // 文件ID | ||
13 | + private String fileId; | ||
14 | + // 文件名称 | ||
15 | + private String fileName; | ||
16 | + // MIME类型 | ||
17 | + private String mimeType; | ||
18 | + // 访问次数 | ||
19 | + private Integer hits; | ||
20 | + // 文件状态 | ||
21 | + private Integer state; | ||
22 | + | ||
23 | + public String getRepositoryId() { | ||
24 | + return repositoryId; | ||
25 | + } | ||
26 | + | ||
27 | + public void setRepositoryId(String repositoryId) { | ||
28 | + this.repositoryId = repositoryId; | ||
29 | + } | ||
30 | + | ||
31 | + public Integer getPipeline() { | ||
32 | + return pipeline; | ||
33 | + } | ||
34 | + | ||
35 | + public void setPipeline(Integer pipeline) { | ||
36 | + this.pipeline = pipeline; | ||
37 | + } | ||
38 | + | ||
39 | + public String getFileId() { | ||
40 | + return fileId; | ||
41 | + } | ||
42 | + | ||
43 | + public void setFileId(String fileId) { | ||
44 | + this.fileId = fileId; | ||
45 | + } | ||
46 | + | ||
47 | + public String getFileName() { | ||
48 | + return fileName; | ||
49 | + } | ||
50 | + | ||
51 | + public void setFileName(String fileName) { | ||
52 | + this.fileName = fileName; | ||
53 | + } | ||
54 | + | ||
55 | + public String getMimeType() { | ||
56 | + return mimeType; | ||
57 | + } | ||
58 | + | ||
59 | + public void setMimeType(String mimeType) { | ||
60 | + this.mimeType = mimeType; | ||
61 | + } | ||
62 | + | ||
63 | + public Integer getHits() { | ||
64 | + return hits; | ||
65 | + } | ||
66 | + | ||
67 | + public void setHits(Integer hits) { | ||
68 | + this.hits = hits; | ||
69 | + } | ||
70 | + | ||
71 | + public Integer getState() { | ||
72 | + return state; | ||
73 | + } | ||
74 | + | ||
75 | + public void setState(Integer state) { | ||
76 | + this.state = state; | ||
77 | + } | ||
78 | + | ||
79 | + public static Builder builder() { | ||
80 | + return new FileObject().new Builder(); | ||
81 | + } | ||
82 | + | ||
83 | + public class Builder { | ||
84 | + public Builder repositoryId(String repositoryId) { | ||
85 | + FileObject.this.repositoryId = repositoryId; | ||
86 | + return this; | ||
87 | + } | ||
88 | + | ||
89 | + public Builder pipeline(int pipeline) { | ||
90 | + FileObject.this.pipeline = pipeline; | ||
91 | + return this; | ||
92 | + } | ||
93 | + | ||
94 | + public Builder fileId(String fileId) { | ||
95 | + FileObject.this.fileId = fileId; | ||
96 | + return this; | ||
97 | + } | ||
98 | + | ||
99 | + public Builder fileName(String fileName) { | ||
100 | + FileObject.this.fileName = fileName; | ||
101 | + return this; | ||
102 | + } | ||
103 | + | ||
104 | + public Builder mimeType(String mimeType) { | ||
105 | + FileObject.this.mimeType = mimeType; | ||
106 | + return this; | ||
107 | + } | ||
108 | + | ||
109 | + public Builder hits(int hits) { | ||
110 | + FileObject.this.hits = hits; | ||
111 | + return this; | ||
112 | + } | ||
113 | + | ||
114 | + public Builder state(int state) { | ||
115 | + FileObject.this.state = state; | ||
116 | + return this; | ||
117 | + } | ||
118 | + | ||
119 | + public Builder createdTime(LocalDateTime createdTime) { | ||
120 | + FileObject.this.createdTime = createdTime; | ||
121 | + return this; | ||
122 | + } | ||
123 | + | ||
124 | + public Builder modifiedTime(LocalDateTime modifiedTime) { | ||
125 | + FileObject.this.modifiedTime = modifiedTime; | ||
126 | + return this; | ||
127 | + } | ||
128 | + | ||
129 | + public FileObject build() { | ||
130 | + return FileObject.this; | ||
131 | + } | ||
132 | + } | ||
133 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/model/FileRepository.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/model/FileRepository.java | ||
1 | +package com.diligrp.assistant.dfs.model; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.domain.BaseDo; | ||
4 | + | ||
5 | +import java.time.LocalDateTime; | ||
6 | + | ||
7 | +public class FileRepository extends BaseDo { | ||
8 | + // 文件仓库 | ||
9 | + private String repositoryId; | ||
10 | + // 名称 | ||
11 | + private String name; | ||
12 | + // 服务通道 | ||
13 | + private Integer pipeline; | ||
14 | + // 描述 | ||
15 | + private String description; | ||
16 | + | ||
17 | + public String getRepositoryId() { | ||
18 | + return repositoryId; | ||
19 | + } | ||
20 | + | ||
21 | + public void setRepositoryId(String repositoryId) { | ||
22 | + this.repositoryId = repositoryId; | ||
23 | + } | ||
24 | + | ||
25 | + public Integer getPipeline() { | ||
26 | + return pipeline; | ||
27 | + } | ||
28 | + | ||
29 | + public void setPipeline(Integer pipeline) { | ||
30 | + this.pipeline = pipeline; | ||
31 | + } | ||
32 | + | ||
33 | + public String getName() { | ||
34 | + return name; | ||
35 | + } | ||
36 | + | ||
37 | + public void setName(String name) { | ||
38 | + this.name = name; | ||
39 | + } | ||
40 | + | ||
41 | + public String getDescription() { | ||
42 | + return description; | ||
43 | + } | ||
44 | + | ||
45 | + public void setDescription(String description) { | ||
46 | + this.description = description; | ||
47 | + } | ||
48 | + | ||
49 | + public static Builder builder() { | ||
50 | + return new FileRepository().new Builder(); | ||
51 | + } | ||
52 | + | ||
53 | + public class Builder { | ||
54 | + public Builder repositoryId(String repositoryId) { | ||
55 | + FileRepository.this.repositoryId = repositoryId; | ||
56 | + return this; | ||
57 | + } | ||
58 | + | ||
59 | + public Builder name(String name) { | ||
60 | + FileRepository.this.name = name; | ||
61 | + return this; | ||
62 | + } | ||
63 | + | ||
64 | + public Builder pipeline(int pipeline) { | ||
65 | + FileRepository.this.pipeline = pipeline; | ||
66 | + return this; | ||
67 | + } | ||
68 | + | ||
69 | + public Builder description(String description) { | ||
70 | + FileRepository.this.description = description; | ||
71 | + return this; | ||
72 | + } | ||
73 | + | ||
74 | + public Builder createdTime(LocalDateTime createdTime) { | ||
75 | + FileRepository.this.createdTime = createdTime; | ||
76 | + return this; | ||
77 | + } | ||
78 | + | ||
79 | + public FileRepository build() { | ||
80 | + return FileRepository.this; | ||
81 | + } | ||
82 | + } | ||
83 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/pipeline/DefaultDfsPipelineManager.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/pipeline/DefaultDfsPipelineManager.java | ||
1 | +package com.diligrp.assistant.dfs.pipeline; | ||
2 | + | ||
3 | +import org.springframework.beans.factory.DisposableBean; | ||
4 | + | ||
5 | +import java.util.ArrayList; | ||
6 | +import java.util.List; | ||
7 | + | ||
8 | +public class DefaultDfsPipelineManager implements DfsPipelineManager, DisposableBean { | ||
9 | + private List<DfsPipeline> pipelines; | ||
10 | + | ||
11 | + public DefaultDfsPipelineManager() { | ||
12 | + this.pipelines = new ArrayList<>(); | ||
13 | + } | ||
14 | + | ||
15 | + @Override | ||
16 | + public void registerPipeline(DfsPipeline pipeline) { | ||
17 | + this.pipelines.add(pipeline); | ||
18 | + } | ||
19 | + | ||
20 | + @Override | ||
21 | + public List<DfsPipeline> pipelines() { | ||
22 | + return this.pipelines; | ||
23 | + } | ||
24 | + | ||
25 | + @Override | ||
26 | + public void destroy() { | ||
27 | + for (DfsPipeline pipeline : pipelines) { | ||
28 | + pipeline.destroy(); | ||
29 | + } | ||
30 | + } | ||
31 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/pipeline/DfsPipeline.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/pipeline/DfsPipeline.java | ||
1 | +package com.diligrp.assistant.dfs.pipeline; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.domain.DfsFile; | ||
4 | +import com.diligrp.assistant.dfs.exception.DfsServiceException; | ||
5 | +import com.diligrp.assistant.dfs.type.PipelineType; | ||
6 | +import com.diligrp.assistant.shared.ErrorCode; | ||
7 | + | ||
8 | +public abstract class DfsPipeline { | ||
9 | + // 通道编码 | ||
10 | + protected int code; | ||
11 | + // 通道名称 | ||
12 | + protected String name; | ||
13 | + // 通道类型 | ||
14 | + protected PipelineType type; | ||
15 | + | ||
16 | + public DfsPipeline(int code, String name, PipelineType type) { | ||
17 | + this.code = code; | ||
18 | + this.name = name; | ||
19 | + this.type = type; | ||
20 | + } | ||
21 | + | ||
22 | + /** | ||
23 | + * 创建文件仓库,并返回仓库唯一标识:名称 | ||
24 | + * | ||
25 | + * @param repositoryId - 仓库ID | ||
26 | + * @return 仓库名称,同仓库ID | ||
27 | + */ | ||
28 | + public String createFileRepository(String repositoryId) { | ||
29 | + throw new DfsServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "文件存储服务通道不支持此操作"); | ||
30 | + } | ||
31 | + | ||
32 | + /** | ||
33 | + * 删除文件仓库 - 空仓库才允许删除 | ||
34 | + * | ||
35 | + * @param repositoryId - 仓库ID | ||
36 | + * @return true/false | ||
37 | + */ | ||
38 | + public boolean deleteFileRepository(String repositoryId) { | ||
39 | + throw new DfsServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "文件存储服务通道不支持此操作"); | ||
40 | + } | ||
41 | + | ||
42 | + /** | ||
43 | + * 存放文件到仓库 | ||
44 | + * | ||
45 | + * @param repositoryId - 仓库ID | ||
46 | + * @param file - 文件 | ||
47 | + */ | ||
48 | + public abstract void putFile(String repositoryId, DfsFile file); | ||
49 | + | ||
50 | + /** | ||
51 | + * 从文件仓库中获取文件 | ||
52 | + * | ||
53 | + * @param repositoryId - 仓库ID | ||
54 | + * @param fileId - 文件标识 | ||
55 | + * @param style- OSS图片处理参数, 参见https://help.aliyun.com/zh/oss/user-guide/adjust-image-quality?spm=a2c4g.11186623.0.0.1c2d2759lemWct | ||
56 | + * @return - 文件 | ||
57 | + */ | ||
58 | + public abstract DfsFile getFile(String repositoryId, String fileId, String style); | ||
59 | + | ||
60 | + /** | ||
61 | + * 从文件仓库中删除文件 | ||
62 | + * | ||
63 | + * @param repositoryId - 仓库ID | ||
64 | + * @param fileId - 文件标识 | ||
65 | + * @return - true/false | ||
66 | + */ | ||
67 | + public abstract boolean deleteFile(String repositoryId, String fileId); | ||
68 | + | ||
69 | + public void destroy() { | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * 获取通道code | ||
74 | + */ | ||
75 | + public int getCode() { | ||
76 | + return this.code; | ||
77 | + } | ||
78 | + | ||
79 | + /** | ||
80 | + * 获取通道编码 | ||
81 | + */ | ||
82 | + public String getName() { | ||
83 | + return this.name; | ||
84 | + } | ||
85 | + | ||
86 | + /** | ||
87 | + * 获取通道类型 | ||
88 | + */ | ||
89 | + public PipelineType getType() { | ||
90 | + return this.type; | ||
91 | + } | ||
92 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/pipeline/DfsPipelineManager.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/pipeline/DfsPipelineManager.java | ||
1 | +package com.diligrp.assistant.dfs.pipeline; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.exception.DfsServiceException; | ||
4 | +import com.diligrp.assistant.shared.ErrorCode; | ||
5 | + | ||
6 | +import java.util.List; | ||
7 | +import java.util.Optional; | ||
8 | + | ||
9 | +public interface DfsPipelineManager { | ||
10 | + | ||
11 | + void registerPipeline(DfsPipeline pipeline); | ||
12 | + | ||
13 | + List<DfsPipeline> pipelines(); | ||
14 | + | ||
15 | + default DfsPipeline findPipelineByCode(int code) { | ||
16 | + Optional<DfsPipeline> pipeline = pipelines().stream().filter(p -> p.code == code).findAny(); | ||
17 | + return pipeline.orElseThrow(() -> new DfsServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "系统未配置此文件存储服务通道")); | ||
18 | + } | ||
19 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/pipeline/OssPipeline.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/pipeline/OssPipeline.java | ||
1 | +package com.diligrp.assistant.dfs.pipeline; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.client.FileRepositoryClient; | ||
4 | +import com.diligrp.assistant.dfs.client.OssFileRepositoryClient; | ||
5 | +import com.diligrp.assistant.dfs.domain.DfsFile; | ||
6 | +import com.diligrp.assistant.dfs.type.PipelineType; | ||
7 | + | ||
8 | +/** | ||
9 | + * 阿里OSS文件存储服务通道 | ||
10 | + */ | ||
11 | +// TODO: 数据库中进行通道配置 | ||
12 | +public class OssPipeline extends DfsPipeline { | ||
13 | + | ||
14 | + private FileRepositoryClient fileRepositoryClient; | ||
15 | + | ||
16 | + public OssPipeline(int code, String name, String uri, String accessKeyId, String accessKeySecret) { | ||
17 | + super(code, name, PipelineType.DFS_OSS); | ||
18 | + this.fileRepositoryClient = new OssFileRepositoryClient(uri, accessKeyId, accessKeySecret); | ||
19 | + } | ||
20 | + | ||
21 | + @Override | ||
22 | + public String createFileRepository(String repositoryId) { | ||
23 | + return fileRepositoryClient.createFileRepository(repositoryId); | ||
24 | + } | ||
25 | + | ||
26 | + @Override | ||
27 | + public boolean deleteFileRepository(String repositoryId) { | ||
28 | + return fileRepositoryClient.deleteFileRepository(repositoryId); | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public void putFile(String repositoryId, DfsFile file) { | ||
33 | + fileRepositoryClient.putFile(repositoryId, file); | ||
34 | + } | ||
35 | + | ||
36 | + @Override | ||
37 | + public DfsFile getFile(String repositoryId, String fileId, String style) { | ||
38 | + return fileRepositoryClient.getFile(repositoryId, fileId, style); | ||
39 | + } | ||
40 | + | ||
41 | + @Override | ||
42 | + public boolean deleteFile(String repositoryId, String fileId) { | ||
43 | + return fileRepositoryClient.deleteFile(repositoryId, fileId); | ||
44 | + } | ||
45 | + | ||
46 | + public void destroy() { | ||
47 | + fileRepositoryClient.destroy(); | ||
48 | + } | ||
49 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/service/FileRepositoryService.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/service/FileRepositoryService.java | ||
1 | +package com.diligrp.assistant.dfs.service; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.domain.DfsAccessToken; | ||
4 | +import com.diligrp.assistant.dfs.domain.DfsFile; | ||
5 | +import com.diligrp.assistant.dfs.model.FileRepository; | ||
6 | + | ||
7 | +public interface FileRepositoryService { | ||
8 | + String createFileRepository(DfsAccessToken accessToken, FileRepository repository); | ||
9 | + | ||
10 | + void deleteFileRepository(DfsAccessToken accessToken); | ||
11 | + | ||
12 | + String uploadFile(DfsAccessToken accessToken, DfsFile file); | ||
13 | + | ||
14 | + DfsFile downloadFile(DfsAccessToken accessToken, String fileId, String style); | ||
15 | + | ||
16 | + void deleteFile(DfsAccessToken accessToken, String fileId); | ||
17 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/service/impl/FileRepositoryServiceImpl.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/service/impl/FileRepositoryServiceImpl.java | ||
1 | +package com.diligrp.assistant.dfs.service.impl; | ||
2 | + | ||
3 | +import com.diligrp.assistant.dfs.dao.FileObjectDao; | ||
4 | +import com.diligrp.assistant.dfs.dao.FileRepositoryDao; | ||
5 | +import com.diligrp.assistant.dfs.domain.DfsAccessToken; | ||
6 | +import com.diligrp.assistant.dfs.domain.DfsFile; | ||
7 | +import com.diligrp.assistant.dfs.model.FileObject; | ||
8 | +import com.diligrp.assistant.dfs.model.FileRepository; | ||
9 | +import com.diligrp.assistant.dfs.pipeline.DfsPipeline; | ||
10 | +import com.diligrp.assistant.dfs.pipeline.DfsPipelineManager; | ||
11 | +import com.diligrp.assistant.dfs.service.FileRepositoryService; | ||
12 | +import com.diligrp.assistant.shared.service.ThreadPollService; | ||
13 | +import jakarta.annotation.Resource; | ||
14 | +import org.springframework.stereotype.Service; | ||
15 | +import org.springframework.transaction.annotation.Transactional; | ||
16 | + | ||
17 | +import java.time.LocalDateTime; | ||
18 | + | ||
19 | +@Service("fileRepositoryService") | ||
20 | +public class FileRepositoryServiceImpl implements FileRepositoryService { | ||
21 | + | ||
22 | + @Resource | ||
23 | + private FileRepositoryDao fileRepositoryDao; | ||
24 | + | ||
25 | + @Resource | ||
26 | + private FileObjectDao fileObjectDao; | ||
27 | + | ||
28 | + @Resource | ||
29 | + private DfsPipelineManager dfsPipelineManager; | ||
30 | + | ||
31 | + /** | ||
32 | + * 创建文件仓库,调用三方文件服务(如阿里OSS)创建Bucket存储 | ||
33 | + */ | ||
34 | + @Override | ||
35 | + @Transactional(rollbackFor = Exception.class) | ||
36 | + public String createFileRepository(DfsAccessToken accessToken, FileRepository repository) { | ||
37 | + DfsPipeline pipeline = dfsPipelineManager.findPipelineByCode(accessToken.getPipeline()); | ||
38 | + fileRepositoryDao.insertFileRepository(repository); | ||
39 | + | ||
40 | + return pipeline.createFileRepository(repository.getRepositoryId()); | ||
41 | + } | ||
42 | + | ||
43 | + @Override | ||
44 | + @Transactional(rollbackFor = Exception.class) | ||
45 | + public void deleteFileRepository(DfsAccessToken accessToken) { | ||
46 | + String repositoryId = accessToken.getRepositoryId(); | ||
47 | + DfsPipeline pipeline = dfsPipelineManager.findPipelineByCode(accessToken.getPipeline()); | ||
48 | + if (pipeline.deleteFileRepository(repositoryId)) { | ||
49 | + fileRepositoryDao.deleteFileRepository(repositoryId); | ||
50 | + } | ||
51 | + } | ||
52 | + | ||
53 | + @Override | ||
54 | + public String uploadFile(DfsAccessToken accessToken, DfsFile file) { | ||
55 | + DfsPipeline pipeline = dfsPipelineManager.findPipelineByCode(accessToken.getPipeline()); | ||
56 | + String repositoryId = accessToken.getRepositoryId(); | ||
57 | + pipeline.putFile(repositoryId, file); | ||
58 | + // 为提高文件上传性能,异步持久化文件对象 | ||
59 | + ThreadPollService.getInstance().submit(() -> { | ||
60 | + LocalDateTime now = LocalDateTime.now(); | ||
61 | + FileObject fileObject = FileObject.builder().repositoryId(repositoryId).pipeline(pipeline.getCode()) | ||
62 | + .fileId(file.getId()).fileName(file.getName()).mimeType(file.getMetadata().getMimeType()).hits(0) | ||
63 | + .state(0).createdTime(now).modifiedTime(now).build(); | ||
64 | + fileObjectDao.insertFileObject(fileObject); | ||
65 | + }); | ||
66 | + return file.getId(); | ||
67 | + } | ||
68 | + | ||
69 | + @Override | ||
70 | + public DfsFile downloadFile(DfsAccessToken accessToken, String fileId, String style) { | ||
71 | + DfsPipeline pipeline = dfsPipelineManager.findPipelineByCode(accessToken.getPipeline()); | ||
72 | + DfsFile file = pipeline.getFile(accessToken.getRepositoryId(), fileId, style); | ||
73 | + // 异步增加文件访问次数 | ||
74 | + ThreadPollService.getInstance().submit(() -> { | ||
75 | + fileObjectDao.hitFileObject(fileId, LocalDateTime.now()); | ||
76 | + }); | ||
77 | + return file; | ||
78 | + } | ||
79 | + | ||
80 | + @Override | ||
81 | + @Transactional(rollbackFor = Exception.class) | ||
82 | + public void deleteFile(DfsAccessToken accessToken, String fileId) { | ||
83 | + DfsPipeline pipeline = dfsPipelineManager.findPipelineByCode(accessToken.getPipeline()); | ||
84 | + if (pipeline.deleteFile(accessToken.getRepositoryId(), fileId)) { | ||
85 | + fileObjectDao.deleteFileObject(fileId); | ||
86 | + } | ||
87 | + } | ||
88 | +} |
assistant-dfs/src/main/java/com/diligrp/assistant/dfs/type/PipelineType.java
0 → 100644
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/type/PipelineType.java | ||
1 | +package com.diligrp.assistant.dfs.type; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.type.IEnumType; | ||
4 | + | ||
5 | +import java.util.Arrays; | ||
6 | +import java.util.List; | ||
7 | +import java.util.Optional; | ||
8 | +import java.util.stream.Stream; | ||
9 | + | ||
10 | +public enum PipelineType implements IEnumType { | ||
11 | + DFS_OSS("阿里云对象存储服务", 1), | ||
12 | + | ||
13 | + DFS_MINIO("MINIO对象存储服务", 2); | ||
14 | + | ||
15 | + private String name; | ||
16 | + private int code; | ||
17 | + | ||
18 | + PipelineType(String name, int code) { | ||
19 | + this.name = name; | ||
20 | + this.code = code; | ||
21 | + } | ||
22 | + | ||
23 | + public static Optional<PipelineType> getType(int code) { | ||
24 | + Stream<PipelineType> GENDERS = Arrays.stream(values()); | ||
25 | + return GENDERS.filter(type -> type.getCode() == code).findFirst(); | ||
26 | + } | ||
27 | + | ||
28 | + public static String getName(int code) { | ||
29 | + Stream<PipelineType> TYPES = Arrays.stream(values()); | ||
30 | + Optional<String> result = TYPES.filter(type -> type.getCode() == code) | ||
31 | + .map(PipelineType::getName).findFirst(); | ||
32 | + return result.isPresent() ? result.get() : null; | ||
33 | + } | ||
34 | + | ||
35 | + public static List<PipelineType> getTypes() { | ||
36 | + return Arrays.asList(values()); | ||
37 | + } | ||
38 | + | ||
39 | + public String getName() { | ||
40 | + return this.name; | ||
41 | + } | ||
42 | + | ||
43 | + public int getCode() { | ||
44 | + return this.code; | ||
45 | + } | ||
46 | + | ||
47 | + public String toString() { | ||
48 | + return this.name; | ||
49 | + } | ||
50 | +} | ||
0 | \ No newline at end of file | 51 | \ No newline at end of file |
assistant-dfs/src/main/resources/com/diligrp/assistant/dao/mapper/FileObjectDao.xml
0 → 100644
1 | +++ a/assistant-dfs/src/main/resources/com/diligrp/assistant/dao/mapper/FileObjectDao.xml | ||
1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||
3 | + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
4 | + | ||
5 | +<mapper namespace="com.diligrp.assistant.dfs.dao.FileObjectDao"> | ||
6 | + <resultMap id="FileObjectMap" type="com.diligrp.assistant.dfs.model.FileObject"> | ||
7 | + <id column="id" property="id"/> | ||
8 | + <result column="repository_id" property="repositoryId"/> | ||
9 | + <result column="pipeline" property="pipeline"/> | ||
10 | + <result column="file_id" property="fileId"/> | ||
11 | + <result column="file_name" property="fileName"/> | ||
12 | + <result column="mime_type" property="mimeType"/> | ||
13 | + <result column="hits" property="hits"/> | ||
14 | + <result column="state" property="state"/> | ||
15 | + <result column="created_time" property="createdTime"/> | ||
16 | + <result column="modified_time" property="modifiedTime"/> | ||
17 | + </resultMap> | ||
18 | + | ||
19 | + <insert id="insertFileObject" parameterType="com.diligrp.assistant.dfs.model.FileObject"> | ||
20 | + INSERT INTO dfs_file_object | ||
21 | + (repository_id, pipeline, file_id, file_name, mime_type, hits, state, created_time, modified_time) | ||
22 | + VALUES | ||
23 | + (#{repositoryId}, #{pipeline}, #{fileId}, #{fileName}, #{mimeType}, #{hits}, #{state}, #{createdTime}, #{modifiedTime}) | ||
24 | + </insert> | ||
25 | + | ||
26 | + <update id="hitFileObject"> | ||
27 | + UPDATE dfs_file_object SET hits = hits + 1, modified_time = #{modifiedTime} | ||
28 | + WHERE file_id = #{fileId} | ||
29 | + </update> | ||
30 | + | ||
31 | + <update id="deleteFileObject" parameterType="string"> | ||
32 | + DELETE FROM dfs_file_object WHERE file_id = #{fileId} | ||
33 | + </update> | ||
34 | +</mapper> |
assistant-dfs/src/main/resources/com/diligrp/assistant/dao/mapper/FileRepositoryDao.xml
0 → 100644
1 | +++ a/assistant-dfs/src/main/resources/com/diligrp/assistant/dao/mapper/FileRepositoryDao.xml | ||
1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||
3 | + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
4 | + | ||
5 | +<mapper namespace="com.diligrp.assistant.dfs.dao.FileRepositoryDao"> | ||
6 | + <resultMap id="FileRepositoryMap" type="com.diligrp.assistant.dfs.model.FileRepository"> | ||
7 | + <id column="id" property="id"/> | ||
8 | + <result column="repository_id" property="repositoryId"/> | ||
9 | + <result column="name" property="name"/> | ||
10 | + <result column="pipeline" property="pipeline"/> | ||
11 | + <result column="description" property="description"/> | ||
12 | + <result column="created_time" property="createdTime"/> | ||
13 | + </resultMap> | ||
14 | + | ||
15 | + <insert id="insertFileRepository" parameterType="com.diligrp.assistant.dfs.model.FileRepository"> | ||
16 | + INSERT INTO dfs_file_repository | ||
17 | + (repository_id, name, pipeline, description, created_time) | ||
18 | + VALUES | ||
19 | + (#{repositoryId}, #{name}, #{pipeline}, #{description}, #{createdTime}) | ||
20 | + </insert> | ||
21 | + | ||
22 | + <select id="findFileRepositoryById" parameterType="string" resultMap="FileRepositoryMap"> | ||
23 | + SELECT * FROM dfs_file_repository WHERE repository_id = #{repositoryId} | ||
24 | + </select> | ||
25 | + | ||
26 | + <update id="deleteFileRepository" parameterType="string"> | ||
27 | + DELETE FROM dfs_file_repository WHERE repository_id = #{repositoryId} | ||
28 | + </update> | ||
29 | +</mapper> |
assistant-logging/build.gradle
0 → 100644
assistant-logging/src/main/java/com/diligrp/assistant/logging/LoggingConfiguration.java
0 → 100644
1 | +++ a/assistant-logging/src/main/java/com/diligrp/assistant/logging/LoggingConfiguration.java | ||
1 | +package com.diligrp.assistant.logging; | ||
2 | + | ||
3 | +import org.springframework.context.annotation.ComponentScan; | ||
4 | +import org.springframework.context.annotation.Configuration; | ||
5 | + | ||
6 | +@Configuration | ||
7 | +@ComponentScan("com.diligrp.assistant.logging") | ||
8 | +public class LoggingConfiguration { | ||
9 | +} |
assistant-product/build.gradle
0 → 100644
assistant-product/src/main/java/com/diligrp/assistant/product/ProductConfiguration.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/ProductConfiguration.java | ||
1 | +package com.diligrp.assistant.product; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.mybatis.MybatisMapperSupport; | ||
4 | +import org.mybatis.spring.annotation.MapperScan; | ||
5 | +import org.springframework.context.annotation.ComponentScan; | ||
6 | +import org.springframework.context.annotation.Configuration; | ||
7 | + | ||
8 | +@Configuration | ||
9 | +@ComponentScan("com.diligrp.assistant.product") | ||
10 | +@MapperScan(basePackages = {"com.diligrp.assistant.product.dao"}, markerInterface = MybatisMapperSupport.class) | ||
11 | +public class ProductConfiguration { | ||
12 | +} | ||
0 | \ No newline at end of file | 13 | \ No newline at end of file |
assistant-product/src/main/java/com/diligrp/assistant/product/controller/CategoryOpenApiController.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/controller/CategoryOpenApiController.java | ||
1 | +package com.diligrp.assistant.product.controller; | ||
2 | + | ||
3 | +import com.diligrp.assistant.product.domain.CategoryVO; | ||
4 | +import com.diligrp.assistant.product.domain.CategoryPageQuery; | ||
5 | +import com.diligrp.assistant.product.domain.ListCategory; | ||
6 | +import com.diligrp.assistant.product.model.Category; | ||
7 | +import com.diligrp.assistant.product.service.ProductCategoryService; | ||
8 | +import com.diligrp.assistant.shared.domain.Message; | ||
9 | +import com.diligrp.assistant.shared.util.AssertUtils; | ||
10 | +import jakarta.annotation.Resource; | ||
11 | +import org.springframework.web.bind.annotation.RequestBody; | ||
12 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
13 | +import org.springframework.web.bind.annotation.RequestParam; | ||
14 | +import org.springframework.web.bind.annotation.RestController; | ||
15 | + | ||
16 | +import java.util.List; | ||
17 | +import java.util.stream.Collectors; | ||
18 | + | ||
19 | +/** | ||
20 | + * 对外接口控制器 | ||
21 | + */ | ||
22 | +@RestController | ||
23 | +@RequestMapping(value = "/api/category") | ||
24 | +public class CategoryOpenApiController { | ||
25 | + | ||
26 | + @Resource | ||
27 | + private ProductCategoryService productCategoryService; | ||
28 | + | ||
29 | + @RequestMapping(value = "/findById.do") | ||
30 | + public Message<CategoryVO> findById(@RequestParam("id") Long id) { | ||
31 | + Category category = productCategoryService.findCategoryById(id); | ||
32 | + return Message.success(CategoryVO.of(category.getId(), category.getParentId(), | ||
33 | + category.getName(), category.getAlias(), category.getLevel(), category.getIcon(), category.getPath())); | ||
34 | + } | ||
35 | + | ||
36 | + @RequestMapping(value = "/findParentById.do") | ||
37 | + public Message<CategoryVO> findParentById(@RequestParam("id") Long id) { | ||
38 | + Category category = productCategoryService.findParentCategoryById(id); | ||
39 | + return Message.success(CategoryVO.of(category.getId(), category.getParentId(), | ||
40 | + category.getName(), category.getAlias(), category.getLevel(), category.getIcon(), category.getPath())); | ||
41 | + } | ||
42 | + | ||
43 | + @RequestMapping(value = "/listParentsById.do") | ||
44 | + public Message<List<CategoryVO>> listParentsById(@RequestParam("id") Long id) { | ||
45 | + List<CategoryVO> categories = productCategoryService.listParentsById(id).stream().map(category -> | ||
46 | + CategoryVO.of(category.getId(), category.getParentId(), category.getName(), category.getAlias(), | ||
47 | + category.getLevel(), category.getIcon(), category.getPath())).collect(Collectors.toList()); | ||
48 | + return Message.success(categories); | ||
49 | + } | ||
50 | + | ||
51 | + @RequestMapping(value = "/listChildrenById.do") | ||
52 | + public Message<List<CategoryVO>> findChildrenById(@RequestBody ListCategory request) { | ||
53 | + AssertUtils.notNull(request.getId(), "id missed"); | ||
54 | + AssertUtils.notNull(request.getPageNo(), "pageNo missed"); | ||
55 | + AssertUtils.notNull(request.getPageSize(), "pageSize missed"); | ||
56 | + | ||
57 | + CategoryPageQuery query = new CategoryPageQuery(); | ||
58 | + query.setId(request.getId()); | ||
59 | + query.from(request.getPageNo(), request.getPageSize()); | ||
60 | + | ||
61 | + List<CategoryVO> categories = productCategoryService.listChildrenById(query).stream().map(category -> | ||
62 | + CategoryVO.of(category.getId(), category.getParentId(), category.getName(), category.getAlias(), | ||
63 | + category.getLevel(), category.getIcon(), category.getPath())).collect(Collectors.toList()); | ||
64 | + return Message.success(categories); | ||
65 | + } | ||
66 | + | ||
67 | + @RequestMapping(value = "/listByLevel.do") | ||
68 | + public Message<List<CategoryVO>> findByLevel(@RequestBody ListCategory request) { | ||
69 | + AssertUtils.notNull(request.getLevel(), "level missed"); | ||
70 | + AssertUtils.notNull(request.getPageNo(), "pageNo missed"); | ||
71 | + AssertUtils.notNull(request.getPageSize(), "pageSize missed"); | ||
72 | + | ||
73 | + CategoryPageQuery query = new CategoryPageQuery(); | ||
74 | + query.setLevel(request.getLevel()); | ||
75 | + query.from(request.getPageNo(), request.getPageSize()); | ||
76 | + | ||
77 | + List<CategoryVO> categories = productCategoryService.listCategoriesByLevel(query).stream().map(category -> | ||
78 | + CategoryVO.of(category.getId(), category.getParentId(), category.getName(), category.getAlias(), | ||
79 | + category.getLevel(), category.getIcon(), category.getPath())).collect(Collectors.toList()); | ||
80 | + return Message.success(categories); | ||
81 | + } | ||
82 | +} |
assistant-product/src/main/java/com/diligrp/assistant/product/controller/ProductCategoryController.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/controller/ProductCategoryController.java | ||
1 | +package com.diligrp.assistant.product.controller; | ||
2 | + | ||
3 | +import com.diligrp.assistant.product.domain.CategoryDTO; | ||
4 | +import com.diligrp.assistant.product.service.ProductCategoryService; | ||
5 | +import com.diligrp.assistant.shared.domain.Message; | ||
6 | +import com.diligrp.assistant.shared.util.AssertUtils; | ||
7 | +import jakarta.annotation.Resource; | ||
8 | +import org.springframework.web.bind.annotation.RequestBody; | ||
9 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
10 | +import org.springframework.web.bind.annotation.RequestParam; | ||
11 | +import org.springframework.web.bind.annotation.RestController; | ||
12 | + | ||
13 | +@RestController | ||
14 | +@RequestMapping(value = "/category") | ||
15 | +public class ProductCategoryController { | ||
16 | + | ||
17 | + @Resource | ||
18 | + private ProductCategoryService productCategoryService; | ||
19 | + | ||
20 | + @RequestMapping(value = "/create.do") | ||
21 | + public Message<?> create(@RequestBody CategoryDTO request) { | ||
22 | + AssertUtils.notNull(request.getParentId(), "parentId missed"); | ||
23 | + AssertUtils.notEmpty(request.getName(), "name missed"); | ||
24 | + | ||
25 | + Long id = productCategoryService.createCategory(request); | ||
26 | + return Message.success(id); | ||
27 | + } | ||
28 | + | ||
29 | + @RequestMapping(value = "/update.do") | ||
30 | + public Message<?> update(@RequestBody CategoryDTO request) { | ||
31 | + AssertUtils.notNull(request.getId(), "id missed"); | ||
32 | + | ||
33 | + productCategoryService.updateCategory(request); | ||
34 | + return Message.success(); | ||
35 | + } | ||
36 | + | ||
37 | + @RequestMapping(value = "/delete.do") | ||
38 | + public Message<?> delete(@RequestParam Long id) { | ||
39 | + productCategoryService.deleteCategory(id); | ||
40 | + return Message.success(); | ||
41 | + } | ||
42 | +} |
assistant-product/src/main/java/com/diligrp/assistant/product/dao/ProductCategoryDao.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/dao/ProductCategoryDao.java | ||
1 | +package com.diligrp.assistant.product.dao; | ||
2 | + | ||
3 | +import com.diligrp.assistant.product.domain.CategoryPageQuery; | ||
4 | +import com.diligrp.assistant.product.model.Category; | ||
5 | +import com.diligrp.assistant.shared.mybatis.MybatisMapperSupport; | ||
6 | +import org.springframework.stereotype.Repository; | ||
7 | + | ||
8 | +import java.util.List; | ||
9 | +import java.util.Optional; | ||
10 | + | ||
11 | +@Repository("productCategoryDao") | ||
12 | +public interface ProductCategoryDao extends MybatisMapperSupport { | ||
13 | + void insertCategory(Category category); | ||
14 | + | ||
15 | + int updateCategory(Category category); | ||
16 | + | ||
17 | + Optional<Category> findCategoryById(Long id); | ||
18 | + | ||
19 | + Optional<Category> findParentCategoryById(Long id); | ||
20 | + | ||
21 | + List<Category> findCategoriesByIds(List<Long> ids); | ||
22 | + | ||
23 | + List<Category> listChildrenById(CategoryPageQuery query); | ||
24 | + | ||
25 | + Long countChildrenById(Long id); | ||
26 | + | ||
27 | + List<Category> listCategoriesByLevel(CategoryPageQuery query); | ||
28 | +} |
assistant-product/src/main/java/com/diligrp/assistant/product/domain/CategoryDTO.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/domain/CategoryDTO.java | ||
1 | +package com.diligrp.assistant.product.domain; | ||
2 | + | ||
3 | +public class CategoryDTO { | ||
4 | + // 品类ID | ||
5 | + private Long id; | ||
6 | + // 父品类ID | ||
7 | + private Long parentId; | ||
8 | + // 名称 | ||
9 | + private String name; | ||
10 | + // 别名 | ||
11 | + private String alias; | ||
12 | + // 拼音 | ||
13 | + private String pyCode; | ||
14 | + // 简拼 | ||
15 | + private String shortCode; | ||
16 | + // 路径 | ||
17 | + private String path; | ||
18 | + // 图标 | ||
19 | + private String icon; | ||
20 | + | ||
21 | + public Long getId() { | ||
22 | + return id; | ||
23 | + } | ||
24 | + | ||
25 | + public void setId(Long id) { | ||
26 | + this.id = id; | ||
27 | + } | ||
28 | + | ||
29 | + public Long getParentId() { | ||
30 | + return parentId; | ||
31 | + } | ||
32 | + | ||
33 | + public void setParentId(Long parentId) { | ||
34 | + this.parentId = parentId; | ||
35 | + } | ||
36 | + | ||
37 | + public String getName() { | ||
38 | + return name; | ||
39 | + } | ||
40 | + | ||
41 | + public void setName(String name) { | ||
42 | + this.name = name; | ||
43 | + } | ||
44 | + | ||
45 | + public String getAlias() { | ||
46 | + return alias; | ||
47 | + } | ||
48 | + | ||
49 | + public void setAlias(String alias) { | ||
50 | + this.alias = alias; | ||
51 | + } | ||
52 | + | ||
53 | + public String getPyCode() { | ||
54 | + return pyCode; | ||
55 | + } | ||
56 | + | ||
57 | + public void setPyCode(String pyCode) { | ||
58 | + this.pyCode = pyCode; | ||
59 | + } | ||
60 | + | ||
61 | + public String getShortCode() { | ||
62 | + return shortCode; | ||
63 | + } | ||
64 | + | ||
65 | + public void setShortCode(String shortCode) { | ||
66 | + this.shortCode = shortCode; | ||
67 | + } | ||
68 | + | ||
69 | + public String getPath() { | ||
70 | + return path; | ||
71 | + } | ||
72 | + | ||
73 | + public void setPath(String path) { | ||
74 | + this.path = path; | ||
75 | + } | ||
76 | + | ||
77 | + public String getIcon() { | ||
78 | + return icon; | ||
79 | + } | ||
80 | + | ||
81 | + public void setIcon(String icon) { | ||
82 | + this.icon = icon; | ||
83 | + } | ||
84 | +} |
assistant-product/src/main/java/com/diligrp/assistant/product/domain/CategoryPageQuery.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/domain/CategoryPageQuery.java | ||
1 | +package com.diligrp.assistant.product.domain; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.domain.PageQuery; | ||
4 | + | ||
5 | +public class CategoryPageQuery extends PageQuery { | ||
6 | + // 区域ID | ||
7 | + private Long id; | ||
8 | + // 区域级别 | ||
9 | + private Integer level; | ||
10 | + | ||
11 | + public Long getId() { | ||
12 | + return id; | ||
13 | + } | ||
14 | + | ||
15 | + public void setId(Long id) { | ||
16 | + this.id = id; | ||
17 | + } | ||
18 | + | ||
19 | + public Integer getLevel() { | ||
20 | + return level; | ||
21 | + } | ||
22 | + | ||
23 | + public void setLevel(Integer level) { | ||
24 | + this.level = level; | ||
25 | + } | ||
26 | +} |
assistant-product/src/main/java/com/diligrp/assistant/product/domain/CategoryVO.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/domain/CategoryVO.java | ||
1 | +package com.diligrp.assistant.product.domain; | ||
2 | + | ||
3 | +public class CategoryVO { | ||
4 | + // ID | ||
5 | + private Long id; | ||
6 | + // 父品类ID | ||
7 | + private Long parentId; | ||
8 | + // 名称 | ||
9 | + private String name; | ||
10 | + // 别名 | ||
11 | + private String alias; | ||
12 | + // 级别 | ||
13 | + private Integer level; | ||
14 | + // 图标 | ||
15 | + private String icon; | ||
16 | + // 路径 | ||
17 | + private String path; | ||
18 | + | ||
19 | + public static CategoryVO of(Long id, Long parentId, String name, String alias, Integer level, String icon, String path) { | ||
20 | + CategoryVO category = new CategoryVO(); | ||
21 | + category.id = id; | ||
22 | + category.parentId = parentId; | ||
23 | + category.name = name; | ||
24 | + category.alias = alias; | ||
25 | + category.level = level; | ||
26 | + category.icon = icon; | ||
27 | + category.path = path; | ||
28 | + | ||
29 | + return category; | ||
30 | + } | ||
31 | + | ||
32 | + public Long getId() { | ||
33 | + return id; | ||
34 | + } | ||
35 | + | ||
36 | + public void setId(Long id) { | ||
37 | + this.id = id; | ||
38 | + } | ||
39 | + | ||
40 | + public Long getParentId() { | ||
41 | + return parentId; | ||
42 | + } | ||
43 | + | ||
44 | + public void setParentId(Long parentId) { | ||
45 | + this.parentId = parentId; | ||
46 | + } | ||
47 | + | ||
48 | + public String getName() { | ||
49 | + return name; | ||
50 | + } | ||
51 | + | ||
52 | + public void setName(String name) { | ||
53 | + this.name = name; | ||
54 | + } | ||
55 | + | ||
56 | + public String getAlias() { | ||
57 | + return alias; | ||
58 | + } | ||
59 | + | ||
60 | + public void setAlias(String alias) { | ||
61 | + this.alias = alias; | ||
62 | + } | ||
63 | + | ||
64 | + public Integer getLevel() { | ||
65 | + return level; | ||
66 | + } | ||
67 | + | ||
68 | + public void setLevel(Integer level) { | ||
69 | + this.level = level; | ||
70 | + } | ||
71 | + | ||
72 | + public String getIcon() { | ||
73 | + return icon; | ||
74 | + } | ||
75 | + | ||
76 | + public void setIcon(String icon) { | ||
77 | + this.icon = icon; | ||
78 | + } | ||
79 | + | ||
80 | + public String getPath() { | ||
81 | + return path; | ||
82 | + } | ||
83 | + | ||
84 | + public void setPath(String path) { | ||
85 | + this.path = path; | ||
86 | + } | ||
87 | +} |
assistant-product/src/main/java/com/diligrp/assistant/product/domain/ListCategory.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/domain/ListCategory.java | ||
1 | +package com.diligrp.assistant.product.domain; | ||
2 | + | ||
3 | +public class ListCategory { | ||
4 | + // 页号 | ||
5 | + private Integer pageNo = 1; | ||
6 | + // 每页记录数 | ||
7 | + private Integer pageSize = 20; | ||
8 | + | ||
9 | + // 品类ID | ||
10 | + private Long id; | ||
11 | + // 品类级别 | ||
12 | + private Integer level; | ||
13 | + | ||
14 | + public Integer getPageNo() { | ||
15 | + return pageNo; | ||
16 | + } | ||
17 | + | ||
18 | + public void setPageNo(Integer pageNo) { | ||
19 | + this.pageNo = pageNo; | ||
20 | + } | ||
21 | + | ||
22 | + public Integer getPageSize() { | ||
23 | + return pageSize; | ||
24 | + } | ||
25 | + | ||
26 | + public void setPageSize(Integer pageSize) { | ||
27 | + this.pageSize = pageSize; | ||
28 | + } | ||
29 | + | ||
30 | + public Long getId() { | ||
31 | + return id; | ||
32 | + } | ||
33 | + | ||
34 | + public void setId(Long id) { | ||
35 | + this.id = id; | ||
36 | + } | ||
37 | + | ||
38 | + public Integer getLevel() { | ||
39 | + return level; | ||
40 | + } | ||
41 | + | ||
42 | + public void setLevel(Integer level) { | ||
43 | + this.level = level; | ||
44 | + } | ||
45 | +} |
assistant-product/src/main/java/com/diligrp/assistant/product/exception/CategoryServiceException.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/exception/CategoryServiceException.java | ||
1 | +package com.diligrp.assistant.product.exception; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.exception.PlatformServiceException; | ||
4 | + | ||
5 | +public class CategoryServiceException extends PlatformServiceException { | ||
6 | + public CategoryServiceException(String message) { | ||
7 | + super(message); | ||
8 | + } | ||
9 | + | ||
10 | + public CategoryServiceException(int code, String message) { | ||
11 | + super(code, message); | ||
12 | + } | ||
13 | + | ||
14 | + public CategoryServiceException(String message, Throwable ex) { | ||
15 | + super(message, ex); | ||
16 | + } | ||
17 | +} |
assistant-product/src/main/java/com/diligrp/assistant/product/model/Category.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/model/Category.java | ||
1 | +package com.diligrp.assistant.product.model; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.domain.BaseDo; | ||
4 | + | ||
5 | +import java.time.LocalDateTime; | ||
6 | + | ||
7 | +public class Category extends BaseDo { | ||
8 | + // 父品类ID | ||
9 | + private Long parentId; | ||
10 | + // 名称 | ||
11 | + private String name; | ||
12 | + // 别名 | ||
13 | + private String alias; | ||
14 | + // 级别 | ||
15 | + private Integer level; | ||
16 | + // 拼音 | ||
17 | + private String pyCode; | ||
18 | + // 简拼 | ||
19 | + private String shortCode; | ||
20 | + // 路径 | ||
21 | + private String path; | ||
22 | + // 图标 | ||
23 | + private String icon; | ||
24 | + // 状态 | ||
25 | + private Integer state; | ||
26 | + | ||
27 | + public Long getParentId() { | ||
28 | + return parentId; | ||
29 | + } | ||
30 | + | ||
31 | + public void setParentId(Long parentId) { | ||
32 | + this.parentId = parentId; | ||
33 | + } | ||
34 | + | ||
35 | + public String getName() { | ||
36 | + return name; | ||
37 | + } | ||
38 | + | ||
39 | + public void setName(String name) { | ||
40 | + this.name = name; | ||
41 | + } | ||
42 | + | ||
43 | + public String getAlias() { | ||
44 | + return alias; | ||
45 | + } | ||
46 | + | ||
47 | + public void setAlias(String alias) { | ||
48 | + this.alias = alias; | ||
49 | + } | ||
50 | + | ||
51 | + public Integer getLevel() { | ||
52 | + return level; | ||
53 | + } | ||
54 | + | ||
55 | + public void setLevel(Integer level) { | ||
56 | + this.level = level; | ||
57 | + } | ||
58 | + | ||
59 | + public String getPyCode() { | ||
60 | + return pyCode; | ||
61 | + } | ||
62 | + | ||
63 | + public void setPyCode(String pyCode) { | ||
64 | + this.pyCode = pyCode; | ||
65 | + } | ||
66 | + | ||
67 | + public String getShortCode() { | ||
68 | + return shortCode; | ||
69 | + } | ||
70 | + | ||
71 | + public void setShortCode(String shortCode) { | ||
72 | + this.shortCode = shortCode; | ||
73 | + } | ||
74 | + | ||
75 | + public String getPath() { | ||
76 | + return path; | ||
77 | + } | ||
78 | + | ||
79 | + public void setPath(String path) { | ||
80 | + this.path = path; | ||
81 | + } | ||
82 | + | ||
83 | + public String getIcon() { | ||
84 | + return icon; | ||
85 | + } | ||
86 | + | ||
87 | + public void setIcon(String icon) { | ||
88 | + this.icon = icon; | ||
89 | + } | ||
90 | + | ||
91 | + public Integer getState() { | ||
92 | + return state; | ||
93 | + } | ||
94 | + | ||
95 | + public void setState(Integer state) { | ||
96 | + this.state = state; | ||
97 | + } | ||
98 | + | ||
99 | + public static Builder builder() { | ||
100 | + return new Category().new Builder(); | ||
101 | + } | ||
102 | + | ||
103 | + public class Builder { | ||
104 | + public Builder parentId(Long parentId) { | ||
105 | + Category.this.parentId = parentId; | ||
106 | + return this; | ||
107 | + } | ||
108 | + | ||
109 | + public Builder name(String name) { | ||
110 | + Category.this.name = name; | ||
111 | + return this; | ||
112 | + } | ||
113 | + | ||
114 | + public Builder alias(String alias) { | ||
115 | + Category.this.alias = alias; | ||
116 | + return this; | ||
117 | + } | ||
118 | + | ||
119 | + public Builder level(Integer level) { | ||
120 | + Category.this.level = level; | ||
121 | + return this; | ||
122 | + } | ||
123 | + | ||
124 | + public Builder pyCode(String pyCode) { | ||
125 | + Category.this.pyCode = pyCode; | ||
126 | + return this; | ||
127 | + } | ||
128 | + | ||
129 | + public Builder shortCode(String shortCode) { | ||
130 | + Category.this.shortCode = shortCode; | ||
131 | + return this; | ||
132 | + } | ||
133 | + | ||
134 | + public Builder path(String path) { | ||
135 | + Category.this.path = path; | ||
136 | + return this; | ||
137 | + } | ||
138 | + | ||
139 | + public Builder icon(String icon) { | ||
140 | + Category.this.icon = icon; | ||
141 | + return this; | ||
142 | + } | ||
143 | + | ||
144 | + public Builder state(Integer state) { | ||
145 | + Category.this.state = state; | ||
146 | + return this; | ||
147 | + } | ||
148 | + | ||
149 | + public Builder version(Integer version) { | ||
150 | + Category.this.version = version; | ||
151 | + return this; | ||
152 | + } | ||
153 | + | ||
154 | + public Builder createdTime(LocalDateTime createdTime) { | ||
155 | + Category.this.createdTime = createdTime; | ||
156 | + return this; | ||
157 | + } | ||
158 | + | ||
159 | + public Builder modifiedTime(LocalDateTime modifiedTime) { | ||
160 | + Category.this.modifiedTime = modifiedTime; | ||
161 | + return this; | ||
162 | + } | ||
163 | + | ||
164 | + public Category build() { | ||
165 | + return Category.this; | ||
166 | + } | ||
167 | + } | ||
168 | +} |
assistant-product/src/main/java/com/diligrp/assistant/product/service/ProductCategoryService.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/service/ProductCategoryService.java | ||
1 | +package com.diligrp.assistant.product.service; | ||
2 | + | ||
3 | +import com.diligrp.assistant.product.domain.CategoryDTO; | ||
4 | +import com.diligrp.assistant.product.domain.CategoryPageQuery; | ||
5 | +import com.diligrp.assistant.product.model.Category; | ||
6 | + | ||
7 | +import java.util.List; | ||
8 | + | ||
9 | +public interface ProductCategoryService { | ||
10 | + /** | ||
11 | + * 创建品类 | ||
12 | + * | ||
13 | + * @param request - 品类 | ||
14 | + * @return 品类ID | ||
15 | + */ | ||
16 | + long createCategory(CategoryDTO request); | ||
17 | + | ||
18 | + /** | ||
19 | + * 修改品类 | ||
20 | + * | ||
21 | + * @param request - 品类 | ||
22 | + */ | ||
23 | + void updateCategory(CategoryDTO request); | ||
24 | + | ||
25 | + /** | ||
26 | + * 删除指定的品类 | ||
27 | + * | ||
28 | + * @param id - 品类ID | ||
29 | + */ | ||
30 | + void deleteCategory(Long id); | ||
31 | + | ||
32 | + /** | ||
33 | + * 根据ID查询品类 | ||
34 | + * | ||
35 | + * @param id - 品类ID | ||
36 | + * @return 品类 | ||
37 | + */ | ||
38 | + Category findCategoryById(Long id); | ||
39 | + | ||
40 | + /** | ||
41 | + * 根据ID查询父级品类 | ||
42 | + * | ||
43 | + * @param id - 品类ID | ||
44 | + * @return 父级品类 | ||
45 | + */ | ||
46 | + Category findParentCategoryById(Long id); | ||
47 | + | ||
48 | + /** | ||
49 | + * 根据ID查询所有的祖先品类,查询结果包含自身且按照等级降序排序 | ||
50 | + * | ||
51 | + * @param id - 品类ID | ||
52 | + * @return 祖先品类 | ||
53 | + */ | ||
54 | + List<Category> listParentsById(Long id); | ||
55 | + | ||
56 | + /** | ||
57 | + * 根据父品类ID分页查询子品类 | ||
58 | + * | ||
59 | + * @param query 查询条件 | ||
60 | + * @return 子品类 | ||
61 | + */ | ||
62 | + List<Category> listChildrenById(CategoryPageQuery query); | ||
63 | + | ||
64 | + /** | ||
65 | + * 根据品类级别分页查询品类 | ||
66 | + * | ||
67 | + * @param query 查询条件 | ||
68 | + * @return 品类 | ||
69 | + */ | ||
70 | + List<Category> listCategoriesByLevel(CategoryPageQuery query); | ||
71 | +} |
assistant-product/src/main/java/com/diligrp/assistant/product/service/impl/ProductCategoryServiceImpl.java
0 → 100644
1 | +++ a/assistant-product/src/main/java/com/diligrp/assistant/product/service/impl/ProductCategoryServiceImpl.java | ||
1 | +package com.diligrp.assistant.product.service.impl; | ||
2 | + | ||
3 | +import com.diligrp.assistant.product.dao.ProductCategoryDao; | ||
4 | +import com.diligrp.assistant.product.domain.CategoryDTO; | ||
5 | +import com.diligrp.assistant.product.domain.CategoryPageQuery; | ||
6 | +import com.diligrp.assistant.product.exception.CategoryServiceException; | ||
7 | +import com.diligrp.assistant.product.model.Category; | ||
8 | +import com.diligrp.assistant.product.service.ProductCategoryService; | ||
9 | +import com.diligrp.assistant.shared.ErrorCode; | ||
10 | +import jakarta.annotation.Resource; | ||
11 | +import org.springframework.stereotype.Service; | ||
12 | +import org.springframework.transaction.annotation.Transactional; | ||
13 | + | ||
14 | +import java.time.LocalDateTime; | ||
15 | +import java.util.*; | ||
16 | + | ||
17 | +@Service("productCategoryService") | ||
18 | +public class ProductCategoryServiceImpl implements ProductCategoryService { | ||
19 | + | ||
20 | + @Resource | ||
21 | + private ProductCategoryDao productCategoryDao; | ||
22 | + | ||
23 | + @Override | ||
24 | + @Transactional(rollbackFor = Exception.class) | ||
25 | + public long createCategory(CategoryDTO request) { | ||
26 | + LocalDateTime now = LocalDateTime.now(); | ||
27 | + Category parent = findCategoryById(request.getParentId()); | ||
28 | + Category category = Category.builder().parentId(request.getParentId()).name(request.getName()) | ||
29 | + .alias(request.getAlias()).level(parent.getLevel() + 1).pyCode(request.getPyCode()) | ||
30 | + .shortCode(request.getShortCode()).path(parent.getPath()).icon(request.getIcon()).state(1).version(0) | ||
31 | + .createdTime(now).modifiedTime(now).build(); | ||
32 | + productCategoryDao.insertCategory(category); | ||
33 | + | ||
34 | + // 更新路径信息, 将自身ID添加到路径信息中 | ||
35 | + String path = parent.getPath() + "," + category.getId(); | ||
36 | + Category update = new Category(); | ||
37 | + update.setId(category.getId()); | ||
38 | + update.setPath(path); | ||
39 | + productCategoryDao.updateCategory(update); | ||
40 | + return category.getId(); | ||
41 | + } | ||
42 | + | ||
43 | + @Override | ||
44 | + @Transactional(rollbackFor = Exception.class) | ||
45 | + public void updateCategory(CategoryDTO request) { | ||
46 | + LocalDateTime now = LocalDateTime.now(); | ||
47 | + Category category = Category.builder().name(request.getName()) | ||
48 | + .alias(request.getAlias()).pyCode(request.getPyCode()).shortCode(request.getShortCode()) | ||
49 | + .icon(request.getIcon()).modifiedTime(now).build(); | ||
50 | + category.setId(request.getId()); | ||
51 | + if (productCategoryDao.updateCategory(category) == 0) { | ||
52 | + throw new CategoryServiceException(ErrorCode.OBJECT_NOT_FOUND, "品类不存在"); | ||
53 | + } | ||
54 | + } | ||
55 | + | ||
56 | + @Override | ||
57 | + @Transactional(rollbackFor = Exception.class) | ||
58 | + public void deleteCategory(Long id) { | ||
59 | + LocalDateTime now = LocalDateTime.now(); | ||
60 | + long children = productCategoryDao.countChildrenById(id); | ||
61 | + if (children > 0) { | ||
62 | + throw new CategoryServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "该品类不能被删除: 存在子品类"); | ||
63 | + } | ||
64 | + | ||
65 | + Category update = new Category(); | ||
66 | + update.setId(id); | ||
67 | + update.setState(0); | ||
68 | + update.setModifiedTime(now); | ||
69 | + if (productCategoryDao.updateCategory(update) == 0) { | ||
70 | + throw new CategoryServiceException(ErrorCode.OBJECT_NOT_FOUND, "该品类删除失败: 品类不存在"); | ||
71 | + } | ||
72 | + } | ||
73 | + | ||
74 | + @Override | ||
75 | + public Category findCategoryById(Long id) { | ||
76 | + return productCategoryDao.findCategoryById(id).orElseThrow(() -> | ||
77 | + new CategoryServiceException(ErrorCode.OBJECT_NOT_FOUND, "品类不存在")); | ||
78 | + } | ||
79 | + | ||
80 | + @Override | ||
81 | + public Category findParentCategoryById(Long id) { | ||
82 | + return productCategoryDao.findParentCategoryById(id).orElseThrow(() -> | ||
83 | + new CategoryServiceException(ErrorCode.OBJECT_NOT_FOUND, "品类不存在")); | ||
84 | + } | ||
85 | + | ||
86 | + @Override | ||
87 | + public List<Category> listParentsById(Long id) { | ||
88 | + Category self = findCategoryById(id); | ||
89 | + String path = self.getPath(); | ||
90 | + | ||
91 | + if (Objects.nonNull(path)) { | ||
92 | + List<Long> ids = new ArrayList<>(); | ||
93 | + StringTokenizer tokenizer = new StringTokenizer(path, ","); | ||
94 | + | ||
95 | + while (tokenizer.hasMoreTokens()) { | ||
96 | + ids.add(Long.parseLong(tokenizer.nextToken())); | ||
97 | + } | ||
98 | + if (ids.isEmpty()) { | ||
99 | + ids.add(id); | ||
100 | + } | ||
101 | + | ||
102 | + return productCategoryDao.findCategoriesByIds(ids); | ||
103 | + } else { | ||
104 | + return Collections.singletonList(self); | ||
105 | + } | ||
106 | + } | ||
107 | + | ||
108 | + @Override | ||
109 | + public List<Category> listChildrenById(CategoryPageQuery query) { | ||
110 | + return productCategoryDao.listChildrenById(query); | ||
111 | + } | ||
112 | + | ||
113 | + @Override | ||
114 | + public List<Category> listCategoriesByLevel(CategoryPageQuery query) { | ||
115 | + return productCategoryDao.listCategoriesByLevel(query); | ||
116 | + } | ||
117 | +} |
assistant-product/src/main/resources/com/diligrp/assistant/dao/mapper/ProductCategoryDao.xml
0 → 100644
1 | +++ a/assistant-product/src/main/resources/com/diligrp/assistant/dao/mapper/ProductCategoryDao.xml | ||
1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||
3 | + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
4 | + | ||
5 | +<mapper namespace="com.diligrp.assistant.product.dao.ProductCategoryDao"> | ||
6 | + <resultMap id="CategoryMap" type="com.diligrp.assistant.product.model.Category"> | ||
7 | + <id column="id" property="id"/> | ||
8 | + <result column="parent_id" property="parentId"/> | ||
9 | + <result column="name" property="name"/> | ||
10 | + <result column="alias" property="alias"/> | ||
11 | + <result column="level" property="level"/> | ||
12 | + <result column="py_code" property="pyCode"/> | ||
13 | + <result column="short_code" property="shortCode"/> | ||
14 | + <result column="path" property="path"/> | ||
15 | + <result column="icon" property="icon"/> | ||
16 | + <result column="state" property="state"/> | ||
17 | + <result column="version" property="version"/> | ||
18 | + <result column="created_time" property="createdTime"/> | ||
19 | + <result column="modified_time" property="modifiedTime"/> | ||
20 | + </resultMap> | ||
21 | + | ||
22 | + <insert id="insertCategory" parameterType="com.diligrp.assistant.product.model.Category" useGeneratedKeys="true" keyProperty="id" keyColumn="id"> | ||
23 | + INSERT INTO product_category(`parent_id`, `name`, `alias`, `level`, `py_code`, `short_code`, `path`, `icon`, `state`, `version`, `created_time`, `modified_time`) | ||
24 | + VALUES (#{parentId}, #{name}, #{alias}, #{level}, #{pyCode}, #{shortCode}, #{path}, #{icon}, #{state}, #{version}, #{createdTime}, #{modifiedTime}) | ||
25 | + </insert> | ||
26 | + | ||
27 | + <update id="updateCategory" parameterType="com.diligrp.assistant.product.model.Category"> | ||
28 | + UPDATE product_category SET version = version + 1 | ||
29 | + <if test="name != null"> | ||
30 | + , name = #{name} | ||
31 | + </if> | ||
32 | + <if test="alias != null"> | ||
33 | + , alias = #{alias} | ||
34 | + </if> | ||
35 | + <if test="pyCode != null"> | ||
36 | + , py_code = #{pyCode} | ||
37 | + </if> | ||
38 | + <if test="shortCode != null"> | ||
39 | + , short_code = #{shortCode} | ||
40 | + </if> | ||
41 | + <if test="path != null"> | ||
42 | + , path = #{path} | ||
43 | + </if> | ||
44 | + <if test="icon != null"> | ||
45 | + , icon = #{icon} | ||
46 | + </if> | ||
47 | + <if test="state != null"> | ||
48 | + , state = #{state} | ||
49 | + </if> | ||
50 | + <if test="modifiedTime != null"> | ||
51 | + , modified_time = #{modifiedTime} | ||
52 | + </if> | ||
53 | + WHERE id = #{id} | ||
54 | + </update> | ||
55 | + | ||
56 | + <select id="findCategoryById" parameterType="long" resultMap="CategoryMap"> | ||
57 | + SELECT * FROM product_category WHERE id = #{id} AND state > 0 | ||
58 | + </select> | ||
59 | + | ||
60 | + <select id="findParentCategoryById" parameterType="long" resultMap="CategoryMap"> | ||
61 | + SELECT | ||
62 | + parent.* | ||
63 | + FROM product_category self | ||
64 | + INNER JOIN product_category parent ON self.parent_id = parent.id | ||
65 | + WHERE self.id = #{id} AND self.state > 0 | ||
66 | + </select> | ||
67 | + | ||
68 | + <select id="findCategoriesByIds" resultMap="CategoryMap"> | ||
69 | + SELECT * FROM product_category WHERE id IN | ||
70 | + <foreach item="id" collection="list" open="(" separator="," close=")"> | ||
71 | + #{id} | ||
72 | + </foreach> | ||
73 | + AND state > 0 ORDER BY level DESC, id | ||
74 | + </select> | ||
75 | + | ||
76 | + <select id="listChildrenById" parameterType="com.diligrp.assistant.product.domain.CategoryPageQuery" resultMap="CategoryMap"> | ||
77 | + SELECT * FROM product_category WHERE parent_Id = #{id} AND state > 0 | ||
78 | + ORDER BY ID LIMIT #{start}, #{limit} | ||
79 | + </select> | ||
80 | + | ||
81 | + <select id="countChildrenById" parameterType="long" resultType="long"> | ||
82 | + SELECT COUNT(*) FROM product_category WHERE parent_Id = #{id} AND state > 0 | ||
83 | + </select> | ||
84 | + | ||
85 | + <select id="listCategoriesByLevel" parameterType="com.diligrp.assistant.product.domain.CategoryPageQuery" resultMap="CategoryMap"> | ||
86 | + SELECT * FROM product_category WHERE level = #{level} AND state > 0 | ||
87 | + ORDER BY ID LIMIT #{start}, #{limit} | ||
88 | + </select> | ||
89 | +</mapper> |
assistant-shared/build.gradle
0 → 100644
1 | +++ a/assistant-shared/build.gradle | ||
1 | + group = 'com.diligrp' | ||
2 | +archivesBaseName = 'assistant-shared' | ||
3 | + | ||
4 | +dependencies { | ||
5 | +// api 'org.springframework.boot:spring-boot-starter-data-mongodb' | ||
6 | + api 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.2' | ||
7 | + api 'org.springframework.boot:spring-boot-starter-data-redis' | ||
8 | + //api 'org.redisson:redisson-spring-boot-starter:3.23.1' | ||
9 | + api 'org.springframework.boot:spring-boot-starter-amqp' | ||
10 | + api 'org.springframework.cloud:spring-cloud-starter-loadbalancer' | ||
11 | + api 'org.springframework.cloud:spring-cloud-starter-openfeign' | ||
12 | + api 'com.github.ben-manes.caffeine:caffeine:3.1.8' | ||
13 | + | ||
14 | + runtimeOnly 'mysql:mysql-connector-java:8.0.33' | ||
15 | +} | ||
0 | \ No newline at end of file | 16 | \ No newline at end of file |
assistant-shared/src/main/java/com/diligrp/assistant/shared/Constants.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/Constants.java | ||
1 | +package com.diligrp.assistant.shared; | ||
2 | + | ||
3 | +public final class Constants { | ||
4 | + public static final String SIGN_ALGORITHM = "SHA1WithRSA"; | ||
5 | + | ||
6 | + public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; | ||
7 | + | ||
8 | + public static final String DATE_FORMAT = "yyyy-MM-dd"; | ||
9 | + | ||
10 | + public static final String TIME_FORMAT = "HH:mm:ss"; | ||
11 | + | ||
12 | + public static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() + 1; | ||
13 | + | ||
14 | + public static final int MAX_POOL_SIZE = 200; | ||
15 | +} | ||
0 | \ No newline at end of file | 16 | \ No newline at end of file |
assistant-shared/src/main/java/com/diligrp/assistant/shared/ErrorCode.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/ErrorCode.java | ||
1 | +package com.diligrp.assistant.shared; | ||
2 | + | ||
3 | +/** | ||
4 | + * 系统错误码列表 - 错误码前三位用于区分模块 | ||
5 | + */ | ||
6 | +public class ErrorCode { | ||
7 | + // 系统未知异常 | ||
8 | + public static final int SYSTEM_UNKNOWN_ERROR = 100000; | ||
9 | + // 无效参数错误 | ||
10 | + public static final int ILLEGAL_ARGUMENT_ERROR = 100001; | ||
11 | + // 访问未授权 | ||
12 | + public static final int UNAUTHORIZED_ACCESS_ERROR = 100002; | ||
13 | + // 操作不允许 | ||
14 | + public static final int OPERATION_NOT_ALLOWED = 100003; | ||
15 | + // 对象不存在 | ||
16 | + public static final int OBJECT_NOT_FOUND = 100004; | ||
17 | + // 对象已存在 | ||
18 | + public static final int OBJECT_ALREADY_EXISTS = 100005; | ||
19 | + // 远程服务访问错误 | ||
20 | + public static final int SERVICE_ACCESS_ERROR = 101000; | ||
21 | + | ||
22 | + public static final String MESSAGE_UNKNOWN_ERROR = "基础服务系统未知异常,请联系管理员"; | ||
23 | + | ||
24 | + public static final String MESSAGE_ACCESS_DENIED = "未授权的系统访问"; | ||
25 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/SharedConfiguration.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/SharedConfiguration.java | ||
1 | +package com.diligrp.assistant.shared; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.exception.PlatformServiceException; | ||
4 | +import com.diligrp.assistant.shared.security.RsaCipher; | ||
5 | +import com.diligrp.assistant.shared.util.JsonUtils; | ||
6 | +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; | ||
7 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | ||
8 | +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; | ||
9 | +import org.springframework.boot.context.properties.ConfigurationPropertiesBinding; | ||
10 | +import org.springframework.context.annotation.Bean; | ||
11 | +import org.springframework.context.annotation.ComponentScan; | ||
12 | +import org.springframework.context.annotation.Configuration; | ||
13 | +import org.springframework.core.convert.converter.Converter; | ||
14 | +import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
15 | +import org.springframework.data.redis.core.RedisTemplate; | ||
16 | +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; | ||
17 | +import org.springframework.data.redis.serializer.StringRedisSerializer; | ||
18 | +import org.springframework.stereotype.Component; | ||
19 | +import org.springframework.util.StringUtils; | ||
20 | + | ||
21 | +import java.security.PrivateKey; | ||
22 | +import java.security.PublicKey; | ||
23 | +import java.text.SimpleDateFormat; | ||
24 | +import java.time.LocalDate; | ||
25 | +import java.time.LocalDateTime; | ||
26 | +import java.time.LocalTime; | ||
27 | +import java.time.format.DateTimeFormatter; | ||
28 | +import java.util.Date; | ||
29 | + | ||
30 | +@Configuration | ||
31 | +@ComponentScan("com.diligrp.assistant.shared") | ||
32 | +public class SharedConfiguration { | ||
33 | + @Bean | ||
34 | + public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { | ||
35 | + RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); | ||
36 | + template.setConnectionFactory(factory); | ||
37 | + template.setKeySerializer(new StringRedisSerializer()); | ||
38 | + template.setHashKeySerializer(new StringRedisSerializer()); | ||
39 | + template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); | ||
40 | + template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); | ||
41 | + template.afterPropertiesSet(); | ||
42 | + return template; | ||
43 | + } | ||
44 | + | ||
45 | + // Jackson DataBinding所有配置 | ||
46 | + @Bean | ||
47 | + @ConditionalOnClass(JavaTimeModule.class) | ||
48 | + public Jackson2ObjectMapperBuilderCustomizer customizeJacksonConfig() { | ||
49 | + return JsonUtils::initObjectMapperBuilder; | ||
50 | + } | ||
51 | + | ||
52 | + @Bean | ||
53 | + public Converter<String, LocalDateTime> localDateTimeConverter() { | ||
54 | + // 不能使用lambda表达式,否则导致springboot启动问题 | ||
55 | + return new Converter<String, LocalDateTime>() { | ||
56 | + @Override | ||
57 | + public LocalDateTime convert(String source) { | ||
58 | + try { | ||
59 | + return StringUtils.hasText(source) ? LocalDateTime.parse(source, DateTimeFormatter.ofPattern(Constants.DATE_TIME_FORMAT)) : null; | ||
60 | + } catch (Exception ex) { | ||
61 | + throw new IllegalArgumentException(String.format("Error parse %s to LocalDateTime", source), ex); | ||
62 | + } | ||
63 | + } | ||
64 | + }; | ||
65 | + } | ||
66 | + | ||
67 | + @Bean | ||
68 | + public Converter<String, LocalDate> localDateConverter() { | ||
69 | + // 不能使用lambda表达式,否则导致springboot启动问题 | ||
70 | + return new Converter<String, LocalDate>() { | ||
71 | + @Override | ||
72 | + public LocalDate convert(String source) { | ||
73 | + try { | ||
74 | + return StringUtils.hasText(source) ? LocalDate.parse(source, DateTimeFormatter.ofPattern(Constants.DATE_FORMAT)) : null; | ||
75 | + } catch (Exception ex) { | ||
76 | + throw new IllegalArgumentException(String.format("Error parse %s to LocalDate", source), ex); | ||
77 | + } | ||
78 | + } | ||
79 | + }; | ||
80 | + } | ||
81 | + | ||
82 | + @Bean | ||
83 | + public Converter<String, LocalTime> localTimeConverter() { | ||
84 | + // 不能使用lambda表达式,否则导致springboot启动问题 | ||
85 | + return new Converter<String, LocalTime>() { | ||
86 | + @Override | ||
87 | + public LocalTime convert(String source) { | ||
88 | + try { | ||
89 | + return StringUtils.hasText(source) ? LocalTime.parse(source, DateTimeFormatter.ofPattern(Constants.TIME_FORMAT)) : null; | ||
90 | + } catch (Exception ex) { | ||
91 | + throw new IllegalArgumentException(String.format("Error parse %s to LocalTime", source), ex); | ||
92 | + } | ||
93 | + } | ||
94 | + }; | ||
95 | + } | ||
96 | + | ||
97 | + @Bean | ||
98 | + public Converter<String, Date> dateConverter() { | ||
99 | + // 不能使用lambda表达式,否则导致springboot启动问题 | ||
100 | + return new Converter<String, Date>() { | ||
101 | + @Override | ||
102 | + public Date convert(String source) { | ||
103 | + try { | ||
104 | + return StringUtils.hasText(source) ? new SimpleDateFormat(Constants.DATE_TIME_FORMAT).parse(source) : null; | ||
105 | + } catch (Exception ex) { | ||
106 | + throw new IllegalArgumentException(String.format("Error parse %s to Date", source), ex); | ||
107 | + } | ||
108 | + } | ||
109 | + }; | ||
110 | + } | ||
111 | + | ||
112 | + @Component | ||
113 | + @ConfigurationPropertiesBinding | ||
114 | + public class PrivateKeyConverter implements Converter<String, PrivateKey> { | ||
115 | + @Override | ||
116 | + public PrivateKey convert(String source) { | ||
117 | + try { | ||
118 | + return RsaCipher.getPrivateKey(source); | ||
119 | + } catch (Exception ex) { | ||
120 | + throw new PlatformServiceException("privateKey configuration failed", ex); | ||
121 | + } | ||
122 | + } | ||
123 | + } | ||
124 | + | ||
125 | + @Component | ||
126 | + @ConfigurationPropertiesBinding | ||
127 | + public class PublicKeyConverter implements Converter<String, PublicKey> { | ||
128 | + @Override | ||
129 | + public PublicKey convert(String source) { | ||
130 | + try { | ||
131 | + return RsaCipher.getPublicKey(source); | ||
132 | + } catch (Exception ex) { | ||
133 | + throw new PlatformServiceException("publicKey configuration failed", ex); | ||
134 | + } | ||
135 | + } | ||
136 | + } | ||
137 | +} | ||
0 | \ No newline at end of file | 138 | \ No newline at end of file |
assistant-shared/src/main/java/com/diligrp/assistant/shared/codec/ByteDecoder.java
0 → 100644
assistant-shared/src/main/java/com/diligrp/assistant/shared/codec/ByteEncoder.java
0 → 100644
assistant-shared/src/main/java/com/diligrp/assistant/shared/codec/StringCodec.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/codec/StringCodec.java | ||
1 | +package com.diligrp.assistant.shared.codec; | ||
2 | + | ||
3 | +import java.nio.charset.StandardCharsets; | ||
4 | + | ||
5 | +public final class StringCodec { | ||
6 | + public static ByteEncoder<String> getEncoder() { | ||
7 | + return StringEncoder.INSTANCE; | ||
8 | + } | ||
9 | + | ||
10 | + public static ByteDecoder<String> getDecoder() { | ||
11 | + return StringDecoder.INSTANCE; | ||
12 | + } | ||
13 | + | ||
14 | + static class StringEncoder implements ByteEncoder<String> { | ||
15 | + | ||
16 | + static final ByteEncoder<String> INSTANCE = new StringEncoder(); | ||
17 | + | ||
18 | + @Override | ||
19 | + public byte[] encode(String payload) { | ||
20 | + return payload.getBytes(StandardCharsets.UTF_8); | ||
21 | + } | ||
22 | + } | ||
23 | + | ||
24 | + static class StringDecoder implements ByteDecoder<String> { | ||
25 | + | ||
26 | + static final ByteDecoder<String> INSTANCE = new StringDecoder(); | ||
27 | + | ||
28 | + @Override | ||
29 | + public String decode(byte[] payload) { | ||
30 | + return new String(payload, StandardCharsets.UTF_8); | ||
31 | + } | ||
32 | + } | ||
33 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/AsyncMessage.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/AsyncMessage.java | ||
1 | +package com.diligrp.assistant.shared.domain; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.util.JsonUtils; | ||
4 | + | ||
5 | +/** | ||
6 | + * MQ异步消息模型 | ||
7 | + */ | ||
8 | +public class AsyncMessage { | ||
9 | + // 消息类型 | ||
10 | + private Integer type; | ||
11 | + // 消息体 | ||
12 | + private String payload; | ||
13 | + // 消息参数 | ||
14 | + private String params; | ||
15 | + | ||
16 | + public static AsyncMessage of(Integer type, String payload, String params) { | ||
17 | + AsyncMessage message = new AsyncMessage(); | ||
18 | + message.type = type; | ||
19 | + message.payload = payload; | ||
20 | + message.params = params; | ||
21 | + return message; | ||
22 | + } | ||
23 | + | ||
24 | + public static AsyncMessage from(String message) { | ||
25 | + return JsonUtils.fromJsonString(message, AsyncMessage.class); | ||
26 | + } | ||
27 | + | ||
28 | + public Integer getType() { | ||
29 | + return type; | ||
30 | + } | ||
31 | + | ||
32 | + public String getPayload() { | ||
33 | + return payload; | ||
34 | + } | ||
35 | + | ||
36 | + public String getParams() { | ||
37 | + return params; | ||
38 | + } | ||
39 | + | ||
40 | + public String toString() { | ||
41 | + return JsonUtils.toJsonString(this); | ||
42 | + } | ||
43 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/BaseDo.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/BaseDo.java | ||
1 | +package com.diligrp.assistant.shared.domain; | ||
2 | + | ||
3 | +import java.time.LocalDateTime; | ||
4 | + | ||
5 | +public class BaseDo { | ||
6 | + // 数据库主键 | ||
7 | + protected Long id; | ||
8 | + // 数据版本 | ||
9 | + protected Integer version; | ||
10 | + // 创建时间 | ||
11 | + protected LocalDateTime createdTime; | ||
12 | + // 修改时间 | ||
13 | + protected LocalDateTime modifiedTime; | ||
14 | + | ||
15 | + public Long getId() { | ||
16 | + return id; | ||
17 | + } | ||
18 | + | ||
19 | + public void setId(Long id) { | ||
20 | + this.id = id; | ||
21 | + } | ||
22 | + | ||
23 | + public Integer getVersion() { | ||
24 | + return version; | ||
25 | + } | ||
26 | + | ||
27 | + public void setVersion(Integer version) { | ||
28 | + this.version = version; | ||
29 | + } | ||
30 | + | ||
31 | + public LocalDateTime getCreatedTime() { | ||
32 | + return createdTime; | ||
33 | + } | ||
34 | + | ||
35 | + public void setCreatedTime(LocalDateTime createdTime) { | ||
36 | + this.createdTime = createdTime; | ||
37 | + } | ||
38 | + | ||
39 | + public LocalDateTime getModifiedTime() { | ||
40 | + return modifiedTime; | ||
41 | + } | ||
42 | + | ||
43 | + public void setModifiedTime(LocalDateTime modifiedTime) { | ||
44 | + this.modifiedTime = modifiedTime; | ||
45 | + } | ||
46 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/ContainerSupport.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/ContainerSupport.java | ||
1 | +package com.diligrp.assistant.shared.domain; | ||
2 | + | ||
3 | +import java.util.HashMap; | ||
4 | +import java.util.List; | ||
5 | +import java.util.Optional; | ||
6 | + | ||
7 | +public abstract class ContainerSupport extends HashMap<String, Object> { | ||
8 | + public ContainerSupport attach(Object object) { | ||
9 | + put(object.getClass().getName(), object); | ||
10 | + return this; | ||
11 | + } | ||
12 | + | ||
13 | + public ContainerSupport attach(String key, Object object) { | ||
14 | + put(key, object); | ||
15 | + return this; | ||
16 | + } | ||
17 | + | ||
18 | + public Long getLong(String param) { | ||
19 | + Object value = get(param); | ||
20 | + if (value != null) { | ||
21 | + return value instanceof Long ? (Long)value : Long.parseLong(value.toString()); | ||
22 | + } | ||
23 | + return null; | ||
24 | + } | ||
25 | + | ||
26 | + public Integer getInteger(String param) { | ||
27 | + Object value = get(param); | ||
28 | + if (value != null) { | ||
29 | + return value instanceof Integer ? (Integer)value : Integer.parseInt(value.toString()); | ||
30 | + } | ||
31 | + return null; | ||
32 | + } | ||
33 | + | ||
34 | + public String getString(String param) { | ||
35 | + Object value = get(param); | ||
36 | + return value != null ? value.toString() : null; | ||
37 | + } | ||
38 | + | ||
39 | + public <T> T getObject(String param, Class<T> type) { | ||
40 | + Object value = get(param); | ||
41 | + return value == null ? null : type.cast(value); | ||
42 | + } | ||
43 | + | ||
44 | + public <T> T getObject(Class<T> type) { | ||
45 | + Object value = get(type.getName()); | ||
46 | + return value == null ? null : type.cast(value); | ||
47 | + } | ||
48 | + | ||
49 | + @SuppressWarnings("unchecked") | ||
50 | + public <T> Optional<T> getObject(String param) { | ||
51 | + Object value = get(param); | ||
52 | + return Optional.ofNullable ((T) value); | ||
53 | + } | ||
54 | + | ||
55 | + @SuppressWarnings("unchecked") | ||
56 | + public <T> Optional<List<T>> getObjects(String param) { | ||
57 | + Object value = get(param); | ||
58 | + return Optional.ofNullable ((List<T>) value); | ||
59 | + } | ||
60 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/Message.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/Message.java | ||
1 | +package com.diligrp.assistant.shared.domain; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.ErrorCode; | ||
4 | + | ||
5 | +public class Message<T> { | ||
6 | + protected static final int CODE_SUCCESS = 200; | ||
7 | + protected static final int CODE_FAILURE = ErrorCode.SYSTEM_UNKNOWN_ERROR; | ||
8 | + protected static final String MSG_SUCCESS = "success"; | ||
9 | + | ||
10 | + private Integer code; | ||
11 | + private String message; | ||
12 | + private T data; | ||
13 | + | ||
14 | + public Message() { | ||
15 | + } | ||
16 | + | ||
17 | + public Integer getCode() { | ||
18 | + return this.code; | ||
19 | + } | ||
20 | + | ||
21 | + public void setCode(Integer code) { | ||
22 | + this.code = code; | ||
23 | + } | ||
24 | + | ||
25 | + public String getMessage() { | ||
26 | + return this.message; | ||
27 | + } | ||
28 | + | ||
29 | + public void setMessage(String message) { | ||
30 | + this.message = message; | ||
31 | + } | ||
32 | + | ||
33 | + public T getData() { | ||
34 | + return this.data; | ||
35 | + } | ||
36 | + | ||
37 | + public void setData(T data) { | ||
38 | + this.data = data; | ||
39 | + } | ||
40 | + | ||
41 | + public static Message<?> success() { | ||
42 | + Message<?> result = new Message(); | ||
43 | + result.code = 200; | ||
44 | + result.message = "success"; | ||
45 | + return result; | ||
46 | + } | ||
47 | + | ||
48 | + public static <E> Message<E> success(E data) { | ||
49 | + Message<E> result = new Message(); | ||
50 | + result.code = 200; | ||
51 | + result.data = data; | ||
52 | + result.message = "success"; | ||
53 | + return result; | ||
54 | + } | ||
55 | + | ||
56 | + public static Message<?> failure(String message) { | ||
57 | + Message<?> result = new Message(); | ||
58 | + result.code = 1000; | ||
59 | + result.message = message; | ||
60 | + return result; | ||
61 | + } | ||
62 | + | ||
63 | + public static Message<?> failure(int code, String message) { | ||
64 | + Message<?> result = new Message(); | ||
65 | + result.code = code; | ||
66 | + result.message = message; | ||
67 | + return result; | ||
68 | + } | ||
69 | +} | ||
0 | \ No newline at end of file | 70 | \ No newline at end of file |
assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/PageMessage.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/PageMessage.java | ||
1 | +package com.diligrp.assistant.shared.domain; | ||
2 | + | ||
3 | +import java.util.List; | ||
4 | + | ||
5 | +/** | ||
6 | + * 分页数据模型 | ||
7 | + */ | ||
8 | +public class PageMessage<E> extends Message<List<E>>{ | ||
9 | + // 总记录数 | ||
10 | + private long total; | ||
11 | + | ||
12 | + public long getTotal() { | ||
13 | + return total; | ||
14 | + } | ||
15 | + | ||
16 | + public void setTotal(long total) { | ||
17 | + this.total = total; | ||
18 | + } | ||
19 | + | ||
20 | + public static <T> PageMessage<T> success(long total, List<T> data) { | ||
21 | + PageMessage<T> page = new PageMessage<>(); | ||
22 | + page.setCode(CODE_SUCCESS); | ||
23 | + page.setTotal(total); | ||
24 | + page.setData(data); | ||
25 | + page.setMessage(MSG_SUCCESS); | ||
26 | + return page; | ||
27 | + } | ||
28 | + | ||
29 | + public static PageMessage<?> failure(String message) { | ||
30 | + PageMessage<?> page = new PageMessage<>(); | ||
31 | + page.setCode(CODE_FAILURE); | ||
32 | + page.setTotal(0); | ||
33 | + page.setData(null); | ||
34 | + page.setMessage(message); | ||
35 | + return page; | ||
36 | + } | ||
37 | + | ||
38 | + public static PageMessage<?> failure(int code, String message) { | ||
39 | + PageMessage<?> page = new PageMessage<>(); | ||
40 | + page.setCode(code); | ||
41 | + page.setTotal(0); | ||
42 | + page.setData(null); | ||
43 | + page.setMessage(message); | ||
44 | + return page; | ||
45 | + } | ||
46 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/PageQuery.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/domain/PageQuery.java | ||
1 | +package com.diligrp.assistant.shared.domain; | ||
2 | + | ||
3 | +/** | ||
4 | + * 分页查询领域模型 | ||
5 | + */ | ||
6 | +public class PageQuery { | ||
7 | + // 起始行下标 | ||
8 | + protected Integer start; | ||
9 | + // 获取的记录行数 | ||
10 | + protected Integer limit; | ||
11 | + | ||
12 | + public Integer getStart() { | ||
13 | + return start; | ||
14 | + } | ||
15 | + | ||
16 | + public void setStart(Integer start) { | ||
17 | + this.start = start; | ||
18 | + } | ||
19 | + | ||
20 | + public Integer getLimit() { | ||
21 | + return limit; | ||
22 | + } | ||
23 | + | ||
24 | + public void setLimit(Integer limit) { | ||
25 | + this.limit = limit; | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * 通过页号、每页记录数计算起始行下标 | ||
30 | + */ | ||
31 | + public void from(int pageNo, int pageSize) { | ||
32 | + this.start = (pageNo - 1) * pageSize; | ||
33 | + this.limit = pageSize; | ||
34 | + } | ||
35 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/exception/DefaultExceptionHandler.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/exception/DefaultExceptionHandler.java | ||
1 | +package com.diligrp.assistant.shared.exception; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.domain.Message; | ||
4 | +import com.diligrp.assistant.shared.ErrorCode; | ||
5 | +import org.slf4j.Logger; | ||
6 | +import org.slf4j.LoggerFactory; | ||
7 | +import org.springframework.web.bind.annotation.ExceptionHandler; | ||
8 | +import org.springframework.web.bind.annotation.RestControllerAdvice; | ||
9 | + | ||
10 | +@RestControllerAdvice | ||
11 | +public class DefaultExceptionHandler { | ||
12 | + private final Logger LOG = LoggerFactory.getLogger(this.getClass()); | ||
13 | + | ||
14 | + @ExceptionHandler(PlatformServiceException.class) | ||
15 | + public Message<?> platformServiceException(PlatformServiceException ex) { | ||
16 | + LOG.warn("assistant platform service exception", ex); | ||
17 | + return Message.failure(ex.getCode(), ex.getMessage()); | ||
18 | + } | ||
19 | + | ||
20 | + @ExceptionHandler(IllegalArgumentException.class) | ||
21 | + public Message<?> illegalArgumentException(IllegalArgumentException ex) { | ||
22 | + LOG.warn("assistant platform service exception", ex); | ||
23 | + return Message.failure(ErrorCode.ILLEGAL_ARGUMENT_ERROR, ex.getMessage()); | ||
24 | + } | ||
25 | + | ||
26 | + @ExceptionHandler(Exception.class) | ||
27 | + public Message<?> defaultExceptionHandler(Exception ex) { | ||
28 | + LOG.warn("assistant platform service exception", ex); | ||
29 | + return Message.failure(ErrorCode.SYSTEM_UNKNOWN_ERROR, ErrorCode.MESSAGE_UNKNOWN_ERROR); | ||
30 | + } | ||
31 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/exception/PlatformServiceException.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/exception/PlatformServiceException.java | ||
1 | +package com.diligrp.assistant.shared.exception; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.ErrorCode; | ||
4 | + | ||
5 | +/** | ||
6 | + * 所有模块异常类的基类 | ||
7 | + */ | ||
8 | +public class PlatformServiceException extends RuntimeException { | ||
9 | + /** | ||
10 | + * 错误码 | ||
11 | + */ | ||
12 | + private int code = ErrorCode.SYSTEM_UNKNOWN_ERROR; | ||
13 | + | ||
14 | + /** | ||
15 | + * 是否打印异常栈 | ||
16 | + */ | ||
17 | + private boolean stackTrace = true; | ||
18 | + | ||
19 | + public PlatformServiceException(String message) { | ||
20 | + super(message); | ||
21 | + } | ||
22 | + | ||
23 | + public PlatformServiceException(int code, String message) { | ||
24 | + super(message); | ||
25 | + this.code = code; | ||
26 | + this.stackTrace = false; | ||
27 | + } | ||
28 | + | ||
29 | + public PlatformServiceException(String message, Throwable ex) { | ||
30 | + super(message, ex); | ||
31 | + } | ||
32 | + | ||
33 | + @Override | ||
34 | + public Throwable fillInStackTrace() { | ||
35 | + return stackTrace ? super.fillInStackTrace() : this; | ||
36 | + } | ||
37 | + | ||
38 | + public int getCode() { | ||
39 | + return code; | ||
40 | + } | ||
41 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/exception/ServiceAccessException.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/exception/ServiceAccessException.java | ||
1 | +package com.diligrp.assistant.shared.exception; | ||
2 | + | ||
3 | +/** | ||
4 | + * 远程服务访问异常 | ||
5 | + */ | ||
6 | +public class ServiceAccessException extends PlatformServiceException { | ||
7 | + public ServiceAccessException(String message) { | ||
8 | + super(message); | ||
9 | + } | ||
10 | + | ||
11 | + public ServiceAccessException(int code, String message) { | ||
12 | + super(code, message); | ||
13 | + } | ||
14 | + | ||
15 | + public ServiceAccessException(String message, Throwable ex) { | ||
16 | + super(message, ex); | ||
17 | + } | ||
18 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/exception/ServiceConnectException.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/exception/ServiceConnectException.java | ||
1 | +package com.diligrp.assistant.shared.exception; | ||
2 | + | ||
3 | +/** | ||
4 | + * 远程服务连接异常 | ||
5 | + */ | ||
6 | +public class ServiceConnectException extends ServiceAccessException { | ||
7 | + | ||
8 | + public ServiceConnectException(String message) { | ||
9 | + super(message); | ||
10 | + } | ||
11 | + | ||
12 | + public ServiceConnectException(int code, String message) { | ||
13 | + super(code, message); | ||
14 | + } | ||
15 | + | ||
16 | + public ServiceConnectException(String message, Throwable ex) { | ||
17 | + super(message, ex); | ||
18 | + } | ||
19 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/exception/ServiceTimeoutException.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/exception/ServiceTimeoutException.java | ||
1 | +package com.diligrp.assistant.shared.exception; | ||
2 | + | ||
3 | +/** | ||
4 | + * 远程服务访问超时异常 | ||
5 | + */ | ||
6 | +public class ServiceTimeoutException extends ServiceAccessException { | ||
7 | + | ||
8 | + public ServiceTimeoutException(String message) { | ||
9 | + super(message); | ||
10 | + } | ||
11 | + | ||
12 | + public ServiceTimeoutException(int code, String message) { | ||
13 | + super(code, message); | ||
14 | + } | ||
15 | + | ||
16 | + public ServiceTimeoutException(String message, Throwable ex) { | ||
17 | + super(message, ex); | ||
18 | + } | ||
19 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/mybatis/GenericEnumTypeHandler.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/mybatis/GenericEnumTypeHandler.java | ||
1 | +package com.diligrp.assistant.shared.mybatis; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.type.IEnumType; | ||
4 | +import org.apache.ibatis.type.BaseTypeHandler; | ||
5 | +import org.apache.ibatis.type.JdbcType; | ||
6 | + | ||
7 | +import java.sql.CallableStatement; | ||
8 | +import java.sql.PreparedStatement; | ||
9 | +import java.sql.ResultSet; | ||
10 | +import java.sql.SQLException; | ||
11 | +import java.util.Arrays; | ||
12 | + | ||
13 | +public class GenericEnumTypeHandler<E extends IEnumType> extends BaseTypeHandler<E> { | ||
14 | + private final E[] enums; | ||
15 | + | ||
16 | + public GenericEnumTypeHandler(Class<E> type) { | ||
17 | + if (type == null) { | ||
18 | + throw new IllegalArgumentException("Type argument cannot be null"); | ||
19 | + } else { | ||
20 | + this.enums = type.getEnumConstants(); | ||
21 | + if (this.enums == null) { | ||
22 | + throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type."); | ||
23 | + } | ||
24 | + } | ||
25 | + } | ||
26 | + | ||
27 | + @Override | ||
28 | + public void setNonNullParameter(PreparedStatement preparedStatement, int i, E e, JdbcType jdbcType) throws SQLException { | ||
29 | + preparedStatement.setInt(i, e.getCode()); | ||
30 | + } | ||
31 | + | ||
32 | + @Override | ||
33 | + public E getNullableResult(ResultSet resultSet, String columnName) throws SQLException { | ||
34 | + int code = resultSet.getInt(columnName); | ||
35 | + if (resultSet.wasNull()) { | ||
36 | + return null; | ||
37 | + } else { | ||
38 | + return getEnumType(code); | ||
39 | + } | ||
40 | + } | ||
41 | + | ||
42 | + @Override | ||
43 | + public E getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException { | ||
44 | + int code = resultSet.getInt(columnIndex); | ||
45 | + if (resultSet.wasNull()) { | ||
46 | + return null; | ||
47 | + } else { | ||
48 | + return getEnumType(code); | ||
49 | + } | ||
50 | + } | ||
51 | + | ||
52 | + @Override | ||
53 | + public E getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException { | ||
54 | + int code = callableStatement.getInt(columnIndex); | ||
55 | + if (callableStatement.wasNull()) { | ||
56 | + return null; | ||
57 | + } else { | ||
58 | + return getEnumType(code); | ||
59 | + } | ||
60 | + } | ||
61 | + | ||
62 | + private E getEnumType(int code) { | ||
63 | + return Arrays.stream(enums).filter(item -> item.getCode() == code).findFirst().orElse(null); | ||
64 | + } | ||
65 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/mybatis/MybatisMapperSupport.java
0 → 100644
assistant-shared/src/main/java/com/diligrp/assistant/shared/security/AesCipher.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/security/AesCipher.java | ||
1 | +package com.diligrp.assistant.shared.security; | ||
2 | + | ||
3 | +import javax.crypto.Cipher; | ||
4 | +import javax.crypto.KeyGenerator; | ||
5 | +import javax.crypto.SecretKey; | ||
6 | +import javax.crypto.spec.SecretKeySpec; | ||
7 | +import java.security.Key; | ||
8 | +import java.util.Base64; | ||
9 | + | ||
10 | +/** | ||
11 | + * AES算法工具类 | ||
12 | + */ | ||
13 | +public class AesCipher { | ||
14 | + private static final String KEY_ALGORITHM = "AES"; | ||
15 | + | ||
16 | + private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding"; | ||
17 | + | ||
18 | + public static String generateSecretKey() throws Exception { | ||
19 | + KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM); | ||
20 | + keyGenerator.init(128); | ||
21 | + | ||
22 | + SecretKey secretKey = keyGenerator.generateKey(); | ||
23 | + return Base64.getEncoder().encodeToString(secretKey.getEncoded()); | ||
24 | + } | ||
25 | + | ||
26 | + public static byte[] encrypt(byte[] data, String secretKey) throws Exception { | ||
27 | + Key key = toKey(secretKey); | ||
28 | + Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); | ||
29 | + cipher.init(Cipher.ENCRYPT_MODE, key); | ||
30 | + | ||
31 | + return cipher.doFinal(data); | ||
32 | + } | ||
33 | + | ||
34 | + public static byte[] decrypt(byte[] data, String secretKey) throws Exception { | ||
35 | + Key key = toKey(secretKey); | ||
36 | + Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); | ||
37 | + cipher.init(Cipher.DECRYPT_MODE, key); | ||
38 | + | ||
39 | + return cipher.doFinal(data); | ||
40 | + } | ||
41 | + | ||
42 | + private static Key toKey(String secretKey) { | ||
43 | + byte[] key = Base64.getDecoder().decode(secretKey); | ||
44 | + return new SecretKeySpec(key, KEY_ALGORITHM); | ||
45 | + } | ||
46 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/security/HexUtils.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/security/HexUtils.java | ||
1 | +package com.diligrp.assistant.shared.security; | ||
2 | + | ||
3 | +/** | ||
4 | + * 字节数组与十六进制字符串转化工具类 | ||
5 | + */ | ||
6 | +public class HexUtils { | ||
7 | + | ||
8 | + private static final int GUARD_CHAR = 0x01; | ||
9 | + | ||
10 | + private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', | ||
11 | + '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; | ||
12 | + | ||
13 | + private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', | ||
14 | + '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; | ||
15 | + | ||
16 | + public static char[] encodeHex(byte[] data) { | ||
17 | + return encodeHex(data, true); | ||
18 | + } | ||
19 | + | ||
20 | + public static char[] encodeHex(byte[] data, boolean toLowerCase) { | ||
21 | + return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); | ||
22 | + } | ||
23 | + | ||
24 | + public static String encodeHexStr(byte[] data) { | ||
25 | + return encodeHexStr(data, true); | ||
26 | + } | ||
27 | + | ||
28 | + public static String encodeHexStr(byte[] data, boolean toLowerCase) { | ||
29 | + return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); | ||
30 | + } | ||
31 | + | ||
32 | + public static byte[] decodeHex(String data) { | ||
33 | + return decodeHex(data.toCharArray()); | ||
34 | + } | ||
35 | + | ||
36 | + public static byte[] decodeHex(char[] data) { | ||
37 | + int len = data.length; | ||
38 | + if ((len & GUARD_CHAR) != 0) { | ||
39 | + throw new RuntimeException("Unknown char"); | ||
40 | + } | ||
41 | + | ||
42 | + byte[] out = new byte[len >> 1]; | ||
43 | + for (int i = 0, j = 0; j < len; i++) { | ||
44 | + int f = toDigit(data[j], j) << 4; | ||
45 | + j++; | ||
46 | + f = f | toDigit(data[j], j); | ||
47 | + j++; | ||
48 | + out[i] = (byte) (f & 0xFF); | ||
49 | + } | ||
50 | + | ||
51 | + return out; | ||
52 | + } | ||
53 | + | ||
54 | + private static char[] encodeHex(byte[] data, char[] toDigits) { | ||
55 | + int l = data.length; | ||
56 | + char[] out = new char[l << 1]; | ||
57 | + for (int i = 0, j = 0; i < l; i++) { | ||
58 | + out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; | ||
59 | + out[j++] = toDigits[0x0F & data[i]]; | ||
60 | + } | ||
61 | + return out; | ||
62 | + } | ||
63 | + | ||
64 | + private static String encodeHexStr(byte[] data, char[] toDigits) { | ||
65 | + return new String(encodeHex(data, toDigits)); | ||
66 | + } | ||
67 | + | ||
68 | + private static int toDigit(char ch, int index) { | ||
69 | + int digit = Character.digit(ch, 16); | ||
70 | + if (digit == -1) { | ||
71 | + throw new RuntimeException("Invalid hex char " + ch + ", index at " + index); | ||
72 | + } | ||
73 | + return digit; | ||
74 | + } | ||
75 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/security/KeyStoreUtils.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/security/KeyStoreUtils.java | ||
1 | +package com.diligrp.assistant.shared.security; | ||
2 | + | ||
3 | +import com.diligrp.assistant.shared.util.ClassUtils; | ||
4 | + | ||
5 | +import java.io.InputStream; | ||
6 | +import java.security.KeyStore; | ||
7 | +import java.security.PrivateKey; | ||
8 | +import java.security.PublicKey; | ||
9 | +import java.security.cert.Certificate; | ||
10 | +import java.security.cert.CertificateFactory; | ||
11 | +import java.util.Base64; | ||
12 | + | ||
13 | +/** | ||
14 | + * 数字证书工具类 | ||
15 | + */ | ||
16 | +public class KeyStoreUtils { | ||
17 | + public static String getPrivateKeyStr(String keyStorePath, String storeType, String storePass, | ||
18 | + String alias, String keyPass) throws Exception { | ||
19 | + InputStream in = ClassUtils.getDefaultClassLoader().getResourceAsStream(keyStorePath); | ||
20 | + PrivateKey privateKey = getPrivateKey(in, storeType, storePass, alias, keyPass); | ||
21 | + return Base64.getEncoder().encodeToString(privateKey.getEncoded()); | ||
22 | + } | ||
23 | + | ||
24 | + public static PrivateKey getPrivateKey(String keyStorePath, String storeType, String storePass, | ||
25 | + String alias, String keyPass) throws Exception { | ||
26 | + InputStream in = ClassUtils.getDefaultClassLoader().getResourceAsStream(keyStorePath); | ||
27 | + return getPrivateKey(in, storeType, storePass, alias, keyPass); | ||
28 | + } | ||
29 | + | ||
30 | + public static PrivateKey getPrivateKey(InputStream in, String storeType, String storePass, String alias, String keyPass) throws Exception { | ||
31 | + KeyStore ks = getKeyStore(in, storeType, storePass); | ||
32 | + PrivateKey key = (PrivateKey) ks.getKey(alias, keyPass.toCharArray()); | ||
33 | + return key; | ||
34 | + } | ||
35 | + | ||
36 | + public static String getPublicKeyStr(String keyStorePath, String storeType, String storePass, String alias) throws Exception { | ||
37 | + InputStream in = ClassUtils.getDefaultClassLoader().getResourceAsStream(keyStorePath); | ||
38 | + PublicKey publicKey = getPublicKey(in, storeType, storePass, alias); | ||
39 | + return Base64.getEncoder().encodeToString(publicKey.getEncoded()); | ||
40 | + } | ||
41 | + | ||
42 | + public static PublicKey getPublicKey(String keyStorePath, String storeType, String storePass, String alias) throws Exception { | ||
43 | + InputStream in = ClassUtils.getDefaultClassLoader().getResourceAsStream(keyStorePath); | ||
44 | + return getPublicKey(in, storeType, storePass, alias); | ||
45 | + } | ||
46 | + | ||
47 | + public static PublicKey getPublicKey(InputStream in, String storeType, String storePass, String alias) throws Exception { | ||
48 | + KeyStore ks = getKeyStore(in, storeType, storePass); | ||
49 | + Certificate cert = ks.getCertificate(alias); | ||
50 | + return cert.getPublicKey(); | ||
51 | + } | ||
52 | + | ||
53 | + public static String getPublicKeyStr(String certificatePath) throws Exception { | ||
54 | + PublicKey publicKey = getPublicKey(certificatePath); | ||
55 | + return Base64.getEncoder().encodeToString(publicKey.getEncoded()); | ||
56 | + } | ||
57 | + | ||
58 | + public static PublicKey getPublicKey(String certificatePath) throws Exception { | ||
59 | + InputStream in = ClassUtils.getDefaultClassLoader().getResourceAsStream(certificatePath); | ||
60 | + Certificate x509Cert = CertificateFactory.getInstance("X509").generateCertificate(in); | ||
61 | + return x509Cert.getPublicKey(); | ||
62 | + } | ||
63 | + | ||
64 | + public static KeyStore getKeyStore(InputStream in, String storeType, String storePass) throws Exception { | ||
65 | + KeyStore ks = KeyStore.getInstance(storeType); | ||
66 | + ks.load(in, storePass.toCharArray()); | ||
67 | + in.close(); | ||
68 | + return ks; | ||
69 | + } | ||
70 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/security/Md5Cipher.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/security/Md5Cipher.java | ||
1 | +package com.diligrp.assistant.shared.security; | ||
2 | + | ||
3 | +import java.security.MessageDigest; | ||
4 | + | ||
5 | +/** | ||
6 | + * MD5算法工具类 | ||
7 | + */ | ||
8 | +public class Md5Cipher { | ||
9 | + private static final String KEY_MD5 = "MD5"; | ||
10 | + | ||
11 | + public static byte[] encrypt(byte[] data) throws Exception { | ||
12 | + MessageDigest md5 = MessageDigest.getInstance(KEY_MD5); | ||
13 | + md5.update(data); | ||
14 | + return md5.digest(); | ||
15 | + } | ||
16 | +} |
assistant-shared/src/main/java/com/diligrp/assistant/shared/security/PasswordUtils.java
0 → 100644
1 | +++ a/assistant-shared/src/main/java/com/diligrp/assistant/shared/security/PasswordUtils.java | ||
1 | +package com.diligrp.assistant.shared.security; | ||
2 | + | ||
3 | +import java.nio.charset.StandardCharsets; | ||
4 | + | ||
5 | +/** | ||
6 | + * 密码加密散列工具类 | ||
7 | + */ | ||
8 | +public class PasswordUtils { | ||
9 | + public static String generateSecretKey() { | ||
10 | + try { | ||
11 | + return AesCipher.generateSecretKey(); | ||
12 | + } catch (Exception ex) { | ||
13 | + throw new RuntimeException("Generate password secret key error", ex); | ||
14 | + } | ||
15 | + } | ||
16 | + | ||
17 | + public static String encrypt(String password, String secretKey) { | ||
18 | + try { | ||
19 | + byte[] data = password.getBytes(StandardCharsets.UTF_8); | ||
20 | + return HexUtils.encodeHexStr(ShaCipher.encrypt(AesCipher.encrypt(data, secretKey))); | ||
21 | + } catch (Exception ex) { | ||
22 | + throw new RuntimeException("Encrypt password error", ex); | ||
23 | + } | ||
24 | + } | ||
25 | +} |