Commit 54e88191b3cb0d250ee3a3cfce65523b6f29f28c

Authored by 谢茂盛
0 parents

feat: init项目

Showing 62 changed files with 8814 additions and 0 deletions
pom.xml 0 → 100644
  1 +++ a/pom.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <parent>
  6 + <groupId>org.springframework.boot</groupId>
  7 + <artifactId>spring-boot-starter-parent</artifactId>
  8 + <version>2.2.5.RELEASE</version>
  9 + <relativePath/> <!-- lookup parent from repository -->
  10 + </parent>
  11 + <modelVersion>4.0.0</modelVersion>
  12 +
  13 + <groupId>org.canrd</groupId>
  14 + <artifactId>webmagic-canrd-service</artifactId>
  15 + <version>1.0-SNAPSHOT</version>
  16 +
  17 + <properties>
  18 + <maven-compiler-plugin>3.7.0</maven-compiler-plugin>
  19 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  20 + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  21 + <java.version>1.8</java.version>
  22 + <joda-time.version>2.9.9</joda-time.version>
  23 + <springboot.version>2.2.5.RELEASE</springboot.version>
  24 + <lombok.version>1.18.12</lombok.version>
  25 + <baomidou.version>3.4.0</baomidou.version>
  26 + <hutool-crypto.version>5.6.1</hutool-crypto.version>
  27 + <hutool-all.version>5.0.6</hutool-all.version>
  28 + <mysql-connector.version>8.0.11</mysql-connector.version>
  29 + <druid.version>1.1.23</druid.version>
  30 + <fastjson.version>1.2.28</fastjson.version>
  31 + <poi.version>3.17</poi.version>
  32 + <poi-ooxml.version>3.17</poi-ooxml.version>
  33 + <poi-excel.version>poi-317.8</poi-excel.version>
  34 + <commons-csv.version>1.6</commons-csv.version>
  35 + <commons-lang3.version>3.8.1</commons-lang3.version>
  36 + <commons-pool2.version>2.11.1</commons-pool2.version>
  37 + <ip2region.version>1.7.2</ip2region.version>
  38 + <userAgentUtils.version>1.20</userAgentUtils.version>
  39 + <swagger.version>2.9.2</swagger.version>
  40 + <swagger-annotations.version>1.5.21</swagger-annotations.version>
  41 + <swagger-models.version>1.5.21</swagger-models.version>
  42 + <guava.version>20.0</guava.version>
  43 + <easy-captcha.version>1.6.2</easy-captcha.version>
  44 + <aliyun-java-sdk-core.version>4.0.3</aliyun-java-sdk-core.version>
  45 + <aliyun-sdk-oss.version>3.15.0</aliyun-sdk-oss.version>
  46 + <thumbnailator.version>0.4.8</thumbnailator.version>
  47 + <jjwt.version>0.10.6</jjwt.version>
  48 + <easyexcel.version>2.2.3</easyexcel.version>
  49 + <webmagic.version>0.10.0</webmagic.version>
  50 + </properties>
  51 +
  52 + <dependencies>
  53 +
  54 + <dependency>
  55 + <groupId>org.springframework.boot</groupId>
  56 + <artifactId>spring-boot-starter-web</artifactId>
  57 + <version>2.2.5.RELEASE</version>
  58 + <exclusions>
  59 + <exclusion>
  60 + <groupId>org.springframework.boot</groupId>
  61 + <artifactId>spring-boot-starter-logging</artifactId>
  62 + </exclusion>
  63 + </exclusions>
  64 + </dependency>
  65 +
  66 + <!-- webmagic核心库 -->
  67 + <dependency>
  68 + <groupId>us.codecraft</groupId>
  69 + <artifactId>webmagic-core</artifactId>
  70 + <version>${webmagic.version}</version>
  71 + </dependency>
  72 +
  73 +
  74 + <!-- webmagic扩展库 -->
  75 + <dependency>
  76 + <groupId>us.codecraft</groupId>
  77 + <artifactId>webmagic-extension</artifactId>
  78 + <version>${webmagic.version}</version>
  79 + </dependency>
  80 +
  81 +
  82 + <!-- Lombok 依赖-->
  83 + <dependency>
  84 + <groupId>org.projectlombok</groupId>
  85 + <artifactId>lombok</artifactId>
  86 + <version>${lombok.version}</version>
  87 + <optional>true</optional>
  88 + </dependency>
  89 + <dependency>
  90 + <groupId>org.springframework.boot</groupId>
  91 + <artifactId>spring-boot-starter-aop</artifactId>
  92 + <version>${springboot.version}</version>
  93 + </dependency>
  94 + <dependency>
  95 + <groupId>org.springframework.boot</groupId>
  96 + <artifactId>spring-boot-starter-test</artifactId>
  97 + <version>${springboot.version}</version>
  98 + <scope>test</scope>
  99 + </dependency>
  100 +
  101 + <dependency>
  102 + <groupId>com.baomidou</groupId>
  103 + <artifactId>mybatis-plus-boot-starter</artifactId>
  104 + <version>${baomidou.version}</version>
  105 + </dependency>
  106 + <!-- <dependency>-->
  107 + <!-- <groupId>com.baomidou</groupId>-->
  108 + <!-- <artifactId>dynamic-datasource-spring-boot-starter</artifactId>-->
  109 + <!-- </dependency>-->
  110 + <dependency>
  111 + <groupId>mysql</groupId>
  112 + <artifactId>mysql-connector-java</artifactId>
  113 + <version>${mysql-connector.version}</version>
  114 + </dependency>
  115 + <dependency>
  116 + <groupId>com.alibaba</groupId>
  117 + <artifactId>druid-spring-boot-starter</artifactId>
  118 + <version>${druid.version}</version>
  119 + </dependency>
  120 +
  121 + <dependency>
  122 + <groupId>org.springframework.boot</groupId>
  123 + <artifactId>spring-boot-starter-log4j2</artifactId>
  124 + <version>${springboot.version}</version>
  125 + </dependency>
  126 +
  127 +
  128 + <dependency>
  129 + <groupId>com.alibaba</groupId>
  130 + <artifactId>fastjson</artifactId>
  131 + <version>${fastjson.version}</version>
  132 + </dependency>
  133 +
  134 + <dependency>
  135 + <groupId>cn.hutool</groupId>
  136 + <artifactId>hutool-crypto</artifactId>
  137 + <version>${hutool-crypto.version}</version>
  138 + </dependency>
  139 +
  140 + <dependency>
  141 + <groupId>org.springframework.boot</groupId>
  142 + <artifactId>spring-boot-starter-data-redis</artifactId>
  143 + <version>${springboot.version}</version>
  144 + </dependency>
  145 +
  146 + <dependency>
  147 + <groupId>org.apache.commons</groupId>
  148 + <artifactId>commons-pool2</artifactId>
  149 + <version>${commons-pool2.version}</version>
  150 + </dependency>
  151 +
  152 +
  153 + <dependency>
  154 + <groupId>org.apache.commons</groupId>
  155 + <artifactId>commons-lang3</artifactId>
  156 + <version>${commons-lang3.version}</version>
  157 + </dependency>
  158 + <dependency>
  159 + <groupId>org.lionsoul</groupId>
  160 + <artifactId>ip2region</artifactId>
  161 + <version>${ip2region.version}</version>
  162 + </dependency>
  163 + <dependency>
  164 + <groupId>eu.bitwalker</groupId>
  165 + <artifactId>UserAgentUtils</artifactId>
  166 + <version>${userAgentUtils.version}</version>
  167 + </dependency>
  168 +
  169 + <!--工具包-->
  170 + <dependency>
  171 + <groupId>cn.hutool</groupId>
  172 + <artifactId>hutool-all</artifactId>
  173 + <version>${hutool-all.version}</version>
  174 + </dependency>
  175 + <dependency>
  176 + <groupId>org.apache.poi</groupId>
  177 + <artifactId>poi</artifactId>
  178 + <version>${poi.version}</version>
  179 + </dependency>
  180 + <dependency>
  181 + <groupId>org.apache.poi</groupId>
  182 + <artifactId>poi-ooxml</artifactId>
  183 + <version>${poi-ooxml.version}</version>
  184 + </dependency>
  185 +
  186 + <dependency>
  187 + <groupId>joda-time</groupId>
  188 + <artifactId>joda-time</artifactId>
  189 + <version>${joda-time.version}</version>
  190 + </dependency>
  191 +
  192 +
  193 +
  194 + </dependencies>
  195 + <build>
  196 + <finalName>webmagic-canrd.service-1.0-SNAPSHOT</finalName>
  197 + <plugins>
  198 + <plugin>
  199 + <groupId>org.apache.maven.plugins</groupId>
  200 + <artifactId>maven-source-plugin</artifactId>
  201 + </plugin>
  202 +
  203 + <plugin>
  204 + <groupId>org.springframework.boot</groupId>
  205 + <artifactId>spring-boot-maven-plugin</artifactId>
  206 + <configuration>
  207 + <executable>true</executable>
  208 + </configuration>
  209 + </plugin>
  210 +
  211 + </plugins>
  212 + </build>
  213 +</project>
0 214 \ No newline at end of file
... ...
src/main/java/com/canrd/webmagic/Application.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/Application.java
  1 +package com.canrd.webmagic;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.DbType;
  4 +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
  5 +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
  6 +import com.canrd.webmagic.common.directory.Path;
  7 +import com.canrd.webmagic.common.utils.SpringContextHolder;
  8 +import org.mybatis.spring.annotation.MapperScan;
  9 +import org.springframework.boot.SpringApplication;
  10 +import org.springframework.boot.autoconfigure.SpringBootApplication;
  11 +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  12 +import org.springframework.context.annotation.Bean;
  13 +import org.springframework.scheduling.annotation.EnableAsync;
  14 +import org.springframework.scheduling.annotation.EnableScheduling;
  15 +import org.springframework.transaction.annotation.EnableTransactionManagement;
  16 +
  17 +/**
  18 + * @author: xms
  19 + * @description:
  20 + * @date: 2024/1/12 14:00
  21 + * @version: 1.0
  22 + */
  23 +@EnableAsync
  24 +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}, scanBasePackages = {"com.canrd.webmagic"})
  25 +@MapperScan("com.canrd.webmagic.**.mapper")
  26 +@EnableScheduling
  27 +@EnableTransactionManagement
  28 +public class Application {
  29 +
  30 + private static void setLogPath() {
  31 + String appPath = Path.getAppPath(Application.class);
  32 + System.setProperty("logging.path", appPath);
  33 + }
  34 +
  35 + @Bean
  36 + public SpringContextHolder springContextHolder() {
  37 + return new SpringContextHolder();
  38 + }
  39 +
  40 + public static void main(String[] args) {
  41 + setLogPath();
  42 + SpringApplication.run(Application.class, args);
  43 + }
  44 +
  45 + /**
  46 + * 分页插件
  47 + *
  48 + * @return
  49 + */
  50 + @Bean
  51 + public MybatisPlusInterceptor mybatisPlusInterceptor() {
  52 + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  53 + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
  54 + return interceptor;
  55 + }
  56 +}
... ...
src/main/java/com/canrd/webmagic/common/annotation/AnonymousAccess.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/annotation/AnonymousAccess.java
  1 +package com.canrd.webmagic.common.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 用于标记匿名访问方法
  10 + */
  11 +@Target(ElementType.METHOD)
  12 +@Retention(RetentionPolicy.RUNTIME)
  13 +public @interface AnonymousAccess {
  14 +
  15 +}
... ...
src/main/java/com/canrd/webmagic/common/constant/Constant.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/constant/Constant.java
  1 +package com.canrd.webmagic.common.constant;
  2 +
  3 +import java.util.Arrays;
  4 +import java.util.List;
  5 +
  6 +public class Constant {
  7 + /**
  8 + * 分隔符英文的横杠
  9 + */
  10 + public static final String CROSS_BAR_CHARACTER = "-";
  11 + /**
  12 + * 英文的 .
  13 + */
  14 + public static final String POINT_BAR_CHARACTER = ".";
  15 + /**
  16 + * 英文的 !
  17 + */
  18 + public static final String EXCLAMATION_MARK_CHARACTER = "!";
  19 + /**
  20 + * 英文的 /
  21 + */
  22 + public static final String SLASH_MARK_CHARACTER = "/";
  23 + /**
  24 + * 英文的 :
  25 + */
  26 + public static final String COLON_CHARACTER = ":";
  27 +
  28 + /**
  29 + * 英文的 ;
  30 + */
  31 + public static final String SEMICOLON_CHARACTER = ";";
  32 +
  33 + /**
  34 + * 英文的逗号
  35 + */
  36 + public static final String COMMA_CHARACTER = ",";
  37 + /**
  38 + * 英文的*号
  39 + */
  40 + public static final String START_CHARACTER = "*";
  41 + /**
  42 + * 分隔符
  43 + */
  44 + public static final String SPLIT_SYMBOL = ",|,";
  45 +
  46 + /**
  47 + * 特殊分隔符 _
  48 + */
  49 + public static final String SPECIAL_KEY = "_";
  50 +
  51 +
  52 + /**
  53 + * 括号
  54 + */
  55 + public static final String BRACKETS_RIGHT = "]";
  56 + /**
  57 + * 括号
  58 + */
  59 + public static final String BRACKETS_LEFT = "[";
  60 +
  61 + /**
  62 + * 手机号码正则校验
  63 + */
  64 + public static final String PHONE_REGEXP = "^[1][3,4,5,6,7,8,9][0-9]{9}$";
  65 +
  66 + /**
  67 + * 脱敏手机号
  68 + */
  69 + public static final String PHONE_DESENSITIZATION_REGEXP = "^[1][3,4,5,6,7,8,9][0-9][*]{4}[0-9]{4}$";
  70 +
  71 + /**
  72 + * 邮箱
  73 + */
  74 + public static final String EMAIL_REGEXP = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$";
  75 +
  76 + /**
  77 + * 三位数字
  78 + */
  79 + public static final String THREE_DIGITS_REGEXP = "\\d{3}";
  80 +
  81 + /**
  82 + * 中文 英文 数字
  83 + */
  84 + public static final String CHI_EN_NUM_REGEXP = "^[A-z0-9\\u4e00-\\u9fa5]*$";
  85 +
  86 +
  87 + /**
  88 + * 仅包含英文和数字
  89 + */
  90 + public static final String EN_REGEXP = "^[a-zA-Z]+$";
  91 +
  92 + public static final String EN_NUM_REGEXP = "^[a-z0-9A-Z]+$";
  93 +
  94 + public static final String LINE_EN_NUM_REGEXP = "^[a-z0-9A-Z\\-]+$";
  95 +
  96 + /**
  97 + * 仅包含英文和中文
  98 + */
  99 + public static final String CHI_EN_REGEXP = "^[A-z\\u4e00-\\u9fa5]*$";
  100 +
  101 + /**
  102 + * 纯数字
  103 + */
  104 + public static final String NUMERIC_REGEXP = "^\\d+$";
  105 + /**
  106 + * 纯中文
  107 + */
  108 + public static final String CHI_REGEXP = "^[\u4e00-\u9fa5]+$";
  109 + /**
  110 + * 不超过两位小数
  111 + */
  112 + public static final String DICMAL_REGEXP = "^(([1-9]{1}\\d*)|([0]{1}))(\\.(\\d){0,3})?$";
  113 +
  114 + /**
  115 + * 默认空字符串
  116 + */
  117 + public static final String EMPTY_STRING = "";
  118 +
  119 + /**
  120 + * 统一返回data的key
  121 + */
  122 + public static final String RESULT_CHARACTER = "result";
  123 +
  124 + /**
  125 + * 统一返回data的key
  126 + */
  127 + public static final String SUCCESS_RESULT_CHARACTER = "success";
  128 +
  129 + /**
  130 + * 返回的默认结果集
  131 + */
  132 + public static final String RESULT_FAIL = null;
  133 +
  134 + /**
  135 + * ENABLE_FLAG
  136 + */
  137 + public static final String ENABLE_FLAG = "enable_flag";
  138 +
  139 + /**
  140 + * 是否可用 10-可用 20-删除
  141 + */
  142 + public static final int ENABLE_TEN = 10;
  143 + /**
  144 + * 是否可用 10-可用 20-删除
  145 + */
  146 + public static final int UNABLE_TWENTY = 20;
  147 +
  148 + public static final int ONE = 1;
  149 +
  150 + public static final Integer INTEGER_ONE = 1;
  151 +
  152 + public static final int TWO = 2;
  153 +
  154 + public static final int THREE = 3;
  155 +
  156 + public static final int FOUR = 4;
  157 +
  158 + public static final int FIVE = 5;
  159 +
  160 + public static final int SIX = 6;
  161 +
  162 + public static final int SEVEN = 7;
  163 +
  164 + public static final int THIRTY = 30;
  165 +
  166 + public static final int NINETEEN = 19;
  167 +
  168 + public static final int THOUSAND = 1000;
  169 +
  170 + public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
  171 +
  172 + public static final int ZERO = 0;
  173 +
  174 + public static final String STRING_ZERO = "0";
  175 +
  176 + public static final String ZERO_STRING = "0";
  177 +
  178 + public static final String THOUSAND_STRING = "1000";
  179 +
  180 + public static final String SYSTEM_USER = "System";
  181 +
  182 + public static final String percent50 = "0.5";
  183 +
  184 + public static final String DELETE_SUCCESS_RESULT_CHARACTER = "删除成功";
  185 +
  186 +
  187 + /**
  188 + * token rediskey
  189 + */
  190 + public static final String TOKEN_FLAG = "token:";
  191 + /**
  192 + * token 限制api请求
  193 + */
  194 + public static final String PERMISSION_API_LIMIT = "token_api_limit:";
  195 +
  196 + /**
  197 + * token过期时间
  198 + */
  199 + public static final Integer TOKEN_EXPIRE_HOURS = 1;
  200 + /**
  201 + * 密码3次错误锁定
  202 + */
  203 + public static final int LOCK_ERROR_TIMES = 3;
  204 +
  205 + /**
  206 + * session字段
  207 + */
  208 + public static final String HEAD_TOKEN = "Authorization";
  209 + public static final String ACCESS_TOKEN = "token";
  210 + public static final String REQUEST_ORIGIN = "source";
  211 + public static final String REQUEST_IP = "ip";
  212 + public static final String USER_INFO = "userInfo";
  213 + public static final String FILED_ID = "id";
  214 + public static final String FILED_USER_NAME = "username";
  215 + public static final String FILED_DEVICE_NUM = "deviceNum";
  216 +
  217 + /**
  218 + * 请求来源
  219 + */
  220 + public static final String ORIGIN_WEB = "WEB";
  221 + public static final String ORIGIN_PDA = "PDA";
  222 +
  223 + /**
  224 + * 1001 参数校验不通过
  225 + * 1002 签名验证不通过
  226 + */
  227 + public static final List<String> ERROR_CODE_LIST = Arrays.asList("1001", "1002");
  228 +
  229 + /**
  230 + * 分布式锁超时时间
  231 + */
  232 + public static final long REDIS_LOCK_DEFAULT_TIME_OUT_MILLIS = 3000;
  233 + public static final long REDIS_LOCK_FIVE_SECONDS_TIME_OUT_MILLIS = 5000;
  234 +
  235 + /**
  236 + * 系统来源WMS
  237 + */
  238 + public static final String SYS_ORIGIN_WMS = "WMS";
  239 +
  240 + public static final String STRING_ONE = "1";
  241 +
  242 +
  243 + public static final String STRING_TWO = "2";
  244 +
  245 + public static final String STRING_THREE = "3";
  246 +
  247 + public static final String STRING_FOUR = "4";
  248 +
  249 + public static final String STRING_FIVE = "5";
  250 +
  251 + public static final String STRING_SIX = "6";
  252 +
  253 + public static final String STRING_SEVEN = "7";
  254 +
  255 + public static final String STRING_EIGHT = "8";
  256 +
  257 + public static final String STRING_NINE = "9";
  258 +
  259 + public static final String STRING_TEN = "10";
  260 +
  261 + public static final String STRING_ELEVEN = "11";
  262 +
  263 + public static final String STRING_TWELVE = "12";
  264 +
  265 + /**
  266 + * 异常延时队列后缀
  267 + */
  268 + public static final String ERROR_DELAY_QUEUE_SUFFIX = "error";
  269 +
  270 + /**
  271 + * 推送出库数据延时队列 redis key prefix
  272 + */
  273 + public static final String OUTBOUND_NOTIFY_DELAY_QUEUE_PREFIX = "outbound:notify:";
  274 +
  275 + /**
  276 + * 同步MES库存队列 redis key prefix
  277 + */
  278 + public static final String MES_STOCK_SYNC_QUEUE_PREFIX = "mes:stock_sync:";
  279 +
  280 + /**
  281 + * 分拣详情 错误码: 157205 返回值段
  282 + */
  283 + public static final String SEPARATE_PICK_QUERY_RETURN_FIELD = "separatePickQuery";
  284 + /**
  285 + * 限制上限值
  286 + */
  287 + public static final Integer LIMIT_999 = 999;
  288 +
  289 + /**
  290 + * 东八区
  291 + */
  292 + public static final String GMT_8 = "GMT+8";
  293 +
  294 + /**
  295 + * 英文的 "
  296 + */
  297 + public static final String QUOTATION_MARK_CHARACTER = "\"";
  298 +
  299 +
  300 + /**
  301 + * 英文的 \"
  302 + */
  303 + public static final String QUOTATION_SLASH_MARK_CHARACTER = "\\\"";
  304 +
  305 + public static final String SUCCESS_VALUE = "success";
  306 +
  307 +
  308 + public static final String TRUE = "true";
  309 +
  310 + public static final String ROOT_PARENT_ID = "0";
  311 +
  312 + public static final Long ROOT_PARENT_ID_LONG = 0L;
  313 +
  314 +
  315 + /**
  316 + * 短信验证码 redis key
  317 + */
  318 + public static final String SMS_AUTH_CODE_PREFIX = "sms:auth:code:";
  319 +
  320 + public static final String DEFAULT_PASSWORD = "JBXT123456";
  321 +
  322 + /**
  323 + * 账号在线队列 redis key
  324 + */
  325 + public static final String ACCOUNT_ONLINE_LIST = "account:online:";
  326 +
  327 + /**
  328 + * 缓存导入excel错误信息 redis key
  329 + */
  330 + public static final String EXCEL_IMPORT_ERROR_PREFIX = "excel:import:error:";
  331 +
  332 +}
... ...
src/main/java/com/canrd/webmagic/common/constant/ElAdminConstant.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/constant/ElAdminConstant.java
  1 +package com.canrd.webmagic.common.constant;
  2 +
  3 +/**
  4 + * 常用静态常量
  5 + *
  6 + * @date 2018-12-26
  7 + */
  8 +public class ElAdminConstant {
  9 +
  10 + public static final String RESET_PASS = "重置密码";
  11 +
  12 + public static final String RESET_MAIL = "重置邮箱";
  13 +
  14 + /**
  15 + * 用于IP定位转换
  16 + */
  17 + public static final String REGION = "内网IP|内网IP";
  18 +
  19 + /**
  20 + * 常用接口
  21 + */
  22 + public static class Url {
  23 + public static final String SM_MS_URL = "https://sm.ms/api";
  24 + }
  25 +}
... ...
src/main/java/com/canrd/webmagic/common/constant/ServerResult.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/constant/ServerResult.java
  1 +package com.canrd.webmagic.common.constant;
  2 +
  3 +
  4 +import java.io.Serializable;
  5 +import java.util.HashMap;
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * @Date: 2020/9/5
  10 + * 统一的返回结果实体
  11 + */
  12 +public class ServerResult<T> implements Serializable {
  13 + /**
  14 + * 序列化ID
  15 + */
  16 + private static final long serialVersionUID = -5809782578272943999L;
  17 + /**
  18 + * 返回的状态码
  19 + */
  20 + private int result = ServerResultCode.SUCCESS.getErrorCode();
  21 + /**
  22 + * 返回的消息
  23 + */
  24 + private String message = ServerResultCode.SUCCESS.getErrorDesc();
  25 + /**
  26 + * 返回的数据实体
  27 + */
  28 + private T data = null;
  29 + /**
  30 + *
  31 + */
  32 + final int INIT_SIZE = 128;
  33 +
  34 + /**
  35 + *
  36 + */
  37 + public ServerResult() {
  38 + }
  39 +
  40 + @Override
  41 + public String toString() {
  42 + StringBuilder buffer = new StringBuilder(INIT_SIZE);
  43 + buffer.append("{\"result\":").append(this.result);
  44 + buffer.append(",\"message\":\"").append(this.message != null ? message : "").append("\"");
  45 + buffer.append(",\"data\":").append(data).append("}");
  46 + return buffer.toString();
  47 + }
  48 +
  49 + public int getResult() {
  50 + return result;
  51 + }
  52 +
  53 + public ServerResult setResult(int result) {
  54 + this.result = result;
  55 + return this;
  56 + }
  57 +
  58 + public ServerResult setResult(ServerResultCode serverResultCode) {
  59 + this.result = serverResultCode.getErrorCode();
  60 + this.message = serverResultCode.getErrorDesc();
  61 + return this;
  62 + }
  63 +
  64 + public ServerResult setResult(int errorCode, String errorDesc) {
  65 + this.result = errorCode;
  66 + this.message = errorDesc;
  67 + return this;
  68 + }
  69 +
  70 + public String getMessage() {
  71 + return message;
  72 + }
  73 +
  74 + public ServerResult<T> setMessage(String message) {
  75 + this.message = message;
  76 + return this;
  77 + }
  78 +
  79 + public T getData() {
  80 + return data;
  81 + }
  82 +
  83 + public ServerResult setData(T data) {
  84 + this.data = data;
  85 + return this;
  86 + }
  87 +
  88 + public static <T> ServerResult<T> success() {
  89 + return new ServerResult()
  90 + .setResult(ServerResultCode.SUCCESS)
  91 + .setMessage(ServerResultCode.SUCCESS.getErrorDesc())
  92 + .setData(defaultResult(ServerResultCode.SUCCESS));
  93 + }
  94 +
  95 + public static <T> ServerResult<T> success(T data) {
  96 + return new ServerResult()
  97 + .setResult(ServerResultCode.SUCCESS)
  98 + .setMessage(ServerResultCode.SUCCESS.getErrorDesc())
  99 + .setData(data);
  100 + }
  101 +
  102 + public static <T> ServerResult<T> success(T data, String message) {
  103 + return new ServerResult()
  104 + .setResult(ServerResultCode.SUCCESS)
  105 + .setMessage(message)
  106 + .setData(data);
  107 + }
  108 +
  109 + /**
  110 + * @description 错误码使用系统错误 1000 错误类型自定义
  111 + * @author dengbin
  112 + * @date 2020/9/12
  113 + */
  114 + public static <T> ServerResult<T> fail(String message) {
  115 + return new ServerResult()
  116 + .setResult(ServerResultCode.FAIL)
  117 + .setMessage(message)
  118 + .setData(defaultResult(Constant.RESULT_FAIL));
  119 + }
  120 +
  121 + /**
  122 + * 错误时需要返回相关数据时使用
  123 + *
  124 + * @param data
  125 + * @param <T>
  126 + * @return
  127 + */
  128 + public static <T> ServerResult<T> fail(T data, ServerResultCode serverResultCode) {
  129 + return new ServerResult()
  130 + .setData(data)
  131 + .setResult(serverResultCode)
  132 + .setMessage(serverResultCode.getErrorDesc());
  133 + }
  134 +
  135 + /**
  136 + * 错误时需要返回相关数据时使用(不设值 data)
  137 + *
  138 + * @param sr
  139 + * @param
  140 + * @return
  141 + */
  142 + public static <T> ServerResult<T> fail(ServerResult<?> sr) {
  143 + return new ServerResult<>()
  144 + .setMessage(sr.getMessage())
  145 + .setResult(sr.getResult());
  146 +
  147 + }
  148 +
  149 + /**
  150 + * @description 错误码使用上面的枚举定义的,错误信息重新定义
  151 + * @author dengbin
  152 + * @date 2020/9/12
  153 + */
  154 + public static <T> ServerResult<T> fail(ServerResultCode serverResultCode, String msg) {
  155 + return new ServerResult()
  156 + .setResult(serverResultCode)
  157 + .setMessage(msg)
  158 + .setData(defaultResult(Constant.RESULT_FAIL));
  159 + }
  160 +
  161 + /**
  162 + * @return
  163 + * @description 直接选用上面的枚举错误码,输出定义的错误信息
  164 + * @author dengbin
  165 + * @date 2020/9/12
  166 + */
  167 + public static <T> ServerResult<T> fail(ServerResultCode serverResultCode) {
  168 + return new ServerResult()
  169 + .setResult(serverResultCode)
  170 + .setMessage(serverResultCode.getErrorDesc())
  171 + .setData(defaultResult(Constant.RESULT_FAIL));
  172 + }
  173 +
  174 + /**
  175 + * 错误时需要返回相关数据时使用
  176 + *
  177 + * @param data
  178 + * @param <T>
  179 + * @return
  180 + */
  181 + public static <T> ServerResult<T> fail(T data, int errorCode, String errorDesc) {
  182 + return new ServerResult()
  183 + .setData(data)
  184 + .setResult(errorCode, errorDesc);
  185 + }
  186 +
  187 +
  188 + public static <T> ServerResult<T> fail() {
  189 + return new ServerResult()
  190 + .setResult(ServerResultCode.FAIL.getErrorCode())
  191 + .setMessage(ServerResultCode.FAIL.getErrorDesc())
  192 + .setData(defaultResult(Constant.RESULT_FAIL));
  193 + }
  194 +
  195 +
  196 + /**
  197 + * @description 直接选用上面的枚举错误码,输出定义的错误信息
  198 + * @author dengbin
  199 + * @date 2020/9/12
  200 + */
  201 + public ServerResult failEnum(ServerResultCode serverResultCode) {
  202 + setResult(serverResultCode);
  203 + setMessage(serverResultCode.getErrorDesc());
  204 + return this;
  205 + }
  206 +
  207 + public static <T> ServerResult<T> fail(int errorCode, String errorDesc) {
  208 + return new ServerResult()
  209 + .setResult(errorCode, errorDesc)
  210 + .setData(defaultResult(Constant.RESULT_FAIL));
  211 +
  212 + }
  213 +
  214 + /**
  215 + * 判断当前的状态码是否是SUCCESS
  216 + *
  217 + * @return 结果 ture or false
  218 + */
  219 + public boolean checkSuccess() {
  220 + return result == ServerResultCode.SUCCESS.getErrorCode();
  221 + }
  222 +
  223 + public boolean checkNotSuccess() {
  224 + return !checkSuccess();
  225 + }
  226 +
  227 + private static Map<String, Object> defaultResult(Object object) {
  228 + Map<String, Object> map = new HashMap<>(Constant.ONE);
  229 + map.put(Constant.RESULT_CHARACTER, null);
  230 + return map;
  231 + }
  232 +}
... ...
src/main/java/com/canrd/webmagic/common/constant/ServerResultCode.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/constant/ServerResultCode.java
  1 +package com.canrd.webmagic.common.constant;
  2 +
  3 +
  4 +import com.canrd.webmagic.common.exception.ErrorInfo;
  5 +import lombok.Setter;
  6 +
  7 +
  8 +/**
  9 + * 请求成功 返回 0
  10 + */
  11 +public enum ServerResultCode implements ErrorInfo {
  12 + //成功 "0"
  13 + SUCCESS(0, "成功"),
  14 + FAIL(1000, "系统内部错误,请联系业务系统运维管理员"),
  15 + FIlE_UPLOAD_TOO_LARGE(1051, "上传文件太大,图片文件一般小于2兆"),
  16 +
  17 + UNAUTHORIZED(401, "登录状态过期"),
  18 +
  19 + //空指针异常
  20 + NULL_POINT(1001, "空指针异常"),
  21 +
  22 + //校验异常
  23 + RUN_ERROR(1002, "程序运行报错"),
  24 + ILLEGAL_ARGUMENT(1003, "参数非法"),
  25 + FILED_ERROR(1004, "传入参数错误"),
  26 + PARAM_ERROR(1005, "入参为空"),
  27 + EMPTY_RESULT(1006, "数据不存在"),
  28 + EMPTY_LIST(1007, "查询结果为空"),
  29 + IMG_CAPTCHA_ERROR(1008, "图片验证码错误"),
  30 + IMG_CAPTCHA_EXPIRE_ERROR(1009, "图片验证码不存在或已过期"),
  31 + SMS_CAPTCHA_ERROR(1010, "短信验证码错误"),
  32 + SMS_CAPTCHA_EXPIRE_ERROR(1011, "短信验证码不存在或已过期"),
  33 +
  34 + //认证授权异常
  35 + UNAUTHENTICATION(401, "未登录"),
  36 +
  37 +
  38 + //用户
  39 + USER_NOT_EXIT(20001, "用户不存在"),
  40 + USER_UN_ENABLE(20002, "用户未激活"),
  41 +
  42 +
  43 + // 公司
  44 + COMPANY_NOT_EXIT(30001, "公司不存在"),
  45 +
  46 + // 短信
  47 + SMS_SEND_OVER_LIMIT_ERROR(40001, "发送频次过高,请一分钟后再发送"),
  48 + EMAIL_SEND_OVER_LIMIT_ERROR(40002, "发送频次过高(一天最多修改三次),请第二天后再发送"),
  49 +
  50 + // 会员
  51 + MEMBER_PHONE_REGISTER_ERROR(50001, "手机已经被注册使用!"),
  52 + MEMBER_AGREE_AGREEMENT_CHOOSE_ERROR(50002, "必须同意注册协议才可进行注册操作!"),
  53 + MEMBER_CONFIRM_PASSWORD_ERROR(50003, "两次密码输入不一致!"),
  54 + MEMBER_LOGIN_PHONE_ERROR(50004, "手机号没有注册,请注册后登录!"),
  55 + MEMBER_LOGIN_LOCKED_TIME_ERROR(50005, "账号被锁定,请稍后再试试!"),
  56 + MEMBER_RECOVER_PASSWORD_ERROR(50006, "对不起,此密码找回链接已失效!"),
  57 + MEMBER_RECOVER_PASSWORD_EXPIRE_ERROR(50007, "对不起,此密码找回链接已过期!"),
  58 +
  59 + //产品
  60 + PRODUCT_NOT_EXIST_ERROR(60001, "此商品已下架!"),
  61 + PRODUCT_NOT_MORE_STORE_ERROR(60002, "添加购物车失败,商品库存不足!"),
  62 +
  63 + //订单
  64 + ORDER_BASE_INFO_EMPTY(70001, "订单基础信息不能为空!"),
  65 +
  66 + //申请
  67 + APPLY_UNLOCK_FIELD_EXIST(80001, "还有未审批完结的申请,请等上一个申请单完结!"),
  68 + APPLY_NOT_EXIST(80002, "申请单不存在!"),
  69 +
  70 + //上传图片
  71 + UPLOAD_IMAGES_ERROR(900021, "上传图片失败!"),
  72 + ;
  73 +
  74 +
  75 + ServerResultCode(Integer errorCode, String errorDesc) {
  76 + this.errorCode = errorCode;
  77 + this.errorDesc = errorDesc;
  78 + }
  79 +
  80 + @Setter
  81 + private Integer errorCode;
  82 + @Setter
  83 + private String errorDesc;
  84 +
  85 + @Override
  86 + public Integer getErrorCode() {
  87 + return this.errorCode;
  88 + }
  89 +
  90 + @Override
  91 + public String getErrorDesc() {
  92 + return this.errorDesc;
  93 + }
  94 +
  95 + /**
  96 + * 根据errorCode获得枚举
  97 + *
  98 + * @param errorCode
  99 + * @return
  100 + */
  101 + public static String getDescByCode(Integer errorCode) {
  102 + if (errorCode == null) {
  103 + return null;
  104 + }
  105 + ServerResultCode[] serverResults = values();
  106 + for (ServerResultCode serverResult : serverResults) {
  107 + if (serverResult.getErrorCode().equals(errorCode)) {
  108 + return serverResult.getErrorDesc();
  109 + }
  110 + }
  111 + return null;
  112 + }
  113 +
  114 +}
0 115 \ No newline at end of file
... ...
src/main/java/com/canrd/webmagic/common/directory/Path.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/directory/Path.java
  1 +package com.canrd.webmagic.common.directory;
  2 +
  3 +import com.canrd.webmagic.common.constant.Constant;
  4 +
  5 +/**
  6 + * @author xms
  7 + */
  8 +public class Path {
  9 + /**
  10 + * 获取程序启动路径
  11 + *
  12 + * @param cls,建议直接传 ServiceApplication.class
  13 + * @return 应用启动路径
  14 + */
  15 + public static String getAppPath(Class cls) {
  16 + String path = cls.getResource(Constant.SLASH_MARK_CHARACTER).getPath();
  17 + String os = System.getProperty("os.name").toLowerCase();
  18 + final String OSWINDOW = "windows";
  19 + if (os.indexOf(OSWINDOW) != -1 && path.length() > 1) {
  20 + //windows路径样例: /D:/work/code/shop-services/online-shop-oss/target/classes/
  21 + return path.substring(1);
  22 + }
  23 +
  24 + //linux 路径样例 file:/opt/target/online-shop-oss-SNAPSHOT.jar!/BOOT-INF/classes!/";
  25 + final String FILE = "file:";
  26 + if (path.indexOf(FILE) != -1) {
  27 + path = path.substring(FILE.length());
  28 + }
  29 +
  30 + int pos = -1;
  31 + if ((pos = path.indexOf(Constant.EXCLAMATION_MARK_CHARACTER)) != -1) {
  32 + if (-1 != (pos = path.lastIndexOf(Constant.SLASH_MARK_CHARACTER, pos))) {
  33 + path = path.substring(0, pos + 1);
  34 + }
  35 + }
  36 +
  37 + return path;
  38 + }
  39 +}
... ...
src/main/java/com/canrd/webmagic/common/exception/BadRequestException.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/exception/BadRequestException.java
  1 +package com.canrd.webmagic.common.exception;
  2 +
  3 +import lombok.Getter;
  4 +import org.springframework.http.HttpStatus;
  5 +
  6 +import static org.springframework.http.HttpStatus.BAD_REQUEST;
  7 +
  8 +/**
  9 + *
  10 + * @date 2018-11-23
  11 + * 统一异常处理
  12 + */
  13 +@Getter
  14 +public class BadRequestException extends RuntimeException {
  15 +
  16 + private Integer status = BAD_REQUEST.value();
  17 +
  18 + public BadRequestException(String msg) {
  19 + super(msg);
  20 + }
  21 +
  22 + public BadRequestException(HttpStatus status, String msg) {
  23 + super(msg);
  24 + this.status = status.value();
  25 + }
  26 +}
... ...
src/main/java/com/canrd/webmagic/common/exception/BusinessException.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/exception/BusinessException.java
  1 +package com.canrd.webmagic.common.exception;
  2 +
  3 +import com.canrd.webmagic.common.constant.ServerResult;
  4 +import com.canrd.webmagic.common.constant.ServerResultCode;
  5 +import lombok.Getter;
  6 +import lombok.Setter;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +
  9 +/**
  10 + * <p>基础异常类,所有自定义异常类都需要继承本类</p>
  11 + */
  12 +@Slf4j
  13 +public class BusinessException extends RuntimeException {
  14 +
  15 + private static final long serialVersionUID = 3152549963899218489L;
  16 + @Setter
  17 + @Getter
  18 + private String errorDesc;
  19 + @Setter
  20 + @Getter
  21 + private Integer errorCode;
  22 + @Setter
  23 + @Getter
  24 + private Object data;
  25 +
  26 + public BusinessException() {
  27 + super(ServerResultCode.FAIL.getErrorDesc());
  28 + this.errorCode = ServerResultCode.FAIL.getErrorCode();
  29 + this.errorDesc = ServerResultCode.FAIL.getErrorDesc();
  30 + }
  31 +
  32 + public BusinessException(int errorCode, String errorDesc) {
  33 + super(errorDesc);
  34 + this.errorCode = errorCode;
  35 + this.errorDesc = errorDesc;
  36 + }
  37 +
  38 + public BusinessException(ServerResultCode serverResultCode) {
  39 + super(serverResultCode.getErrorDesc());
  40 + this.errorCode = serverResultCode.getErrorCode();
  41 + this.errorDesc = serverResultCode.getErrorDesc();
  42 + log.error("业务异常: ", this);
  43 + }
  44 +
  45 + public BusinessException(ErrorInfo errorInfo) {
  46 + super(errorInfo.getErrorDesc());
  47 + this.errorCode = errorInfo.getErrorCode();
  48 + this.errorDesc = errorInfo.getErrorDesc();
  49 + log.error("业务异常: ", this);
  50 + }
  51 +
  52 + public BusinessException(ServerResult<?> serverResult) {
  53 + super(serverResult == null ? ServerResultCode.FAIL.getErrorDesc() : serverResult.getMessage());
  54 + if (serverResult == null) {
  55 + this.errorCode = ServerResultCode.FAIL.getErrorCode();
  56 + this.errorDesc = ServerResultCode.FAIL.getErrorDesc();
  57 + } else {
  58 + this.errorCode = serverResult.getResult();
  59 + this.errorDesc = serverResult.getMessage();
  60 + this.data = serverResult.getData();
  61 + }
  62 + log.error("业务异常: ", this);
  63 + }
  64 +
  65 + public BusinessException(String message) {
  66 + super(message);
  67 + }
  68 +
  69 + public BusinessException(Throwable cause) {
  70 + super(cause);
  71 + log.error("业务异常: ", this);
  72 + }
  73 +
  74 + public BusinessException(String message, Throwable cause) {
  75 + super(message, cause);
  76 + log.error("业务异常: ", this);
  77 + }
  78 +}
... ...
src/main/java/com/canrd/webmagic/common/exception/BusinessExceptionHandlerAdvice.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/exception/BusinessExceptionHandlerAdvice.java
  1 +package com.canrd.webmagic.common.exception;
  2 +
  3 +import com.canrd.webmagic.common.constant.ServerResult;
  4 +import com.canrd.webmagic.common.constant.ServerResultCode;
  5 +import org.springframework.core.annotation.Order;
  6 +import org.springframework.http.HttpStatus;
  7 +import org.springframework.http.ResponseEntity;
  8 +import org.springframework.web.bind.annotation.ControllerAdvice;
  9 +import org.springframework.web.bind.annotation.ExceptionHandler;
  10 +import org.springframework.web.bind.annotation.ResponseStatus;
  11 +
  12 +import java.util.Optional;
  13 +
  14 +/**
  15 + * 业务异常统一处理类
  16 + *
  17 + * @date 2021/1/11
  18 + */
  19 +@ControllerAdvice
  20 +@Order(5)
  21 +public class BusinessExceptionHandlerAdvice {
  22 +
  23 +
  24 + @ExceptionHandler(value = {BusinessException.class})
  25 + @ResponseStatus(value = HttpStatus.OK)
  26 + public ResponseEntity<Object> handleException(BusinessException exception) throws Exception {
  27 + return new ResponseEntity<Object>(handleBusinessException(exception), HttpStatus.OK);
  28 + }
  29 +
  30 + private ServerResult handleBusinessException(BusinessException exception) {
  31 + Integer code = Optional.ofNullable(exception.getErrorCode()).orElse(ServerResultCode.FAIL.getErrorCode());
  32 + String msg = Optional.ofNullable(exception.getMessage()).orElse(ServerResultCode.FAIL.getErrorDesc());
  33 + Object data = Optional.ofNullable(exception.getData()).orElse(null);
  34 + return ServerResult.fail(data, code, msg);
  35 + }
  36 +}
... ...
src/main/java/com/canrd/webmagic/common/exception/EntityExistException.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/exception/EntityExistException.java
  1 +package com.canrd.webmagic.common.exception;
  2 +
  3 +import org.springframework.util.StringUtils;
  4 +
  5 +/**
  6 + *
  7 + * @date 2018-11-23
  8 + */
  9 +public class EntityExistException extends RuntimeException {
  10 +
  11 + public EntityExistException(Class clazz, String field, String val) {
  12 + super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val));
  13 + }
  14 +
  15 + private static String generateMessage(String entity, String field, String val) {
  16 + return StringUtils.capitalize(entity)
  17 + + " with " + field + " " + val + " existed";
  18 + }
  19 +}
0 20 \ No newline at end of file
... ...
src/main/java/com/canrd/webmagic/common/exception/EntityNotFoundException.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/exception/EntityNotFoundException.java
  1 +package com.canrd.webmagic.common.exception;
  2 +
  3 +import org.springframework.util.StringUtils;
  4 +
  5 +/**
  6 + *
  7 + * @date 2018-11-23
  8 + */
  9 +public class EntityNotFoundException extends RuntimeException {
  10 +
  11 + public EntityNotFoundException(Class clazz, String field, String val) {
  12 + super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val));
  13 + }
  14 +
  15 + private static String generateMessage(String entity, String field, String val) {
  16 + return StringUtils.capitalize(entity)
  17 + + " with " + field + " " + val + " does not exist";
  18 + }
  19 +}
0 20 \ No newline at end of file
... ...
src/main/java/com/canrd/webmagic/common/exception/ErrorInfo.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/exception/ErrorInfo.java
  1 +package com.canrd.webmagic.common.exception;
  2 +
  3 +/**
  4 + * @date 2023-01-12
  5 + */
  6 +public interface ErrorInfo {
  7 +
  8 + Integer getErrorCode();
  9 +
  10 + String getErrorDesc();
  11 +}
... ...
src/main/java/com/canrd/webmagic/common/exception/handler/ApiError.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/exception/handler/ApiError.java
  1 +package com.canrd.webmagic.common.exception.handler;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonFormat;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +/**
  9 + *
  10 + * @date 2018-11-23
  11 + */
  12 +@Data
  13 +class ApiError {
  14 +
  15 + private Integer status = 200;
  16 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  17 + private LocalDateTime timestamp;
  18 + private String message;
  19 + private String errorCode;
  20 +
  21 + private ApiError() {
  22 + timestamp = LocalDateTime.now();
  23 + }
  24 +
  25 + public static ApiError error(String message){
  26 + ApiError apiError = new ApiError();
  27 + apiError.setMessage(message);
  28 + return apiError;
  29 + }
  30 +
  31 + public static ApiError error(Integer status, String message){
  32 + ApiError apiError = new ApiError();
  33 + apiError.setStatus(status);
  34 + apiError.setMessage(message);
  35 + return apiError;
  36 + }
  37 +}
  38 +
  39 +
... ...
src/main/java/com/canrd/webmagic/common/exception/handler/GlobalExceptionHandler.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/exception/handler/GlobalExceptionHandler.java
  1 +package com.canrd.webmagic.common.exception.handler;
  2 +
  3 +import com.canrd.webmagic.common.constant.ServerResult;
  4 +import com.canrd.webmagic.common.constant.ServerResultCode;
  5 +import com.canrd.webmagic.common.exception.BusinessException;
  6 +import com.canrd.webmagic.common.exception.EntityExistException;
  7 +import com.canrd.webmagic.common.exception.EntityNotFoundException;
  8 +import com.canrd.webmagic.common.utils.ThrowableUtil;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.http.HttpStatus;
  11 +import org.springframework.http.ResponseEntity;
  12 +import org.springframework.web.bind.MethodArgumentNotValidException;
  13 +import org.springframework.web.bind.annotation.ExceptionHandler;
  14 +import org.springframework.web.bind.annotation.ResponseStatus;
  15 +import org.springframework.web.bind.annotation.RestControllerAdvice;
  16 +import org.springframework.web.multipart.MaxUploadSizeExceededException;
  17 +
  18 +import java.util.Objects;
  19 +
  20 +/**
  21 + * @date 2018-11-23
  22 + */
  23 +@Slf4j
  24 +@RestControllerAdvice
  25 +public class GlobalExceptionHandler {
  26 + /**
  27 + * @param exception
  28 + * @return
  29 + * @throws Exception
  30 + */
  31 + @ExceptionHandler(value = RuntimeException.class)
  32 + public ResponseEntity<Object> handleServiceException(Exception exception) throws Exception {
  33 + return new ResponseEntity(translateException(exception), HttpStatus.OK);
  34 + }
  35 +
  36 + /**
  37 + * @param exception
  38 + * @return
  39 + * @throws Exception
  40 + */
  41 + @ExceptionHandler(value = Exception.class)
  42 + @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
  43 + public ResponseEntity<Object> handleException(Exception exception) throws Exception {
  44 + return new ResponseEntity<Object>(translateException(exception), HttpStatus.OK);
  45 + }
  46 +
  47 +
  48 + /**
  49 + * 处理所有接口数据验证异常
  50 + *
  51 + * @param e
  52 + * @return
  53 + */
  54 + @ExceptionHandler(MethodArgumentNotValidException.class)
  55 + public ResponseEntity<ServerResult> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
  56 + // 打印堆栈信息
  57 + log.error(ThrowableUtil.getStackTrace(e));
  58 + String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\.");
  59 + String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
  60 + String msg = "不能为空";
  61 + if (msg.equals(message)) {
  62 + message = str[1] + ":" + message;
  63 + }
  64 + return buildResponseEntity(ServerResult.fail(message));
  65 + }
  66 +
  67 + /**
  68 + * 处理自定义异常
  69 + *
  70 + * @param e
  71 + * @return
  72 + */
  73 + @ExceptionHandler(value = BusinessException.class)
  74 + public ResponseEntity<ServerResult> badRequestException(BusinessException e) {
  75 + // 打印堆栈信息
  76 + log.error(ThrowableUtil.getStackTrace(e));
  77 + return buildResponseEntity(ServerResult.fail(e.getErrorCode(), e.getMessage()));
  78 + }
  79 +
  80 + /**
  81 + * 处理 EntityExist
  82 + */
  83 + @ExceptionHandler(value = EntityExistException.class)
  84 + public ResponseEntity<ServerResult> entityExistException(EntityExistException e) {
  85 + // 打印堆栈信息
  86 + log.error(ThrowableUtil.getStackTrace(e));
  87 + return buildResponseEntity(ServerResult.fail(e.getMessage()));
  88 + }
  89 +
  90 + /**
  91 + * 处理 EntityNotFound
  92 + *
  93 + * @param e
  94 + * @return
  95 + */
  96 + @ExceptionHandler(value = EntityNotFoundException.class)
  97 + public ResponseEntity<ServerResult> entityNotFoundException(EntityNotFoundException e) {
  98 + // 打印堆栈信息
  99 + log.error(ThrowableUtil.getStackTrace(e));
  100 + return buildResponseEntity(ServerResult.fail(HttpStatus.NOT_FOUND.value(), e.getMessage()));
  101 + }
  102 +
  103 + /**
  104 + * @param serverResult
  105 + * @return
  106 + */
  107 + private ResponseEntity<ServerResult> buildResponseEntity(ServerResult serverResult) {
  108 + return new ResponseEntity<>(serverResult, HttpStatus.valueOf(200));
  109 + }
  110 +
  111 + /**
  112 + * @param e
  113 + * @return
  114 + * @throws Exception
  115 + */
  116 + private Object translateException(Exception e) throws Exception {
  117 + ServerResult serverResult = null;
  118 + if (e instanceof NullPointerException) {
  119 + serverResult = ServerResult.fail(ServerResultCode.NULL_POINT);
  120 + } else if (e instanceof IllegalArgumentException) {
  121 + serverResult = ServerResult.fail(ServerResultCode.FAIL);
  122 + } else if (e instanceof MaxUploadSizeExceededException) {
  123 + serverResult = ServerResult.fail(ServerResultCode.FIlE_UPLOAD_TOO_LARGE);
  124 + } else if (e instanceof BusinessException) {
  125 + serverResult = ServerResult.fail(((BusinessException) e).getErrorCode(), ((BusinessException) e).getErrorDesc());
  126 + } else {
  127 + serverResult = ServerResult.fail(ServerResultCode.FAIL);
  128 + serverResult.setMessage(serverResult.getMessage() + "|,业务异常:" + e.getMessage());
  129 + }
  130 +
  131 + log.error("业务异常", e);
  132 + return serverResult;
  133 + }
  134 +}
... ...
src/main/java/com/canrd/webmagic/common/jsr303/ListValueConstraintValidator.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/jsr303/ListValueConstraintValidator.java
  1 +package com.canrd.webmagic.common.jsr303;
  2 +
  3 +
  4 +import com.canrd.webmagic.common.jsr303.annotation.ListIntValue;
  5 +
  6 +import javax.validation.ConstraintValidator;
  7 +import javax.validation.ConstraintValidatorContext;
  8 +import java.util.HashSet;
  9 +import java.util.Set;
  10 +
  11 +/**
  12 + * 自定义校验注解 -枚举值校验
  13 + *
  14 + * @author fanzhenyu
  15 + * @date 2023-01-15
  16 + */
  17 +public class ListValueConstraintValidator implements ConstraintValidator<ListIntValue, Integer> {
  18 + private Set<Integer> set = new HashSet<>();
  19 + // 是否必填
  20 + private boolean require;
  21 +
  22 + @Override
  23 + public void initialize(ListIntValue constraintAnnotation) {
  24 + for (int i : constraintAnnotation.enumValue()) {
  25 + set.add(i);
  26 + }
  27 + require = constraintAnnotation.require();
  28 + }
  29 +
  30 + /**
  31 + * 判断是否通过校验
  32 + *
  33 + * @param value 传入的值
  34 + * @param context
  35 + * @return
  36 + */
  37 + @Override
  38 + public boolean isValid(Integer value, ConstraintValidatorContext context) {
  39 + if (!require && value == null) {
  40 + return true;
  41 + }
  42 + return set.contains(value);
  43 + }
  44 +
  45 +}
... ...
src/main/java/com/canrd/webmagic/common/jsr303/OperateGroup.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/jsr303/OperateGroup.java
  1 +package com.canrd.webmagic.common.jsr303;
  2 +
  3 +
  4 +public class OperateGroup {
  5 + /**
  6 + * 新增校验
  7 + */
  8 + public interface Save {
  9 + }
  10 +
  11 + /**
  12 + * 删除校验
  13 + */
  14 + public interface Delete {
  15 + }
  16 +
  17 + /**
  18 + * 修改校验
  19 + */
  20 + public interface Update {
  21 + }
  22 +
  23 + /**
  24 + * 查询列表
  25 + */
  26 + public interface List {
  27 + }
  28 +
  29 + /**
  30 + * 分页查询
  31 + */
  32 + public interface Page {
  33 + }
  34 +
  35 + /**
  36 + * 长度校验
  37 + */
  38 + public interface Length {
  39 + }
  40 +
  41 + /**
  42 + * 格式校验
  43 + */
  44 + public interface Format {
  45 + }
  46 +
  47 + /**
  48 + * 详情
  49 + */
  50 + public interface Detail {
  51 + }
  52 +
  53 + /**
  54 + * 单条
  55 + */
  56 + public interface One {
  57 + }
  58 +
  59 +
  60 + public interface Trace {
  61 +
  62 + }
  63 +
  64 + /**
  65 + * 批量查询
  66 + */
  67 + public interface BatchQuery {
  68 + }
  69 +
  70 +
  71 + /**
  72 + * 导出
  73 + */
  74 + public interface Export {
  75 + }
  76 +
  77 +}
... ...
src/main/java/com/canrd/webmagic/common/jsr303/annotation/ListIntValue.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/jsr303/annotation/ListIntValue.java
  1 +package com.canrd.webmagic.common.jsr303.annotation;
  2 +
  3 +
  4 +import com.canrd.webmagic.common.jsr303.ListValueConstraintValidator;
  5 +
  6 +import javax.validation.Constraint;
  7 +import javax.validation.Payload;
  8 +import java.lang.annotation.*;
  9 +
  10 +/**
  11 + * @date 2023-01-15
  12 + */
  13 +@Constraint(validatedBy = {ListValueConstraintValidator.class})
  14 +@Documented
  15 +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
  16 +@Retention(RetentionPolicy.RUNTIME)
  17 +public @interface ListIntValue {
  18 +
  19 +
  20 + // 配置文件中错误提示信息的名称
  21 + String message() default "非法的类型";
  22 +
  23 + Class<?>[] groups() default {};
  24 +
  25 + Class<? extends Payload>[] payload() default {};
  26 +
  27 + // 自定义值的类型
  28 + int[] enumValue() default {};
  29 +
  30 + // 是否必填,默认允许为空
  31 + boolean require() default false;
  32 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/DateUtil.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/DateUtil.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +
  4 +import java.text.DateFormat;
  5 +import java.text.ParseException;
  6 +import java.text.SimpleDateFormat;
  7 +import java.time.*;
  8 +import java.time.format.DateTimeFormatter;
  9 +import java.time.temporal.ChronoField;
  10 +import java.time.temporal.TemporalAdjusters;
  11 +import java.util.Date;
  12 +import java.util.Locale;
  13 +import java.util.TimeZone;
  14 +
  15 +/**
  16 + * @Date: 2020/9/1
  17 + * 基于Java8的时间工具类
  18 + */
  19 +public class DateUtil {
  20 + /**
  21 + * 例如:2018-12-28
  22 + */
  23 + public static final String DATE = "yyyy-MM-dd";
  24 + /**
  25 + * 例如:2018.12.28
  26 + */
  27 + public static final String DATE_WITH_POINT = "yyyy.MM.dd";
  28 + /**
  29 + * 例如:2018-12-28 10:00:00
  30 + */
  31 + public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
  32 + /**
  33 + * 例如:2018-12-28 10:00:00:215
  34 + */
  35 + public static final String DATE_TIME_MS = "yyyy-MM-dd HH:mm:ss.SSS";
  36 + /**
  37 + * 例如:10:00:00
  38 + */
  39 + public static final String TIME = "HHmmss";
  40 + /**
  41 + * 例如:10:00:00
  42 + */
  43 + public static final String TIME_HAVE_SECOND = "HH:mm:ss";
  44 + /**
  45 + * 例如:10:00
  46 + */
  47 + public static final String TIME_WITHOUT_SECOND = "HH:mm";
  48 +
  49 + /**
  50 + * 例如:2018-12-28 10:00
  51 + */
  52 + public static final String DATE_TIME_WITHOUT_SECONDS = "yyyy-MM-dd HH:mm";
  53 +
  54 + /**
  55 + * 例如 2020/04/16 12:23:0
  56 + */
  57 + public static final String DATE_TIME_WITHOUT_SECONDS_OTHER = "yyyy/MM/dd HH:mm:ss";
  58 +
  59 + /**
  60 + * 例如:2020年04月23日 10:00
  61 + */
  62 + public static final String DATE_CHINESE_TIME = "yyyy年MM月dd日 HH:mm";
  63 +
  64 + /**
  65 + * 例如:20181228100000215
  66 + */
  67 + public static final String MAX_DATE = "9999-12-31 59:59:59";
  68 +
  69 + /**
  70 + * 例如:20210822082134
  71 + */
  72 + public static final String DATE_TIME_HMS = "yyyyMMddHHmmssSSS";
  73 +
  74 + public static final String YYMMDD = "yyyyMMdd";
  75 +
  76 + public static final String YMMDD = "yyMMdd";
  77 +
  78 + public static final String YYMMDDHHMMSS = "yyMMddHHmmss";
  79 +
  80 + public static final String MONTH_TIME = "MM-dd HH:mm:ss";
  81 +
  82 + /**
  83 + * 例如:2018-12-28 10:00
  84 + */
  85 + public static final String DDMMYYYYHHMMSS = "dd/MM/yyyy HH:mm:ss";
  86 +
  87 + public static LocalDateTime getCurrentTime() {
  88 + LocalDateTime now = LocalDateTime.now();
  89 + return now;
  90 + }
  91 +
  92 + public static Date getNextDay() {
  93 + LocalDateTime now = LocalDateTime.now();
  94 + LocalDateTime tomorrow = now.minusDays(-1);
  95 + return Date.from(tomorrow.atZone(ZoneId.systemDefault()).toInstant());
  96 + }
  97 +
  98 + public static Date getAppointDay(Integer count) {
  99 + LocalDateTime now = LocalDateTime.now();
  100 + LocalDateTime tomorrow = now.minusDays(count);
  101 + return Date.from(tomorrow.atZone(ZoneId.systemDefault()).toInstant());
  102 + }
  103 +
  104 + /**
  105 + * 获取年
  106 + *
  107 + * @return 年
  108 + */
  109 + public static int getYear() {
  110 + LocalDateTime localDateTime = LocalDateTime.now();
  111 + return localDateTime.get(ChronoField.YEAR);
  112 + }
  113 +
  114 + /**
  115 + * 获取月份
  116 + *
  117 + * @return 月份
  118 + */
  119 + public static int getMonth() {
  120 + LocalDateTime localDateTime = LocalDateTime.now();
  121 + return localDateTime.get(ChronoField.MONTH_OF_YEAR);
  122 + }
  123 +
  124 + /**
  125 + * 获取某月的第几天
  126 + *
  127 + * @return 几号
  128 + */
  129 + public static int getMonthOfDay() {
  130 + LocalDateTime localDateTime = LocalDateTime.now();
  131 + return localDateTime.get(ChronoField.DAY_OF_MONTH);
  132 + }
  133 +
  134 + /**
  135 + * 格式化日期为字符串
  136 + *
  137 + * @param date date
  138 + * @param pattern 格式
  139 + * @return 日期字符串
  140 + */
  141 + public static String formatOrElseBlank(Date date, String pattern) {
  142 + if (date == null || pattern == null) {
  143 + return "";
  144 + }
  145 + Instant instant = date.toInstant();
  146 +
  147 + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
  148 +
  149 + return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
  150 + }
  151 +
  152 + /**
  153 + * 格式化日期为字符串
  154 + *
  155 + * @param date date
  156 + * @param pattern 格式
  157 + * @return 日期字符串
  158 + */
  159 + public static String format(Date date, String pattern) {
  160 +
  161 + Instant instant = date.toInstant();
  162 +
  163 + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
  164 +
  165 + return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
  166 + }
  167 +
  168 + public static String formatNow(String pattern) {
  169 + LocalDateTime localDateTime = LocalDateTime.now();
  170 +
  171 + return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
  172 + }
  173 +
  174 +
  175 + public static String format(LocalDateTime date, String pattern) {
  176 + return date.format(DateTimeFormatter.ofPattern(pattern));
  177 + }
  178 +
  179 + public static String format(LocalDate date, String pattern) {
  180 + return date.format(DateTimeFormatter.ofPattern(pattern));
  181 + }
  182 +
  183 + /**
  184 + * 解析字符串日期为LocalDateTime
  185 + *
  186 + * @param dateStr 日期字符串
  187 + * @param pattern 格式
  188 + * @return Date
  189 + */
  190 + public static LocalDateTime parse(String dateStr, String pattern) {
  191 + return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
  192 + }
  193 +
  194 + /**
  195 + * 解析字符串日期为LocalDateTime
  196 + *
  197 + * @param dateStr 日期字符串
  198 + * @param pattern 格式
  199 + * @return Date
  200 + */
  201 + public static LocalDateTime parseStrByPattern(String dateStr, String pattern) {
  202 + try {
  203 + return parse(dateStr, pattern);
  204 + } catch (Exception e) {
  205 + return getCurrentTime();
  206 + }
  207 + }
  208 +
  209 + /**
  210 + * 解析字符串日期为LocalDate
  211 + *
  212 + * @param dateStr
  213 + * @param pattern
  214 + * @return
  215 + */
  216 + public static LocalDate parseDate(String dateStr, String pattern) {
  217 + return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
  218 + }
  219 +
  220 + /**
  221 + * @param dateTimeStr
  222 + * @param prePattern
  223 + * @param expectPattern
  224 + * @return
  225 + */
  226 + public static String format(String dateTimeStr, String prePattern, String expectPattern) {
  227 + LocalDateTime localDateTime = parseDate(dateTimeStr, prePattern).atStartOfDay();
  228 + return localDateTime.format(DateTimeFormatter.ofPattern(expectPattern));
  229 + }
  230 +
  231 + /**
  232 + * String -> Date
  233 + *
  234 + * @param date
  235 + * @return
  236 + */
  237 + public static Date parseStringToDate(String date, String pattern) {
  238 + SimpleDateFormat sdf = new SimpleDateFormat(pattern);
  239 + try {
  240 + return sdf.parse(date);
  241 + } catch (ParseException e) {
  242 + return null;
  243 + }
  244 + }
  245 +
  246 + /**
  247 + * 为Date增加分钟,减传负数
  248 + *
  249 + * @param date 日期
  250 + * @param plusMinutes 要增加的分钟数
  251 + * @return 新的日期
  252 + */
  253 + public static Date addMinutes(Date date, Long plusMinutes) {
  254 + LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
  255 + LocalDateTime newDateTime = dateTime.plusMinutes(plusMinutes);
  256 + return Date.from(newDateTime.atZone(ZoneId.systemDefault()).toInstant());
  257 + }
  258 +
  259 + /**
  260 + * 增加时间
  261 + *
  262 + * @param date date
  263 + * @param hour 要增加的小时数
  264 + * @return new date
  265 + */
  266 + public static Date addHour(Date date, Long hour) {
  267 + LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
  268 + LocalDateTime localDateTime = dateTime.plusHours(hour);
  269 + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
  270 + }
  271 +
  272 + /**
  273 + * @return 返回当天的起始时间
  274 + */
  275 + public static Date getStartTime() {
  276 +
  277 + LocalDateTime now = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
  278 + return localDateTime2Date(now);
  279 + }
  280 +
  281 +
  282 + /**
  283 + * @return 返回当天的结束时间
  284 + */
  285 + public static Date getEndTime() {
  286 + LocalDateTime now = LocalDateTime.now().withHour(23).withMinute(59).withSecond(59).withNano(999999999);
  287 + return localDateTime2Date(now);
  288 + }
  289 +
  290 + /**
  291 + * @return 获取入参当天结束时间
  292 + */
  293 + public static LocalDateTime getEndTime(LocalDate localDate) {
  294 + return localDate.atTime(23, 59, 59, 999999999);
  295 + }
  296 +
  297 + /**
  298 + * 减月份
  299 + *
  300 + * @param monthsToSubtract 月份
  301 + * @return Date
  302 + */
  303 + public static Date minusMonths(long monthsToSubtract) {
  304 + LocalDate localDate = LocalDate.now().minusMonths(monthsToSubtract);
  305 +
  306 + return localDate2Date(localDate);
  307 + }
  308 +
  309 + /**
  310 + * LocalDate类型转为Date
  311 + *
  312 + * @param localDate LocalDate object
  313 + * @return Date object
  314 + */
  315 + public static Date localDate2Date(LocalDate localDate) {
  316 +
  317 + ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
  318 +
  319 + return Date.from(zonedDateTime.toInstant());
  320 + }
  321 +
  322 + /**
  323 + * Date类型转为LocalDateTime
  324 + *
  325 + * @param date Date object
  326 + * @return localDate LocalDateTime
  327 + */
  328 + public static LocalDateTime date2LocalDateTime(Date date) {
  329 +
  330 + Instant instant = date.toInstant();
  331 + ZoneId zoneId = ZoneId.systemDefault();
  332 + LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
  333 + return localDateTime;
  334 + }
  335 +
  336 +
  337 + /**
  338 + * LocalDateTime类型转为Date
  339 + *
  340 + * @param localDateTime LocalDateTime object
  341 + * @return Date object
  342 + */
  343 + public static Date localDateTime2Date(LocalDateTime localDateTime) {
  344 + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
  345 + }
  346 +
  347 + /**
  348 + * 查询当前年的第一天
  349 + *
  350 + * @param pattern 格式,默认格式yyyyMMdd
  351 + * @return 20190101
  352 + */
  353 + public static String getFirstDayOfCurrentYear(String pattern) {
  354 + LocalDateTime localDateTime = LocalDateTime.now().withMonth(1).withDayOfMonth(1);
  355 +
  356 + if (StringUtils.isEmpty(pattern)) {
  357 + pattern = "yyyyMMdd";
  358 + }
  359 +
  360 + return format(localDateTime2Date(localDateTime), pattern);
  361 + }
  362 +
  363 + /**
  364 + * 查询前一年最后一个月第一天
  365 + *
  366 + * @param pattern 格式,默认格式yyyyMMdd
  367 + * @return 20190101
  368 + */
  369 + public static String getLastMonthFirstDayOfPreviousYear(String pattern) {
  370 + LocalDateTime localDateTime = LocalDateTime.now().minusYears(1L).withMonth(12).withDayOfMonth(1);
  371 +
  372 + if (StringUtils.isEmpty(pattern)) {
  373 + pattern = "yyyyMMdd";
  374 + }
  375 +
  376 + return format(localDateTime2Date(localDateTime), pattern);
  377 + }
  378 +
  379 + /**
  380 + * 查询前一年最后一个月第一天
  381 + *
  382 + * @param pattern 格式,默认格式yyyyMMdd
  383 + * @return 20190101
  384 + */
  385 + public static String getLastMonthLastDayOfPreviousYear(String pattern) {
  386 + LocalDateTime localDateTime = LocalDateTime.now().minusYears(1L).with(TemporalAdjusters.lastDayOfYear());
  387 +
  388 + if (StringUtils.isEmpty(pattern)) {
  389 + pattern = "yyyyMMdd";
  390 + }
  391 +
  392 + return format(localDateTime2Date(localDateTime), pattern);
  393 + }
  394 +
  395 + /**
  396 + * 获取当前日期
  397 + *
  398 + * @param pattern 格式,默认格式yyyyMMdd
  399 + * @return 20190101
  400 + */
  401 + public static String getCurrentDay(String pattern) {
  402 + LocalDateTime localDateTime = LocalDateTime.now();
  403 +
  404 + if (StringUtils.isEmpty(pattern)) {
  405 + pattern = "yyyyMMdd";
  406 + }
  407 +
  408 + return format(localDateTime2Date(localDateTime), pattern);
  409 + }
  410 +
  411 + public static String getTransitionTime(LocalDateTime time, String pattern) {
  412 + if (StringUtils.isEmpty(pattern)) {
  413 + pattern = "yyyyMMdd";
  414 + }
  415 + return format(localDateTime2Date(time), pattern);
  416 + }
  417 +
  418 +
  419 + /**
  420 + * 用于判断两个时间段有没有重合, 重合: true,未重合: false
  421 + *
  422 + * @param aStartTime
  423 + * @param aEndTime
  424 + * @param bStartTime
  425 + * @param bEndTime
  426 + * @return
  427 + * @author A80068
  428 + */
  429 + public static boolean judgeTimeSlotCoincidence(LocalDateTime aStartTime, LocalDateTime aEndTime, LocalDateTime bStartTime, LocalDateTime bEndTime) {
  430 + /**
  431 + * 旧版
  432 + */
  433 + //boolean flag;
  434 + //if(aStartTime.isAfter(bStartTime)){
  435 + // if (aStartTime.isBefore(bEndTime) || aStartTime.isEqual(bEndTime)){
  436 + // flag = true;
  437 + // }else{
  438 + // flag = false;
  439 + // }
  440 + //}else if(aStartTime.isBefore(bStartTime)){
  441 + // if(aEndTime.isAfter(bStartTime) || aEndTime.isEqual(bStartTime)){
  442 + // flag = true;
  443 + // }else{
  444 + // flag = false;
  445 + // }
  446 + //}else{
  447 + // flag = true;
  448 + //}
  449 + //return flag;
  450 + /**
  451 + * 优化版
  452 + */
  453 + boolean flag = false;
  454 + if ((aStartTime.isBefore(bEndTime) || aStartTime.isEqual(bEndTime))) {
  455 + if ((aEndTime.isAfter(bStartTime)) || aEndTime.isEqual(bStartTime)) {
  456 + flag = true;
  457 + }
  458 + }
  459 + return flag;
  460 + }
  461 +
  462 + /**
  463 + * @param aStartTimeStr
  464 + * @param aEndTimeStr
  465 + * @param bStartTimeStr
  466 + * @param bEndTimeStr
  467 + * @return
  468 + * @author A80068
  469 + */
  470 + public static boolean judgeTimeSlotCoincidenceString(String aStartTimeStr, String aEndTimeStr, String bStartTimeStr, String bEndTimeStr) {
  471 +
  472 + LocalDateTime aStartTime = parse(aStartTimeStr, DATE_TIME);
  473 + LocalDateTime aEndTime = parse(aEndTimeStr, DATE_TIME);
  474 + LocalDateTime bStartTime = parse(bStartTimeStr, DATE_TIME);
  475 + LocalDateTime bEndTime = parse(bEndTimeStr, DATE_TIME);
  476 +
  477 + return judgeTimeSlotCoincidence(aStartTime, aEndTime, bStartTime, bEndTime);
  478 + }
  479 +
  480 + /**
  481 + * @param strGMT
  482 + * @return
  483 + * @throws ParseException
  484 + * @throws ParseException
  485 + */
  486 + public static Date getCST(String strGMT) throws ParseException, ParseException {
  487 + DateFormat df = new SimpleDateFormat("EEE, d-MMM-yyyy HH:mm:ss z", Locale.ENGLISH);
  488 + return df.parse(strGMT);
  489 + }
  490 +
  491 + /**
  492 + * @param dateCST
  493 + * @return
  494 + */
  495 + public static Date getGMT(Date dateCST) throws ParseException {
  496 + DateFormat df = new SimpleDateFormat("EEE, d-MMM-yyyy HH:mm:ss z", Locale.ENGLISH);
  497 + df.setTimeZone(TimeZone.getTimeZone("GMT")); // modify Time Zone.
  498 + return df.parse(df.format(dateCST));
  499 + }
  500 +
  501 + /**
  502 + * LocalDateTime转化为cron表达式
  503 + *
  504 + * @param dateTime
  505 + * @return
  506 + */
  507 + public static String dateToCron(LocalDateTime dateTime) {
  508 + if (dateTime == null) {
  509 + return "";
  510 + }
  511 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ss mm HH dd MM ? yyyy");
  512 + return formatter.format(dateTime);
  513 + }
  514 +
  515 + /**
  516 + * cron表达式转为LocalDateTime
  517 + *
  518 + * @param cron
  519 + * @return
  520 + */
  521 + public static LocalDateTime cronToDate(String cron) {
  522 + if (StringUtils.isNotBlank(cron)) {
  523 + return null;
  524 + }
  525 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ss mm HH dd MM ? yyyy");
  526 + return LocalDateTime.parse(cron, formatter);
  527 + }
  528 +
  529 + public static String timeToString(long time) {
  530 + DateTimeFormatter ftf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  531 + return ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()));
  532 + }
  533 +
  534 + public static String timeToString(String time) {
  535 + try {
  536 + return timeToString(Long.parseLong(time));
  537 + } catch (Exception e) {
  538 + }
  539 + return time;
  540 + }
  541 +
  542 + /**
  543 + * 比较时间大小
  544 + *
  545 + * @param date1
  546 + * @param date2
  547 + * @return
  548 + */
  549 + public static int compareDate(Date date1, Date date2) {
  550 + if (date1 == null || date2 == null) {
  551 + return -2;
  552 + }
  553 + if (date1.getTime() < date2.getTime()) {
  554 + return -1;
  555 + } else if (date1.getTime() > date2.getTime()) {
  556 + return 1;
  557 + }
  558 + return 0;
  559 + }
  560 +
  561 + /**
  562 + * 判斷两个时间是否在同一分钟
  563 + */
  564 + public static boolean isMinuteIdentical(LocalDateTime date1, LocalDateTime date2) {
  565 + return date1.getYear() == date2.getYear() && date1.getMonth() == date2.getMonth() && date1.getMinute() == date2.getMinute();
  566 + }
  567 +
  568 + /**
  569 + * 时区
  570 + */
  571 + public static class Zone {
  572 + public static final String GMT8 = "GMT+8";
  573 + }
  574 +
  575 + public static LocalDateTime parseProductDate(String dateStr) {
  576 + if (StringUtils.isBlank(dateStr)) {
  577 + return null;
  578 + }
  579 + if (dateStr.length() == 8) {
  580 + dateStr = dateStr + " 00:00:00";
  581 + }
  582 + if (dateStr.contains("/")) {
  583 + dateStr = dateStr.replaceAll("/", "-");
  584 + }
  585 + try {
  586 + return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
  587 + } catch (Exception e) {
  588 + return null;
  589 + }
  590 + }
  591 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/DateUtils.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/DateUtils.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +
  4 +import java.text.DateFormat;
  5 +import java.text.ParseException;
  6 +import java.text.SimpleDateFormat;
  7 +import java.time.*;
  8 +import java.time.format.DateTimeFormatter;
  9 +import java.time.temporal.ChronoField;
  10 +import java.time.temporal.TemporalAdjusters;
  11 +import java.util.Date;
  12 +import java.util.Locale;
  13 +import java.util.TimeZone;
  14 +
  15 +/**
  16 + * @Date: 2020/9/1
  17 + * 基于Java8的时间工具类
  18 + */
  19 +public class DateUtils {
  20 + /**
  21 + * 例如:2018-12-28
  22 + */
  23 + public static final String DATE = "yyyy-MM-dd";
  24 + /**
  25 + * 例如:2018.12.28
  26 + */
  27 + public static final String DATE_WITH_POINT = "yyyy.MM.dd";
  28 + /**
  29 + * 例如:2018-12-28 10:00:00
  30 + */
  31 + public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
  32 + /**
  33 + * 例如:2018-12-28 10:00:00:215
  34 + */
  35 + public static final String DATE_TIME_MS = "yyyy-MM-dd HH:mm:ss.SSS";
  36 + /**
  37 + * 例如:10:00:00
  38 + */
  39 + public static final String TIME = "HHmmss";
  40 + /**
  41 + * 例如:10:00:00
  42 + */
  43 + public static final String TIME_HAVE_SECOND = "HH:mm:ss";
  44 + /**
  45 + * 例如:10:00
  46 + */
  47 + public static final String TIME_WITHOUT_SECOND = "HH:mm";
  48 +
  49 + /**
  50 + * 例如:2018-12-28 10:00
  51 + */
  52 + public static final String DATE_TIME_WITHOUT_SECONDS = "yyyy-MM-dd HH:mm";
  53 +
  54 + /**
  55 + * 例如 2020/04/16 12:23:0
  56 + */
  57 + public static final String DATE_TIME_WITHOUT_SECONDS_OTHER = "yyyy/MM/dd HH:mm:ss";
  58 +
  59 + /**
  60 + * 例如:2020年04月23日 10:00
  61 + */
  62 + public static final String DATE_CHINESE_TIME = "yyyy年MM月dd日 HH:mm";
  63 +
  64 + /**
  65 + * 例如:20181228100000215
  66 + */
  67 + public static final String MAX_DATE = "9999-12-31 59:59:59";
  68 +
  69 + /**
  70 + * 例如:20210822082134
  71 + */
  72 + public static final String DATE_TIME_HMS = "yyyyMMddHHmmssSSS";
  73 +
  74 + public static final String YYMMDD = "yyyyMMdd";
  75 +
  76 + public static final String YMMDD = "yyMMdd";
  77 +
  78 + public static final String YYMMDDHHMMSS = "yyMMddHHmmss";
  79 +
  80 + public static final String MONTH_TIME = "MM-dd HH:mm:ss";
  81 +
  82 + public static LocalDateTime getCurrentTime() {
  83 + LocalDateTime now = LocalDateTime.now();
  84 + return now;
  85 + }
  86 +
  87 + public static Date getNextDay() {
  88 + LocalDateTime now = LocalDateTime.now();
  89 + LocalDateTime tomorrow = now.minusDays(-1);
  90 + return Date.from(tomorrow.atZone(ZoneId.systemDefault()).toInstant());
  91 + }
  92 +
  93 + public static Date getAppointDay(Integer count) {
  94 + LocalDateTime now = LocalDateTime.now();
  95 + LocalDateTime tomorrow = now.minusDays(count);
  96 + return Date.from(tomorrow.atZone(ZoneId.systemDefault()).toInstant());
  97 + }
  98 +
  99 + /**
  100 + * 获取年
  101 + *
  102 + * @return 年
  103 + */
  104 + public static int getYear() {
  105 + LocalDateTime localDateTime = LocalDateTime.now();
  106 + return localDateTime.get(ChronoField.YEAR);
  107 + }
  108 +
  109 + /**
  110 + * 获取月份
  111 + *
  112 + * @return 月份
  113 + */
  114 + public static int getMonth() {
  115 + LocalDateTime localDateTime = LocalDateTime.now();
  116 + return localDateTime.get(ChronoField.MONTH_OF_YEAR);
  117 + }
  118 +
  119 + /**
  120 + * 获取某月的第几天
  121 + *
  122 + * @return 几号
  123 + */
  124 + public static int getMonthOfDay() {
  125 + LocalDateTime localDateTime = LocalDateTime.now();
  126 + return localDateTime.get(ChronoField.DAY_OF_MONTH);
  127 + }
  128 +
  129 + /**
  130 + * 格式化日期为字符串
  131 + *
  132 + * @param date date
  133 + * @param pattern 格式
  134 + * @return 日期字符串
  135 + */
  136 + public static String formatOrElseBlank(Date date, String pattern) {
  137 + if (date == null || pattern == null) {
  138 + return "";
  139 + }
  140 + Instant instant = date.toInstant();
  141 +
  142 + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
  143 +
  144 + return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
  145 + }
  146 +
  147 + /**
  148 + * 格式化日期为字符串
  149 + *
  150 + * @param date date
  151 + * @param pattern 格式
  152 + * @return 日期字符串
  153 + */
  154 + public static String format(Date date, String pattern) {
  155 +
  156 + Instant instant = date.toInstant();
  157 +
  158 + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
  159 +
  160 + return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
  161 + }
  162 +
  163 + public static String formatNow(String pattern) {
  164 + LocalDateTime localDateTime = LocalDateTime.now();
  165 +
  166 + return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
  167 + }
  168 +
  169 +
  170 + public static String format(LocalDateTime date, String pattern) {
  171 + return date.format(DateTimeFormatter.ofPattern(pattern));
  172 + }
  173 +
  174 + public static String format(LocalDate date, String pattern) {
  175 + return date.format(DateTimeFormatter.ofPattern(pattern));
  176 + }
  177 +
  178 + /**
  179 + * 解析字符串日期为LocalDateTime
  180 + *
  181 + * @param dateStr 日期字符串
  182 + * @param pattern 格式
  183 + * @return Date
  184 + */
  185 + public static LocalDateTime parse(String dateStr, String pattern) {
  186 + return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
  187 + }
  188 +
  189 + /**
  190 + * 解析字符串日期为LocalDateTime
  191 + *
  192 + * @param dateStr 日期字符串
  193 + * @param pattern 格式
  194 + * @return Date
  195 + */
  196 + public static LocalDateTime parseStrByPattern(String dateStr, String pattern) {
  197 + try {
  198 + return parse(dateStr, pattern);
  199 + } catch (Exception e) {
  200 + return getCurrentTime();
  201 + }
  202 + }
  203 +
  204 + /**
  205 + * 解析字符串日期为LocalDate
  206 + *
  207 + * @param dateStr
  208 + * @param pattern
  209 + * @return
  210 + */
  211 + public static LocalDate parseDate(String dateStr, String pattern) {
  212 + return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
  213 + }
  214 +
  215 + /**
  216 + * @param dateTimeStr
  217 + * @param prePattern
  218 + * @param expectPattern
  219 + * @return
  220 + */
  221 + public static String format(String dateTimeStr, String prePattern, String expectPattern) {
  222 + LocalDateTime localDateTime = parseDate(dateTimeStr, prePattern).atStartOfDay();
  223 + return localDateTime.format(DateTimeFormatter.ofPattern(expectPattern));
  224 + }
  225 +
  226 + /**
  227 + * String -> Date
  228 + *
  229 + * @param date
  230 + * @return
  231 + */
  232 + public static Date parseStringToDate(String date, String pattern) {
  233 + SimpleDateFormat sdf = new SimpleDateFormat(pattern);
  234 + try {
  235 + return sdf.parse(date);
  236 + } catch (ParseException e) {
  237 + return null;
  238 + }
  239 + }
  240 +
  241 + /**
  242 + * 为Date增加分钟,减传负数
  243 + *
  244 + * @param date 日期
  245 + * @param plusMinutes 要增加的分钟数
  246 + * @return 新的日期
  247 + */
  248 + public static Date addMinutes(Date date, Long plusMinutes) {
  249 + LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
  250 + LocalDateTime newDateTime = dateTime.plusMinutes(plusMinutes);
  251 + return Date.from(newDateTime.atZone(ZoneId.systemDefault()).toInstant());
  252 + }
  253 +
  254 + /**
  255 + * 增加时间
  256 + *
  257 + * @param date date
  258 + * @param hour 要增加的小时数
  259 + * @return new date
  260 + */
  261 + public static Date addHour(Date date, Long hour) {
  262 + LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
  263 + LocalDateTime localDateTime = dateTime.plusHours(hour);
  264 + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
  265 + }
  266 +
  267 + /**
  268 + * @return 返回当天的起始时间
  269 + */
  270 + public static Date getStartTime() {
  271 +
  272 + LocalDateTime now = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
  273 + return localDateTime2Date(now);
  274 + }
  275 +
  276 +
  277 + /**
  278 + * @return 返回当天的结束时间
  279 + */
  280 + public static Date getEndTime() {
  281 + LocalDateTime now = LocalDateTime.now().withHour(23).withMinute(59).withSecond(59).withNano(999999999);
  282 + return localDateTime2Date(now);
  283 + }
  284 +
  285 + /**
  286 + * @return 获取入参当天结束时间
  287 + */
  288 + public static LocalDateTime getEndTime(LocalDate localDate) {
  289 + return localDate.atTime(23, 59, 59, 999999999);
  290 + }
  291 +
  292 + /**
  293 + * 减月份
  294 + *
  295 + * @param monthsToSubtract 月份
  296 + * @return Date
  297 + */
  298 + public static Date minusMonths(long monthsToSubtract) {
  299 + LocalDate localDate = LocalDate.now().minusMonths(monthsToSubtract);
  300 +
  301 + return localDate2Date(localDate);
  302 + }
  303 +
  304 + /**
  305 + * LocalDate类型转为Date
  306 + *
  307 + * @param localDate LocalDate object
  308 + * @return Date object
  309 + */
  310 + public static Date localDate2Date(LocalDate localDate) {
  311 +
  312 + ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
  313 +
  314 + return Date.from(zonedDateTime.toInstant());
  315 + }
  316 +
  317 + /**
  318 + * Date类型转为LocalDateTime
  319 + *
  320 + * @param date Date object
  321 + * @return localDate LocalDateTime
  322 + */
  323 + public static LocalDateTime date2LocalDateTime(Date date) {
  324 +
  325 + Instant instant = date.toInstant();
  326 + ZoneId zoneId = ZoneId.systemDefault();
  327 + LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
  328 + return localDateTime;
  329 + }
  330 +
  331 +
  332 + /**
  333 + * LocalDateTime类型转为Date
  334 + *
  335 + * @param localDateTime LocalDateTime object
  336 + * @return Date object
  337 + */
  338 + public static Date localDateTime2Date(LocalDateTime localDateTime) {
  339 + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
  340 + }
  341 +
  342 + /**
  343 + * 查询当前年的第一天
  344 + *
  345 + * @param pattern 格式,默认格式yyyyMMdd
  346 + * @return 20190101
  347 + */
  348 + public static String getFirstDayOfCurrentYear(String pattern) {
  349 + LocalDateTime localDateTime = LocalDateTime.now().withMonth(1).withDayOfMonth(1);
  350 +
  351 + if (StringUtils.isEmpty(pattern)) {
  352 + pattern = "yyyyMMdd";
  353 + }
  354 +
  355 + return format(localDateTime2Date(localDateTime), pattern);
  356 + }
  357 +
  358 + /**
  359 + * 查询前一年最后一个月第一天
  360 + *
  361 + * @param pattern 格式,默认格式yyyyMMdd
  362 + * @return 20190101
  363 + */
  364 + public static String getLastMonthFirstDayOfPreviousYear(String pattern) {
  365 + LocalDateTime localDateTime = LocalDateTime.now().minusYears(1L).withMonth(12).withDayOfMonth(1);
  366 +
  367 + if (StringUtils.isEmpty(pattern)) {
  368 + pattern = "yyyyMMdd";
  369 + }
  370 +
  371 + return format(localDateTime2Date(localDateTime), pattern);
  372 + }
  373 +
  374 + /**
  375 + * 查询前一年最后一个月第一天
  376 + *
  377 + * @param pattern 格式,默认格式yyyyMMdd
  378 + * @return 20190101
  379 + */
  380 + public static String getLastMonthLastDayOfPreviousYear(String pattern) {
  381 + LocalDateTime localDateTime = LocalDateTime.now().minusYears(1L).with(TemporalAdjusters.lastDayOfYear());
  382 +
  383 + if (StringUtils.isEmpty(pattern)) {
  384 + pattern = "yyyyMMdd";
  385 + }
  386 +
  387 + return format(localDateTime2Date(localDateTime), pattern);
  388 + }
  389 +
  390 + /**
  391 + * 获取当前日期
  392 + *
  393 + * @param pattern 格式,默认格式yyyyMMdd
  394 + * @return 20190101
  395 + */
  396 + public static String getCurrentDay(String pattern) {
  397 + LocalDateTime localDateTime = LocalDateTime.now();
  398 +
  399 + if (StringUtils.isEmpty(pattern)) {
  400 + pattern = "yyyyMMdd";
  401 + }
  402 +
  403 + return format(localDateTime2Date(localDateTime), pattern);
  404 + }
  405 +
  406 + public static String getTransitionTime(LocalDateTime time, String pattern) {
  407 + if (StringUtils.isEmpty(pattern)) {
  408 + pattern = "yyyyMMdd";
  409 + }
  410 + return format(localDateTime2Date(time), pattern);
  411 + }
  412 +
  413 +
  414 + /**
  415 + * 用于判断两个时间段有没有重合, 重合: true,未重合: false
  416 + *
  417 + * @param aStartTime
  418 + * @param aEndTime
  419 + * @param bStartTime
  420 + * @param bEndTime
  421 + * @return
  422 + * @author A80068
  423 + */
  424 + public static boolean judgeTimeSlotCoincidence(LocalDateTime aStartTime, LocalDateTime aEndTime, LocalDateTime bStartTime, LocalDateTime bEndTime) {
  425 + /**
  426 + * 旧版
  427 + */
  428 + //boolean flag;
  429 + //if(aStartTime.isAfter(bStartTime)){
  430 + // if (aStartTime.isBefore(bEndTime) || aStartTime.isEqual(bEndTime)){
  431 + // flag = true;
  432 + // }else{
  433 + // flag = false;
  434 + // }
  435 + //}else if(aStartTime.isBefore(bStartTime)){
  436 + // if(aEndTime.isAfter(bStartTime) || aEndTime.isEqual(bStartTime)){
  437 + // flag = true;
  438 + // }else{
  439 + // flag = false;
  440 + // }
  441 + //}else{
  442 + // flag = true;
  443 + //}
  444 + //return flag;
  445 + /**
  446 + * 优化版
  447 + */
  448 + boolean flag = false;
  449 + if ((aStartTime.isBefore(bEndTime) || aStartTime.isEqual(bEndTime))) {
  450 + if ((aEndTime.isAfter(bStartTime)) || aEndTime.isEqual(bStartTime)) {
  451 + flag = true;
  452 + }
  453 + }
  454 + return flag;
  455 + }
  456 +
  457 + /**
  458 + * @param aStartTimeStr
  459 + * @param aEndTimeStr
  460 + * @param bStartTimeStr
  461 + * @param bEndTimeStr
  462 + * @return
  463 + * @author A80068
  464 + */
  465 + public static boolean judgeTimeSlotCoincidenceString(String aStartTimeStr, String aEndTimeStr, String bStartTimeStr, String bEndTimeStr) {
  466 +
  467 + LocalDateTime aStartTime = parse(aStartTimeStr, DATE_TIME);
  468 + LocalDateTime aEndTime = parse(aEndTimeStr, DATE_TIME);
  469 + LocalDateTime bStartTime = parse(bStartTimeStr, DATE_TIME);
  470 + LocalDateTime bEndTime = parse(bEndTimeStr, DATE_TIME);
  471 +
  472 + return judgeTimeSlotCoincidence(aStartTime, aEndTime, bStartTime, bEndTime);
  473 + }
  474 +
  475 + /**
  476 + * @param strGMT
  477 + * @return
  478 + * @throws ParseException
  479 + * @throws ParseException
  480 + */
  481 + public static Date getCST(String strGMT) throws ParseException, ParseException {
  482 + DateFormat df = new SimpleDateFormat("EEE, d-MMM-yyyy HH:mm:ss z", Locale.ENGLISH);
  483 + return df.parse(strGMT);
  484 + }
  485 +
  486 + /**
  487 + * @param dateCST
  488 + * @return
  489 + */
  490 + public static Date getGMT(Date dateCST) throws ParseException {
  491 + DateFormat df = new SimpleDateFormat("EEE, d-MMM-yyyy HH:mm:ss z", Locale.ENGLISH);
  492 + df.setTimeZone(TimeZone.getTimeZone("GMT")); // modify Time Zone.
  493 + return df.parse(df.format(dateCST));
  494 + }
  495 +
  496 + /**
  497 + * LocalDateTime转化为cron表达式
  498 + *
  499 + * @param dateTime
  500 + * @return
  501 + */
  502 + public static String dateToCron(LocalDateTime dateTime) {
  503 + if (dateTime == null) {
  504 + return "";
  505 + }
  506 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ss mm HH dd MM ? yyyy");
  507 + return formatter.format(dateTime);
  508 + }
  509 +
  510 + /**
  511 + * cron表达式转为LocalDateTime
  512 + *
  513 + * @param cron
  514 + * @return
  515 + */
  516 + public static LocalDateTime cronToDate(String cron) {
  517 + if (StringUtils.isNotBlank(cron)) {
  518 + return null;
  519 + }
  520 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ss mm HH dd MM ? yyyy");
  521 + return LocalDateTime.parse(cron, formatter);
  522 + }
  523 +
  524 + public static String timeToString(long time) {
  525 + DateTimeFormatter ftf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  526 + return ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()));
  527 + }
  528 +
  529 + public static String timeToString(String time) {
  530 + try {
  531 + return timeToString(Long.parseLong(time));
  532 + } catch (Exception e) {
  533 + }
  534 + return time;
  535 + }
  536 +
  537 + /**
  538 + * 比较时间大小
  539 + *
  540 + * @param date1
  541 + * @param date2
  542 + * @return
  543 + */
  544 + public static int compareDate(Date date1, Date date2) {
  545 + if (date1 == null || date2 == null) {
  546 + return -2;
  547 + }
  548 + if (date1.getTime() < date2.getTime()) {
  549 + return -1;
  550 + } else if (date1.getTime() > date2.getTime()) {
  551 + return 1;
  552 + }
  553 + return 0;
  554 + }
  555 +
  556 + /**
  557 + * 判斷两个时间是否在同一分钟
  558 + */
  559 + public static boolean isMinuteIdentical(LocalDateTime date1, LocalDateTime date2) {
  560 + return date1.getYear() == date2.getYear() && date1.getMonth() == date2.getMonth() && date1.getMinute() == date2.getMinute();
  561 + }
  562 +
  563 + /**
  564 + * 时区
  565 + */
  566 + public static class Zone {
  567 + public static final String GMT8 = "GMT+8";
  568 + }
  569 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/EncryptUtils.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/EncryptUtils.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import javax.crypto.Cipher;
  4 +import javax.crypto.SecretKey;
  5 +import javax.crypto.SecretKeyFactory;
  6 +import javax.crypto.spec.DESKeySpec;
  7 +import javax.crypto.spec.IvParameterSpec;
  8 +import java.nio.charset.StandardCharsets;
  9 +
  10 +/**
  11 + * 加密
  12 + *
  13 + * @date 2018-11-23
  14 + */
  15 +public class EncryptUtils {
  16 +
  17 + private static String strParam = "Passw0rd";
  18 +
  19 + private static Cipher cipher;
  20 +
  21 + private static IvParameterSpec iv = new IvParameterSpec(strParam.getBytes(StandardCharsets.UTF_8));
  22 +
  23 + private static DESKeySpec getDesKeySpec(String source) throws Exception {
  24 + if (source == null || source.length() == 0) {
  25 + return null;
  26 + }
  27 + cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
  28 + String strKey = "Passw0rd";
  29 + return new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8));
  30 + }
  31 +
  32 + /**
  33 + * 对称加密
  34 + */
  35 + public static String desEncrypt(String source) throws Exception {
  36 + DESKeySpec desKeySpec = getDesKeySpec(source);
  37 + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  38 + SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
  39 + cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
  40 + return byte2hex(
  41 + cipher.doFinal(source.getBytes(StandardCharsets.UTF_8))).toUpperCase();
  42 + }
  43 +
  44 + /**
  45 + * 对称解密
  46 + */
  47 + public static String desDecrypt(String source) throws Exception {
  48 + byte[] src = hex2byte(source.getBytes());
  49 + DESKeySpec desKeySpec = getDesKeySpec(source);
  50 + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  51 + SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
  52 + cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
  53 + byte[] retByte = cipher.doFinal(src);
  54 + return new String(retByte);
  55 + }
  56 +
  57 + private static String byte2hex(byte[] inStr) {
  58 + String stmp;
  59 + StringBuilder out = new StringBuilder(inStr.length * 2);
  60 + for (byte b : inStr) {
  61 + stmp = Integer.toHexString(b & 0xFF);
  62 + if (stmp.length() == 1) {
  63 + // 如果是0至F的单位字符串,则添加0
  64 + out.append("0").append(stmp);
  65 + } else {
  66 + out.append(stmp);
  67 + }
  68 + }
  69 + return out.toString();
  70 + }
  71 +
  72 + private static byte[] hex2byte(byte[] b) {
  73 + int size = 2;
  74 + if ((b.length % size) != 0) {
  75 + throw new IllegalArgumentException("长度不是偶数");
  76 + }
  77 + byte[] b2 = new byte[b.length / 2];
  78 + for (int n = 0; n < b.length; n += size) {
  79 + String item = new String(b, n, 2);
  80 + b2[n / 2] = (byte) Integer.parseInt(item, 16);
  81 + }
  82 + return b2;
  83 + }
  84 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/FileUtil.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/FileUtil.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import cn.hutool.core.codec.Base64;
  4 +import cn.hutool.core.io.IoUtil;
  5 +import cn.hutool.core.util.IdUtil;
  6 +import cn.hutool.poi.excel.BigExcelWriter;
  7 +import cn.hutool.poi.excel.ExcelUtil;
  8 +import org.apache.poi.util.IOUtils;
  9 +import org.springframework.web.multipart.MultipartFile;
  10 +
  11 +import javax.activation.MimetypesFileTypeMap;
  12 +import javax.servlet.ServletOutputStream;
  13 +import javax.servlet.http.HttpServletRequest;
  14 +import javax.servlet.http.HttpServletResponse;
  15 +import java.io.*;
  16 +import java.security.MessageDigest;
  17 +import java.text.DecimalFormat;
  18 +import java.text.SimpleDateFormat;
  19 +import java.util.Date;
  20 +import java.util.List;
  21 +import java.util.Map;
  22 +
  23 +/**
  24 + * File工具类,扩展 hutool 工具包
  25 + *
  26 + * @date 2018-12-27
  27 + */
  28 +public class FileUtil extends cn.hutool.core.io.FileUtil {
  29 +
  30 + /**
  31 + * 定义GB的计算常量
  32 + */
  33 + private static final int GB = 1024 * 1024 * 1024;
  34 + /**
  35 + * 定义MB的计算常量
  36 + */
  37 + private static final int MB = 1024 * 1024;
  38 + /**
  39 + * 定义KB的计算常量
  40 + */
  41 + private static final int KB = 1024;
  42 +
  43 + /**
  44 + * 格式化小数
  45 + */
  46 + private static final DecimalFormat DF = new DecimalFormat("0.00");
  47 +
  48 + /**
  49 + * MultipartFile转File
  50 + */
  51 + public static File toFile(MultipartFile multipartFile) {
  52 + // 获取文件名
  53 + String fileName = multipartFile.getOriginalFilename();
  54 + // 获取文件后缀
  55 + String prefix = "." + getExtensionName(fileName);
  56 + File file = null;
  57 + try {
  58 + // 用uuid作为文件名,防止生成的临时文件重复
  59 + file = File.createTempFile(IdUtil.simpleUUID(), prefix);
  60 + // MultipartFile to File
  61 + multipartFile.transferTo(file);
  62 + } catch (IOException e) {
  63 + e.printStackTrace();
  64 + }
  65 + return file;
  66 + }
  67 +
  68 + /**
  69 + * 获取文件扩展名,不带 .
  70 + */
  71 + public static String getExtensionName(String filename) {
  72 + if ((filename != null) && (filename.length() > 0)) {
  73 + int dot = filename.lastIndexOf('.');
  74 + if ((dot > -1) && (dot < (filename.length() - 1))) {
  75 + return filename.substring(dot + 1);
  76 + }
  77 + }
  78 + return filename;
  79 + }
  80 +
  81 + /**
  82 + * Java文件操作 获取不带扩展名的文件名
  83 + */
  84 + public static String getFileNameNoEx(String filename) {
  85 + if ((filename != null) && (filename.length() > 0)) {
  86 + int dot = filename.lastIndexOf('.');
  87 + if ((dot > -1) && (dot < (filename.length()))) {
  88 + return filename.substring(0, dot);
  89 + }
  90 + }
  91 + return filename;
  92 + }
  93 +
  94 + /**
  95 + * 文件大小转换
  96 + */
  97 + public static String getSize(long size) {
  98 + String resultSize;
  99 + if (size / GB >= 1) {
  100 + //如果当前Byte的值大于等于1GB
  101 + resultSize = DF.format(size / (float) GB) + "GB ";
  102 + } else if (size / MB >= 1) {
  103 + //如果当前Byte的值大于等于1MB
  104 + resultSize = DF.format(size / (float) MB) + "MB ";
  105 + } else if (size / KB >= 1) {
  106 + //如果当前Byte的值大于等于1KB
  107 + resultSize = DF.format(size / (float) KB) + "KB ";
  108 + } else {
  109 + resultSize = size + "B ";
  110 + }
  111 + return resultSize;
  112 + }
  113 +
  114 + /**
  115 + * inputStream 转 File
  116 + */
  117 + public static File inputStreamToFile(InputStream ins, String name) throws Exception {
  118 + File file = new File(System.getProperty("java.io.tmpdir") + File.separator + name);
  119 + if (file.exists()) {
  120 + return file;
  121 + }
  122 + OutputStream os = new FileOutputStream(file);
  123 + int bytesRead;
  124 + int len = 8192;
  125 + byte[] buffer = new byte[len];
  126 + while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
  127 + os.write(buffer, 0, bytesRead);
  128 + }
  129 + os.close();
  130 + ins.close();
  131 + return file;
  132 + }
  133 +
  134 + /**
  135 + * 将文件转换为byte数组,作为图片数据导入
  136 + *
  137 + * @param file
  138 + * @return byte[]
  139 + */
  140 + public static byte[] imageParseBytes(File file) {
  141 + FileInputStream fileInputStream = null;
  142 + try {
  143 + fileInputStream = new FileInputStream(file);
  144 + } catch (FileNotFoundException e) {
  145 + e.printStackTrace();
  146 + }
  147 + return imageParseBytes(fileInputStream);
  148 + }
  149 +
  150 + /**
  151 + * 将流转换为byte数组,作为图片数据导入
  152 + *
  153 + * @param fis
  154 + * @return byte[]
  155 + */
  156 + public static byte[] imageParseBytes(InputStream fis) {
  157 + byte[] buffer = null;
  158 + ByteArrayOutputStream bos = null;
  159 + try {
  160 + bos = new ByteArrayOutputStream(1024);
  161 + byte[] b = new byte[1024];
  162 + int n;
  163 + while ((n = fis.read(b)) != -1) {
  164 + bos.write(b, 0, n);
  165 + }
  166 + buffer = bos.toByteArray();
  167 + } catch (Exception e) {
  168 + e.printStackTrace();
  169 + } finally {
  170 + try {
  171 + fis.close();
  172 + bos.close();
  173 + } catch (IOException e) {
  174 + e.printStackTrace();
  175 + }
  176 + }
  177 + return buffer;
  178 + }
  179 +
  180 + /**
  181 + * 将文件名解析成文件的上传路径
  182 + */
  183 + public static File upload(MultipartFile file, String filePath) {
  184 + Date date = new Date();
  185 + SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
  186 + String name = getFileNameNoEx(file.getOriginalFilename());
  187 + String suffix = getExtensionName(file.getOriginalFilename());
  188 + String nowStr = "-" + format.format(date);
  189 + try {
  190 + String fileName = name + nowStr + "." + suffix;
  191 + String path = filePath + fileName;
  192 + // getCanonicalFile 可解析正确各种路径
  193 + File dest = new File(path).getCanonicalFile();
  194 + // 检测是否存在目录
  195 + if (!dest.getParentFile().exists()) {
  196 + dest.getParentFile().mkdirs();
  197 + }
  198 + // 文件写入
  199 + file.transferTo(dest);
  200 + return dest;
  201 + } catch (Exception e) {
  202 + e.printStackTrace();
  203 + }
  204 + return null;
  205 + }
  206 +
  207 + public static String fileToBase64(File file) throws Exception {
  208 + FileInputStream inputFile = new FileInputStream(file);
  209 + String base64;
  210 + byte[] buffer = new byte[(int) file.length()];
  211 + inputFile.read(buffer);
  212 + inputFile.close();
  213 + base64 = Base64.encode(buffer);
  214 + return base64.replaceAll("[\\s*\t\n\r]", "");
  215 + }
  216 +
  217 + /**
  218 + * 导出excel
  219 + */
  220 + public static void downloadExcel(List<Map<String, Object>> list, HttpServletResponse response) throws IOException {
  221 + String tempPath = System.getProperty("java.io.tmpdir") + IdUtil.fastSimpleUUID() + ".xlsx";
  222 + File file = new File(tempPath);
  223 + BigExcelWriter writer = ExcelUtil.getBigWriter(file);
  224 + // 一次性写出内容,使用默认样式,强制输出标题
  225 + writer.write(list, true);
  226 + //response为HttpServletResponse对象
  227 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
  228 + //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
  229 + response.setHeader("Content-Disposition", "attachment;filename=file.xlsx");
  230 + ServletOutputStream out = response.getOutputStream();
  231 + // 终止后删除临时文件
  232 + file.deleteOnExit();
  233 + writer.flush(out, true);
  234 + //此处记得关闭输出Servlet流
  235 + IoUtil.close(out);
  236 + }
  237 +
  238 + public static String getFileType(String type) {
  239 + String documents = "txt doc pdf ppt pps xlsx xls docx";
  240 + String music = "mp3 wav wma mpa ram ra aac aif m4a";
  241 + String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
  242 + String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
  243 + if (image.contains(type)) {
  244 + return "images";
  245 + } else if (documents.contains(type)) {
  246 + return "docs";
  247 + } else if (music.contains(type)) {
  248 + return "musics";
  249 + } else if (video.contains(type)) {
  250 + return "videos";
  251 + } else {
  252 + return "others";
  253 + }
  254 + }
  255 +
  256 + public static String getFileTypeByMimeType(String type) {
  257 + String mimeType = new MimetypesFileTypeMap().getContentType("." + type);
  258 + return mimeType.split("/")[0];
  259 + }
  260 +
  261 + public static void checkSize(long maxSize, long size) {
  262 + // 1M
  263 + int len = 1024 * 1024;
  264 + if (size > (maxSize * len)) {
  265 + throw new RuntimeException("文件超出规定大小");
  266 + }
  267 + }
  268 +
  269 + /**
  270 + * 判断两个文件是否相同
  271 + */
  272 + public static boolean check(File file1, File file2) {
  273 + String img1Md5 = getMd5(file1);
  274 + String img2Md5 = getMd5(file2);
  275 + return img1Md5.equals(img2Md5);
  276 + }
  277 +
  278 + /**
  279 + * 判断两个文件是否相同
  280 + */
  281 + public static boolean check(String file1Md5, String file2Md5) {
  282 + return file1Md5.equals(file2Md5);
  283 + }
  284 +
  285 + private static byte[] getByte(File file) {
  286 + // 得到文件长度
  287 + byte[] b = new byte[(int) file.length()];
  288 + try {
  289 + InputStream in = new FileInputStream(file);
  290 + try {
  291 + in.read(b);
  292 + } catch (IOException e) {
  293 + e.printStackTrace();
  294 + }
  295 + } catch (FileNotFoundException e) {
  296 + e.printStackTrace();
  297 + return null;
  298 + }
  299 + return b;
  300 + }
  301 +
  302 + private static String getMd5(byte[] bytes) {
  303 + // 16进制字符
  304 + char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
  305 + try {
  306 + MessageDigest mdTemp = MessageDigest.getInstance("MD5");
  307 + mdTemp.update(bytes);
  308 + byte[] md = mdTemp.digest();
  309 + int j = md.length;
  310 + char[] str = new char[j * 2];
  311 + int k = 0;
  312 + // 移位 输出字符串
  313 + for (byte byte0 : md) {
  314 + str[k++] = hexDigits[byte0 >>> 4 & 0xf];
  315 + str[k++] = hexDigits[byte0 & 0xf];
  316 + }
  317 + return new String(str);
  318 + } catch (Exception e) {
  319 + e.printStackTrace();
  320 + }
  321 + return null;
  322 + }
  323 +
  324 + /**
  325 + * 下载文件
  326 + *
  327 + * @param request /
  328 + * @param response /
  329 + * @param file /
  330 + */
  331 + public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) {
  332 + response.setCharacterEncoding(request.getCharacterEncoding());
  333 + response.setContentType("application/octet-stream");
  334 + FileInputStream fis = null;
  335 + try {
  336 + fis = new FileInputStream(file);
  337 + response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
  338 + IOUtils.copy(fis, response.getOutputStream());
  339 + response.flushBuffer();
  340 + } catch (Exception e) {
  341 + e.printStackTrace();
  342 + } finally {
  343 + if (fis != null) {
  344 + try {
  345 + fis.close();
  346 + if (deleteOnExit) {
  347 + file.deleteOnExit();
  348 + }
  349 + } catch (IOException e) {
  350 + e.printStackTrace();
  351 + }
  352 + }
  353 + }
  354 + }
  355 +
  356 + public static String getMd5(File file) {
  357 + return getMd5(getByte(file));
  358 + }
  359 +
  360 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/JsonUtil.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/JsonUtil.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +
  4 +import com.alibaba.fastjson.JSONException;
  5 +import com.alibaba.fastjson.JSONObject;
  6 +import com.fasterxml.jackson.annotation.JsonInclude;
  7 +import com.fasterxml.jackson.core.JsonGenerator;
  8 +import com.fasterxml.jackson.core.JsonProcessingException;
  9 +import com.fasterxml.jackson.core.type.TypeReference;
  10 +import com.fasterxml.jackson.databind.*;
  11 +import com.fasterxml.jackson.databind.node.ArrayNode;
  12 +import com.fasterxml.jackson.databind.node.ObjectNode;
  13 +import lombok.extern.slf4j.Slf4j;
  14 +
  15 +import java.io.IOException;
  16 +
  17 +/**
  18 + *
  19 + * @author achims
  20 + * @date 2019/11/4
  21 + * 用于转换成json字符串以及解析成对象
  22 + */
  23 +@Slf4j
  24 +public class JsonUtil {
  25 +
  26 + private static ObjectMapper mapper = new ObjectMapper();
  27 +
  28 + static {
  29 + log.info("注册jackson-datatype-jsr310的java8时间处理模块");
  30 + mapper.findAndRegisterModules();
  31 + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  32 + mapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
  33 + @Override
  34 + public void serialize(Object paramT, JsonGenerator paramJsonGenerator,
  35 + SerializerProvider paramSerializerProvider) throws IOException {
  36 + //设置返回null转为 空字符串""
  37 + paramJsonGenerator.writeString("");
  38 + }
  39 + });
  40 + }
  41 +
  42 +
  43 +
  44 +
  45 + /**
  46 + * Create empty json node
  47 + *
  48 + * @return
  49 + */
  50 + public static ObjectNode createJsonNode() {
  51 + return mapper.createObjectNode();
  52 + }
  53 +
  54 + /**
  55 + * Create empty json Array
  56 + *
  57 + * @return
  58 + */
  59 + public static ArrayNode createJsonArray() {
  60 + return mapper.createArrayNode();
  61 +
  62 + }
  63 +
  64 + /**
  65 + * Convert the object to corresponding json string
  66 + *
  67 + * @param obj
  68 + * @return
  69 + */
  70 + public static String toJsonString(Object obj) {
  71 + try {
  72 + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
  73 + return mapper.writeValueAsString(obj);
  74 + } catch (JsonProcessingException e) {
  75 + return null;
  76 + }
  77 + }
  78 +
  79 + /**
  80 + * 转成格式化后的json,便于调试排错
  81 + * @param obj
  82 + * @return
  83 + */
  84 + public static String toJsonStringWithDefaultPretty(Object obj) {
  85 + try {
  86 + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
  87 + return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
  88 + } catch (JsonProcessingException e) {
  89 +
  90 + return null;
  91 + }
  92 + }
  93 +
  94 + public static <T> T jsonToEntity(String json, Class<T> clazz) {
  95 + if (StringUtils.isEmpty(json)) return null;
  96 + try {
  97 + return mapper.readValue(json, clazz);
  98 + } catch (IOException e) {
  99 + e.printStackTrace();
  100 + }
  101 + return null;
  102 + }
  103 +
  104 + /**
  105 + * 借助json做中转,实体类转实体类
  106 + * @param obj 实体
  107 + * @param clazz 目标类型
  108 + * @param <T> 目标泛型
  109 + * @return 结果
  110 + */
  111 + public static <T> T entityConvert(Object obj, Class<T> clazz) {
  112 + return jsonToEntity(toJsonString(obj), clazz);
  113 + }
  114 +
  115 + /**
  116 + * 带泛型返回不告警
  117 + * @param json json字符
  118 + * @param typeReference TypeReference
  119 + * @param <R> 返回类型
  120 + * @param <T> 转换的类型
  121 + * @return 转换结果
  122 + * @author 刘迪榕
  123 + * @version Date 2022-08-26
  124 + */
  125 + public static <R, T extends R> R jsonToEntity(String json, TypeReference<T> typeReference) {
  126 + if (StringUtils.isEmpty(json)) return null;
  127 + try {
  128 + return mapper.readValue(json, typeReference);
  129 + } catch (IOException e) {
  130 + e.printStackTrace();
  131 + }
  132 + return null;
  133 + }
  134 +
  135 + public static JsonNode readStringAsJsonNode(String json) {
  136 + try {
  137 + return mapper.readValue(json, JsonNode.class);
  138 + } catch (IOException e) {
  139 + e.printStackTrace();
  140 + }
  141 + return null;
  142 + }
  143 +
  144 + public static JsonNode valueToTree(Object value) {
  145 + return mapper.valueToTree(value);
  146 + }
  147 +
  148 + public static <T> T treeToValue(JsonNode jsonNode, Class<T> clazz) {
  149 + try {
  150 + return mapper.treeToValue(jsonNode, clazz);
  151 + } catch (IOException e) {
  152 + e.printStackTrace();
  153 + }
  154 + return null;
  155 + }
  156 +
  157 + /**
  158 + * 是否爲json格式的數據
  159 + *
  160 + * @param test
  161 + * @return
  162 + */
  163 + public final static boolean isJSONValid(String test) {
  164 + try {
  165 + JSONObject.parseObject(test);
  166 + } catch (JSONException ex) {
  167 + try {
  168 + JSONObject.parseArray(test);
  169 + } catch (JSONException ex1) {
  170 + return false;
  171 + }
  172 + }
  173 + return true;
  174 + }
  175 +
  176 + public <T> T paraseJsonTOClass(String json, Class<T> cla) {
  177 + try {
  178 + return JSONObject.parseObject(json, cla);
  179 + } catch (JSONException ex) {
  180 + return null;
  181 + }
  182 + }
  183 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/LocalDateTimeUtil.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/LocalDateTimeUtil.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import org.joda.time.DateTime;
  4 +
  5 +import java.time.LocalDateTime;
  6 +
  7 +/**
  8 + * @author: xms
  9 + * @description: TODO
  10 + * @date: 2023/1/16 16:35
  11 + * @version: 1.0
  12 + */
  13 +public class LocalDateTimeUtil {
  14 +
  15 + /**
  16 + * @param dateTime
  17 + * @return
  18 + */
  19 + public static LocalDateTime toLocalDateTime(DateTime dateTime) {
  20 + return LocalDateTime.of(dateTime.getYear(), dateTime.getMonthOfYear(),
  21 + dateTime.getDayOfMonth(), dateTime.getHourOfDay(),
  22 + dateTime.getMinuteOfHour(), dateTime.getSecondOfMinute());
  23 + }
  24 +
  25 + /**
  26 + *
  27 + * @param localDateTime
  28 + * @return
  29 + */
  30 + public static DateTime toDateTime(LocalDateTime localDateTime) {
  31 + return new DateTime().withYear(localDateTime.getYear()).withMonthOfYear(localDateTime.getMonthValue())
  32 + .withDayOfMonth(localDateTime.getDayOfMonth()).withHourOfDay(localDateTime.getHour())
  33 + .withMinuteOfHour(localDateTime.getMinute()).withSecondOfMinute(localDateTime.getSecond());
  34 + }
  35 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/PageUtils.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/PageUtils.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import com.baomidou.mybatisplus.core.metadata.IPage;
  4 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  5 +import com.canrd.webmagic.domain.vo.BasePageVO;
  6 +import org.springframework.util.CollectionUtils;
  7 +
  8 +import java.io.Serializable;
  9 +import java.util.*;
  10 +
  11 +/**
  12 + * @Author: dengbin
  13 + * @Date: 2020/9/11
  14 + * 分页工具类
  15 + */
  16 +
  17 +public class PageUtils implements Serializable {
  18 + private static final long serialVersionUID = 4359709211352400087L;
  19 + private static final String PAGE_INDEX = "pageNo";
  20 + private static final String PAGE_SIZE = "pageSize";
  21 + private static final String TOTAL_ROWS = "total";
  22 + private static final String TOTAL_PAGES = "pages";
  23 + private static final String RECORDS = "records";
  24 +
  25 + private static final int DEFAULT_PAGE_INDEX = 1;
  26 + private static final int DEFAULT_PAGE_SIZE = 10;
  27 + private static final int DEFAULT_MAP_CAPACITY = 5;
  28 +
  29 + /**
  30 + * 统一分页返回对象
  31 + *
  32 + * @param list
  33 + * @return
  34 + */
  35 + public static Map<String, Object> getUnifiedPageReturn(IPage list) {
  36 + if (list == null) {
  37 + return getUnifiedEmptyPage(DEFAULT_PAGE_INDEX, DEFAULT_PAGE_SIZE);
  38 + }
  39 +
  40 + Map<String, Object> resultMap = new HashMap<>(DEFAULT_MAP_CAPACITY);
  41 + resultMap.put(PAGE_INDEX, list.getCurrent());
  42 + resultMap.put(PAGE_SIZE, list.getSize());
  43 + resultMap.put(RECORDS, list.getRecords());
  44 + resultMap.put(TOTAL_PAGES, list.getPages());
  45 + resultMap.put(TOTAL_ROWS, list.getTotal());
  46 +
  47 + return resultMap;
  48 + }
  49 +
  50 + /**
  51 + * 返回空分页信息给前端
  52 + * 返回空或其他字段不满足前端要求,会报错
  53 + *
  54 + * @return
  55 + */
  56 + public static Map<String, Object> getUnifiedEmptyPage(int pageIndex, int pageSize) {
  57 + Map<String, Object> resultMap = new HashMap<>(DEFAULT_MAP_CAPACITY);
  58 + resultMap.put(PAGE_INDEX, pageIndex);
  59 + resultMap.put(PAGE_SIZE, pageSize);
  60 + resultMap.put(RECORDS, new ArrayList<>());
  61 + resultMap.put(TOTAL_PAGES, 0);
  62 + resultMap.put(TOTAL_ROWS, 0);
  63 + return resultMap;
  64 + }
  65 +
  66 + public static Map<String, Object> getUnifiedEmptyPage(BasePageVO pageVO) {
  67 + return getUnifiedEmptyPage(pageVO.getCurrent(), pageVO.getSize());
  68 + }
  69 +
  70 +
  71 + /**
  72 + * 将旧的分页转换成新的分页对象
  73 + *
  74 + * @param oldPage 旧的分页对象,例如:xxDo的分页对象
  75 + * @param records 新的分页对象,例如:xxVo的分页对象
  76 + * @param <T> 新的分页对象的类型
  77 + * @return 统一的返回的分页对象
  78 + */
  79 + public static <T> Map<String, Object> transferPage(IPage<?> oldPage, List<T> records) {
  80 + Page<T> newPage = new Page<>();
  81 + newPage.setCurrent(oldPage.getCurrent());
  82 + newPage.setSize(oldPage.getSize());
  83 + newPage.setRecords(records);
  84 + newPage.setPages(oldPage.getPages());
  85 + newPage.setTotal(oldPage.getTotal());
  86 + return getUnifiedPageReturn(newPage);
  87 + }
  88 +
  89 + /**
  90 + * 统一分页返回对象
  91 + *
  92 + * @param records 分页数据
  93 + * @param pageVO 分页参数
  94 + * @return
  95 + */
  96 + public static Map<String, Object> getPageReturn(List records, BasePageVO pageVO) {
  97 + if (records == null) {
  98 + return getUnifiedEmptyPage(DEFAULT_PAGE_INDEX, DEFAULT_PAGE_SIZE);
  99 + }
  100 + if (CollectionUtils.isEmpty(records)) {
  101 + return getUnifiedEmptyPage(Math.toIntExact(pageVO.getCurrent()), Math.toIntExact(pageVO.getSize()));
  102 + }
  103 + Map<String, Object> resultMap = new HashMap<>(DEFAULT_MAP_CAPACITY);
  104 + resultMap.put(PAGE_INDEX, pageVO.getCurrent());
  105 + resultMap.put(PAGE_SIZE, pageVO.getSize());
  106 + resultMap.put(RECORDS, records);
  107 + resultMap.put(TOTAL_PAGES, (pageVO.getTotal() + pageVO.getSize() - 1) / pageVO.getSize());
  108 + resultMap.put(TOTAL_ROWS, pageVO.getTotal());
  109 +
  110 + return resultMap;
  111 + }
  112 +
  113 + public static <T> Page<T> getRAMPageReturn(Integer current, Integer size, List<T> records) {
  114 + if (Objects.isNull(current)) {
  115 + current = 1;
  116 + }
  117 + if (Objects.isNull(size)) {
  118 + size = 10;
  119 + }
  120 + int startIndex = (current - 1) * size;
  121 + int endIndex = Math.min(current * size, records.size());
  122 + if (startIndex > endIndex) {
  123 + startIndex = endIndex;
  124 + }
  125 + Page<T> page = new Page<>();
  126 + page.setCurrent(current);
  127 + page.setSize(size);
  128 + page.setRecords(records.subList(startIndex, endIndex));
  129 + int totalPages = size == 0 ? 0 : records.size() % size == 0 ? (records.size() / size) : (records.size() / size + 1);
  130 + page.setPages(totalPages);
  131 + page.setTotal(records.size());
  132 + return page;
  133 + }
  134 +
  135 +
  136 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/RedisUtil.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/RedisUtil.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.springframework.data.redis.connection.DataType;
  5 +import org.springframework.data.redis.core.*;
  6 +import org.springframework.stereotype.Repository;
  7 +
  8 +import javax.annotation.Resource;
  9 +import java.util.*;
  10 +import java.util.concurrent.TimeUnit;
  11 +import java.util.stream.Collectors;
  12 +
  13 +/**
  14 + * @Date: 2020/9/1
  15 + */
  16 +@Slf4j
  17 +@Repository("redisUtil")
  18 +public class RedisUtil {
  19 +
  20 + @Resource(name = "stringRedisTemplate")
  21 + private StringRedisTemplate redisTemplate;
  22 +
  23 +
  24 + /* -------------------key相关操作--------------------- */
  25 +
  26 + /**
  27 + * 删除key
  28 + *
  29 + * @param key key key
  30 + */
  31 + public void delete(String key) {
  32 + redisTemplate.delete(key);
  33 + }
  34 +
  35 + /**
  36 + * 批量删除key
  37 + *
  38 + * @param keys keys
  39 + */
  40 + public void delete(Collection<String> keys) {
  41 + redisTemplate.delete(keys);
  42 + }
  43 +
  44 + /**
  45 + * 序列化key
  46 + *
  47 + * @param key key
  48 + * @return
  49 + */
  50 + public byte[] dump(String key) {
  51 + return redisTemplate.dump(key);
  52 + }
  53 +
  54 + /**
  55 + * 是否存在key
  56 + *
  57 + * @param key key
  58 + * @return
  59 + */
  60 + public Boolean hasKey(String key) {
  61 + return redisTemplate.hasKey(key);
  62 + }
  63 +
  64 + /**
  65 + * 设置过期时间
  66 + *
  67 + * @param key key
  68 + * @param timeout
  69 + * @param unit
  70 + * @return
  71 + */
  72 + public Boolean expire(String key, long timeout, TimeUnit unit) {
  73 + return redisTemplate.expire(key, timeout, unit);
  74 + }
  75 +
  76 + /**
  77 + * 设置过期时间
  78 + *
  79 + * @param key key
  80 + * @param date
  81 + * @return
  82 + */
  83 + public Boolean expireAt(String key, Date date) {
  84 + return redisTemplate.expireAt(key, date);
  85 + }
  86 +
  87 + /**
  88 + * 查找匹配的key
  89 + *
  90 + * @param pattern
  91 + * @return
  92 + */
  93 + public Set<String> keys(String pattern) {
  94 + return redisTemplate.keys(pattern);
  95 + }
  96 +
  97 + /**
  98 + * 将当前数据库的 key 移动到给定的数据库 db 当中
  99 + *
  100 + * @param key key
  101 + * @param dbIndex
  102 + * @return
  103 + */
  104 + public Boolean move(String key, int dbIndex) {
  105 + return redisTemplate.move(key, dbIndex);
  106 + }
  107 +
  108 + /**
  109 + * 移除 key 的过期时间,key 将持久保持
  110 + *
  111 + * @param key key
  112 + * @return
  113 + */
  114 + public Boolean persist(String key) {
  115 + return redisTemplate.persist(key);
  116 + }
  117 +
  118 + /**
  119 + * 返回 key 的剩余的过期时间
  120 + *
  121 + * @param key key
  122 + * @param unit
  123 + * @return
  124 + */
  125 + public Long getExpire(String key, TimeUnit unit) {
  126 + return redisTemplate.getExpire(key, unit);
  127 + }
  128 +
  129 + /**
  130 + * 返回 key 的剩余的过期时间
  131 + *
  132 + * @param key key
  133 + * @return
  134 + */
  135 + public Long getExpire(String key) {
  136 + return redisTemplate.getExpire(key);
  137 + }
  138 +
  139 + /**
  140 + * 从当前数据库中随机返回一个 key
  141 + *
  142 + * @return
  143 + */
  144 + public String randomKey() {
  145 + return redisTemplate.randomKey();
  146 + }
  147 +
  148 + /**
  149 + * 修改 key 的名称
  150 + *
  151 + * @param oldKey
  152 + * @param newKey
  153 + */
  154 + public void rename(String oldKey, String newKey) {
  155 + redisTemplate.rename(oldKey, newKey);
  156 + }
  157 +
  158 + /**
  159 + * 仅当 newkey 不存在时,将 oldKey 改名为 newkey
  160 + *
  161 + * @param oldKey
  162 + * @param newKey
  163 + * @return
  164 + */
  165 + public Boolean renameIfAbsent(String oldKey, String newKey) {
  166 + return redisTemplate.renameIfAbsent(oldKey, newKey);
  167 + }
  168 +
  169 + /**
  170 + * 返回 key 所储存的值的类型
  171 + *
  172 + * @param key key
  173 + * @return
  174 + */
  175 + public DataType type(String key) {
  176 + return redisTemplate.type(key);
  177 + }
  178 +
  179 + /**
  180 + * -------------------string相关操作---------------------
  181 + *//*
  182 +
  183 + /**
  184 + * 设置指定 key 的值
  185 + * @param key key
  186 + * @param value val
  187 + */
  188 + public void set(String key, String value) {
  189 + redisTemplate.opsForValue().set(key, value);
  190 + }
  191 +
  192 + /**
  193 + * 设置缓存,指定有效时间
  194 + * 时间单位为 秒
  195 + *
  196 + * @param key
  197 + * @param value
  198 + * @param expireTime
  199 + */
  200 + public void set(String key, String value, Long expireTime) {
  201 + redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);
  202 + }
  203 +
  204 + /**
  205 + * 设置缓存,指定有效时间
  206 + * 时间单位 自定义
  207 + *
  208 + * @param key
  209 + * @param value
  210 + * @param expireTime
  211 + * @param timeUnit
  212 + */
  213 + public void set(String key, String value, Long expireTime, TimeUnit timeUnit) {
  214 + redisTemplate.opsForValue().set(key, value, expireTime, timeUnit);
  215 + }
  216 +
  217 + /**
  218 + * 获取指定 key 的值
  219 + *
  220 + * @param key key
  221 + * @return
  222 + */
  223 + public String get(String key) {
  224 + return redisTemplate.opsForValue().get(key);
  225 + }
  226 +
  227 + /**
  228 + * 返回 key 中字符串值的子字符
  229 + *
  230 + * @param key key
  231 + * @param start
  232 + * @param end
  233 + * @return
  234 + */
  235 + public String getRange(String key, long start, long end) {
  236 + return redisTemplate.opsForValue().get(key, start, end);
  237 + }
  238 +
  239 + /**
  240 + * 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
  241 + *
  242 + * @param key key
  243 + * @param value val
  244 + * @return
  245 + */
  246 + public String getAndSet(String key, String value) {
  247 + return redisTemplate.opsForValue().getAndSet(key, value);
  248 + }
  249 +
  250 + /**
  251 + * 对 key 所储存的字符串值,获取指定偏移量上的位(bit)
  252 + *
  253 + * @param key key
  254 + * @param offset
  255 + * @return
  256 + */
  257 + public Boolean getBit(String key, long offset) {
  258 + return redisTemplate.opsForValue().getBit(key, offset);
  259 + }
  260 +
  261 + /**
  262 + * 批量获取
  263 + *
  264 + * @param keys keys
  265 + * @return 多个key的value
  266 + */
  267 + public List<String> multiGet(Collection<String> keys) {
  268 + return redisTemplate.opsForValue().multiGet(keys);
  269 + }
  270 +
  271 + public List<String> multiGetPip(Collection<String> keys) {
  272 + return redisTemplate.executePipelined((RedisCallback<String>) connection -> {
  273 + keys.forEach(a -> connection.get(a.getBytes()));
  274 + return null;
  275 + }).stream()
  276 + .filter(Objects::nonNull)
  277 + .map(Object::toString)
  278 + .collect(Collectors.toList());
  279 + }
  280 +
  281 + /**
  282 + * 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value
  283 + *
  284 + * @param key key
  285 + * @param offset 偏移
  286 + * @param value val
  287 + */
  288 + public Boolean setBit(String key, long offset, boolean value) {
  289 + return redisTemplate.opsForValue().setBit(key, offset, value);
  290 + }
  291 +
  292 + /**
  293 + * 将值 value 关联到 key ,并将 key 的过期时间设为 timeout
  294 + *
  295 + * @param key key
  296 + * @param value val
  297 + * @param timeout 过期时间
  298 + * @param unit 时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES
  299 + * 秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
  300 + */
  301 + public void setEx(String key, String value, long timeout, TimeUnit unit) {
  302 + redisTemplate.opsForValue().set(key, value, timeout, unit);
  303 + }
  304 +
  305 + /**
  306 + * 只有在 key 不存在时设置 key 的值
  307 + *
  308 + * @param key key
  309 + * @param value val
  310 + * @return 之前已经存在返回false, 不存在返回true
  311 + */
  312 + public Boolean setIfAbsent(String key, String value) {
  313 + return redisTemplate.opsForValue().setIfAbsent(key, value);
  314 + }
  315 +
  316 +
  317 + /**
  318 + * 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始
  319 + *
  320 + * @param key key
  321 + * @param value val
  322 + * @param offset 从指定位置开始覆写
  323 + */
  324 + public void setRange(String key, String value, long offset) {
  325 + redisTemplate.opsForValue().set(key, value, offset);
  326 + }
  327 +
  328 + /**
  329 + * 获取字符串的长度
  330 + *
  331 + * @param key key
  332 + */
  333 + public Long size(String key) {
  334 + return redisTemplate.opsForValue().size(key);
  335 + }
  336 +
  337 + /**
  338 + * 批量添加
  339 + */
  340 + public void multiSet(Map<String, String> maps) {
  341 + redisTemplate.opsForValue().multiSet(maps);
  342 + }
  343 +
  344 + /**
  345 + * 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
  346 + *
  347 + * @return 之前已经存在返回false, 不存在返回true
  348 + */
  349 + public Boolean multiSetIfAbsent(Map<String, String> maps) {
  350 + return redisTemplate.opsForValue().multiSetIfAbsent(maps);
  351 + }
  352 +
  353 + /**
  354 + * 增加(自增长), 负数则为自减
  355 + *
  356 + * @param key key
  357 + * @param increment 步长
  358 + */
  359 + public Long incrBy(String key, long increment) {
  360 + return redisTemplate.opsForValue().increment(key, increment);
  361 + }
  362 +
  363 + /**
  364 + * @param key key
  365 + * @param increment 步长
  366 + */
  367 + public Double incrByFloat(String key, double increment) {
  368 + return redisTemplate.opsForValue().increment(key, increment);
  369 + }
  370 +
  371 + /**
  372 + * 增加(自增长), 负数则为自减
  373 + *
  374 + * @param key key redisKey
  375 + * @param decrement 步长
  376 + */
  377 + public Long decreByLong(String key, long decrement) {
  378 + return redisTemplate.opsForValue().decrement(key, decrement);
  379 + }
  380 +
  381 + /**
  382 + * @param key key redisKey
  383 + */
  384 + public Long decreBy(String key) {
  385 + return redisTemplate.opsForValue().decrement(key);
  386 + }
  387 +
  388 + /**
  389 + * 追加到末尾
  390 + *
  391 + * @param key key
  392 + * @param value val
  393 + * @return
  394 + */
  395 + public Integer append(String key, String value) {
  396 + return redisTemplate.opsForValue().append(key, value);
  397 + }
  398 +
  399 + /** -------------------hash相关操作------------------------- */
  400 +
  401 + /**
  402 + * 获取存储在哈希表中指定字段的值
  403 + *
  404 + * @param key key
  405 + * @param field
  406 + * @return
  407 + */
  408 + public Object hGet(String key, String field) {
  409 + return redisTemplate.opsForHash().get(key, field);
  410 + }
  411 +
  412 + /**
  413 + * 获取所有给定字段的值
  414 + *
  415 + * @param key key
  416 + * @return
  417 + */
  418 + public Map<Object, Object> hGetAll(String key) {
  419 + return redisTemplate.opsForHash().entries(key);
  420 + }
  421 +
  422 + /**
  423 + * 获取所有给定字段的值
  424 + *
  425 + * @param key key
  426 + * @param fields
  427 + * @return
  428 + */
  429 + public List<Object> hMultiGet(String key, Collection<Object> fields) {
  430 + return redisTemplate.opsForHash().multiGet(key, fields);
  431 + }
  432 +
  433 + public void hPut(String key, String hashKey, String value) {
  434 + redisTemplate.opsForHash().put(key, hashKey, value);
  435 + }
  436 +
  437 + public void hPutAll(String key, Map<String, String> maps) {
  438 + redisTemplate.opsForHash().putAll(key, maps);
  439 + }
  440 +
  441 + /**
  442 + * 仅当hashKey不存在时才设置
  443 + *
  444 + * @param key key
  445 + * @param hashKey
  446 + * @param value val
  447 + * @return
  448 + */
  449 + public Boolean hPutIfAbsent(String key, String hashKey, String value) {
  450 + return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
  451 + }
  452 +
  453 + /**
  454 + * 删除一个或多个哈希表字段
  455 + *
  456 + * @param key key
  457 + * @param fields
  458 + * @return
  459 + */
  460 + public Long hDelete(String key, Object... fields) {
  461 + return redisTemplate.opsForHash().delete(key, fields);
  462 + }
  463 +
  464 + /**
  465 + * 查看哈希表 key 中,指定的字段是否存在
  466 + *
  467 + * @param key key
  468 + * @param field
  469 + * @return
  470 + */
  471 + public Boolean hExists(String key, String field) {
  472 + return redisTemplate.opsForHash().hasKey(key, field);
  473 + }
  474 +
  475 + /**
  476 + * 为哈希表 key 中的指定字段的整数值加上增量 increment
  477 + *
  478 + * @param key key
  479 + * @param field
  480 + * @param increment
  481 + * @return
  482 + */
  483 + public Long hIncrBy(String key, Object field, long increment) {
  484 + return redisTemplate.opsForHash().increment(key, field, increment);
  485 + }
  486 +
  487 + /**
  488 + * 为哈希表 key 中的指定字段的整数值加上增量 increment
  489 + *
  490 + * @param key key
  491 + * @param field
  492 + * @param delta
  493 + * @return
  494 + */
  495 + public Double hIncrByFloat(String key, Object field, double delta) {
  496 + return redisTemplate.opsForHash().increment(key, field, delta);
  497 + }
  498 +
  499 + /**
  500 + * 获取所有哈希表中的字段
  501 + *
  502 + * @param key key
  503 + * @return
  504 + */
  505 + public Set<Object> hKeys(String key) {
  506 + return redisTemplate.opsForHash().keys(key);
  507 + }
  508 +
  509 + /**
  510 + * 获取哈希表中字段的数量
  511 + *
  512 + * @param key key
  513 + * @return
  514 + */
  515 + public Long hSize(String key) {
  516 + return redisTemplate.opsForHash().size(key);
  517 + }
  518 +
  519 + /**
  520 + * 获取哈希表中所有值
  521 + *
  522 + * @param key key
  523 + * @return
  524 + */
  525 + public List<Object> hValues(String key) {
  526 + return redisTemplate.opsForHash().values(key);
  527 + }
  528 +
  529 + /**
  530 + * 迭代哈希表中的键值对
  531 + *
  532 + * @param key key
  533 + * @param options
  534 + * @return
  535 + */
  536 + public Cursor<Map.Entry<Object, Object>> hScan(String key, ScanOptions options) {
  537 + return redisTemplate.opsForHash().scan(key, options);
  538 + }
  539 +
  540 + /** ------------------------list相关操作---------------------------- */
  541 +
  542 + /**
  543 + * 通过索引获取列表中的元素
  544 + *
  545 + * @param key key
  546 + * @param index
  547 + * @return
  548 + */
  549 + public String lIndex(String key, long index) {
  550 + return redisTemplate.opsForList().index(key, index);
  551 + }
  552 +
  553 + /**
  554 + * 获取列表指定范围内的元素
  555 + *
  556 + * @param key key
  557 + * @param start 开始位置, 0是开始位置
  558 + * @param end 结束位置, -1返回所有
  559 + * @return
  560 + */
  561 + public List<String> lRange(String key, long start, long end) {
  562 + return redisTemplate.opsForList().range(key, start, end);
  563 + }
  564 +
  565 + /**
  566 + * 存储在list头部
  567 + *
  568 + * @param key key
  569 + * @param value val
  570 + * @return
  571 + */
  572 + public Long lLeftPush(String key, String value) {
  573 + return redisTemplate.opsForList().leftPush(key, value);
  574 + }
  575 +
  576 + /**
  577 + * @param key key
  578 + * @param value val
  579 + * @return
  580 + */
  581 + public Long lLeftPushAll(String key, String... value) {
  582 + return redisTemplate.opsForList().leftPushAll(key, value);
  583 + }
  584 +
  585 + /**
  586 + * @param key key
  587 + * @param value val
  588 + * @return
  589 + */
  590 + public Long lLeftPushAll(String key, Collection<String> value) {
  591 + return redisTemplate.opsForList().leftPushAll(key, value);
  592 + }
  593 +
  594 + /**
  595 + * 当list存在的时候才加入
  596 + *
  597 + * @param key key
  598 + * @param value val
  599 + * @return
  600 + */
  601 + public Long lLeftPushIfPresent(String key, String value) {
  602 + return redisTemplate.opsForList().leftPushIfPresent(key, value);
  603 + }
  604 +
  605 + /**
  606 + * 如果pivot存在,再pivot前面添加
  607 + *
  608 + * @param key key
  609 + * @param pivot
  610 + * @param value val
  611 + * @return
  612 + */
  613 + public Long lLeftPush(String key, String pivot, String value) {
  614 + return redisTemplate.opsForList().leftPush(key, pivot, value);
  615 + }
  616 +
  617 + /**
  618 + * @param key key
  619 + * @param value val
  620 + * @return
  621 + */
  622 + public Long lRightPush(String key, String value) {
  623 + return redisTemplate.opsForList().rightPush(key, value);
  624 + }
  625 +
  626 + /**
  627 + * @param key key
  628 + * @param value val
  629 + * @return
  630 + */
  631 + public Long lRightPushAll(String key, String... value) {
  632 + return redisTemplate.opsForList().rightPushAll(key, value);
  633 + }
  634 +
  635 + /**
  636 + * @param key key
  637 + * @param value val
  638 + * @return
  639 + */
  640 + public Long lRightPushAll(String key, Collection<String> value) {
  641 + return redisTemplate.opsForList().rightPushAll(key, value);
  642 + }
  643 +
  644 + /**
  645 + * 为已存在的列表添加值
  646 + *
  647 + * @param key key
  648 + * @param value val
  649 + * @return
  650 + */
  651 + public Long lRightPushIfPresent(String key, String value) {
  652 + return redisTemplate.opsForList().rightPushIfPresent(key, value);
  653 + }
  654 +
  655 + /**
  656 + * 在pivot元素的右边添加值
  657 + *
  658 + * @param key key
  659 + * @param pivot
  660 + * @param value val
  661 + * @return
  662 + */
  663 + public Long lRightPush(String key, String pivot, String value) {
  664 + return redisTemplate.opsForList().rightPush(key, pivot, value);
  665 + }
  666 +
  667 + /**
  668 + * 通过索引设置列表元素的值
  669 + *
  670 + * @param key key
  671 + * @param index 位置
  672 + * @param value val
  673 + */
  674 + public void lSet(String key, long index, String value) {
  675 + redisTemplate.opsForList().set(key, index, value);
  676 + }
  677 +
  678 + /**
  679 + * 移出并获取列表的第一个元素
  680 + *
  681 + * @param key key
  682 + * @return 删除的元素
  683 + */
  684 + public String lLeftPop(String key) {
  685 + return redisTemplate.opsForList().leftPop(key);
  686 + }
  687 +
  688 + /**
  689 + * 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
  690 + *
  691 + * @param key key
  692 + * @param timeout 等待时间
  693 + * @param unit 时间单位
  694 + * @return
  695 + */
  696 + public String lbLeftPop(String key, long timeout, TimeUnit unit) {
  697 + return redisTemplate.opsForList().leftPop(key, timeout, unit);
  698 + }
  699 +
  700 + /**
  701 + * 移除并获取列表最后一个元素
  702 + *
  703 + * @param key key
  704 + * @return 删除的元素
  705 + */
  706 + public String lRightPop(String key) {
  707 + return redisTemplate.opsForList().rightPop(key);
  708 + }
  709 +
  710 + /**
  711 + * 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
  712 + *
  713 + * @param key key
  714 + * @param timeout 等待时间
  715 + * @param unit 时间单位
  716 + * @return
  717 + */
  718 + public String lbRightPop(String key, long timeout, TimeUnit unit) {
  719 + return redisTemplate.opsForList().rightPop(key, timeout, unit);
  720 + }
  721 +
  722 + /**
  723 + * 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
  724 + *
  725 + * @param sourceKey
  726 + * @param destinationKey
  727 + * @return
  728 + */
  729 + public String lRightPopAndLeftPush(String sourceKey, String destinationKey) {
  730 + return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey);
  731 + }
  732 +
  733 + /**
  734 + * 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
  735 + *
  736 + * @param sourceKey
  737 + * @param destinationKey
  738 + * @param timeout
  739 + * @param unit
  740 + * @return
  741 + */
  742 + public String lbRightPopAndLeftPush(String sourceKey, String destinationKey,
  743 + long timeout, TimeUnit unit) {
  744 + return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey, timeout, unit);
  745 + }
  746 +
  747 + /**
  748 + * 删除集合中值等于value得元素
  749 + *
  750 + * @param key key
  751 + * @param index index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素;
  752 + * index<0, 从尾部开始删除第一个值等于value的元素;
  753 + * @param value val
  754 + * @return
  755 + */
  756 + public Long lRemove(String key, long index, String value) {
  757 + return redisTemplate.opsForList().remove(key, index, value);
  758 + }
  759 +
  760 + /**
  761 + * 裁剪list
  762 + *
  763 + * @param key key
  764 + * @param start
  765 + * @param end
  766 + */
  767 + public void lTrim(String key, long start, long end) {
  768 + redisTemplate.opsForList().trim(key, start, end);
  769 + }
  770 +
  771 + /**
  772 + * 获取列表长度
  773 + *
  774 + * @param key key
  775 + * @return
  776 + */
  777 + public Long lLen(String key) {
  778 + return redisTemplate.opsForList().size(key);
  779 + }
  780 +
  781 + /** --------------------set相关操作-------------------------- */
  782 +
  783 + /**
  784 + * set添加元素
  785 + *
  786 + * @param key key
  787 + * @param values vals
  788 + * @return
  789 + */
  790 + public Long sAdd(String key, String... values) {
  791 + return redisTemplate.opsForSet().add(key, values);
  792 + }
  793 +
  794 + /**
  795 + * set移除元素
  796 + *
  797 + * @param key key
  798 + * @param values vals
  799 + * @return
  800 + */
  801 + public Long sRemove(String key, Object... values) {
  802 + return redisTemplate.opsForSet().remove(key, values);
  803 + }
  804 +
  805 + /**
  806 + * 移除并返回集合的一个随机元素
  807 + *
  808 + * @param key key
  809 + * @return
  810 + */
  811 + public String sPop(String key) {
  812 + return redisTemplate.opsForSet().pop(key);
  813 + }
  814 +
  815 + /**
  816 + * 移除并返回集合的多个随机元素
  817 + *
  818 + * @param key key
  819 + * @return
  820 + */
  821 + public List<String> sPop(String key, int count) {
  822 + return redisTemplate.opsForSet().pop(key, count);
  823 + }
  824 +
  825 + /**
  826 + * 将元素value从一个集合移到另一个集合
  827 + *
  828 + * @param key key
  829 + * @param value val
  830 + * @param destKey
  831 + * @return
  832 + */
  833 + public Boolean sMove(String key, String value, String destKey) {
  834 + return redisTemplate.opsForSet().move(key, value, destKey);
  835 + }
  836 +
  837 + /**
  838 + * 获取集合的大小
  839 + *
  840 + * @param key key
  841 + * @return
  842 + */
  843 + public Long sSize(String key) {
  844 + return redisTemplate.opsForSet().size(key);
  845 + }
  846 +
  847 + /**
  848 + * 判断集合是否包含value
  849 + *
  850 + * @param key key
  851 + * @param value val
  852 + * @return
  853 + */
  854 + public Boolean sIsMember(String key, Object value) {
  855 + return redisTemplate.opsForSet().isMember(key, value);
  856 + }
  857 +
  858 + /**
  859 + * 获取两个集合的交集
  860 + *
  861 + * @param key key
  862 + * @param otherKey
  863 + * @return
  864 + */
  865 + public Set<String> sIntersect(String key, String otherKey) {
  866 + return redisTemplate.opsForSet().intersect(key, otherKey);
  867 + }
  868 +
  869 + /**
  870 + * 获取key集合与多个集合的交集
  871 + *
  872 + * @param key key
  873 + * @param otherKeys
  874 + * @return
  875 + */
  876 + public Set<String> sIntersect(String key, Collection<String> otherKeys) {
  877 + return redisTemplate.opsForSet().intersect(key, otherKeys);
  878 + }
  879 +
  880 + /**
  881 + * key集合与otherKey集合的交集存储到destKey集合中
  882 + *
  883 + * @param key key
  884 + * @param otherKey
  885 + * @param destKey
  886 + * @return
  887 + */
  888 + public Long sIntersectAndStore(String key, String otherKey, String destKey) {
  889 + return redisTemplate.opsForSet().intersectAndStore(key, otherKey, destKey);
  890 + }
  891 +
  892 + /**
  893 + * key集合与多个集合的交集存储到destKey集合中
  894 + *
  895 + * @param key key
  896 + * @param otherKeys
  897 + * @param destKey
  898 + * @return
  899 + */
  900 + public Long sIntersectAndStore(String key, Collection<String> otherKeys, String destKey) {
  901 + return redisTemplate.opsForSet().intersectAndStore(key, otherKeys, destKey);
  902 + }
  903 +
  904 + /**
  905 + * 获取两个集合的并集
  906 + *
  907 + * @param key key
  908 + * @param otherKeys
  909 + * @return
  910 + */
  911 + public Set<String> sUnion(String key, String otherKeys) {
  912 + return redisTemplate.opsForSet().union(key, otherKeys);
  913 + }
  914 +
  915 + /**
  916 + * 获取key集合与多个集合的并集
  917 + *
  918 + * @param key key
  919 + * @param otherKeys
  920 + * @return
  921 + */
  922 + public Set<String> sUnion(String key, Collection<String> otherKeys) {
  923 + return redisTemplate.opsForSet().union(key, otherKeys);
  924 + }
  925 +
  926 + /**
  927 + * key集合与otherKey集合的并集存储到destKey中
  928 + *
  929 + * @param key key
  930 + * @param otherKey
  931 + * @param destKey
  932 + * @return
  933 + */
  934 + public Long sUnionAndStore(String key, String otherKey, String destKey) {
  935 + return redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey);
  936 + }
  937 +
  938 + /**
  939 + * key集合与多个集合的并集存储到destKey中
  940 + *
  941 + * @param key key
  942 + * @param otherKeys
  943 + * @param destKey
  944 + * @return
  945 + */
  946 + public Long sUnionAndStore(String key, Collection<String> otherKeys, String destKey) {
  947 + return redisTemplate.opsForSet().unionAndStore(key, otherKeys, destKey);
  948 + }
  949 +
  950 + /**
  951 + * 获取两个集合的差集
  952 + *
  953 + * @param key key
  954 + * @param otherKey
  955 + * @return
  956 + */
  957 + public Set<String> sDifference(String key, String otherKey) {
  958 + return redisTemplate.opsForSet().difference(key, otherKey);
  959 + }
  960 +
  961 + /**
  962 + * 获取key集合与多个集合的差集
  963 + *
  964 + * @param key key
  965 + * @param otherKeys
  966 + * @return
  967 + */
  968 + public Set<String> sDifference(String key, Collection<String> otherKeys) {
  969 + return redisTemplate.opsForSet().difference(key, otherKeys);
  970 + }
  971 +
  972 + /**
  973 + * key集合与otherKey集合的差集存储到destKey中
  974 + *
  975 + * @param key key
  976 + * @param otherKey
  977 + * @param destKey
  978 + * @return
  979 + */
  980 + public Long sDifference(String key, String otherKey, String destKey) {
  981 + return redisTemplate.opsForSet().differenceAndStore(key, otherKey, destKey);
  982 + }
  983 +
  984 + /**
  985 + * key集合与多个集合的差集存储到destKey中
  986 + *
  987 + * @param key key
  988 + * @param otherKeys
  989 + * @param destKey
  990 + * @return
  991 + */
  992 + public Long sDifference(String key, Collection<String> otherKeys, String destKey) {
  993 + return redisTemplate.opsForSet().differenceAndStore(key, otherKeys, destKey);
  994 + }
  995 +
  996 + /**
  997 + * 获取集合所有元素
  998 + *
  999 + * @param key key
  1000 + * @param
  1001 + * @param
  1002 + * @return
  1003 + */
  1004 + public Set<String> setMembers(String key) {
  1005 + return redisTemplate.opsForSet().members(key);
  1006 + }
  1007 +
  1008 + /**
  1009 + * 随机获取集合中的一个元素
  1010 + *
  1011 + * @param key key
  1012 + * @return
  1013 + */
  1014 + public String sRandomMember(String key) {
  1015 + return redisTemplate.opsForSet().randomMember(key);
  1016 + }
  1017 +
  1018 + /**
  1019 + * 随机获取集合中count个元素
  1020 + *
  1021 + * @param key key
  1022 + * @param count
  1023 + * @return
  1024 + */
  1025 + public List<String> sRandomMembers(String key, long count) {
  1026 + return redisTemplate.opsForSet().randomMembers(key, count);
  1027 + }
  1028 +
  1029 + /**
  1030 + * 随机获取集合中count个元素并且去除重复的
  1031 + *
  1032 + * @param key key
  1033 + * @param count
  1034 + * @return
  1035 + */
  1036 + public Set<String> sDistinctRandomMembers(String key, long count) {
  1037 + return redisTemplate.opsForSet().distinctRandomMembers(key, count);
  1038 + }
  1039 +
  1040 + /**
  1041 + * @param key key
  1042 + * @param options
  1043 + * @return
  1044 + */
  1045 + public Cursor<String> sScan(String key, ScanOptions options) {
  1046 + return redisTemplate.opsForSet().scan(key, options);
  1047 + }
  1048 +
  1049 + /**------------------zSet相关操作--------------------------------*/
  1050 +
  1051 + /**
  1052 + * 添加元素,有序集合是按照元素的score值由小到大排列
  1053 + *
  1054 + * @param key key
  1055 + * @param value val
  1056 + * @param score
  1057 + * @return
  1058 + */
  1059 + public Boolean zAdd(String key, String value, double score) {
  1060 + return redisTemplate.opsForZSet().add(key, value, score);
  1061 + }
  1062 +
  1063 + /**
  1064 + * @param key key
  1065 + * @param values val
  1066 + * @return
  1067 + */
  1068 + public Long zAdd(String key, Set<ZSetOperations.TypedTuple<String>> values) {
  1069 + return redisTemplate.opsForZSet().add(key, values);
  1070 + }
  1071 +
  1072 + /**
  1073 + * @param key key
  1074 + * @param values val
  1075 + * @return 已删除元素的数量
  1076 + */
  1077 + public Long zRemove(String key, Object... values) {
  1078 + return redisTemplate.opsForZSet().remove(key, values);
  1079 + }
  1080 +
  1081 + /**
  1082 + * 增加元素的score值,并返回增加后的值
  1083 + *
  1084 + * @param key key
  1085 + * @param value val
  1086 + * @param delta 分数值
  1087 + * @return 增加后的值
  1088 + */
  1089 + public Double zIncrementScore(String key, String value, double delta) {
  1090 + return redisTemplate.opsForZSet().incrementScore(key, value, delta);
  1091 + }
  1092 +
  1093 + /**
  1094 + * 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
  1095 + *
  1096 + * @param key key
  1097 + * @param value val
  1098 + * @return 0表示第一位
  1099 + */
  1100 + public Long zRank(String key, Object value) {
  1101 + return redisTemplate.opsForZSet().rank(key, value);
  1102 +
  1103 + }
  1104 +
  1105 + /**
  1106 + * 返回元素在集合的排名,按元素的score值由大到小排列
  1107 + *
  1108 + * @param key key
  1109 + * @param value val
  1110 + */
  1111 + public Long zReverseRank(String key, Object value) {
  1112 + return redisTemplate.opsForZSet().reverseRank(key, value);
  1113 + }
  1114 +
  1115 + /**
  1116 + * 获取集合的元素, 从小到大排序
  1117 + *
  1118 + * @param key key
  1119 + * @param start 开始位置
  1120 + * @param end 结束位置, -1查询所有
  1121 + */
  1122 + public Set<String> zRange(String key, long start, long end) {
  1123 + return redisTemplate.opsForZSet().range(key, start, end);
  1124 + }
  1125 +
  1126 + /**
  1127 + * 获取集合元素, 并且把score值也获取
  1128 + *
  1129 + * @param key key
  1130 + * @param start
  1131 + * @param end
  1132 + * @return
  1133 + */
  1134 + public Set<ZSetOperations.TypedTuple<String>> zRangeWithScores(String key, long start, long end) {
  1135 + return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
  1136 + }
  1137 +
  1138 + /**
  1139 + * 根据Score值查询集合元素
  1140 + *
  1141 + * @param key key
  1142 + * @param min 最小值
  1143 + * @param max 最大值
  1144 + * @return
  1145 + */
  1146 + public Set<String> zRangeByScore(String key, double min, double max) {
  1147 + return redisTemplate.opsForZSet().rangeByScore(key, min, max);
  1148 + }
  1149 +
  1150 + /**
  1151 + * 根据Score值查询集合元素, 从小到大排序
  1152 + *
  1153 + * @param key key
  1154 + * @param min 最小值
  1155 + * @param max 最大值
  1156 + * @return
  1157 + */
  1158 + public Set<ZSetOperations.TypedTuple<String>> zRangeByScoreWithScores(String key,
  1159 + double min, double max) {
  1160 + return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
  1161 + }
  1162 +
  1163 + /**
  1164 + * @param key key
  1165 + * @param min
  1166 + * @param max
  1167 + * @param start
  1168 + * @param end
  1169 + * @return
  1170 + */
  1171 + public Set<ZSetOperations.TypedTuple<String>> zRangeByScoreWithScores(String key, double min, double max, long start, long end) {
  1172 + return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max, start, end);
  1173 + }
  1174 +
  1175 + /**
  1176 + * 获取集合的元素, 从大到小排序
  1177 + *
  1178 + * @param key key
  1179 + * @param start
  1180 + * @param end
  1181 + * @return
  1182 + */
  1183 + public Set<String> zReverseRange(String key, long start, long end) {
  1184 + return redisTemplate.opsForZSet().reverseRange(key, start, end);
  1185 + }
  1186 +
  1187 + /**
  1188 + * 获取集合的元素, 从大到小排序, 并返回score值
  1189 + *
  1190 + * @param key key
  1191 + * @param start
  1192 + * @param end
  1193 + * @return
  1194 + */
  1195 + public Set<ZSetOperations.TypedTuple<String>> zReverseRangeWithScores(String key,
  1196 + long start, long end) {
  1197 + return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
  1198 + }
  1199 +
  1200 + /**
  1201 + * 根据Score值查询集合元素, 从大到小排序
  1202 + *
  1203 + * @param key key
  1204 + * @param min
  1205 + * @param max
  1206 + * @return
  1207 + */
  1208 + public Set<String> zReverseRangeByScore(String key, double min, double max) {
  1209 + return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
  1210 + }
  1211 +
  1212 + /**
  1213 + * 根据Score值查询集合元素, 从大到小排序
  1214 + *
  1215 + * @param key key
  1216 + * @param min
  1217 + * @param max
  1218 + * @return
  1219 + */
  1220 + public Set<ZSetOperations.TypedTuple<String>> zReverseRangeByScoreWithScores(String key, double min, double max) {
  1221 + return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, min, max);
  1222 + }
  1223 +
  1224 + /**
  1225 + * @param key key
  1226 + * @param min
  1227 + * @param max
  1228 + * @param start
  1229 + * @param end
  1230 + * @return
  1231 + */
  1232 + public Set<String> zReverseRangeByScore(String key, double min,
  1233 + double max, long start, long end) {
  1234 + return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max, start, end);
  1235 + }
  1236 +
  1237 + /**
  1238 + * 根据score值获取集合元素数量
  1239 + *
  1240 + * @param key key
  1241 + * @param min
  1242 + * @param max
  1243 + * @return
  1244 + */
  1245 + public Long zCount(String key, double min, double max) {
  1246 + return redisTemplate.opsForZSet().count(key, min, max);
  1247 + }
  1248 +
  1249 + /**
  1250 + * 获取集合大小
  1251 + *
  1252 + * @param key key
  1253 + * @return
  1254 + */
  1255 + public Long zSize(String key) {
  1256 + return redisTemplate.opsForZSet().size(key);
  1257 + }
  1258 +
  1259 + /**
  1260 + * 获取集合大小
  1261 + *
  1262 + * @param key key
  1263 + * @return
  1264 + */
  1265 + public Long zzCard(String key) {
  1266 + return redisTemplate.opsForZSet().zCard(key);
  1267 + }
  1268 +
  1269 + /**
  1270 + * 获取集合中value元素的score值
  1271 + *
  1272 + * @param key key
  1273 + * @param value val
  1274 + * @return
  1275 + */
  1276 + public Double zScore(String key, Object value) {
  1277 + return redisTemplate.opsForZSet().score(key, value);
  1278 + }
  1279 +
  1280 + /**
  1281 + * 移除指定索引位置的成员
  1282 + *
  1283 + * @param key key
  1284 + * @param start
  1285 + * @param end
  1286 + * @return
  1287 + */
  1288 + public Long zRemoveRange(String key, long start, long end) {
  1289 + return redisTemplate.opsForZSet().removeRange(key, start, end);
  1290 + }
  1291 +
  1292 + /**
  1293 + * 根据指定的score值的范围来移除成员
  1294 + *
  1295 + * @param key key
  1296 + * @param min
  1297 + * @param max
  1298 + * @return
  1299 + */
  1300 + public Long zRemoveRangeByScore(String key, double min, double max) {
  1301 + return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
  1302 + }
  1303 +
  1304 + /**
  1305 + * 获取key和otherKey的并集并存储在destKey中
  1306 + *
  1307 + * @param key key
  1308 + * @param otherKey
  1309 + * @param destKey
  1310 + * @return
  1311 + */
  1312 + public Long zUnionAndStore(String key, String otherKey, String destKey) {
  1313 + return redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey);
  1314 + }
  1315 +
  1316 + /**
  1317 + * @param key key
  1318 + * @param otherKeys
  1319 + * @param destKey
  1320 + * @return
  1321 + */
  1322 + public Long zUnionAndStore(String key, Collection<String> otherKeys, String destKey) {
  1323 + return redisTemplate.opsForZSet().unionAndStore(key, otherKeys, destKey);
  1324 + }
  1325 +
  1326 + /**
  1327 + * 交集
  1328 + *
  1329 + * @param key key
  1330 + * @param otherKey
  1331 + * @param destKey
  1332 + * @return
  1333 + */
  1334 + public Long zIntersectAndStore(String key, String otherKey, String destKey) {
  1335 + return redisTemplate.opsForZSet().intersectAndStore(key, otherKey, destKey);
  1336 + }
  1337 +
  1338 + /**
  1339 + * 交集
  1340 + *
  1341 + * @param key key
  1342 + * @param otherKeys
  1343 + * @param destKey
  1344 + * @return
  1345 + */
  1346 + public Long zIntersectAndStore(String key, Collection<String> otherKeys, String destKey) {
  1347 + return redisTemplate.opsForZSet().intersectAndStore(key, otherKeys, destKey);
  1348 + }
  1349 +
  1350 + /**
  1351 + * @param key key
  1352 + * @param options
  1353 + * @return
  1354 + */
  1355 + public Cursor<ZSetOperations.TypedTuple<String>> zScan(String key, ScanOptions options) {
  1356 + return redisTemplate.opsForZSet().scan(key, options);
  1357 + }
  1358 +
  1359 + /* -------------------锁相关操作--------------------- */
  1360 +
  1361 +
  1362 + /**
  1363 + * 获得锁
  1364 + */
  1365 + public boolean getLock(String lockId, String value, long millisecond) {
  1366 + Boolean success = redisTemplate.opsForValue().setIfAbsent(lockId, value, millisecond, TimeUnit.MILLISECONDS);
  1367 + return success != null && success;
  1368 + }
  1369 +
  1370 + /**
  1371 + * 获得锁,并自旋,返回
  1372 + */
  1373 + public boolean getLock(String lockId, String value, long millisecond, long timeout) {
  1374 + long start = System.currentTimeMillis();
  1375 + do {
  1376 + boolean success = getLock(lockId, value, millisecond);
  1377 + if (success) {
  1378 + return true;
  1379 + }
  1380 + try {
  1381 + Thread.sleep(100);
  1382 + } catch (InterruptedException e) {
  1383 + e.printStackTrace();
  1384 + }
  1385 + } while (System.currentTimeMillis() - start < timeout);
  1386 + return false;
  1387 + }
  1388 +
  1389 + /**
  1390 + * 释放锁
  1391 + */
  1392 + public void releaseLock(String id, String lockValue) {
  1393 + if (StringUtils.isNotEmpty(lockValue) && lockValue.equals(this.get(id))) {
  1394 + log.debug("RedisUtil releaseLock, key: {}, value: {}", id, lockValue);
  1395 + redisTemplate.delete(id);
  1396 + }
  1397 + }
  1398 +
  1399 + /* -------------------HyperLogLog相关操作--------------------- */
  1400 +
  1401 + /**
  1402 + * HyperLogLog 添加元素
  1403 + * <p> key不存在则新增
  1404 + *
  1405 + * @param key key
  1406 + * @param value value集合
  1407 + * @return true表示加入成功
  1408 + * @author A80080
  1409 + * @createDate 2021/3/26
  1410 + */
  1411 + public boolean pfAdd(String key, String... value) {
  1412 + return redisTemplate.opsForHyperLogLog().add(key, value) == 1;
  1413 + }
  1414 +
  1415 + /**
  1416 + * HyperLogLog 统计key中元素个数
  1417 + * <p> key 不存在则返回0
  1418 + *
  1419 + * @param key key
  1420 + * @return key中数据大小(基数统计存在误差)
  1421 + * @author A80080
  1422 + * @createDate 2021/3/26
  1423 + */
  1424 + public Long pfCount(String key) {
  1425 + return redisTemplate.opsForHyperLogLog().size(key);
  1426 + }
  1427 +
  1428 + /**
  1429 + * 合并HyperLogLog key,并统计新key元素个数
  1430 + * <p>不删除参与合并的key; 新key不存在则新增,
  1431 + *
  1432 + * @param destination 合并后的key名称
  1433 + * @param sourceKeys 参与合并的key
  1434 + * @return 合并后的key元素个数
  1435 + * @author A80080
  1436 + * @createDate 2021/3/26
  1437 + */
  1438 + public Long pfMerge(String destination, String... sourceKeys) {
  1439 + return redisTemplate.opsForHyperLogLog().union(destination, sourceKeys);
  1440 + }
  1441 +
  1442 +
  1443 +}
0 1444 \ No newline at end of file
... ...
src/main/java/com/canrd/webmagic/common/utils/RedisUtils.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/RedisUtils.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import org.springframework.beans.factory.annotation.Value;
  4 +import org.springframework.data.redis.connection.RedisConnection;
  5 +import org.springframework.data.redis.connection.RedisConnectionFactory;
  6 +import org.springframework.data.redis.core.Cursor;
  7 +import org.springframework.data.redis.core.RedisConnectionUtils;
  8 +import org.springframework.data.redis.core.RedisTemplate;
  9 +import org.springframework.data.redis.core.ScanOptions;
  10 +import org.springframework.stereotype.Component;
  11 +import org.springframework.util.CollectionUtils;
  12 +
  13 +import java.util.*;
  14 +import java.util.concurrent.TimeUnit;
  15 +
  16 +/**
  17 + * @author /
  18 + */
  19 +@Component
  20 +@SuppressWarnings({"unchecked", "all"})
  21 +public class RedisUtils {
  22 +
  23 + private RedisTemplate<Object, Object> redisTemplate;
  24 + @Value("${jwt.online-key}")
  25 + private String onlineKey;
  26 +
  27 + public RedisUtils(RedisTemplate<Object, Object> redisTemplate) {
  28 + this.redisTemplate = redisTemplate;
  29 + }
  30 +
  31 + // =============================common============================
  32 +
  33 + /**
  34 + * 指定缓存失效时间
  35 + *
  36 + * @param key 键
  37 + * @param time 时间(秒)
  38 + */
  39 + public boolean expire(String key, long time) {
  40 + try {
  41 + if (time > 0) {
  42 + redisTemplate.expire(key, time, TimeUnit.SECONDS);
  43 + }
  44 + } catch (Exception e) {
  45 + e.printStackTrace();
  46 + return false;
  47 + }
  48 + return true;
  49 + }
  50 +
  51 + /**
  52 + * 根据 key 获取过期时间
  53 + *
  54 + * @param key 键 不能为null
  55 + * @return 时间(秒) 返回0代表为永久有效
  56 + */
  57 + public long getExpire(Object key) {
  58 + return redisTemplate.getExpire(key, TimeUnit.SECONDS);
  59 + }
  60 +
  61 + /**
  62 + * 查找匹配key
  63 + *
  64 + * @param pattern key
  65 + * @return /
  66 + */
  67 + public List<String> scan(String pattern) {
  68 + ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
  69 + RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
  70 + RedisConnection rc = Objects.requireNonNull(factory).getConnection();
  71 + Cursor<byte[]> cursor = rc.scan(options);
  72 + List<String> result = new ArrayList<>();
  73 + while (cursor.hasNext()) {
  74 + result.add(new String(cursor.next()));
  75 + }
  76 + try {
  77 + RedisConnectionUtils.releaseConnection(rc, factory);
  78 + } catch (Exception e) {
  79 + e.printStackTrace();
  80 + }
  81 + return result;
  82 + }
  83 +
  84 + /**
  85 + * 分页查询 key
  86 + *
  87 + * @param patternKey key
  88 + * @param page 页码
  89 + * @param size 每页数目
  90 + * @return /
  91 + */
  92 + public List<String> findKeysForPage(String patternKey, int page, int size) {
  93 + ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();
  94 + RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
  95 + RedisConnection rc = Objects.requireNonNull(factory).getConnection();
  96 + Cursor<byte[]> cursor = rc.scan(options);
  97 + List<String> result = new ArrayList<>(size);
  98 + int tmpIndex = 0;
  99 + int fromIndex = page * size;
  100 + int toIndex = page * size + size;
  101 + while (cursor.hasNext()) {
  102 + if (tmpIndex >= fromIndex && tmpIndex < toIndex) {
  103 + result.add(new String(cursor.next()));
  104 + tmpIndex++;
  105 + continue;
  106 + }
  107 + // 获取到满足条件的数据后,就可以退出了
  108 + if (tmpIndex >= toIndex) {
  109 + break;
  110 + }
  111 + tmpIndex++;
  112 + cursor.next();
  113 + }
  114 + try {
  115 + RedisConnectionUtils.releaseConnection(rc, factory);
  116 + } catch (Exception e) {
  117 + e.printStackTrace();
  118 + }
  119 + return result;
  120 + }
  121 +
  122 + /**
  123 + * 判断key是否存在
  124 + *
  125 + * @param key 键
  126 + * @return true 存在 false不存在
  127 + */
  128 + public boolean hasKey(String key) {
  129 + try {
  130 + return redisTemplate.hasKey(key);
  131 + } catch (Exception e) {
  132 + e.printStackTrace();
  133 + return false;
  134 + }
  135 + }
  136 +
  137 + /**
  138 + * 删除缓存
  139 + *
  140 + * @param key 可以传一个值 或多个
  141 + */
  142 + public void del(String... key) {
  143 + if (key != null && key.length > 0) {
  144 + if (key.length == 1) {
  145 + redisTemplate.delete(key[0]);
  146 + } else {
  147 + redisTemplate.delete(CollectionUtils.arrayToList(key));
  148 + }
  149 + }
  150 + }
  151 +
  152 + // ============================String=============================
  153 +
  154 + /**
  155 + * 普通缓存获取
  156 + *
  157 + * @param key 键
  158 + * @return 值
  159 + */
  160 + public Object get(String key) {
  161 + return key == null ? null : redisTemplate.opsForValue().get(key);
  162 + }
  163 +
  164 + /**
  165 + * 批量获取
  166 + *
  167 + * @param keys
  168 + * @return
  169 + */
  170 + public List<Object> multiGet(List<String> keys) {
  171 + Object obj = redisTemplate.opsForValue().multiGet(Collections.singleton(keys));
  172 + return null;
  173 + }
  174 +
  175 + /**
  176 + * 普通缓存放入
  177 + *
  178 + * @param key 键
  179 + * @param value 值
  180 + * @return true成功 false失败
  181 + */
  182 + public boolean set(String key, Object value) {
  183 + try {
  184 + redisTemplate.opsForValue().set(key, value);
  185 + return true;
  186 + } catch (Exception e) {
  187 + e.printStackTrace();
  188 + return false;
  189 + }
  190 + }
  191 +
  192 + /**
  193 + * 普通缓存放入并设置时间
  194 + *
  195 + * @param key 键
  196 + * @param value 值
  197 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
  198 + * @return true成功 false 失败
  199 + */
  200 + public boolean set(String key, Object value, long time) {
  201 + try {
  202 + if (time > 0) {
  203 + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
  204 + } else {
  205 + set(key, value);
  206 + }
  207 + return true;
  208 + } catch (Exception e) {
  209 + e.printStackTrace();
  210 + return false;
  211 + }
  212 + }
  213 +
  214 + /**
  215 + * 普通缓存放入并设置时间
  216 + *
  217 + * @param key 键
  218 + * @param value 值
  219 + * @param time 时间
  220 + * @param timeUnit 类型
  221 + * @return true成功 false 失败
  222 + */
  223 + public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
  224 + try {
  225 + if (time > 0) {
  226 + redisTemplate.opsForValue().set(key, value, time, timeUnit);
  227 + } else {
  228 + set(key, value);
  229 + }
  230 + return true;
  231 + } catch (Exception e) {
  232 + e.printStackTrace();
  233 + return false;
  234 + }
  235 + }
  236 +
  237 + // ================================Map=================================
  238 +
  239 + /**
  240 + * HashGet
  241 + *
  242 + * @param key 键 不能为null
  243 + * @param item 项 不能为null
  244 + * @return 值
  245 + */
  246 + public Object hget(String key, String item) {
  247 + return redisTemplate.opsForHash().get(key, item);
  248 + }
  249 +
  250 + /**
  251 + * 获取hashKey对应的所有键值
  252 + *
  253 + * @param key 键
  254 + * @return 对应的多个键值
  255 + */
  256 + public Map<Object, Object> hmget(String key) {
  257 + return redisTemplate.opsForHash().entries(key);
  258 +
  259 + }
  260 +
  261 + /**
  262 + * HashSet
  263 + *
  264 + * @param key 键
  265 + * @param map 对应多个键值
  266 + * @return true 成功 false 失败
  267 + */
  268 + public boolean hmset(String key, Map<String, Object> map) {
  269 + try {
  270 + redisTemplate.opsForHash().putAll(key, map);
  271 + return true;
  272 + } catch (Exception e) {
  273 + e.printStackTrace();
  274 + return false;
  275 + }
  276 + }
  277 +
  278 + /**
  279 + * HashSet 并设置时间
  280 + *
  281 + * @param key 键
  282 + * @param map 对应多个键值
  283 + * @param time 时间(秒)
  284 + * @return true成功 false失败
  285 + */
  286 + public boolean hmset(String key, Map<String, Object> map, long time) {
  287 + try {
  288 + redisTemplate.opsForHash().putAll(key, map);
  289 + if (time > 0) {
  290 + expire(key, time);
  291 + }
  292 + return true;
  293 + } catch (Exception e) {
  294 + e.printStackTrace();
  295 + return false;
  296 + }
  297 + }
  298 +
  299 + /**
  300 + * 向一张hash表中放入数据,如果不存在将创建
  301 + *
  302 + * @param key 键
  303 + * @param item 项
  304 + * @param value 值
  305 + * @return true 成功 false失败
  306 + */
  307 + public boolean hset(String key, String item, Object value) {
  308 + try {
  309 + redisTemplate.opsForHash().put(key, item, value);
  310 + return true;
  311 + } catch (Exception e) {
  312 + e.printStackTrace();
  313 + return false;
  314 + }
  315 + }
  316 +
  317 + /**
  318 + * 向一张hash表中放入数据,如果不存在将创建
  319 + *
  320 + * @param key 键
  321 + * @param item 项
  322 + * @param value 值
  323 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
  324 + * @return true 成功 false失败
  325 + */
  326 + public boolean hset(String key, String item, Object value, long time) {
  327 + try {
  328 + redisTemplate.opsForHash().put(key, item, value);
  329 + if (time > 0) {
  330 + expire(key, time);
  331 + }
  332 + return true;
  333 + } catch (Exception e) {
  334 + e.printStackTrace();
  335 + return false;
  336 + }
  337 + }
  338 +
  339 + /**
  340 + * 删除hash表中的值
  341 + *
  342 + * @param key 键 不能为null
  343 + * @param item 项 可以使多个 不能为null
  344 + */
  345 + public void hdel(String key, Object... item) {
  346 + redisTemplate.opsForHash().delete(key, item);
  347 + }
  348 +
  349 + /**
  350 + * 判断hash表中是否有该项的值
  351 + *
  352 + * @param key 键 不能为null
  353 + * @param item 项 不能为null
  354 + * @return true 存在 false不存在
  355 + */
  356 + public boolean hHasKey(String key, String item) {
  357 + return redisTemplate.opsForHash().hasKey(key, item);
  358 + }
  359 +
  360 + /**
  361 + * hash递增 如果不存在,就会创建一个 并把新增后的值返回
  362 + *
  363 + * @param key 键
  364 + * @param item 项
  365 + * @param by 要增加几(大于0)
  366 + * @return
  367 + */
  368 + public double hincr(String key, String item, double by) {
  369 + return redisTemplate.opsForHash().increment(key, item, by);
  370 + }
  371 +
  372 + /**
  373 + * hash递减
  374 + *
  375 + * @param key 键
  376 + * @param item 项
  377 + * @param by 要减少记(小于0)
  378 + * @return
  379 + */
  380 + public double hdecr(String key, String item, double by) {
  381 + return redisTemplate.opsForHash().increment(key, item, -by);
  382 + }
  383 +
  384 + // ============================set=============================
  385 +
  386 + /**
  387 + * 根据key获取Set中的所有值
  388 + *
  389 + * @param key 键
  390 + * @return
  391 + */
  392 + public Set<Object> sGet(String key) {
  393 + try {
  394 + return redisTemplate.opsForSet().members(key);
  395 + } catch (Exception e) {
  396 + e.printStackTrace();
  397 + return null;
  398 + }
  399 + }
  400 +
  401 + /**
  402 + * 根据value从一个set中查询,是否存在
  403 + *
  404 + * @param key 键
  405 + * @param value 值
  406 + * @return true 存在 false不存在
  407 + */
  408 + public boolean sHasKey(String key, Object value) {
  409 + try {
  410 + return redisTemplate.opsForSet().isMember(key, value);
  411 + } catch (Exception e) {
  412 + e.printStackTrace();
  413 + return false;
  414 + }
  415 + }
  416 +
  417 + /**
  418 + * 将数据放入set缓存
  419 + *
  420 + * @param key 键
  421 + * @param values 值 可以是多个
  422 + * @return 成功个数
  423 + */
  424 + public long sSet(String key, Object... values) {
  425 + try {
  426 + return redisTemplate.opsForSet().add(key, values);
  427 + } catch (Exception e) {
  428 + e.printStackTrace();
  429 + return 0;
  430 + }
  431 + }
  432 +
  433 + /**
  434 + * 将set数据放入缓存
  435 + *
  436 + * @param key 键
  437 + * @param time 时间(秒)
  438 + * @param values 值 可以是多个
  439 + * @return 成功个数
  440 + */
  441 + public long sSetAndTime(String key, long time, Object... values) {
  442 + try {
  443 + Long count = redisTemplate.opsForSet().add(key, values);
  444 + if (time > 0) {
  445 + expire(key, time);
  446 + }
  447 + return count;
  448 + } catch (Exception e) {
  449 + e.printStackTrace();
  450 + return 0;
  451 + }
  452 + }
  453 +
  454 + /**
  455 + * 获取set缓存的长度
  456 + *
  457 + * @param key 键
  458 + * @return
  459 + */
  460 + public long sGetSetSize(String key) {
  461 + try {
  462 + return redisTemplate.opsForSet().size(key);
  463 + } catch (Exception e) {
  464 + e.printStackTrace();
  465 + return 0;
  466 + }
  467 + }
  468 +
  469 + /**
  470 + * 移除值为value的
  471 + *
  472 + * @param key 键
  473 + * @param values 值 可以是多个
  474 + * @return 移除的个数
  475 + */
  476 + public long setRemove(String key, Object... values) {
  477 + try {
  478 + Long count = redisTemplate.opsForSet().remove(key, values);
  479 + return count;
  480 + } catch (Exception e) {
  481 + e.printStackTrace();
  482 + return 0;
  483 + }
  484 + }
  485 +
  486 + // ===============================list=================================
  487 +
  488 + /**
  489 + * 获取list缓存的内容
  490 + *
  491 + * @param key 键
  492 + * @param start 开始
  493 + * @param end 结束 0 到 -1代表所有值
  494 + * @return
  495 + */
  496 + public List<Object> lGet(String key, long start, long end) {
  497 + try {
  498 + return redisTemplate.opsForList().range(key, start, end);
  499 + } catch (Exception e) {
  500 + e.printStackTrace();
  501 + return null;
  502 + }
  503 + }
  504 +
  505 + /**
  506 + * 获取list缓存的长度
  507 + *
  508 + * @param key 键
  509 + * @return
  510 + */
  511 + public long lGetListSize(String key) {
  512 + try {
  513 + return redisTemplate.opsForList().size(key);
  514 + } catch (Exception e) {
  515 + e.printStackTrace();
  516 + return 0;
  517 + }
  518 + }
  519 +
  520 + /**
  521 + * 通过索引 获取list中的值
  522 + *
  523 + * @param key 键
  524 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
  525 + * @return
  526 + */
  527 + public Object lGetIndex(String key, long index) {
  528 + try {
  529 + return redisTemplate.opsForList().index(key, index);
  530 + } catch (Exception e) {
  531 + e.printStackTrace();
  532 + return null;
  533 + }
  534 + }
  535 +
  536 + /**
  537 + * 将list放入缓存
  538 + *
  539 + * @param key 键
  540 + * @param value 值
  541 + * @return
  542 + */
  543 + public boolean lSet(String key, Object value) {
  544 + try {
  545 + redisTemplate.opsForList().rightPush(key, value);
  546 + return true;
  547 + } catch (Exception e) {
  548 + e.printStackTrace();
  549 + return false;
  550 + }
  551 + }
  552 +
  553 + /**
  554 + * 将list放入缓存
  555 + *
  556 + * @param key 键
  557 + * @param value 值
  558 + * @param time 时间(秒)
  559 + * @return
  560 + */
  561 + public boolean lSet(String key, Object value, long time) {
  562 + try {
  563 + redisTemplate.opsForList().rightPush(key, value);
  564 + if (time > 0) {
  565 + expire(key, time);
  566 + }
  567 + return true;
  568 + } catch (Exception e) {
  569 + e.printStackTrace();
  570 + return false;
  571 + }
  572 + }
  573 +
  574 + /**
  575 + * 将list放入缓存
  576 + *
  577 + * @param key 键
  578 + * @param value 值
  579 + * @return
  580 + */
  581 + public boolean lSet(String key, List<Object> value) {
  582 + try {
  583 + redisTemplate.opsForList().rightPushAll(key, value);
  584 + return true;
  585 + } catch (Exception e) {
  586 + e.printStackTrace();
  587 + return false;
  588 + }
  589 + }
  590 +
  591 + /**
  592 + * 将list放入缓存
  593 + *
  594 + * @param key 键
  595 + * @param value 值
  596 + * @param time 时间(秒)
  597 + * @return
  598 + */
  599 + public boolean lSet(String key, List<Object> value, long time) {
  600 + try {
  601 + redisTemplate.opsForList().rightPushAll(key, value);
  602 + if (time > 0) {
  603 + expire(key, time);
  604 + }
  605 + return true;
  606 + } catch (Exception e) {
  607 + e.printStackTrace();
  608 + return false;
  609 + }
  610 + }
  611 +
  612 + /**
  613 + * 根据索引修改list中的某条数据
  614 + *
  615 + * @param key 键
  616 + * @param index 索引
  617 + * @param value 值
  618 + * @return /
  619 + */
  620 + public boolean lUpdateIndex(String key, long index, Object value) {
  621 + try {
  622 + redisTemplate.opsForList().set(key, index, value);
  623 + return true;
  624 + } catch (Exception e) {
  625 + e.printStackTrace();
  626 + return false;
  627 + }
  628 + }
  629 +
  630 + /**
  631 + * 移除N个值为value
  632 + *
  633 + * @param key 键
  634 + * @param count 移除多少个
  635 + * @param value 值
  636 + * @return 移除的个数
  637 + */
  638 + public long lRemove(String key, long count, Object value) {
  639 + try {
  640 + return redisTemplate.opsForList().remove(key, count, value);
  641 + } catch (Exception e) {
  642 + e.printStackTrace();
  643 + return 0;
  644 + }
  645 + }
  646 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/RequestContextUtil.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/RequestContextUtil.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import org.springframework.web.context.ContextLoader;
  4 +import org.springframework.web.context.request.RequestContextHolder;
  5 +import org.springframework.web.context.request.ServletRequestAttributes;
  6 +
  7 +import javax.servlet.ServletContext;
  8 +import javax.servlet.http.HttpServletRequest;
  9 +import javax.servlet.http.HttpServletResponse;
  10 +import javax.servlet.http.HttpSession;
  11 +
  12 +
  13 +public class RequestContextUtil {
  14 +
  15 + public static HttpServletRequest getRequest() {
  16 + return getRequestAttributes().getRequest();
  17 + }
  18 +
  19 + public static HttpServletResponse getResponse() {
  20 + return getRequestAttributes().getResponse();
  21 + }
  22 +
  23 + public static HttpSession getSession() {
  24 + return getRequest().getSession();
  25 + }
  26 +
  27 + public static ServletRequestAttributes getRequestAttributes() {
  28 + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
  29 + }
  30 +
  31 + public static ServletContext getServletContext() {
  32 + return ContextLoader.getCurrentWebApplicationContext().getServletContext();
  33 + }
  34 +
  35 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/RequestHolder.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/RequestHolder.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import org.springframework.web.context.request.RequestContextHolder;
  4 +import org.springframework.web.context.request.ServletRequestAttributes;
  5 +
  6 +import javax.servlet.http.HttpServletRequest;
  7 +import java.util.Objects;
  8 +
  9 +/**
  10 + * 获取 HttpServletRequest
  11 + *
  12 + * @date 2018-11-24
  13 + */
  14 +public class RequestHolder {
  15 +
  16 + public static HttpServletRequest getHttpServletRequest() {
  17 + return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
  18 + }
  19 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/RequestStringUtils.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/RequestStringUtils.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import cn.hutool.core.io.resource.ClassPathResource;
  4 +import com.canrd.webmagic.common.constant.ElAdminConstant;
  5 +import eu.bitwalker.useragentutils.Browser;
  6 +import eu.bitwalker.useragentutils.UserAgent;
  7 +import org.lionsoul.ip2region.DataBlock;
  8 +import org.lionsoul.ip2region.DbConfig;
  9 +import org.lionsoul.ip2region.DbSearcher;
  10 +
  11 +import javax.servlet.http.HttpServletRequest;
  12 +import java.io.File;
  13 +import java.io.IOException;
  14 +import java.lang.reflect.Method;
  15 +import java.net.InetAddress;
  16 +import java.net.UnknownHostException;
  17 +import java.util.Calendar;
  18 +import java.util.Date;
  19 +
  20 +/**
  21 + * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
  22 + */
  23 +public class RequestStringUtils extends org.apache.commons.lang3.StringUtils {
  24 +
  25 + private static final char SEPARATOR = '_';
  26 +
  27 + private static final String UNKNOWN = "unknown";
  28 +
  29 + /**
  30 + * 驼峰命名法工具
  31 + *
  32 + * @return toCamelCase(" hello_world ") == "helloWorld"
  33 + * toCapitalizeCamelCase("hello_world") == "HelloWorld"
  34 + * toUnderScoreCase("helloWorld") = "hello_world"
  35 + */
  36 + public static String toCamelCase(String s) {
  37 + if (s == null) {
  38 + return null;
  39 + }
  40 +
  41 + s = s.toLowerCase();
  42 +
  43 + StringBuilder sb = new StringBuilder(s.length());
  44 + boolean upperCase = false;
  45 + for (int i = 0; i < s.length(); i++) {
  46 + char c = s.charAt(i);
  47 +
  48 + if (c == SEPARATOR) {
  49 + upperCase = true;
  50 + } else if (upperCase) {
  51 + sb.append(Character.toUpperCase(c));
  52 + upperCase = false;
  53 + } else {
  54 + sb.append(c);
  55 + }
  56 + }
  57 +
  58 + return sb.toString();
  59 + }
  60 +
  61 + /**
  62 + * 驼峰命名法工具
  63 + *
  64 + * @return toCamelCase(" hello_world ") == "helloWorld"
  65 + * toCapitalizeCamelCase("hello_world") == "HelloWorld"
  66 + * toUnderScoreCase("helloWorld") = "hello_world"
  67 + */
  68 + public static String toCapitalizeCamelCase(String s) {
  69 + if (s == null) {
  70 + return null;
  71 + }
  72 + s = toCamelCase(s);
  73 + return s.substring(0, 1).toUpperCase() + s.substring(1);
  74 + }
  75 +
  76 + /**
  77 + * 驼峰命名法工具
  78 + *
  79 + * @return toCamelCase(" hello_world ") == "helloWorld"
  80 + * toCapitalizeCamelCase("hello_world") == "HelloWorld"
  81 + * toUnderScoreCase("helloWorld") = "hello_world"
  82 + */
  83 + static String toUnderScoreCase(String s) {
  84 + if (s == null) {
  85 + return null;
  86 + }
  87 +
  88 + StringBuilder sb = new StringBuilder();
  89 + boolean upperCase = false;
  90 + for (int i = 0; i < s.length(); i++) {
  91 + char c = s.charAt(i);
  92 +
  93 + boolean nextUpperCase = true;
  94 +
  95 + if (i < (s.length() - 1)) {
  96 + nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
  97 + }
  98 +
  99 + if ((i > 0) && Character.isUpperCase(c)) {
  100 + if (!upperCase || !nextUpperCase) {
  101 + sb.append(SEPARATOR);
  102 + }
  103 + upperCase = true;
  104 + } else {
  105 + upperCase = false;
  106 + }
  107 +
  108 + sb.append(Character.toLowerCase(c));
  109 + }
  110 +
  111 + return sb.toString();
  112 + }
  113 +
  114 + /**
  115 + * 获取ip地址
  116 + */
  117 + public static String getIp(HttpServletRequest request) {
  118 + String ip = request.getHeader("x-forwarded-for");
  119 + if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
  120 + ip = request.getHeader("Proxy-Client-IP");
  121 + }
  122 + if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
  123 + ip = request.getHeader("WL-Proxy-Client-IP");
  124 + }
  125 + if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
  126 + ip = request.getRemoteAddr();
  127 + }
  128 + String comma = ",";
  129 + String localhost = "127.0.0.1";
  130 + if (ip.contains(comma)) {
  131 + ip = ip.split(",")[0];
  132 + }
  133 + if (localhost.equals(ip)) {
  134 + // 获取本机真正的ip地址
  135 + try {
  136 + ip = InetAddress.getLocalHost().getHostAddress();
  137 + } catch (UnknownHostException e) {
  138 + e.printStackTrace();
  139 + }
  140 + }
  141 + return ip;
  142 + }
  143 +
  144 + /**
  145 + * 根据ip获取详细地址
  146 + */
  147 + public static String getCityInfo(String ip) {
  148 + DbSearcher searcher = null;
  149 + try {
  150 + String path = "ip2region/ip2region.db";
  151 + String name = "ip2region.db";
  152 + DbConfig config = new DbConfig();
  153 + File file = FileUtil.inputStreamToFile(new ClassPathResource(path).getStream(), name);
  154 + searcher = new DbSearcher(config, file.getPath());
  155 + Method method;
  156 + method = searcher.getClass().getMethod("btreeSearch", String.class);
  157 + DataBlock dataBlock;
  158 + dataBlock = (DataBlock) method.invoke(searcher, ip);
  159 + String address = dataBlock.getRegion().replace("0|", "");
  160 + char symbol = '|';
  161 + if (address.charAt(address.length() - 1) == symbol) {
  162 + address = address.substring(0, address.length() - 1);
  163 + }
  164 + return address.equals(ElAdminConstant.REGION) ? "内网IP" : address;
  165 + } catch (Exception e) {
  166 + e.printStackTrace();
  167 + } finally {
  168 + if (searcher != null) {
  169 + try {
  170 + searcher.close();
  171 + } catch (IOException ignored) {
  172 + }
  173 + }
  174 +
  175 + }
  176 + return "";
  177 + }
  178 +
  179 + public static String getBrowser(HttpServletRequest request) {
  180 + UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
  181 + Browser browser = userAgent.getBrowser();
  182 + return browser.getName();
  183 + }
  184 +
  185 + /**
  186 + * 获得当天是周几
  187 + */
  188 + public static String getWeekDay() {
  189 + String[] weekDays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  190 + Calendar cal = Calendar.getInstance();
  191 + cal.setTime(new Date());
  192 +
  193 + int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
  194 + if (w < 0) {
  195 + w = 0;
  196 + }
  197 + return weekDays[w];
  198 + }
  199 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/ServletUtils.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/ServletUtils.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import com.canrd.webmagic.common.constant.ServerResult;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.http.HttpStatus;
  6 +
  7 +import javax.servlet.http.HttpServletResponse;
  8 +import java.io.IOException;
  9 +
  10 +/**
  11 + * @date 2023-02-02
  12 + */
  13 +@Slf4j
  14 +public class ServletUtils {
  15 +
  16 +
  17 + public static void renderServerResult(HttpServletResponse response, ServerResult serverResult, HttpStatus httpStatus) {
  18 + try {
  19 + response.setStatus(httpStatus.value());
  20 + response.setContentType("application/json");
  21 + response.setCharacterEncoding("utf-8");
  22 + response.getWriter().print(JsonUtil.toJsonString(serverResult));
  23 + } catch (IOException e) {
  24 + log.error("ServletUtils#renderServerResult:", e);
  25 + }
  26 + }
  27 +
  28 +
  29 + public static void renderExcelFileNotFound(HttpServletResponse response) {
  30 + try {
  31 + response.setStatus(404);
  32 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
  33 + //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
  34 + response.setHeader("Content-Disposition", "attachment;filename=file.xlsx");
  35 + response.sendError(HttpStatus.NOT_FOUND.value(), "下载失败,资源不存在");
  36 + } catch (IOException e) {
  37 + log.error("ServletUtils#renderWithResourceNotFound:", e);
  38 + }
  39 + }
  40 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/SpringContextHolder.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/SpringContextHolder.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.springframework.beans.BeansException;
  5 +import org.springframework.beans.factory.DisposableBean;
  6 +import org.springframework.context.ApplicationContext;
  7 +import org.springframework.context.ApplicationContextAware;
  8 +
  9 +/**
  10 + * @author Jie
  11 + * @date 2019-01-07
  12 + */
  13 +@Slf4j
  14 +public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
  15 +
  16 + private static ApplicationContext applicationContext = null;
  17 +
  18 + /**
  19 + * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
  20 + */
  21 + @SuppressWarnings("unchecked")
  22 + public static <T> T getBean(String name) {
  23 + assertContextInjected();
  24 + return (T) applicationContext.getBean(name);
  25 + }
  26 +
  27 + /**
  28 + * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
  29 + */
  30 + public static <T> T getBean(Class<T> requiredType) {
  31 + assertContextInjected();
  32 + return applicationContext.getBean(requiredType);
  33 + }
  34 +
  35 + /**
  36 + * 检查ApplicationContext不为空.
  37 + */
  38 + private static void assertContextInjected() {
  39 + if (applicationContext == null) {
  40 + throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
  41 + ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
  42 + }
  43 + }
  44 +
  45 + /**
  46 + * 清除SpringContextHolder中的ApplicationContext为Null.
  47 + */
  48 + private static void clearHolder() {
  49 + log.debug("清除SpringContextHolder中的ApplicationContext:"
  50 + + applicationContext);
  51 + applicationContext = null;
  52 + }
  53 +
  54 + @Override
  55 + public void destroy() {
  56 + SpringContextHolder.clearHolder();
  57 + }
  58 +
  59 + @Override
  60 + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  61 + if (SpringContextHolder.applicationContext != null) {
  62 + log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
  63 + }
  64 + SpringContextHolder.applicationContext = applicationContext;
  65 + }
  66 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/StringUtils.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/StringUtils.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import com.canrd.webmagic.common.constant.Constant;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.util.CollectionUtils;
  6 +
  7 +import java.math.BigDecimal;
  8 +import java.nio.charset.StandardCharsets;
  9 +import java.util.*;
  10 +import java.util.regex.Matcher;
  11 +import java.util.regex.Pattern;
  12 +import java.util.regex.PatternSyntaxException;
  13 +import java.util.stream.Collectors;
  14 +import java.util.stream.Stream;
  15 +
  16 +/**
  17 + * @param
  18 + * @version 0.1.0
  19 + * @Description
  20 + * @return
  21 + * @date 2021/4/16 17:44
  22 + * @since 0.1.0
  23 + */
  24 +@Slf4j
  25 +public class StringUtils {
  26 + /**
  27 + * 首字母变小写
  28 + *
  29 + * @param str
  30 + * @return
  31 + */
  32 + public static String firstCharToLowerCase(String str) {
  33 + char firstChar = str.charAt(0);
  34 + if (firstChar >= 'A' && firstChar <= 'Z') {
  35 + char[] arr = str.toCharArray();
  36 + arr[0] += ('a' - 'A');
  37 + return new String(arr);
  38 + }
  39 + return str;
  40 + }
  41 +
  42 + /**
  43 + * 首字母变大写
  44 + *
  45 + * @param str
  46 + * @return
  47 + */
  48 + public static String firstCharToUpperCase(String str) {
  49 + char firstChar = str.charAt(0);
  50 + if (firstChar >= 'a' && firstChar <= 'z') {
  51 + char[] arr = str.toCharArray();
  52 + arr[0] -= ('a' - 'A');
  53 + return new String(arr);
  54 + }
  55 + return str;
  56 + }
  57 +
  58 + /**
  59 + * 判断是否为空
  60 + *
  61 + * @param str
  62 + * @return
  63 + */
  64 + public static boolean isEmpty(final String str) {
  65 + return (str == null) || (str.length() == 0);
  66 + }
  67 +
  68 + /**
  69 + * 判断是否不为空
  70 + *
  71 + * @param str
  72 + * @return
  73 + */
  74 + public static boolean isNotEmpty(final String str) {
  75 + return !isEmpty(str);
  76 + }
  77 +
  78 + /**
  79 + * 判断是否空白
  80 + *
  81 + * @param str
  82 + * @return
  83 + */
  84 + public static boolean isBlank(final String str) {
  85 + int strLen;
  86 + if ((str == null) || ((strLen = str.length()) == 0)) {
  87 + return true;
  88 + }
  89 + for (int i = 0; i < strLen; i++) {
  90 + if (!Character.isWhitespace(str.charAt(i))) {
  91 + return false;
  92 + }
  93 + }
  94 + return true;
  95 + }
  96 +
  97 + /**
  98 + * 判断是否不是空白
  99 + *
  100 + * @param str
  101 + * @return
  102 + */
  103 + public static boolean isNotBlank(final String str) {
  104 + return !isBlank(str);
  105 + }
  106 +
  107 + /**
  108 + * 判断多个字符串全部是否为空
  109 + *
  110 + * @param strings
  111 + * @return
  112 + */
  113 + public static boolean isAllEmpty(String... strings) {
  114 + if (strings == null) {
  115 + return true;
  116 + }
  117 + for (String str : strings) {
  118 + if (isNotEmpty(str)) {
  119 + return false;
  120 + }
  121 + }
  122 + return true;
  123 + }
  124 +
  125 + /**
  126 + * 判断多个字符串其中任意一个是否为空
  127 + *
  128 + * @param strings
  129 + * @return
  130 + */
  131 + public static boolean isHasEmpty(String... strings) {
  132 + if (strings == null) {
  133 + return true;
  134 + }
  135 + for (String str : strings) {
  136 + if (isEmpty(str)) {
  137 + return true;
  138 + }
  139 + }
  140 + return false;
  141 + }
  142 +
  143 + /**
  144 + * 判断多个字符串是否都为blank
  145 + *
  146 + * @param strings
  147 + * @return
  148 + */
  149 + public static boolean isAllBlank(String... strings) {
  150 + if (strings == null) {
  151 + return true;
  152 + }
  153 + for (String str : strings) {
  154 + if (isNotBlank(str)) {
  155 + return false;
  156 + }
  157 + }
  158 + return true;
  159 + }
  160 +
  161 + /**
  162 + * checkValue为 null 或者为 "" 时返回 defaultValue
  163 + *
  164 + * @param checkValue
  165 + * @param defaultValue
  166 + * @return
  167 + */
  168 + public static String isEmpty(String checkValue, String defaultValue) {
  169 + return isEmpty(checkValue) ? defaultValue : checkValue;
  170 + }
  171 +
  172 + /**
  173 + * 字符串不为 null 而且不为 "" 并且等于other
  174 + *
  175 + * @param str
  176 + * @param other
  177 + * @return
  178 + */
  179 + public static boolean isNotEmptyAndEqualsOther(String str, String other) {
  180 + return !isEmpty(str) && str.equals(other);
  181 + }
  182 +
  183 + /**
  184 + * 字符串不为 null 而且不为 "" 并且不等于other
  185 + *
  186 + * @param str
  187 + * @param other
  188 + * @return
  189 + */
  190 + public static boolean isNotEmptyAndNotEqualsOther(String str, String... other) {
  191 + if (isEmpty(str)) {
  192 + return false;
  193 + }
  194 + for (String s : other) {
  195 + if (str.equals(s)) {
  196 + return false;
  197 + }
  198 + }
  199 + return true;
  200 + }
  201 +
  202 + /**
  203 + * 字符串不等于other
  204 + *
  205 + * @param str
  206 + * @param other
  207 + * @return
  208 + */
  209 + public static boolean isNotEqualsOther(String str, String... other) {
  210 + for (String s : other) {
  211 + if (s.equals(str)) {
  212 + return false;
  213 + }
  214 + }
  215 + return true;
  216 + }
  217 +
  218 + /**
  219 + * 判断字符串不为空
  220 + *
  221 + * @param strings
  222 + * @return
  223 + */
  224 + public static boolean isNotEmpty(String... strings) {
  225 + if (strings == null || strings.length == 0) {
  226 + return false;
  227 + }
  228 + for (String str : strings) {
  229 + if (str == null || "".equals(str.trim())) {
  230 + return false;
  231 + }
  232 + }
  233 + return true;
  234 + }
  235 +
  236 + /**
  237 + * 比较字符相等
  238 + *
  239 + * @param value
  240 + * @param equals
  241 + * @return
  242 + */
  243 + public static boolean equals(String value, String equals) {
  244 + if (isAllEmpty(value, equals)) {
  245 + return true;
  246 + }
  247 + //进一步判断value是不是空,如果是空,要直接equals会报NPE异常
  248 + if (value == null) {
  249 + return false;
  250 + }
  251 + return value.equals(equals);
  252 + }
  253 +
  254 + /**
  255 + * @description 将字符串转换为数字数组
  256 + * @author 黄楷涵
  257 + * @date 2020/9/15
  258 + */
  259 + public static int[] stringParseToInt(String str, String regex) {
  260 + return stringParseToInt(str.split(regex));
  261 + }
  262 +
  263 + /**
  264 + * @description 将字符串数组转换为数字数组
  265 + * @author dengbin
  266 + * @date 2020/9/15
  267 + */
  268 + public static int[] stringParseToInt(String[] str) {
  269 + int[] num = new int[str.length];
  270 + for (int i = 0; i < str.length; i++) {
  271 + num[i] = Integer.parseInt(str[i]);
  272 + }
  273 + return num;
  274 + }
  275 +
  276 + /**
  277 + * 比较字符串不相等
  278 + *
  279 + * @param value
  280 + * @param equals
  281 + * @return
  282 + */
  283 + public static boolean isNotEquals(String value, String equals) {
  284 + return !equals(value, equals);
  285 + }
  286 +
  287 + public static String[] split(String content, String separatorChars) {
  288 + return splitWorker(content, separatorChars, -1, false);
  289 + }
  290 +
  291 + public static String[] split(String str, String separatorChars, int max) {
  292 + return splitWorker(str, separatorChars, max, false);
  293 + }
  294 +
  295 + public static final String[] EMPTY_STRING_ARRAY = new String[0];
  296 +
  297 + private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens) {
  298 + if (str == null) {
  299 + return null;
  300 + }
  301 + int len = str.length();
  302 + if (len == 0) {
  303 + return EMPTY_STRING_ARRAY;
  304 + }
  305 + List<String> list = new ArrayList<String>();
  306 + int sizePlus1 = 1;
  307 + int i = 0, start = 0;
  308 + boolean match = false;
  309 + boolean lastMatch = false;
  310 + if (separatorChars == null) {
  311 + while (i < len) {
  312 + if (Character.isWhitespace(str.charAt(i))) {
  313 + if (match || preserveAllTokens) {
  314 + lastMatch = true;
  315 + if (sizePlus1++ == max) {
  316 + i = len;
  317 + lastMatch = false;
  318 + }
  319 + list.add(str.substring(start, i));
  320 + match = false;
  321 + }
  322 + start = ++i;
  323 + continue;
  324 + }
  325 + lastMatch = false;
  326 + match = true;
  327 + i++;
  328 + }
  329 + } else if (separatorChars.length() == 1) {
  330 + char sep = separatorChars.charAt(0);
  331 + while (i < len) {
  332 + if (str.charAt(i) == sep) {
  333 + if (match || preserveAllTokens) {
  334 + lastMatch = true;
  335 + if (sizePlus1++ == max) {
  336 + i = len;
  337 + lastMatch = false;
  338 + }
  339 + list.add(str.substring(start, i));
  340 + match = false;
  341 + }
  342 + start = ++i;
  343 + continue;
  344 + }
  345 + lastMatch = false;
  346 + match = true;
  347 + i++;
  348 + }
  349 + } else {
  350 + while (i < len) {
  351 + if (separatorChars.indexOf(str.charAt(i)) >= 0) {
  352 + if (match || preserveAllTokens) {
  353 + lastMatch = true;
  354 + if (sizePlus1++ == max) {
  355 + i = len;
  356 + lastMatch = false;
  357 + }
  358 + list.add(str.substring(start, i));
  359 + match = false;
  360 + }
  361 + start = ++i;
  362 + continue;
  363 + }
  364 + lastMatch = false;
  365 + match = true;
  366 + i++;
  367 + }
  368 + }
  369 + if (match || (preserveAllTokens && lastMatch)) {
  370 + list.add(str.substring(start, i));
  371 + }
  372 + return list.toArray(EMPTY_STRING_ARRAY);
  373 + }
  374 +
  375 + /**
  376 + * 消除转义字符
  377 + *
  378 + * @param str
  379 + * @return
  380 + */
  381 + public static String escapeXml(String str) {
  382 + if (str == null) {
  383 + return "";
  384 + }
  385 + StringBuilder sb = new StringBuilder();
  386 + for (int i = 0; i < str.length(); ++i) {
  387 + char c = str.charAt(i);
  388 + switch (c) {
  389 + case '\u00FF':
  390 + case '\u0024':
  391 + break;
  392 + case '&':
  393 + sb.append("&amp;");
  394 + break;
  395 + case '<':
  396 + sb.append("&lt;");
  397 + break;
  398 + case '>':
  399 + sb.append("&gt;");
  400 + break;
  401 + case '\"':
  402 + sb.append("&quot;");
  403 + break;
  404 + case '\'':
  405 + sb.append("&apos;");
  406 + break;
  407 + default:
  408 + if (c <= '\u001F') {
  409 + break;
  410 + }
  411 + if (c >= '\uE000' && c <= '\uF8FF') {
  412 + break;
  413 + }
  414 + if (c >= '\uFFF0') {
  415 + break;
  416 + }
  417 + sb.append(c);
  418 + break;
  419 + }
  420 + }
  421 + return sb.toString();
  422 + }
  423 +
  424 + /**
  425 + * 将字符串中特定模式的字符转换成map中对应的值
  426 + *
  427 + * @param s 需要转换的字符串
  428 + * @param map 转换所需的键值对集合
  429 + * @return 转换后的字符串
  430 + */
  431 + public static String replace(String s, Map<String, Object> map) {
  432 + StringBuilder ret = new StringBuilder((int) (s.length() * 1.5));
  433 + int cursor = 0;
  434 + for (int start, end; (start = s.indexOf("${", cursor)) != -1 && (end = s.indexOf("}", start)) != -1; ) {
  435 + ret.append(s.substring(cursor, start)).append(map.get(s.substring(start + 2, end)));
  436 + cursor = end + 1;
  437 + }
  438 + ret.append(s.substring(cursor, s.length()));
  439 + return ret.toString();
  440 + }
  441 +
  442 + public static String replace(String s, Object... objs) {
  443 + if (objs == null || objs.length == 0) {
  444 + return s;
  445 + }
  446 + if (!s.contains("{}")) {
  447 + return s;
  448 + }
  449 + StringBuilder ret = new StringBuilder((int) (s.length() * 1.5));
  450 + int cursor = 0;
  451 + int index = 0;
  452 + for (int start; (start = s.indexOf("{}", cursor)) != -1; ) {
  453 + ret.append(s.substring(cursor, start));
  454 + if (index < objs.length) {
  455 + ret.append(objs[index]);
  456 + } else {
  457 + ret.append("{}");
  458 + }
  459 + cursor = start + 2;
  460 + index++;
  461 + }
  462 + ret.append(s.substring(cursor, s.length()));
  463 + return ret.toString();
  464 + }
  465 +
  466 +
  467 + /**
  468 + * 转换为字节数组
  469 + *
  470 + * @param bytes
  471 + * @return
  472 + */
  473 + public static String toString(byte[] bytes) {
  474 + return new String(bytes, StandardCharsets.UTF_8);
  475 + }
  476 +
  477 + /**
  478 + * 转换为字节数组
  479 + *
  480 + * @param str
  481 + * @return
  482 + */
  483 + public static byte[] getBytes(String str) {
  484 + return str != null ? str.getBytes(StandardCharsets.UTF_8) : null;
  485 + }
  486 +
  487 + public static boolean isNumeric(String cs) {
  488 + if (isEmpty(cs)) {
  489 + return false;
  490 + }
  491 + for (int i = 0, sz = cs.length(); i < sz; ++i) {
  492 + if (!Character.isDigit(cs.charAt(i))) {
  493 + return false;
  494 + }
  495 + }
  496 + return true;
  497 +
  498 + }
  499 +
  500 + /**
  501 + * 手机号脱敏
  502 + *
  503 + * @param phoneNumber
  504 + * @return
  505 + */
  506 + public static String desensitizedPhoneNumber(String phoneNumber) {
  507 + if (StringUtils.isNotEmpty(phoneNumber)) {
  508 + phoneNumber = phoneNumber.replaceAll("(\\w{3})\\w*(\\w{4})", "$1****$2");
  509 + }
  510 + return phoneNumber;
  511 + }
  512 +
  513 + /**
  514 + * 校验3位小数
  515 + *
  516 + * @param str
  517 + * @return
  518 + */
  519 + public static boolean checkDecimal(String str) {
  520 + return Pattern.compile(Constant.DICMAL_REGEXP).matcher(str).find();
  521 + }
  522 +
  523 + /**
  524 + * 校验11位国内手机号
  525 + * <p>规则: 11位数,首位必须为1,第二位可以是3-9;其他位数不限制
  526 + *
  527 + * @param phone 手机号
  528 + * @return 格式正确则返回false; 反之为true
  529 + * @author A80080
  530 + * @createDate 2020/12/19
  531 + */
  532 + public static boolean checkPhoneNum(String phone) {
  533 + return StringUtils.isEmpty(phone) || !Pattern.compile("^1([3-9])[0-9]{9}$").matcher(phone).find();
  534 + }
  535 +
  536 + /**
  537 + * @param str
  538 + * @return boolean
  539 + * @Description 判断字符串是否含有空格
  540 + * @version 0.1.0
  541 + * @author 邓彬
  542 + * @date 2021/1/13 18:10
  543 + * @since 0.1.0
  544 + */
  545 + public static boolean checkStringContainEmpty(String str) {
  546 + return !StringUtils.isEmpty(str) && str.contains(" ");
  547 + }
  548 +
  549 + /**
  550 + * 字符串切分
  551 + *
  552 + * @param splitStr
  553 + * @param splitFlag
  554 + * @return
  555 + */
  556 + public static List<String> splitTag(String splitStr, String splitFlag) {
  557 + return StringUtils.isBlank(splitStr) || StringUtils.isBlank(splitFlag) ?
  558 + new ArrayList<>() :
  559 + Arrays.stream(splitStr.split(splitFlag)).collect(Collectors.toList());
  560 + }
  561 +
  562 + /**
  563 + * @param name
  564 + * @return true代表全是汉字
  565 + * @Description 校验String是否全是中文
  566 + * @version 0.1.0
  567 + * @author 邓彬
  568 + * @date 2021/1/18 19:54
  569 + * @since 0.1.0
  570 + */
  571 + public static boolean checkNameChina(String name) {
  572 + boolean res = true;
  573 + char[] cTemp = name.toCharArray();
  574 + for (int i = 0; i < name.length(); i++) {
  575 + if (!isChinese(cTemp[i])) {
  576 + res = false;
  577 + break;
  578 + }
  579 + }
  580 + return res;
  581 + }
  582 +
  583 + /**
  584 + * @param c
  585 + * @return true代表是汉字
  586 + * @Description 判定输入的是否是汉字
  587 + * @version 0.1.0
  588 + * @author 邓彬
  589 + * @date 2021/1/18 19:53
  590 + * @since 0.1.0
  591 + */
  592 + public static boolean isChinese(char c) {
  593 + Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
  594 + if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
  595 + || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
  596 + || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
  597 + || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
  598 + || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
  599 + || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
  600 + return true;
  601 + }
  602 + return false;
  603 + }
  604 +
  605 + /**
  606 + * @param c
  607 + * @return true代表符合条件
  608 + * @Description 校验某个字符是否是a-z、A-Z、_、0-9
  609 + * @version 0.1.0
  610 + * @author 邓彬
  611 + * @date 2021/1/18 19:56
  612 + * @since 0.1.0
  613 + */
  614 + public static boolean isWord(char c) {
  615 + return Pattern.compile("[\\w]").matcher("" + c).matches();
  616 + }
  617 +
  618 + /**
  619 + * @param str
  620 + * @return boolean
  621 + * @Description 字符串是否仅包含数字和字母
  622 + * @version 0.1.0
  623 + * @author 邓彬
  624 + * @date 2021/1/18 20:00
  625 + * @since 0.1.0
  626 + */
  627 + public static boolean isLetterDigit(String str) {
  628 + return str.matches("^[a-z0-9A-Z]+$");
  629 + }
  630 +
  631 + /**
  632 + * @param str
  633 + * @return boolean
  634 + * @Description 判断是否是纯数字
  635 + * @version 0.1.0
  636 + * @author 邓彬
  637 + * @date 2021/1/23 16:33
  638 + * @since 0.1.0
  639 + */
  640 + public static boolean isDigit(String str) {
  641 + return str.matches("^[0-9]+$");
  642 + }
  643 +
  644 + /**
  645 + * 是否合法手机号
  646 + *
  647 + * @param phone
  648 + * @return
  649 + */
  650 + public static boolean isMobilePhone(String phone) {
  651 + return Pattern.compile(Constant.PHONE_REGEXP).matcher(phone).matches();
  652 + }
  653 +
  654 + /**
  655 + * 是否脱敏手机号
  656 + *
  657 + * @param phone
  658 + * @return
  659 + */
  660 + public static boolean isDesensitizationMobilePhone(String phone) {
  661 + return Pattern.compile(Constant.PHONE_DESENSITIZATION_REGEXP).matcher(phone).matches();
  662 + }
  663 +
  664 + /**
  665 + * 判断String是否是整数<br>
  666 + * 支持10进制
  667 + *
  668 + * @param s String
  669 + * @return 是否为整数
  670 + */
  671 + public static boolean isInteger(String s) {
  672 + try {
  673 + Integer.parseInt(s);
  674 + } catch (NumberFormatException e) {
  675 + return false;
  676 + }
  677 + return true;
  678 + }
  679 +
  680 + /**
  681 + * 判断对象能否转
  682 + *
  683 + * @param o Object
  684 + * @return 是否为Integer
  685 + */
  686 + public static boolean isInteger(Object o) {
  687 + try {
  688 + Integer.parseInt(String.valueOf(o));
  689 + return true;
  690 + } catch (NumberFormatException e) {
  691 + return false;
  692 + }
  693 + }
  694 +
  695 + public static String escapeCharacter(String str) {
  696 + if (!isEmpty(str)) {
  697 + if (str.contains("\\")) {
  698 + str = str.replaceAll("\\\\", "\\\\\\\\");
  699 + }
  700 + }
  701 + return str;
  702 + }
  703 +
  704 + /**
  705 + * @param str
  706 + * @return boolean
  707 + * @Description 匹配字符串是,数字、26个英文字母、下划线组成的8-16位的字符串组合
  708 + * @version 0.1.0
  709 + * @author A80077-刘始达
  710 + * @date 2021/04/06
  711 + * @since 0.1.0
  712 + */
  713 + public static boolean checkPWD(String str) {
  714 + return str.matches("^(?=.*([a-zA-Z].*))(?=.*[0-9].*)[a-zA-Z0-9-_]{8,16}+$");
  715 + }
  716 +
  717 + /**
  718 + * 判断是否包含特殊字符
  719 + *
  720 + * @param str
  721 + * @return
  722 + */
  723 + public static boolean checkSpecificSymbol(String str) {
  724 + String regEx = "[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]|\n|\r|\t";
  725 + Pattern p = Pattern.compile(regEx);
  726 + Matcher m = p.matcher(str);
  727 + return m.find();
  728 + }
  729 +
  730 + /**
  731 + * 拼接图片标签url
  732 + *
  733 + * @param str
  734 + * @param ossDomain
  735 + * @return
  736 + */
  737 + public static String replaceHtmlTag(String str, String ossDomain) {
  738 + if (StringUtils.isEmpty(str)) {
  739 + return "";
  740 + }
  741 + if (StringUtils.isEmpty(ossDomain)) {
  742 + return str;
  743 + }
  744 + return replaceHtmlTag(str, "img", "src", "src=\"" + ossDomain, "\"");
  745 + }
  746 +
  747 + /**
  748 + * html格式处理:替换指定标签的属性和值
  749 + *
  750 + * @param str 需要处理的字符串
  751 + * @param tag 标签名称
  752 + * @param tagAttrib 要替换的标签属性值
  753 + * @param startTag 新标签开始标记
  754 + * @param endTag 新标签结束标记
  755 + * @return
  756 + */
  757 + public static String replaceHtmlTag(String str, String tag, String tagAttrib, String startTag, String endTag) {
  758 + String regxpForTag = "<\\s*" + tag + "\\s+([^>]*)\\s*";
  759 + String regxpForTagAttrib = tagAttrib + "=\\s*\"([^\"]+)\"";
  760 + Pattern patternForTag = Pattern.compile(regxpForTag, Pattern.CASE_INSENSITIVE);
  761 + Pattern patternForAttrib = Pattern.compile(regxpForTagAttrib, Pattern.CASE_INSENSITIVE);
  762 + Matcher matcherForTag = patternForTag.matcher(str);
  763 + StringBuffer sb = new StringBuffer();
  764 + boolean result = matcherForTag.find();
  765 + while (result) {
  766 + StringBuffer stringBuffer = new StringBuffer("<" + tag + " ");
  767 + Matcher matcherForAttrib = patternForAttrib.matcher(matcherForTag.group(1));
  768 + if (matcherForAttrib.find()) {
  769 + String attributeStr = matcherForAttrib.group(1);
  770 + if (!attributeStr.contains("https") && !attributeStr.contains("http")) {
  771 + matcherForAttrib.appendReplacement(stringBuffer, startTag + attributeStr + endTag);
  772 + }
  773 + }
  774 + matcherForAttrib.appendTail(stringBuffer);
  775 + matcherForTag.appendReplacement(sb, stringBuffer.toString());
  776 + result = matcherForTag.find();
  777 + }
  778 + matcherForTag.appendTail(sb);
  779 + return sb.toString();
  780 + }
  781 +
  782 + /**
  783 + * @param str
  784 + * @return java.util.Map<String, List < String>>
  785 + * @Description 字符串的连续切割 返回中文词组 数字和字母的集合
  786 + * @version 0.1.0
  787 + * @author 邓彬
  788 + * @date 2021/4/15 13:53
  789 + * @since 0.1.0
  790 + */
  791 + public static Map<String, List<String>> convertStrToChineseList(String str) {
  792 + if (StringUtils.isEmpty(str)) {
  793 + return null;
  794 + }
  795 + Map<String, List<String>> resultMap = new HashMap<>();
  796 + List<String> chineseList;
  797 + List<String> charList;
  798 + char[] list = str.toCharArray();
  799 + StringBuilder chineseStr = new StringBuilder();
  800 + StringBuilder charStr = new StringBuilder();
  801 + for (char c : list) {
  802 + if (StringUtils.isChinese(c)) {
  803 + chineseStr.append(c);
  804 + charStr.append(Constant.SLASH_MARK_CHARACTER);
  805 + } else if (Character.isLetterOrDigit(c)) {
  806 + charStr.append(c);
  807 + chineseStr.append(Constant.SLASH_MARK_CHARACTER);
  808 + } else {
  809 + charStr.append(Constant.SLASH_MARK_CHARACTER);
  810 + chineseStr.append(Constant.SLASH_MARK_CHARACTER);
  811 + }
  812 +
  813 + }
  814 + chineseList = Arrays.stream(chineseStr.toString()
  815 + .split(Constant.SLASH_MARK_CHARACTER))
  816 + .filter(StringUtils::isNotEmpty).collect(Collectors.toList());
  817 + charList = Arrays.stream(charStr.toString()
  818 + .split(Constant.SLASH_MARK_CHARACTER))
  819 + .filter(StringUtils::isNotEmpty).map(String::toLowerCase).collect(Collectors.toList());
  820 +
  821 + resultMap.put("chineseKey", chineseList);
  822 + resultMap.put("charKey", charList);
  823 + return resultMap;
  824 + }
  825 +
  826 + /**
  827 + * 单个字符转换为小写
  828 + *
  829 + * @param c
  830 + * @return
  831 + */
  832 + public static char singleCharToLowerCase(char c) {
  833 + if (c >= 'A' && c <= 'Z') {
  834 + c += ('a' - 'A');
  835 + return c;
  836 + }
  837 + return c;
  838 + }
  839 +
  840 + public static boolean isLong(String shopId) {
  841 + try {
  842 + Long.parseLong(shopId);
  843 + } catch (NumberFormatException e) {
  844 + return false;
  845 + }
  846 + return true;
  847 + }
  848 +
  849 + public static String priceFormatting(String price) {
  850 + if (StringUtils.isEmpty(price)) {
  851 + return Constant.EMPTY_STRING;
  852 + }
  853 +
  854 + String newPrice = "";
  855 + // 价格不存在小数点,则直接返回,无需处理
  856 + if (!price.contains(Constant.POINT_BAR_CHARACTER)) {
  857 + newPrice = price;
  858 + return newPrice;
  859 + }
  860 +
  861 + // 有小数点,则分割字符串
  862 + String[] s = price.split("\\.");
  863 +
  864 + // 小数位数大于0 且小于2 且存在非0字符
  865 + if (s[1].length() > 0 && s[1].length() <= 2 && !judgeIsNumeric(s[1])) {
  866 + BigDecimal bigDecimal = new BigDecimal(price).setScale(2, BigDecimal.ROUND_HALF_UP);
  867 + newPrice = bigDecimal.toPlainString();
  868 + }
  869 + // 【保留这个else if】小数位数大于0 且大于2 且存在非0字符,理论上不会存在,因为新增商品时已经限定最多输入2个小数点
  870 + else if (s[1].length() > 0 && s[1].length() > 2 && !judgeIsNumeric(s[1])) {
  871 + BigDecimal bigDecimal = new BigDecimal(price).setScale(2, BigDecimal.ROUND_HALF_UP);
  872 + String[] split = bigDecimal.toPlainString().split("\\.");
  873 + if (split[1].length() > 0 && judgeIsNumeric(split[1])) {
  874 + newPrice = new BigDecimal(bigDecimal.toPlainString()).setScale(0, BigDecimal.ROUND_HALF_UP).toPlainString();
  875 + } else {
  876 + newPrice = bigDecimal.toPlainString();
  877 + }
  878 + } else {
  879 + // 小数位数大于0 且小于2 且小数点都是0
  880 + newPrice = new BigDecimal(price).setScale(0, BigDecimal.ROUND_HALF_UP).toPlainString();
  881 + }
  882 + return newPrice;
  883 + }
  884 +
  885 + /**
  886 + * 判断字符串是否只包含0
  887 + *
  888 + * @param str
  889 + * @return
  890 + */
  891 + private static boolean judgeIsNumeric(String str) {
  892 + return Pattern.compile("[0]*").matcher(str).matches();
  893 + }
  894 +
  895 + /**
  896 + * 字符串以","分隔后转为String[]
  897 + *
  898 + * @param s
  899 + * @return
  900 + */
  901 + public static String[] string2ArraySplitByComma(String s) {
  902 + if (s == null || s.length() == 0) {
  903 + return new String[]{};
  904 + }
  905 + return s.split(Constant.COMMA_CHARACTER);
  906 + }
  907 +
  908 + public static boolean isStringArrayContainsSpecifiedValue(String[] strings, String value) {
  909 + if (null == strings || strings.length <= 0 || value == null || value.length() == 0) {
  910 + return false;
  911 + }
  912 + boolean isContainsSpecifiedValue = false;
  913 + for (String s : strings) {
  914 + if (s.equals(value)) {
  915 + isContainsSpecifiedValue = true;
  916 + break;
  917 + }
  918 + }
  919 + return isContainsSpecifiedValue;
  920 + }
  921 +
  922 + /**
  923 + * 字符串以","分隔后转为list
  924 + *
  925 + * @param s
  926 + * @return
  927 + */
  928 + public static List<String> string2ListSplitByComma(String s) {
  929 + List<String> stringList = new ArrayList<>();
  930 + if (s == null || s.length() == 0) {
  931 + return stringList;
  932 + }
  933 + String[] strArray = string2ArraySplitByComma(s);
  934 +
  935 + for (String st : strArray) {
  936 + if (null != st && st.trim() != null || st.trim().length() != 0) {
  937 + stringList.add(st.trim());
  938 + }
  939 + }
  940 +
  941 + return stringList;
  942 + }
  943 +
  944 + /**
  945 + * 字符串按照特殊符号
  946 + * ".*[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?\\\\]+.*"
  947 + * 截取转成字符串集合
  948 + *
  949 + * @param str
  950 + * @return
  951 + */
  952 + public static List<String> splitStringBySpecificSymbol(String str) throws PatternSyntaxException {
  953 + String regEx = "[`~!@#$%^&*()\\-+=|{}':;,\\[\\].<>/?!¥…()—【】‘;:”“’。,、?\\\\]";
  954 + Pattern p = Pattern.compile(regEx);
  955 + Matcher m = p.matcher(str);
  956 + return Stream.of(m.replaceAll("_").split("_")).map(String::trim).filter(StringUtils::isNotBlank).collect(Collectors.toList());
  957 + }
  958 +
  959 + /**
  960 + * 将list转为字符串,用逗号隔开
  961 + *
  962 + * @param list
  963 + * @return
  964 + */
  965 + public static String listTransToStr(List<String> list) {
  966 + if (CollectionUtils.isEmpty(list)) return null;
  967 + StringBuilder sb = new StringBuilder();
  968 + list.forEach(x -> {
  969 + sb.append(x);
  970 + sb.append(",");
  971 + });
  972 + String str = sb.toString();
  973 + return str.substring(0, str.length() - 1);
  974 + }
  975 +
  976 + /**
  977 + * 是否包含中英文
  978 + *
  979 + * @param str
  980 + * @return
  981 + */
  982 + public static boolean checkCnAndEn(String str) {
  983 + String regEx = Constant.CHI_EN_REGEXP;
  984 + Pattern p = Pattern.compile(regEx);
  985 + Matcher m = p.matcher(str);
  986 + return m.find();
  987 + }
  988 +
  989 +
  990 + /**
  991 + * @param code 要隐藏显示的字符串
  992 + * @param head 前面保留的位数
  993 + * @param tail 后面保留的位数
  994 + * @return 处理后的字符串
  995 + */
  996 + public static String getEncryptCode(String code, int head, int tail) {
  997 + int body = code.length() - head - tail;
  998 + String regexVar = "(\\w{%d})(\\w{%d})(\\w{%d})";
  999 + String regex = String.format(regexVar, head, body, tail);
  1000 + String bodyPart = code.replaceAll(regex, "$2");
  1001 + String bodyEncrypt = bodyPart.replaceAll("\\w", "*");
  1002 + String replacement = String.format("$1%s$3", bodyEncrypt);
  1003 + return code.replaceAll(regex, replacement);
  1004 + }
  1005 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/TemplateFormatUtils.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/TemplateFormatUtils.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import java.util.Map;
  4 +import java.util.regex.Matcher;
  5 +import java.util.regex.Pattern;
  6 +
  7 +/**
  8 + *
  9 + * 消息模板占位符替换工具
  10 + *
  11 + * @author fanzhenyu
  12 + * @date 2022-04-20
  13 + */
  14 +public class TemplateFormatUtils {
  15 +
  16 +
  17 + /**
  18 + * 正则 匹配 { + "多个任意字符" + }
  19 + */
  20 + private static final String DEFAULT_REG = "\\{[\\w]+\\}";
  21 +
  22 + /**
  23 + *
  24 + * @param text 原模板 占位符格式必须为:{fieldName}
  25 + * @param map 模板参数
  26 + * @return
  27 + */
  28 + public static String replaceTemplateContent(String text, Map<String, String> map){
  29 + return replaceTemplateContent(text,map,DEFAULT_REG);
  30 + }
  31 +
  32 + /**
  33 + *
  34 + * @param text 原模板 占位符格式必须为:{fieldName}
  35 + * @param map 模板参数
  36 + * @param reg 自定义占位符样式 - 正则匹配
  37 + * @return
  38 + */
  39 + public static String replaceTemplateContent(String text,Map<String,String> map,String reg){
  40 +
  41 + if(StringUtils.isBlank(reg)){
  42 + reg = DEFAULT_REG;
  43 + }
  44 +
  45 + Pattern pattern = Pattern.compile(reg);
  46 + Matcher m = pattern.matcher(text);
  47 + while(m.find()){
  48 + String currentGroup = m.group();
  49 + String currentPattern = currentGroup.replaceAll("^\\{", "").replaceAll("\\}$", "").trim();
  50 + String mapValue = map.get(currentPattern);
  51 + if (mapValue != null){
  52 + text = text.replace(currentGroup, mapValue);
  53 + }
  54 + }
  55 + return text;
  56 + }
  57 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/ThrowableUtil.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/ThrowableUtil.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import com.canrd.webmagic.common.exception.BusinessException;
  4 +
  5 +import javax.validation.ConstraintViolationException;
  6 +import java.io.PrintWriter;
  7 +import java.io.StringWriter;
  8 +
  9 +/**
  10 + * 异常工具 2019-01-06
  11 + */
  12 +public class ThrowableUtil {
  13 +
  14 + /**
  15 + * 获取堆栈信息
  16 + */
  17 + public static String getStackTrace(Throwable throwable) {
  18 + StringWriter sw = new StringWriter();
  19 + try (PrintWriter pw = new PrintWriter(sw)) {
  20 + throwable.printStackTrace(pw);
  21 + return sw.toString();
  22 + }
  23 + }
  24 +
  25 + public static void throwForeignKeyException(Throwable e, String msg) {
  26 + Throwable t = e.getCause();
  27 + while ((t != null) && !(t instanceof ConstraintViolationException)) {
  28 + t = t.getCause();
  29 + }
  30 + if (t != null) {
  31 + throw new BusinessException(msg);
  32 + }
  33 + assert false;
  34 + throw new BusinessException("删除失败:" + t.getMessage());
  35 + }
  36 +}
... ...
src/main/java/com/canrd/webmagic/common/utils/TransactionHelper.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/common/utils/TransactionHelper.java
  1 +package com.canrd.webmagic.common.utils;
  2 +
  3 +import org.springframework.stereotype.Component;
  4 +import org.springframework.transaction.annotation.Propagation;
  5 +import org.springframework.transaction.annotation.Transactional;
  6 +
  7 +import java.util.function.Supplier;
  8 +
  9 +/**
  10 + * @author:
  11 + * @date: 2021/12/21
  12 + */
  13 +@Component
  14 +public class TransactionHelper {
  15 +
  16 + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  17 + public <T> T run(Supplier<T> command) {
  18 + return command.get();
  19 + }
  20 +
  21 + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  22 + public void run(Runnable command) {
  23 + command.run();
  24 + }
  25 +
  26 +
  27 +}
... ...
src/main/java/com/canrd/webmagic/config/AdminMetaObjectHandler.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/config/AdminMetaObjectHandler.java
  1 +package com.canrd.webmagic.config;
  2 +
  3 +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
  4 +import com.canrd.webmagic.common.constant.Constant;
  5 +import lombok.extern.slf4j.Slf4j;
  6 +import org.apache.ibatis.reflection.MetaObject;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import java.time.LocalDateTime;
  10 +
  11 +
  12 +@Slf4j
  13 +@Component
  14 +public class AdminMetaObjectHandler implements MetaObjectHandler {
  15 +
  16 +
  17 + private static final String CREATE_TIME = "createTime";
  18 + private static final String MODIFY_TIME = "modifyTime";
  19 + private static final String CREATE_BY = "createBy";
  20 + private static final String MODIFY_BY = "modifyBy";
  21 + private static final String ENABLE_FLAG = "enableFlag";
  22 + private static final String STRING_CLASS_NAME = "java.lang.String";
  23 + private static final String LONG_CLASS_NAME = "java.lang.Long";
  24 +
  25 + @Override
  26 + public void insertFill(MetaObject metaObject) {
  27 + LocalDateTime now = LocalDateTime.now();
  28 + this.strictInsertFill(metaObject, CREATE_TIME, LocalDateTime.class, now);
  29 + this.strictInsertFill(metaObject, MODIFY_TIME, LocalDateTime.class, now);
  30 + this.strictInsertFill(metaObject, ENABLE_FLAG, Integer.class, Constant.ENABLE_TEN);
  31 + try {
  32 +// UserDetails loginUser = SecurityUtils.getUserDetails();
  33 + this.strictInsertFill(metaObject, CREATE_BY, String.class, "system");
  34 + this.strictInsertFill(metaObject, MODIFY_BY, String.class, "system");
  35 +
  36 +// this.strictInsertFill(metaObject, CREATE_BY, String.class, loginUser.getUsername());
  37 +// this.strictInsertFill(metaObject, MODIFY_BY, String.class, loginUser.getUsername());
  38 + } catch (Exception e) {
  39 + this.strictInsertFill(metaObject, CREATE_BY, String.class, "system");
  40 +
  41 + this.strictInsertFill(metaObject, MODIFY_BY, String.class, "system");
  42 + }
  43 +
  44 +
  45 + }
  46 +
  47 + @Override
  48 + public void updateFill(MetaObject metaObject) {
  49 +
  50 + this.strictUpdateFill(metaObject, MODIFY_TIME, LocalDateTime.class, LocalDateTime.now());
  51 +
  52 +
  53 + try {
  54 +// UserDetails loginUser = SecurityUtils.getUserDetails();
  55 +// if (null == loginUser) {
  56 +// return;
  57 +// }
  58 +// this.strictUpdateFill(metaObject, MODIFY_BY, String.class, loginUser.getUsername());
  59 + this.strictUpdateFill(metaObject, MODIFY_BY, String.class, "system");
  60 +
  61 + } catch (Exception e) {
  62 + this.strictUpdateFill(metaObject, MODIFY_BY, String.class, "system");
  63 + }
  64 +
  65 + }
  66 +}
... ...
src/main/java/com/canrd/webmagic/config/ConfigurerAdapter.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/config/ConfigurerAdapter.java
  1 +package com.canrd.webmagic.config;
  2 +
  3 +import org.springframework.context.annotation.Bean;
  4 +import org.springframework.context.annotation.Configuration;
  5 +import org.springframework.web.cors.CorsConfiguration;
  6 +import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
  7 +import org.springframework.web.filter.CorsFilter;
  8 +import org.springframework.web.servlet.config.annotation.EnableWebMvc;
  9 +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  10 +
  11 +/**
  12 + * WebMvcConfigurer
  13 + *
  14 + * @date 2018-11-30
  15 + */
  16 +@Configuration
  17 +@EnableWebMvc
  18 +public class ConfigurerAdapter implements WebMvcConfigurer {
  19 +
  20 +
  21 + @Bean
  22 + public CorsFilter corsFilter() {
  23 + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  24 + CorsConfiguration config = new CorsConfiguration();
  25 + config.setAllowCredentials(true);
  26 + config.addAllowedOrigin("*");
  27 + config.addAllowedHeader("*");
  28 + config.addAllowedMethod("*");
  29 + source.registerCorsConfiguration("/**", config);
  30 + return new CorsFilter(source);
  31 + }
  32 +}
... ...
src/main/java/com/canrd/webmagic/config/MybatisPlusConfig.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/config/MybatisPlusConfig.java
  1 +package com.canrd.webmagic.config;
  2 +
  3 +import org.springframework.context.annotation.Configuration;
  4 +
  5 +
  6 +@Configuration
  7 +public class MybatisPlusConfig {
  8 +
  9 +}
... ...
src/main/java/com/canrd/webmagic/config/RedisConfig.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/config/RedisConfig.java
  1 +package com.canrd.webmagic.config;
  2 +
  3 +import org.springframework.context.annotation.Bean;
  4 +import org.springframework.data.redis.connection.RedisConnectionFactory;
  5 +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
  6 +import org.springframework.data.redis.core.RedisTemplate;
  7 +import org.springframework.data.redis.core.StringRedisTemplate;
  8 +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
  9 +import org.springframework.data.redis.serializer.StringRedisSerializer;
  10 +
  11 +import javax.annotation.Resource;
  12 +
  13 +
  14 +public class RedisConfig {
  15 +
  16 +
  17 + @Resource
  18 + private LettuceConnectionFactory lqlcfactory;
  19 +
  20 + /**
  21 + * @param connectionFactory
  22 + * @return
  23 + */
  24 + @Bean
  25 + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
  26 + RedisTemplate template = new RedisTemplate();
  27 + template.setConnectionFactory(connectionFactory);
  28 + return template;
  29 + }
  30 +
  31 + /**
  32 + * 配置该bean是为了获取logistics 1.0存入redis的数据
  33 + * 序列化方式保持跟logistics 1.0统一
  34 + *
  35 + * @param factory
  36 + * @return
  37 + */
  38 + @Bean(name = "logisticsRedisTemplate")
  39 + public RedisTemplate<String, Object> logisticsRedisTemplate(RedisConnectionFactory factory) {
  40 + RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
  41 + redisTemplate.setConnectionFactory(lqlcfactory);
  42 + redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
  43 + redisTemplate.setKeySerializer(new StringRedisSerializer());
  44 + return redisTemplate;
  45 + }
  46 +
  47 + @Bean
  48 + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
  49 + StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
  50 + // lqlcfactory.setShareNativeConnection(true);
  51 + stringRedisTemplate.setConnectionFactory(lqlcfactory);
  52 + return stringRedisTemplate;
  53 +
  54 + }
  55 +}
... ...
src/main/java/com/canrd/webmagic/config/RestTemplateConfig.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/config/RestTemplateConfig.java
  1 +package com.canrd.webmagic.config;
  2 +
  3 +import org.springframework.context.annotation.Bean;
  4 +import org.springframework.context.annotation.Configuration;
  5 +import org.springframework.http.client.ClientHttpRequestFactory;
  6 +import org.springframework.http.client.SimpleClientHttpRequestFactory;
  7 +import org.springframework.web.client.RestTemplate;
  8 +
  9 +
  10 +@Configuration
  11 +public class RestTemplateConfig {
  12 +
  13 + @Bean
  14 + public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
  15 + return new RestTemplate(factory);
  16 + }
  17 +
  18 + @Bean
  19 + public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
  20 + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
  21 + factory.setReadTimeout(3000);
  22 + factory.setConnectTimeout(5000);
  23 + return factory;
  24 + }
  25 +
  26 +}
... ...
src/main/java/com/canrd/webmagic/config/WebConfig.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/config/WebConfig.java
  1 +package com.canrd.webmagic.config;
  2 +
  3 +import com.alibaba.fastjson.support.config.FastJsonConfig;
  4 +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
  5 +import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.context.annotation.Configuration;
  7 +import org.springframework.http.MediaType;
  8 +import org.springframework.http.converter.HttpMessageConverter;
  9 +import org.springframework.http.converter.StringHttpMessageConverter;
  10 +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  11 +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  12 +
  13 +import java.nio.charset.StandardCharsets;
  14 +import java.util.ArrayList;
  15 +import java.util.Collections;
  16 +import java.util.List;
  17 +import java.util.stream.Collectors;
  18 +
  19 +
  20 +@Slf4j
  21 +@Configuration
  22 +public class WebConfig implements WebMvcConfigurer {
  23 +
  24 +
  25 + @Override
  26 + public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
  27 + FastJsonHttpMessageConverter fastConverter = getFastJsonHttpMessageConverter();
  28 +
  29 + StringHttpMessageConverter stringHttpMessageConverter = getStringHttpMessageConverter();
  30 +
  31 + /**
  32 + * 添加StringHttpMessageConverter ,让其转化String。注意顺序,StringHttpMessageConverter 要在FastJsonHttpMessageConverter 之前。
  33 + *
  34 + * https://www.cnblogs.com/slankka/p/11437034.html
  35 + */
  36 + converters.add(0, fastConverter);
  37 + converters.add(0, stringHttpMessageConverter);
  38 + log.info("HttpMessageConverter顺序\n{}", converters.stream().map(c -> c.getClass().getName()).collect(Collectors.joining("\n")));
  39 + }
  40 +
  41 + private static StringHttpMessageConverter getStringHttpMessageConverter() {
  42 + StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
  43 + stringHttpMessageConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_PLAIN));
  44 + return stringHttpMessageConverter;
  45 + }
  46 +
  47 + private static FastJsonHttpMessageConverter getFastJsonHttpMessageConverter() {
  48 + FastJsonConfig fastJsonConfig = new FastJsonConfig();
  49 + //解决空值序列化的问题,改为不序列化
  50 + /*fastJsonConfig.setSerializeFilters(new PropertyFilter() {
  51 + @Override
  52 + public boolean apply(Object source,String name, Object value) {
  53 + //if(value.getClass().isPrimitive() == null){
  54 + if(value == null){
  55 + return false;
  56 + }
  57 + return true;
  58 + }
  59 + });*/
  60 + fastJsonConfig.setCharset(StandardCharsets.UTF_8);
  61 + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
  62 + List<MediaType> supportedMediaTypes = new ArrayList<>();
  63 + supportedMediaTypes.add(MediaType.APPLICATION_JSON);
  64 + supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
  65 + supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
  66 +// supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
  67 + supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
  68 + supportedMediaTypes.add(MediaType.APPLICATION_PDF);
  69 + supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
  70 + supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
  71 +// supportedMediaTypes.add(MediaType.APPLICATION_XML);
  72 + supportedMediaTypes.add(MediaType.IMAGE_GIF);
  73 + supportedMediaTypes.add(MediaType.IMAGE_JPEG);
  74 + supportedMediaTypes.add(MediaType.IMAGE_PNG);
  75 + supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
  76 + supportedMediaTypes.add(MediaType.TEXT_HTML);
  77 + supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
  78 + supportedMediaTypes.add(MediaType.TEXT_PLAIN);
  79 +// supportedMediaTypes.add(MediaType.TEXT_XML);
  80 + fastConverter.setSupportedMediaTypes(supportedMediaTypes);
  81 + fastConverter.setFastJsonConfig(fastJsonConfig);
  82 + fastConverter.setDefaultCharset(StandardCharsets.UTF_8);
  83 + return fastConverter;
  84 + }
  85 +
  86 + @Override
  87 + public void addResourceHandlers(ResourceHandlerRegistry registry) {
  88 + registry.addResourceHandler("/**").addResourceLocations(
  89 + "classpath:/static/");
  90 + registry.addResourceHandler("swagger-ui.html").addResourceLocations(
  91 + "classpath:/META-INF/resources/");
  92 + registry.addResourceHandler("/webjars/**").addResourceLocations(
  93 + "classpath:/META-INF/resources/webjars/");
  94 + WebMvcConfigurer.super.addResourceHandlers(registry);
  95 + }
  96 +}
... ...
src/main/java/com/canrd/webmagic/controller/TestController.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/controller/TestController.java
  1 +package com.canrd.webmagic.controller;
  2 +
  3 +
  4 +import com.canrd.webmagic.common.constant.ServerResult;
  5 +import com.canrd.webmagic.common.jsr303.OperateGroup;
  6 +import com.canrd.webmagic.domain.vo.TestQueryVO;
  7 +import com.canrd.webmagic.domain.vo.TestVO;
  8 +import com.canrd.webmagic.service.TestService;
  9 +import org.springframework.validation.annotation.Validated;
  10 +import org.springframework.web.bind.annotation.PostMapping;
  11 +import org.springframework.web.bind.annotation.RequestBody;
  12 +import org.springframework.web.bind.annotation.RequestMapping;
  13 +import org.springframework.web.bind.annotation.RestController;
  14 +
  15 +import javax.annotation.Resource;
  16 +
  17 +/**
  18 + * (Test)表控制层
  19 + *
  20 + * @author makejava
  21 + * @since 2024-01-12 14:36:56
  22 + */
  23 +@RestController
  24 +@RequestMapping("/lift-hub/test")
  25 +public class TestController {
  26 + /**
  27 + * 服务对象
  28 + */
  29 + @Resource
  30 + private TestService testService;
  31 +
  32 + /**
  33 + * 分页查询
  34 + *
  35 + * @param testQueryVO 查询条件
  36 + * @return 查询结果
  37 + */
  38 + @PostMapping("/list")
  39 + public ServerResult list(@RequestBody @Validated({OperateGroup.List.class}) TestQueryVO testQueryVO) {
  40 + return testService.list(testQueryVO);
  41 + }
  42 +
  43 + /**
  44 + * 通过主键查询单条数据
  45 + *
  46 + * @param testQueryVO 查询条件
  47 + * @return 单条数据
  48 + */
  49 + @PostMapping("/query_by_id")
  50 + public ServerResult queryById(@RequestBody TestQueryVO testQueryVO) {
  51 + return testService.queryById(testQueryVO);
  52 + }
  53 +
  54 + /**
  55 + * 新增数据
  56 + *
  57 + * @param testVO 数据VO
  58 + * @return 新增结果
  59 + */
  60 + @PostMapping("/add")
  61 + public ServerResult add(@RequestBody TestVO testVO) {
  62 + return testService.add(testVO);
  63 + }
  64 +
  65 + /**
  66 + * 编辑数据
  67 + *
  68 + * @param testVO 数据VO
  69 + * @return 编辑结果
  70 + */
  71 + @PostMapping("/edit")
  72 + public ServerResult edit(@RequestBody TestVO testVO) {
  73 + return testService.edit(testVO);
  74 + }
  75 +
  76 + /**
  77 + * 删除数据
  78 + *
  79 + * @param testQueryVO 查询条件
  80 + * @return 删除是否成功
  81 + */
  82 + @PostMapping("/delete_by_id")
  83 + public ServerResult deleteById(@RequestBody TestQueryVO testQueryVO) {
  84 + return testService.deleteById(testQueryVO);
  85 + }
  86 +
  87 +}
  88 +
... ...
src/main/java/com/canrd/webmagic/domain/dto/BaseDO.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/domain/dto/BaseDO.java
  1 +package com.canrd.webmagic.domain.dto;
  2 +
  3 +import com.alibaba.fastjson.annotation.JSONField;
  4 +import com.baomidou.mybatisplus.annotation.FieldFill;
  5 +import com.baomidou.mybatisplus.annotation.TableField;
  6 +import com.baomidou.mybatisplus.annotation.TableLogic;
  7 +import com.canrd.webmagic.common.utils.DateUtil;
  8 +import com.fasterxml.jackson.annotation.JsonFormat;
  9 +import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
  10 +import com.fasterxml.jackson.databind.annotation.JsonSerialize;
  11 +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
  12 +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
  13 +import lombok.AllArgsConstructor;
  14 +import lombok.Data;
  15 +import lombok.NoArgsConstructor;
  16 +import lombok.experimental.SuperBuilder;
  17 +import org.apache.ibatis.type.LocalDateTimeTypeHandler;
  18 +import org.springframework.format.annotation.DateTimeFormat;
  19 +
  20 +import java.io.Serializable;
  21 +import java.time.LocalDateTime;
  22 +
  23 +
  24 +@Data
  25 +@SuperBuilder(toBuilder = true)
  26 +@NoArgsConstructor
  27 +@AllArgsConstructor
  28 +public class BaseDO implements Serializable {
  29 +
  30 + /**
  31 + * 创建时间
  32 + */
  33 + @TableField(fill = FieldFill.INSERT, typeHandler = LocalDateTimeTypeHandler.class)
  34 + @JsonFormat(pattern = DateUtil.DATE_TIME, timezone = DateUtil.Zone.GMT8)
  35 + @DateTimeFormat(pattern = DateUtil.DATE_TIME)
  36 + @JSONField(format = DateUtil.DATE_TIME)
  37 + @JsonDeserialize(using = LocalDateTimeDeserializer.class)
  38 + @JsonSerialize(using = LocalDateTimeSerializer.class)
  39 + private LocalDateTime createTime;
  40 +
  41 + /**
  42 + * 创建人
  43 + */
  44 + @TableField(fill = FieldFill.INSERT)
  45 + private String createBy;
  46 +
  47 + /**
  48 + * 修改时间
  49 + */
  50 + @TableField(fill = FieldFill.INSERT_UPDATE, typeHandler = LocalDateTimeTypeHandler.class)
  51 + @JsonFormat(pattern = DateUtil.DATE_TIME, timezone = DateUtil.Zone.GMT8)
  52 + @DateTimeFormat(pattern = DateUtil.DATE_TIME)
  53 + @JSONField(format = DateUtil.DATE_TIME)
  54 + @JsonDeserialize(using = LocalDateTimeDeserializer.class)
  55 + @JsonSerialize(using = LocalDateTimeSerializer.class)
  56 + private LocalDateTime modifyTime;
  57 +
  58 + /**
  59 + * 修改人
  60 + */
  61 + @TableField(fill = FieldFill.INSERT_UPDATE)
  62 + private String modifyBy;
  63 +
  64 + /**
  65 + * 是否可用 10-可用 20-删除 30-禁用
  66 + */
  67 + @TableLogic
  68 + @TableField(fill = FieldFill.INSERT)
  69 + private Integer enableFlag;
  70 +
  71 + /**
  72 + * 版本号--乐观锁预留字段
  73 + */
  74 + private Integer version;
  75 +}
... ...
src/main/java/com/canrd/webmagic/domain/dto/TestDO.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/domain/dto/TestDO.java
  1 +package com.canrd.webmagic.domain.dto;
  2 +
  3 +
  4 +import com.baomidou.mybatisplus.annotation.TableName;
  5 +import lombok.*;
  6 +import lombok.experimental.SuperBuilder;
  7 +
  8 +import java.io.Serializable;
  9 +
  10 +/**
  11 + * (Test)实体类
  12 + *
  13 + * @author makejava
  14 + * @since 2024-01-12 14:36:56
  15 + */
  16 +@TableName("test")
  17 +@Data
  18 +@AllArgsConstructor
  19 +@ToString
  20 +@NoArgsConstructor
  21 +@EqualsAndHashCode(callSuper = false)
  22 +@SuperBuilder
  23 +public class TestDO extends BaseDO implements Serializable {
  24 + private static final long serialVersionUID = 856841241099412904L;
  25 +
  26 + private Integer id;
  27 +
  28 + private String username;
  29 +
  30 + private String email;
  31 +
  32 +}
... ...
src/main/java/com/canrd/webmagic/domain/vo/BasePageVO.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/domain/vo/BasePageVO.java
  1 +package com.canrd.webmagic.domain.vo;
  2 +
  3 +import com.canrd.webmagic.common.constant.Constant;
  4 +import com.canrd.webmagic.common.jsr303.OperateGroup;
  5 +import com.fasterxml.jackson.annotation.JsonInclude;
  6 +import lombok.AllArgsConstructor;
  7 +import lombok.Data;
  8 +import lombok.NoArgsConstructor;
  9 +import lombok.experimental.SuperBuilder;
  10 +
  11 +import javax.validation.constraints.Max;
  12 +import javax.validation.constraints.Min;
  13 +import javax.validation.constraints.NotNull;
  14 +
  15 +
  16 +@SuperBuilder(toBuilder = true)
  17 +@Data
  18 +@NoArgsConstructor
  19 +@AllArgsConstructor
  20 +public class BasePageVO {
  21 +
  22 + /**
  23 + * 页码
  24 + */
  25 + @JsonInclude(JsonInclude.Include.NON_NULL)
  26 + @NotNull(message = "页码不能为空", groups = {OperateGroup.List.class})
  27 + @Min(value = Constant.ONE, message = "页码不能小于1", groups = {OperateGroup.List.class})
  28 + private Integer current = 1;
  29 + /**
  30 + * 页
  31 + */
  32 + @JsonInclude(JsonInclude.Include.NON_NULL)
  33 + @NotNull(message = "每页大小不能为空", groups = {OperateGroup.List.class})
  34 + @Min(value = 1, message = "每页大小不能小于1", groups = {OperateGroup.List.class})
  35 + @Max(value = 5000, message = "每页大小不能大于5000", groups = {OperateGroup.List.class})
  36 + private Integer size = 10;
  37 +
  38 + /**
  39 + * 总数
  40 + */
  41 + @JsonInclude(JsonInclude.Include.NON_NULL)
  42 + private Integer total;
  43 +}
... ...
src/main/java/com/canrd/webmagic/domain/vo/TestQueryVO.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/domain/vo/TestQueryVO.java
  1 +package com.canrd.webmagic.domain.vo;
  2 +
  3 +import lombok.*;
  4 +import lombok.experimental.SuperBuilder;
  5 +
  6 +import java.io.Serializable;
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * @author makejava
  11 + * @since 2024-01-12 14:36:56
  12 + */
  13 +@Data
  14 +@AllArgsConstructor
  15 +@ToString
  16 +@NoArgsConstructor
  17 +@EqualsAndHashCode(callSuper = false)
  18 +@SuperBuilder
  19 +public class TestQueryVO extends BasePageVO implements Serializable {
  20 + private static final long serialVersionUID = 542072710112757366L;
  21 +
  22 + private List<Long> ids;
  23 +
  24 +
  25 + private Integer id;
  26 +
  27 + private String username;
  28 +
  29 + private String email;
  30 +
  31 +
  32 +}
  33 +
... ...
src/main/java/com/canrd/webmagic/domain/vo/TestVO.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/domain/vo/TestVO.java
  1 +package com.canrd.webmagic.domain.vo;
  2 +
  3 +
  4 +import lombok.*;
  5 +import lombok.experimental.SuperBuilder;
  6 +
  7 +import java.io.Serializable;
  8 +
  9 +/**
  10 + * (Test)实体类
  11 + *
  12 + * @author makejava
  13 + * @since 2024-01-12 14:36:56
  14 + */
  15 +@Data
  16 +@AllArgsConstructor
  17 +@ToString
  18 +@NoArgsConstructor
  19 +@EqualsAndHashCode(callSuper = false)
  20 +@SuperBuilder
  21 +public class TestVO implements Serializable {
  22 + private static final long serialVersionUID = 257625796831027116L;
  23 +
  24 + private Integer id;
  25 +
  26 + private String username;
  27 +
  28 + private String email;
  29 +
  30 +
  31 +}
... ...
src/main/java/com/canrd/webmagic/mapper/TestMapper.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/mapper/TestMapper.java
  1 +package com.canrd.webmagic.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import com.canrd.webmagic.domain.dto.TestDO;
  5 +
  6 +/**
  7 + * (Test)表数据库访问层
  8 + *
  9 + * @author makejava
  10 + * @since 2024-01-12 14:36:56
  11 + */
  12 +public interface TestMapper extends BaseMapper<TestDO> {
  13 +
  14 +
  15 +}
  16 +
... ...
src/main/java/com/canrd/webmagic/processor/BaiduHotSearchPageProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/processor/BaiduHotSearchPageProcessor.java
  1 +package com.canrd.webmagic.processor;
  2 +
  3 +import us.codecraft.webmagic.Page;
  4 +import us.codecraft.webmagic.Site;
  5 +import us.codecraft.webmagic.Spider;
  6 +import us.codecraft.webmagic.processor.PageProcessor;
  7 +import us.codecraft.webmagic.selector.Selectable;
  8 +import us.codecraft.webmagic.selector.XpathSelector;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * @author: xms
  14 + * @description: TODO
  15 + * @date: 2024/4/1 14:19
  16 + * @version: 1.0
  17 + */
  18 +public class BaiduHotSearchPageProcessor implements PageProcessor {
  19 +
  20 + // 抓取网站的相关配置,包括编码、抓取间隔、重试次数等
  21 + private Site site = Site.me().setRetryTimes(3).setSleepTime(100);
  22 +
  23 + /**
  24 + * 定制爬虫逻辑的核心接口,在这里编写抽取逻辑
  25 + *
  26 + * @param page
  27 + */
  28 + @Override
  29 + public void process(Page page) {
  30 +
  31 + System.out.println(page.getHtml());
  32 + /**
  33 + * 通过page.getHtml()可以获取到main函数中Spider.create(new BaiduHotSearchPageProcessor()).addUrl中的地址的网页内容
  34 + * 1、通过$或css()方法获取到该page html下某元素dom
  35 + */
  36 + Selectable selectable = page.getHtml().$(".theme-hot").select(
  37 + new XpathSelector("a[@class='item-wrap_2oCLZ']")
  38 + );
  39 + List<Selectable> nodes = selectable.nodes();
  40 +
  41 + /**
  42 + * 获取到指定的dom后,从这些dom中提取元素内容。
  43 + */
  44 + System.out.println("今日百度热搜:");
  45 + for (int i = 1; i <= nodes.size() - 1; i++) {
  46 + Selectable node = nodes.get(i);
  47 + String link = node.$(".item-wrap_2oCLZ", "href").get();
  48 + String title = node.$(".c-single-text-ellipsis", "text").get();
  49 + System.out.printf("%d、%s,访问地址:%s%n", i, title, link);
  50 + }
  51 + }
  52 +
  53 + @Override
  54 + public Site getSite() {
  55 + return site;
  56 + }
  57 +
  58 + public static void main(String[] args) {
  59 + // 创建一个Spider,并把我们的处理器放进去
  60 + Spider.create(new BaiduHotSearchPageProcessor())
  61 + // 添加这个Spider要爬取的网页地址
  62 + .addUrl("https://top.baidu.com/board?platform=pc&sa=pcindex_entry")
  63 + // 开启5个线程执行,并开始爬取
  64 + .thread(5).run();
  65 + }
  66 +}
0 67 \ No newline at end of file
... ...
src/main/java/com/canrd/webmagic/processor/GithubRepoPageProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/processor/GithubRepoPageProcessor.java
  1 +package com.canrd.webmagic.processor;
  2 +
  3 +import us.codecraft.webmagic.Page;
  4 +import us.codecraft.webmagic.Site;
  5 +import us.codecraft.webmagic.Spider;
  6 +import us.codecraft.webmagic.processor.PageProcessor;
  7 +
  8 +/**
  9 + * @author: xms
  10 + * @description: TODO
  11 + * @date: 2024/4/1 12:11
  12 + * @version: 1.0
  13 + */
  14 +public class GithubRepoPageProcessor implements PageProcessor {
  15 +
  16 + private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);
  17 +
  18 + @Override
  19 + public void process(Page page) {
  20 + page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all());
  21 + page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString());
  22 + page.putField("name", page.getHtml().xpath("//h1[@class='public']/strong/a/text()").toString());
  23 + if (page.getResultItems().get("name")==null){
  24 + //skip this page
  25 + page.setSkip(true);
  26 + }
  27 + page.putField("readme", page.getHtml().xpath("//div[@id='readme']/tidyText()"));
  28 + }
  29 +
  30 + @Override
  31 + public Site getSite() {
  32 + return site;
  33 + }
  34 +
  35 + public static void main(String[] args) {
  36 + Spider.create(new GithubRepoPageProcessor()).addUrl("https://github.com/code4craft").thread(5).run();
  37 + }
  38 +}
0 39 \ No newline at end of file
... ...
src/main/java/com/canrd/webmagic/processor/NatureSearchPageProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/processor/NatureSearchPageProcessor.java
  1 +package com.canrd.webmagic.processor;
  2 +
  3 +import org.jsoup.nodes.Element;
  4 +import org.jsoup.nodes.TextNode;
  5 +import us.codecraft.webmagic.Page;
  6 +import us.codecraft.webmagic.Site;
  7 +import us.codecraft.webmagic.Spider;
  8 +import us.codecraft.webmagic.processor.PageProcessor;
  9 +import us.codecraft.webmagic.selector.HtmlNode;
  10 +import us.codecraft.webmagic.selector.Selectable;
  11 +import us.codecraft.webmagic.selector.XpathSelector;
  12 +
  13 +import java.util.List;
  14 +
  15 +/**
  16 + * @author: xms
  17 + * @description: TODO
  18 + * @date: 2024/4/1 14:19
  19 + * @version: 1.0
  20 + */
  21 +public class NatureSearchPageProcessor implements PageProcessor {
  22 +
  23 + // 抓取网站的相关配置,包括编码、抓取间隔、重试次数等
  24 + private Site site = Site.me().setRetryTimes(3).setSleepTime(100);
  25 +
  26 + /**
  27 + * 定制爬虫逻辑的核心接口,在这里编写抽取逻辑
  28 + *
  29 + * @param page
  30 + */
  31 + @Override
  32 + public void process(Page page) {
  33 +
  34 + System.out.println(page.getHtml());
  35 + /**
  36 + * 通过page.getHtml()可以获取到main函数中Spider.create(new BaiduHotSearchPageProcessor()).addUrl中的地址的网页内容
  37 + * 1、通过$或css()方法获取到该page html下某元素dom
  38 + */
  39 + Selectable selectable = page.getHtml().$(".app-article-list-row").select(
  40 + new XpathSelector("li[@class='app-article-list-row__item']")
  41 + );
  42 + List<Selectable> nodes = selectable.nodes();
  43 +
  44 + /**
  45 + * 获取到指定的dom后,从这些dom中提取元素内容。
  46 + */
  47 + System.out.println("今日百度热搜:");
  48 + for (int i = 1; i <= nodes.size() - 1; i++) {
  49 + Selectable node = nodes.get(i).$(".u-full-height").nodes().get(2).nodes().get(0).$(".u-full-height").select(new XpathSelector("a[@class='c-card__link u-link-inherit']")).nodes().get(0);
  50 + String link = node.$("a","href").get();
  51 + String title = node.$("a","text").get();
  52 + System.out.printf("%d、%s,访问地址:%s%n", i, title, link);
  53 + }
  54 + }
  55 +
  56 + @Override
  57 + public Site getSite() {
  58 + return site;
  59 + }
  60 +
  61 + public static void main(String[] args) {
  62 + // 创建一个Spider,并把我们的处理器放进去
  63 + Spider.create(new NatureSearchPageProcessor())
  64 + // 添加这个Spider要爬取的网页地址
  65 + .addUrl("https://www.nature.com/search?q=battery&page=1")
  66 + // 开启5个线程执行,并开始爬取
  67 + .thread(5).run();
  68 + }
  69 +}
0 70 \ No newline at end of file
... ...
src/main/java/com/canrd/webmagic/service/TestService.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/service/TestService.java
  1 +package com.canrd.webmagic.service;
  2 +
  3 +import com.baomidou.mybatisplus.extension.service.IService;
  4 +import com.canrd.webmagic.common.constant.ServerResult;
  5 +import com.canrd.webmagic.domain.dto.TestDO;
  6 +import com.canrd.webmagic.domain.vo.TestQueryVO;
  7 +import com.canrd.webmagic.domain.vo.TestVO;
  8 +
  9 +/**
  10 + * (Test)表服务接口
  11 + *
  12 + * @author makejava
  13 + * @since 2024-01-12 14:36:57
  14 + */
  15 +public interface TestService extends IService<TestDO> {
  16 +
  17 + /**
  18 + * 通过ID查询单条数据
  19 + *
  20 + * @param testQueryVO 主键
  21 + * @return 实例对象
  22 + */
  23 + ServerResult queryById(TestQueryVO testQueryVO);
  24 +
  25 + /**
  26 + * 分页查询
  27 + *
  28 + * @param testQueryVO 筛选条件
  29 + * @return 查询结果
  30 + */
  31 + ServerResult list(TestQueryVO testQueryVO);
  32 +
  33 + /**
  34 + * 新增数据
  35 + *
  36 + * @param testVO 数据VO
  37 + * @return 新增结果
  38 + */
  39 + ServerResult add(TestVO testVO);
  40 +
  41 + /**
  42 + * 修改数据
  43 + *
  44 + * @param testVO 数据VO
  45 + * @return 编辑结果
  46 + */
  47 + ServerResult edit(TestVO testVO);
  48 +
  49 + /**
  50 + * 通过主键删除数据
  51 + *
  52 + * @param testQueryVO 筛选条件
  53 + * @return 是否成功
  54 + */
  55 + ServerResult deleteById(TestQueryVO testQueryVO);
  56 +
  57 +}
... ...
src/main/java/com/canrd/webmagic/service/impl/TestServiceImpl.java 0 → 100644
  1 +++ a/src/main/java/com/canrd/webmagic/service/impl/TestServiceImpl.java
  1 +package com.canrd.webmagic.service.impl;
  2 +
  3 +import cn.hutool.core.bean.BeanUtil;
  4 +import cn.hutool.core.collection.CollUtil;
  5 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  6 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  7 +import com.baomidou.mybatisplus.core.metadata.IPage;
  8 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  9 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  10 +import com.canrd.webmagic.common.constant.Constant;
  11 +import com.canrd.webmagic.common.constant.ServerResult;
  12 +import com.canrd.webmagic.common.utils.PageUtils;
  13 +import com.canrd.webmagic.domain.dto.TestDO;
  14 +import com.canrd.webmagic.domain.vo.TestQueryVO;
  15 +import com.canrd.webmagic.domain.vo.TestVO;
  16 +import com.canrd.webmagic.mapper.TestMapper;
  17 +import com.canrd.webmagic.service.TestService;
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.stereotype.Service;
  20 +
  21 +import java.util.List;
  22 +import java.util.Objects;
  23 +
  24 +/**
  25 + * (Test)表服务实现类
  26 + *
  27 + * @author makejava
  28 + * @since 2024-01-12 14:36:57
  29 + */
  30 +@Slf4j
  31 +@Service
  32 +public class TestServiceImpl extends ServiceImpl<TestMapper, TestDO> implements TestService {
  33 +
  34 +
  35 + /**
  36 + * 通过ID查询单条数据
  37 + * <p>
  38 + * testQueryVO 主键
  39 + *
  40 + * @return 实例对象
  41 + */
  42 + @Override
  43 + public ServerResult queryById(TestQueryVO testQueryVO) {
  44 + if (Objects.isNull(testQueryVO.getId())) {
  45 + return ServerResult.fail("id 不能为空");
  46 + }
  47 + TestDO TestDo = getById(testQueryVO.getId());
  48 + if (Objects.isNull(TestDo)) {
  49 + return ServerResult.success(null);
  50 + }
  51 + return ServerResult.success(BeanUtil.copyProperties(TestDo, TestVO.class));
  52 + }
  53 +
  54 + /**
  55 + * 分页查询
  56 + *
  57 + * @param testQueryVO 筛选条件
  58 + * @return 查询结果
  59 + */
  60 + @Override
  61 + public ServerResult list(TestQueryVO testQueryVO) {
  62 +
  63 + LambdaQueryWrapper<TestDO> queryWapper = new LambdaQueryWrapper<TestDO>()
  64 + .eq(TestDO::getEnableFlag, Constant.ENABLE_TEN)
  65 + .orderByDesc(TestDO::getId);
  66 + Page page = new Page<>(testQueryVO.getCurrent(), testQueryVO.getSize());
  67 + IPage<TestDO> iPage = page(page, queryWapper);
  68 + testQueryVO.setTotal(Long.valueOf(iPage.getTotal()).intValue());
  69 + return ServerResult.success(PageUtils.getPageReturn(iPage.getRecords(), testQueryVO));
  70 + }
  71 +
  72 + /**
  73 + * 新增数据
  74 + *
  75 + * @param testVO 实例对象
  76 + * @return 实例对象
  77 + */
  78 + @Override
  79 + public ServerResult add(TestVO testVO) {
  80 + //todo 校验
  81 + if (Objects.nonNull(testVO.getId())) {
  82 + testVO.setId(null);
  83 + }
  84 + TestDO testDo = BeanUtil.copyProperties(testVO, TestDO.class);
  85 +
  86 + save(testDo);
  87 +
  88 + return ServerResult.success();
  89 + }
  90 +
  91 + /**
  92 + * 修改数据
  93 + *
  94 + * @param testVO 实例对象
  95 + * @return 实例对象
  96 + */
  97 + @Override
  98 + public ServerResult edit(TestVO testVO) {
  99 + //todo 校验
  100 + if (Objects.isNull(testVO.getId())) {
  101 + return ServerResult.fail("id 不能为空");
  102 + }
  103 + TestDO testDo = BeanUtil.copyProperties(testVO, TestDO.class);
  104 +
  105 + updateById(testDo);
  106 +
  107 + return ServerResult.success();
  108 + }
  109 +
  110 + /**
  111 + * 通过主键删除数据
  112 + *
  113 + * @param testQueryVO 筛选条件
  114 + * @return 是否成功
  115 + */
  116 + @Override
  117 + public ServerResult deleteById(TestQueryVO testQueryVO) {
  118 + List<Long> ids = testQueryVO.getIds();
  119 + if (CollUtil.isEmpty(ids)) {
  120 + return ServerResult.fail("ids 参数不能为空");
  121 + }
  122 + List<TestDO> testList = listByIds(ids);
  123 + if (CollUtil.isEmpty(testList)) {
  124 + return ServerResult.success();
  125 + }
  126 + //todo 校验是否可以逻辑删除
  127 + LambdaUpdateWrapper<TestDO> updateWrapper = new LambdaUpdateWrapper<TestDO>()
  128 + .in(TestDO::getId, ids)
  129 + .set(TestDO::getEnableFlag, Constant.UNABLE_TWENTY);
  130 + update(updateWrapper);
  131 + return ServerResult.success();
  132 + }
  133 +}
... ...
src/main/resources/application-local.yml 0 → 100644
  1 +++ a/src/main/resources/application-local.yml
  1 +mybatis-plus:
  2 + configuration:
  3 + cache-enabled: false
  4 + call-setters-on-nulls: true
  5 + jdbc-type-for-null: 'null'
  6 + map-underscore-to-camel-case: true
  7 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  8 + global-config:
  9 + db-config:
  10 + capital-mode: false
  11 + field-strategy: NOT_NULL
  12 + id-type: AUTO
  13 + logic-delete-field: enable_flag
  14 + logic-delete-value: 20
  15 + logic-not-delete-value: 10
  16 + mapper-locations: classpath:/mapper/**.xml
  17 + type-aliases-package: com.order.erp.**.dto
  18 +#spring:
  19 +# datasource:
  20 +# dynamic:
  21 +# primary: overtime #设置默认的数据源或者数据源组,默认值即为master
  22 +# strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
  23 +# datasource:
  24 +# wms_warehouse:
  25 +# url: jdbc:mysql://127.0.0.1:3306/overtime?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=false&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&allowMultiQueries=true&useAffectedRows=true&autoReconnectForPools=true&rewriteBatchedStatements=true
  26 +# username: root
  27 +# password: root
  28 +# driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
  29 +# druid:
  30 +# initial-size: 5
  31 +# max-active: 20
  32 +# max-evictable-idle-time-millis: 300000
  33 +# max-wait: 60000
  34 +# min-evictable-idle-time-millis: 300000
  35 +# min-idle: 5
  36 +# time-between-eviction-runs-millis: 60000
  37 +# type: com.alibaba.druid.pool.DruidDataSource
  38 +spring:
  39 + servlet:
  40 + multipart:
  41 + enabled: true
  42 + max-file-size: 100MB
  43 + max-request-size: 20MB
  44 + file-size-threshold: 20MB
  45 + datasource:
  46 + db-type: com.alibaba.druid.pool.DruidDataSource
  47 + driverClassName: com.mysql.cj.jdbc.Driver
  48 + initial-size: 5
  49 + max-active: 30
  50 + max-wait: 30000
  51 + min-idle: 5
  52 + #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
  53 + timeBetweenEvictionRunsMillis: 30000
  54 + #配置一个连接在池中最小生存的时间,单位是毫秒,30000=30s
  55 + minEvictableIdleTimeMillis: 30000
  56 + validationQuery: SELECT 'x'
  57 + testWhileIdle: true
  58 + testOnBorrow: true
  59 + testOnReturn: true
  60 + password: canrd@2024
  61 + time-between-eviction-runs-millis: 1000
  62 + url: jdbc:mysql://39.108.227.113:3307/order-erp1?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=false&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&allowMultiQueries=true&useAffectedRows=true&autoReconnectForPools=true
  63 + username: root
  64 + redis:
  65 + database: 0
  66 + host: 39.108.227.113
  67 + lettuce:
  68 + pool:
  69 + max-active: 2000
  70 + max-idle: 10
  71 + max-wait: -1
  72 + min-idle: 3
  73 + time-between-eviction-runs: 100
  74 + password: ''
  75 + port: 6379
  76 + timeout: 2000
  77 + mail:
  78 + # 配置 SMTP 服务器地址
  79 + host: smtp.mxhichina.com
  80 + # 发送者邮箱,已开通POP3/SMTP服务的邮箱,也就是你自己的
  81 + username: system@canrd.com
  82 + # 配置密码,注意不是真正的密码,而是刚刚申请到的授权码
  83 + password: Kelude2015
  84 + # 邮件接收者
  85 + mailRecipient: #邮件接收者邮箱
  86 + # 端口号465或587(QQ邮箱发送邮件仅支持587端口协议)
  87 + port: 587
  88 + # 默认的邮件编码为UTF-8
  89 + default-encoding: UTF-8
  90 + # 配置SSL 加密工厂
  91 + properties:
  92 + mail:
  93 + smtp:
  94 + socketFactoryClass: javax.net.ssl.SSLSocketFactory
  95 + #表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误
  96 + debug: true
  97 +
  98 + freemarker:
  99 + template-loader-path: classpath:/template/
  100 + suffix: .flt
  101 + enabled: true
  102 + cache: false
  103 + charset: UTF-8
  104 + content-type: text/html
  105 + allow-request-override: false
  106 + check-template-location: true
  107 + expose-request-attributes: false
  108 + expose-session-attributes: false
  109 + expose-spring-macro-helpers: false
  110 +
  111 +
  112 +logging:
  113 + config: classpath:log4j2-dev.xml
  114 +
  115 +#登录图形验证码有效时间/分钟
  116 +loginCode:
  117 + expiration: 2
  118 +
  119 +#密码加密传输,前端公钥加密,后端私钥解密
  120 +rsa:
  121 + private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==
  122 +
  123 +
  124 +#jwt
  125 +jwt:
  126 + header: Authorization
  127 + # 令牌前缀
  128 + token-start-with: Bearer
  129 + # 必须使用最少88位的Base64对该令牌进行编码
  130 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
  131 + # 令牌过期时间 此处单位/毫秒 ,默认2小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html
  132 + token-validity-in-seconds: 720000000
  133 + # 在线用户key
  134 + online-key: online-token
  135 + # 验证码
  136 + code-key: code-key
  137 +
  138 +outsys:
  139 + sms:
  140 + regionId: cn-hangzhou
  141 + accessKeyId: LTAIZCPI7OaWud0m
  142 + secret: nvtGeScBwRztGeoj8WSp5OWalalgpK
  143 + domain: dysmsapi.aliyuncs.com
  144 + version: 2017-05-25
  145 + action: SendSms
  146 + signName: canrd
  147 + templateCode: SMS_173005236
  148 + email:
  149 + host: http://core.canrd.com
  150 + passwordRecoverKey: http://www.canrd.com/canrd/shop/member/passwordModify
  151 +
  152 +
  153 +
  154 +system:
  155 + isLoginFailureLock: true
  156 + loginFailureLockTime: 5
  157 + loginFailureLockCount: 3
  158 +
  159 +openai:
  160 + token: Bearer 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
  161 +
  162 +# 文件存储路径
  163 +file:
  164 + path: /home/canrd/order-erp/files/
  165 + host: http://39.108.227.113
  166 + avatar: /home/order-erp/avatar/
  167 + # 文件大小 /M
  168 + maxSize: 100
  169 + avatarMaxSize: 5
  170 +
  171 +# 阿里pss图片服务
  172 +oss:
  173 + endpoint: https://oss-cn-qingdao.aliyuncs.com
  174 + accessKeyId: LTAIZCPI7OaWud0m
  175 + accessKeySecret: nvtGeScBwRztGeoj8WSp5OWalalgpK
  176 + bucket: order-erp
  177 +
  178 +
  179 +db:
  180 + mysql:
  181 + ip: 39.108.227.113
  182 + port: 3307
  183 + user: root
  184 + password: 123456
  185 + databaseName: order-erp
  186 + savePath: /home/canrd/order-erp/files/backup/
... ...
src/main/resources/application-prod.yml 0 → 100644
  1 +++ a/src/main/resources/application-prod.yml
  1 +mybatis-plus:
  2 + configuration:
  3 + cache-enabled: false
  4 + call-setters-on-nulls: true
  5 + jdbc-type-for-null: 'null'
  6 + map-underscore-to-camel-case: true
  7 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  8 + global-config:
  9 + db-config:
  10 + capital-mode: false
  11 + field-strategy: NOT_NULL
  12 + id-type: AUTO
  13 + logic-delete-field: enable_flag
  14 + logic-delete-value: 20
  15 + logic-not-delete-value: 10
  16 + mapper-locations: classpath:/mapper/**.xml
  17 + type-aliases-package: com.order.erp.**.dto
  18 +#spring:
  19 +# datasource:
  20 +# dynamic:
  21 +# primary: overtime #设置默认的数据源或者数据源组,默认值即为master
  22 +# strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
  23 +# datasource:
  24 +# wms_warehouse:
  25 +# url: jdbc:mysql://127.0.0.1:3306/overtime?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=false&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&allowMultiQueries=true&useAffectedRows=true&autoReconnectForPools=true&rewriteBatchedStatements=true
  26 +# username: root
  27 +# password: root
  28 +# driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
  29 +# druid:
  30 +# initial-size: 5
  31 +# max-active: 20
  32 +# max-evictable-idle-time-millis: 300000
  33 +# max-wait: 60000
  34 +# min-evictable-idle-time-millis: 300000
  35 +# min-idle: 5
  36 +# time-between-eviction-runs-millis: 60000
  37 +# type: com.alibaba.druid.pool.DruidDataSource
  38 +spring:
  39 + servlet:
  40 + multipart:
  41 + enabled: true
  42 + max-file-size: 100MB
  43 + max-request-size: 20MB
  44 + file-size-threshold: 20MB
  45 + datasource:
  46 + db-type: com.alibaba.druid.pool.DruidDataSource
  47 + driverClassName: com.mysql.cj.jdbc.Driver
  48 + initial-size: 5
  49 + max-active: 30
  50 + max-wait: 30000
  51 + min-idle: 5
  52 + #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
  53 + timeBetweenEvictionRunsMillis: 30000
  54 + #配置一个连接在池中最小生存的时间,单位是毫秒,30000=30s
  55 + minEvictableIdleTimeMillis: 30000
  56 + validationQuery: SELECT 'x'
  57 + testWhileIdle: true
  58 + testOnBorrow: true
  59 + testOnReturn: true
  60 + password: 123456
  61 + time-between-eviction-runs-millis: 1000
  62 + url: jdbc:mysql://172.17.0.1:3306/order-erp?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=false&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&allowMultiQueries=true&useAffectedRows=true&autoReconnectForPools=true
  63 + username: root
  64 + redis:
  65 + database: 0
  66 + host: 172.17.0.1
  67 + lettuce:
  68 + pool:
  69 + max-active: 2000
  70 + max-idle: 10
  71 + max-wait: -1
  72 + min-idle: 3
  73 + time-between-eviction-runs: 100
  74 + password: ''
  75 + port: 6379
  76 + timeout: 2000
  77 + mail:
  78 + # 配置 SMTP 服务器地址
  79 + host: xxx
  80 + # 发送者邮箱,已开通POP3/SMTP服务的邮箱,也就是你自己的
  81 + username: xxxx
  82 + # 配置密码,注意不是真正的密码,而是刚刚申请到的授权码
  83 + password: xxx
  84 + # 邮件接收者
  85 + mailRecipient: #邮件接收者邮箱
  86 + # 端口号465或587(QQ邮箱发送邮件仅支持587端口协议)
  87 + port: 587
  88 + # 默认的邮件编码为UTF-8
  89 + default-encoding: UTF-8
  90 + # 配置SSL 加密工厂
  91 + properties:
  92 + mail:
  93 + smtp:
  94 + socketFactoryClass: javax.net.ssl.SSLSocketFactory
  95 + #表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误
  96 + debug: true
  97 +
  98 + freemarker:
  99 + template-loader-path: classpath:/template/
  100 + suffix: .flt
  101 + enabled: true
  102 + cache: false
  103 + charset: UTF-8
  104 + content-type: text/html
  105 + allow-request-override: false
  106 + check-template-location: true
  107 + expose-request-attributes: false
  108 + expose-session-attributes: false
  109 + expose-spring-macro-helpers: false
  110 +
  111 +
  112 +logging:
  113 + config: classpath:log4j2-prod.xml
  114 +
  115 +#登录图形验证码有效时间/分钟
  116 +loginCode:
  117 + expiration: 2
  118 +
  119 +#密码加密传输,前端公钥加密,后端私钥解密
  120 +rsa:
  121 + private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==
  122 +
  123 +
  124 +#jwt
  125 +jwt:
  126 + header: Authorization
  127 + # 令牌前缀
  128 + token-start-with: Bearer
  129 + # 必须使用最少88位的Base64对该令牌进行编码
  130 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
  131 + # 令牌过期时间 此处单位/毫秒 ,默认2小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html
  132 + token-validity-in-seconds: 720000000
  133 + # 在线用户key
  134 + online-key: online-token
  135 + # 验证码
  136 + code-key: code-key
  137 +
  138 +outsys:
  139 + sms:
  140 + regionId: cn-hangzhou
  141 + accessKeyId: LTAIZCPI7OaWud0m
  142 + secret: nvtGeScBwRztGeoj8WSp5OWalalgpK
  143 + domain: dysmsapi.aliyuncs.com
  144 + version: 2017-05-25
  145 + action: SendSms
  146 + signName: canrd
  147 + templateCode: SMS_173005236
  148 + email:
  149 + host: xxxx
  150 + passwordRecoverKey: xxxxx
  151 +
  152 +
  153 +
  154 +system:
  155 + isLoginFailureLock: true
  156 + loginFailureLockTime: 5
  157 + loginFailureLockCount: 3
  158 +
  159 +openai:
  160 + token: Bearer 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
  161 +
  162 +# 文件存储路径
  163 +file:
  164 + path: /home/canrd/order-erp/files/
  165 + host: http://47.104.8.35
  166 + avatar: /home/order-erp/avatar/
  167 + # 文件大小 /M
  168 + maxSize: 100
  169 + avatarMaxSize: 5
  170 +
  171 +# 阿里pss图片服务
  172 +oss:
  173 + endpoint: https://oss-cn-qingdao.aliyuncs.com
  174 + accessKeyId: LTAI5t7u1gXR2vm82sd6CkVz
  175 + accessKeySecret: m4NzHZZsZiauKmRO8y7DihmcGNdQk4
  176 + bucket: alterego
  177 +
  178 +
  179 +db:
  180 + mysql:
  181 + ip: 172.17.0.1
  182 + port: 3306
  183 + user: root
  184 + password: 123456
  185 + databaseName: order-erp
  186 + savePath: /home/canrd/order-erp/files/backup/
... ...
src/main/resources/application-test.yml 0 → 100644
  1 +++ a/src/main/resources/application-test.yml
  1 +mybatis-plus:
  2 + configuration:
  3 + cache-enabled: false
  4 + call-setters-on-nulls: true
  5 + jdbc-type-for-null: 'null'
  6 + map-underscore-to-camel-case: true
  7 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  8 + global-config:
  9 + db-config:
  10 + capital-mode: false
  11 + field-strategy: NOT_NULL
  12 + id-type: AUTO
  13 + logic-delete-field: enable_flag
  14 + logic-delete-value: 20
  15 + logic-not-delete-value: 10
  16 + mapper-locations: classpath:/mapper/**.xml
  17 + type-aliases-package: com.order.erp.**.dto
  18 +#spring:
  19 +# datasource:
  20 +# dynamic:
  21 +# primary: overtime #设置默认的数据源或者数据源组,默认值即为master
  22 +# strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
  23 +# datasource:
  24 +# wms_warehouse:
  25 +# url: jdbc:mysql://127.0.0.1:3306/overtime?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=false&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&allowMultiQueries=true&useAffectedRows=true&autoReconnectForPools=true&rewriteBatchedStatements=true
  26 +# username: root
  27 +# password: root
  28 +# driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
  29 +# druid:
  30 +# initial-size: 5
  31 +# max-active: 20
  32 +# max-evictable-idle-time-millis: 300000
  33 +# max-wait: 60000
  34 +# min-evictable-idle-time-millis: 300000
  35 +# min-idle: 5
  36 +# time-between-eviction-runs-millis: 60000
  37 +# type: com.alibaba.druid.pool.DruidDataSource
  38 +spring:
  39 + servlet:
  40 + multipart:
  41 + enabled: true
  42 + max-file-size: 100MB
  43 + max-request-size: 20MB
  44 + file-size-threshold: 20MB
  45 + datasource:
  46 + db-type: com.alibaba.druid.pool.DruidDataSource
  47 + driverClassName: com.mysql.cj.jdbc.Driver
  48 + initial-size: 5
  49 + max-active: 30
  50 + max-wait: 30000
  51 + min-idle: 5
  52 + #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
  53 + timeBetweenEvictionRunsMillis: 30000
  54 + #配置一个连接在池中最小生存的时间,单位是毫秒,30000=30s
  55 + minEvictableIdleTimeMillis: 30000
  56 + validationQuery: SELECT 'x'
  57 + testWhileIdle: true
  58 + testOnBorrow: true
  59 + testOnReturn: true
  60 + password: 123456
  61 + time-between-eviction-runs-millis: 1000
  62 + url: jdbc:mysql://39.108.227.113:3307/order-erp?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=false&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&allowMultiQueries=true&useAffectedRows=true&autoReconnectForPools=true
  63 + username: root
  64 + redis:
  65 + database: 0
  66 + host: 39.108.227.113
  67 + lettuce:
  68 + pool:
  69 + max-active: 2000
  70 + max-idle: 10
  71 + max-wait: -1
  72 + min-idle: 3
  73 + time-between-eviction-runs: 100
  74 + password: ''
  75 + port: 6379
  76 + timeout: 2000
  77 + mail:
  78 + # 配置 SMTP 服务器地址
  79 + host: smtp.mxhichina.com
  80 + # 发送者邮箱,已开通POP3/SMTP服务的邮箱,也就是你自己的
  81 + username: system@canrd.com
  82 + # 配置密码,注意不是真正的密码,而是刚刚申请到的授权码
  83 + password: Kelude2015
  84 + # 邮件接收者
  85 + mailRecipient: #邮件接收者邮箱
  86 + # 端口号465或587(QQ邮箱发送邮件仅支持587端口协议)
  87 + port: 587
  88 + # 默认的邮件编码为UTF-8
  89 + default-encoding: UTF-8
  90 + # 配置SSL 加密工厂
  91 + properties:
  92 + mail:
  93 + smtp:
  94 + socketFactoryClass: javax.net.ssl.SSLSocketFactory
  95 + #表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误
  96 + debug: true
  97 +
  98 + freemarker:
  99 + template-loader-path: classpath:/template/
  100 + suffix: .flt
  101 + enabled: true
  102 + cache: false
  103 + charset: UTF-8
  104 + content-type: text/html
  105 + allow-request-override: false
  106 + check-template-location: true
  107 + expose-request-attributes: false
  108 + expose-session-attributes: false
  109 + expose-spring-macro-helpers: false
  110 +
  111 +
  112 +logging:
  113 + config: classpath:log4j2-dev.xml
  114 +
  115 +#登录图形验证码有效时间/分钟
  116 +loginCode:
  117 + expiration: 2
  118 +
  119 +#密码加密传输,前端公钥加密,后端私钥解密
  120 +rsa:
  121 + private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==
  122 +
  123 +
  124 +#jwt
  125 +jwt:
  126 + header: Authorization
  127 + # 令牌前缀
  128 + token-start-with: Bearer
  129 + # 必须使用最少88位的Base64对该令牌进行编码
  130 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
  131 + # 令牌过期时间 此处单位/毫秒 ,默认2小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html
  132 + token-validity-in-seconds: 720000000
  133 + # 在线用户key
  134 + online-key: online-token
  135 + # 验证码
  136 + code-key: code-key
  137 +
  138 +outsys:
  139 + sms:
  140 + regionId: cn-hangzhou
  141 + accessKeyId: LTAIZCPI7OaWud0m
  142 + secret: nvtGeScBwRztGeoj8WSp5OWalalgpK
  143 + domain: dysmsapi.aliyuncs.com
  144 + version: 2017-05-25
  145 + action: SendSms
  146 + signName: canrd
  147 + templateCode: SMS_173005236
  148 + email:
  149 + host: http://core.canrd.com
  150 + passwordRecoverKey: http://www.canrd.com/canrd/shop/member/passwordModify
  151 +
  152 +
  153 +
  154 +system:
  155 + isLoginFailureLock: true
  156 + loginFailureLockTime: 5
  157 + loginFailureLockCount: 3
  158 +
  159 +openai:
  160 + token: Bearer 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
  161 +
  162 +# 文件存储路径
  163 +file:
  164 + path: /home/canrd/order-erp/files/
  165 + host: http://39.108.227.113
  166 + avatar: /home/order-erp/avatar/
  167 + # 文件大小 /M
  168 + maxSize: 100
  169 + avatarMaxSize: 5
  170 +
  171 +# 阿里pss图片服务
  172 +oss:
  173 + endpoint: https://oss-cn-qingdao.aliyuncs.com
  174 + accessKeyId: LTAIZCPI7OaWud0m
  175 + accessKeySecret: nvtGeScBwRztGeoj8WSp5OWalalgpK
  176 + bucket: order-erp
  177 +
  178 +
  179 +db:
  180 + mysql:
  181 + ip: 39.108.227.113
  182 + port: 3307
  183 + user: root
  184 + password: 123456
  185 + databaseName: order-erp
  186 + savePath: /home/canrd/order-erp/files/backup/
... ...
src/main/resources/application.yml 0 → 100644
  1 +++ a/src/main/resources/application.yml
  1 +server:
  2 + port: 9000
  3 +
  4 +spring:
  5 + profiles:
  6 + active: local
0 7 \ No newline at end of file
... ...
src/main/resources/ip2region/ip2region.db 0 → 100644
No preview for this file type
src/main/resources/log4j2-dev.xml 0 → 100644
  1 +++ a/src/main/resources/log4j2-dev.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
  3 +<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出 -->
  4 +<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数 -->
  5 +<configuration status="debug" monitorInterval="30">
  6 + <!--<contextName>log4j2</contextName>-->
  7 + <properties>
  8 + <!--${sys:catalina.home}表示linux中环境变量中的tomcat根目录 用户主目录-->
  9 + <!--原来用logback时候在统一配置中心也配置一个logging.path=/opt/tomcat-log/${spring.application.name} LOG_PATH是内置变量-->
  10 + <!--${sys:user.home} 用户主目录-->
  11 + <!-- <Property name="log_path">${sys:user.home}/logs</Property>-->
  12 +<!-- <Property name="log_path" value="./logs/" />-->
  13 + <property name="console_log_pattern">%d|%t|%traceId|%-5level|%F:%L|%M|%m%n</property>
  14 + <!-- 保留日志天数 D H M S 分别对应天 小时 分钟 秒 -->
  15 + <property name="KEEP_LOG_DAY">60D</property>
  16 + <!-- 日志切割的最小单位 -->
  17 + <property name="EVERY_FILE_SIZE">100M</property>
  18 + </properties>
  19 + <!--先定义所有的appender -->
  20 + <appenders>
  21 + <console name="Console" target="SYSTEM_OUT">
  22 + <!--输出日志的格式 -->
  23 + <PatternLayout charset="UTF-8" pattern="${console_log_pattern}"/>
  24 + <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
  25 + </console>
  26 + <!--这个输出控制台的配置 -->
  27 + <!--<console name="Console" target="SYSTEM_OUT" follow="false">-->
  28 + <!--&lt;!&ndash;输出日志的格式 &ndash;&gt;-->
  29 + <!--<PatternLayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n" />-->
  30 + <!--</console>-->
  31 +
  32 + <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
  33 + <RollingFile name="RollingFileInfo" fileName="${sys:logging.path}/logs/overtime.log" filePattern="${sys:logging.path}/logs/$${date:yyyy-MM-dd}/info-%d{yyyy-MM-dd}-%i.log">
  34 + <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
  35 + <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
  36 + <!--<Filters>-->
  37 + <!--<ThresholdFilter level="INFO"/>-->
  38 + <!--<ThresholdFilter level="WARN" onMatch="DENY"-->
  39 + <!--onMismatch="NEUTRAL"/>-->
  40 + <!--</Filters>-->
  41 + <PatternLayout charset="UTF-8" pattern="${console_log_pattern}"/>
  42 + <Policies>
  43 + <!-- 归档每天的文件 -->
  44 + <!--<TimeBasedTriggeringPolicy interval="1" modulate="true"/>-->
  45 + <TimeBasedTriggeringPolicy />
  46 + <!-- 限制单个文件大小 -->
  47 + <SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}"/>
  48 + </Policies>
  49 + <!-- 限制每天文件个数 --> <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了100 -->
  50 + <DefaultRolloverStrategy max="256">
  51 + <Delete basePath="${sys:logging.path}/logs/" maxDepth="3">
  52 + <IfFileName glob="*/*info*.log"/>
  53 + <IfLastModified age="${KEEP_LOG_DAY}"/>
  54 + </Delete>
  55 + </DefaultRolloverStrategy>
  56 + </RollingFile>
  57 + </appenders>
  58 + <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
  59 + <loggers>
  60 + <!--过滤掉spring和mybatis的一些无用的DEBUG信息 -->
  61 + <logger name="org.springframework" level="debug" >
  62 + <ThresholdFilter level="debug"/>
  63 + <appender-ref ref="RollingFileInfo" />
  64 + </logger>
  65 + <logger name="org.mybatis" level="DEBUG" >
  66 + <ThresholdFilter level="debug"/>
  67 + <appender-ref ref="RollingFileInfo" />
  68 + </logger>
  69 + <logger name="com.canrd.shop" level="DEBUG" >
  70 + <ThresholdFilter level="debug"/>
  71 + <appender-ref ref="RollingFileInfo" />
  72 + </logger>
  73 + <!--<root level="all">-->
  74 + <root level="debug">
  75 + <appender-ref ref="Console" />
  76 + </root>
  77 + </loggers>
  78 +</configuration>
... ...
src/main/resources/log4j2-prod.xml 0 → 100644
  1 +++ a/src/main/resources/log4j2-prod.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
  3 +<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出 -->
  4 +<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数 -->
  5 +<configuration status="INFO" monitorInterval="30">
  6 + <!--<contextName>log4j2</contextName>-->
  7 + <properties>
  8 + <!--${sys:catalina.home}表示linux中环境变量中的tomcat根目录 用户主目录-->
  9 + <!--原来用logback时候在统一配置中心也配置一个logging.path=/opt/tomcat-log/${spring.application.name} LOG_PATH是内置变量-->
  10 + <!--${sys:user.home} 用户主目录-->
  11 + <!-- <Property name="log_path">${sys:user.home}/logs</Property>-->
  12 +<!-- <Property name="log_path" value="./logs/" />-->
  13 + <property name="console_log_pattern">%d|%t|%traceId|%-5level|%F:%L|%M|%m%n</property>
  14 + <!-- 保留日志天数 D H M S 分别对应天 小时 分钟 秒 -->
  15 + <property name="KEEP_LOG_DAY">60D</property>
  16 + <!-- 日志切割的最小单位 -->
  17 + <property name="EVERY_FILE_SIZE">100M</property>
  18 + </properties>
  19 + <!--先定义所有的appender -->
  20 + <appenders>
  21 + <console name="Console" target="SYSTEM_OUT">
  22 + <!--输出日志的格式 -->
  23 + <PatternLayout charset="UTF-8" pattern="${console_log_pattern}"/>
  24 + <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
  25 + </console>
  26 + <!--这个输出控制台的配置 -->
  27 + <!--<console name="Console" target="SYSTEM_OUT" follow="false">-->
  28 + <!--&lt;!&ndash;输出日志的格式 &ndash;&gt;-->
  29 + <!--<PatternLayout pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n" />-->
  30 + <!--</console>-->
  31 +
  32 + <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
  33 + <RollingFile name="RollingFileInfo" fileName="${sys:logging.path}/logs/overtime.log" filePattern="${sys:logging.path}/logs/$${date:yyyy-MM-dd}/info-%d{yyyy-MM-dd}-%i.log">
  34 + <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
  35 + <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
  36 + <!--<Filters>-->
  37 + <!--<ThresholdFilter level="INFO"/>-->
  38 + <!--<ThresholdFilter level="WARN" onMatch="DENY"-->
  39 + <!--onMismatch="NEUTRAL"/>-->
  40 + <!--</Filters>-->
  41 + <PatternLayout charset="UTF-8" pattern="${console_log_pattern}"/>
  42 + <Policies>
  43 + <!-- 归档每天的文件 -->
  44 + <!--<TimeBasedTriggeringPolicy interval="1" modulate="true"/>-->
  45 + <TimeBasedTriggeringPolicy />
  46 + <!-- 限制单个文件大小 -->
  47 + <SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}"/>
  48 + </Policies>
  49 + <!-- 限制每天文件个数 --> <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了100 -->
  50 + <DefaultRolloverStrategy max="256">
  51 + <Delete basePath="${sys:logging.path}/logs/" maxDepth="3">
  52 + <IfFileName glob="*/*info*.log"/>
  53 + <IfLastModified age="${KEEP_LOG_DAY}"/>
  54 + </Delete>
  55 + </DefaultRolloverStrategy>
  56 + </RollingFile>
  57 + </appenders>
  58 + <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
  59 + <loggers>
  60 + <logger name="org.springframework" level="info" >
  61 + <ThresholdFilter level="info"/>
  62 + <appender-ref ref="RollingFileInfo" />
  63 + </logger>
  64 + <logger name="org.mybatis" level="info" >
  65 + <ThresholdFilter level="info"/>
  66 + <appender-ref ref="RollingFileInfo" />
  67 + </logger>
  68 + <logger name="com.canrd.shop" level="info" >
  69 + <ThresholdFilter level="info"/>
  70 + <appender-ref ref="RollingFileInfo" />
  71 + </logger>
  72 + </loggers>
  73 +</configuration>
... ...