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 | 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 | 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 | 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 | 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 | 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 | 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
1 | +++ a/assistant-dfs/src/main/java/com/diligrp/assistant/dfs/Constants.java | |
1 | +package com.diligrp.assistant.dfs; | |
2 | + | |
3 | +public final class Constants { | |
4 | + public static final String HEADER_AUTHORIZATION = "Dfs-Authorization"; | |
5 | + | |
6 | + public static final String FILE_METADATA_NAME = "name"; | |
7 | +} | ... | ... |
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | +} | ... | ... |