From 4713da5b2bb5607f70e557c0191227be92591562 Mon Sep 17 00:00:00 2001 From: djz236 Date: Thu, 31 Mar 2022 21:01:16 +0800 Subject: [PATCH] 2022-03-31 --- yxt-common/pom.xml | 19 + yxt-common/yxt-common-base/pom.xml | 189 ++++++ .../common/base/config/GloableException.java | 33 + .../yxt/common/base/config/JacksonConfig.java | 73 +++ .../yxt/common/base/config/KaptchaConfig.java | 34 + .../common/base/config/MybatisPlusConfig.java | 68 ++ .../yxt/common/base/config/RedisConfig.java | 107 ++++ .../com/yxt/common/base/config/RedisUtil.java | 322 ++++++++++ .../base/config/captcha/CaptchaBaseParam.java | 23 + .../base/config/captcha/CaptchaException.java | 27 + .../base/config/captcha/CaptchaType.java | 44 ++ .../base/config/captcha/ImageUtils.java | 116 ++++ .../base/config/captcha/RandomUtils.java | 32 + .../captcha/factory/CaptchaFactory.java | 24 + .../captcha/factory/ICaptchaFactory.java | 15 + .../captcha/factory/impl/AbstractCaptcha.java | 105 ++++ .../factory/impl/BlockPuzzleCaptcha.java | 225 +++++++ .../factory/impl/ClickWordCaptcha.java | 148 +++++ .../component/FileBatchUploadComponent.java | 164 +++++ .../config/component/FileUploadComponent.java | 447 +++++++++++++ .../config/component/ImageUploadUtil.java | 103 +++ .../handler/GlobalExceptionHandler.java | 137 ++++ .../common/base/config/utils/SpringUtil.java | 105 ++++ .../base/config/web/FileController.java | 216 +++++++ .../base/service/MybatisBaseService.java | 416 +++++++++++++ .../com/yxt/common/base/utils/AjaxResult.java | 142 +++++ .../com/yxt/common/base/utils/Base64.java | 250 ++++++++ .../yxt/common/base/utils/BeanMapUtils.java | 38 ++ .../yxt/common/base/utils/ConstantUtils.java | 405 ++++++++++++ .../com/yxt/common/base/utils/DateUtils.java | 588 ++++++++++++++++++ .../com/yxt/common/base/utils/Encodes.java | 188 ++++++ .../com/yxt/common/base/utils/Exceptions.java | 74 +++ .../common/base/utils/ExportExcelUtils.java | 279 +++++++++ .../common/base/utils/GlobalConstants.java | 32 + .../com/yxt/common/base/utils/HttpStatus.java | 15 + .../yxt/common/base/utils/HttpStatusEnum.java | 69 ++ .../com/yxt/common/base/utils/HttpUtils.java | 100 +++ .../yxt/common/base/utils/JPushServer.java | 239 +++++++ .../com/yxt/common/base/utils/JWTUtil.java | 54 ++ .../common/base/utils/JacobPDFConverter.java | 114 ++++ .../common/base/utils/JsonUtilJackson.java | 110 ++++ .../java/com/yxt/common/base/utils/MsgWs.java | 64 ++ .../com/yxt/common/base/utils/PagerUtil.java | 102 +++ .../yxt/common/base/utils/PinYinUtils.java | 278 +++++++++ .../common/base/utils/PropertiesLoader.java | 147 +++++ .../com/yxt/common/base/utils/QRCodeUtil.java | 255 ++++++++ .../com/yxt/common/base/utils/RegexUtil.java | 220 +++++++ .../yxt/common/base/utils/StringRandom.java | 27 + .../yxt/common/base/utils/StringUtils.java | 395 ++++++++++++ .../base/utils/TencentCloudApiUtils.java | 429 +++++++++++++ .../java/com/yxt/common/base/utils/Tools.java | 23 + .../common/base/utils/VerifyCodeUtils.java | 227 +++++++ .../com/yxt/common/base/utils/WafKit.java | 120 ++++ .../common/base/utils/WafRequestWrapper.java | 162 +++++ .../com/yxt/common/base/utils/WebUtil.java | 214 +++++++ .../com/yxt/common/base/utils/WordUtils.java | 191 ++++++ .../com/yxt/common/base/utils/ZipUtils.java | 269 ++++++++ .../src/main/resources/lib/jacob.jar | Bin 0 -> 49231 bytes .../yxt-common-base/yxt-common-base.iml | 157 +++++ yxt-common/yxt-common-core/pom.xml | 52 ++ .../java/com/yxt/common/core/api/BaseApi.java | 84 +++ .../yxt/common/core/constant/HttpStatus.java | 20 + .../yxt/common/core/domain/BaseEntity.java | 159 +++++ .../com/yxt/common/core/domain/Entity.java | 7 + .../yxt/common/core/domain/EntityWithId.java | 48 ++ .../com/yxt/common/core/dto/Base64File.java | 99 +++ .../java/com/yxt/common/core/dto/Dto.java | 53 ++ .../com/yxt/common/core/query/PagerQuery.java | 126 ++++ .../java/com/yxt/common/core/query/Query.java | 45 ++ .../yxt/common/core/result/AppResultData.java | 30 + .../common/core/result/FileUploadResult.java | 101 +++ .../common/core/result/IResultCodeMsg.java | 44 ++ .../yxt/common/core/result/ResultBean.java | 305 +++++++++ .../common/core/result/ResultBeanOfEnum.java | 333 ++++++++++ .../common/core/utils/ExportEntityMap.java | 17 + .../utils/desensitized/DesensitizedUtils.java | 166 +++++ .../core/utils/desensitized/Sensitive.java | 42 ++ .../desensitized/SensitiveSerialize.java | 89 +++ .../utils/desensitized/SensitiveTypeEnum.java | 51 ++ .../common/core/vo/BlockPuzzleCaptchaVO.java | 38 ++ .../com/yxt/common/core/vo/CaptchaBaseVO.java | 25 + .../common/core/vo/ClickWordCaptchaVO.java | 39 ++ .../java/com/yxt/common/core/vo/PagerVo.java | 123 ++++ .../java/com/yxt/common/core/vo/Tail.java | 46 ++ .../java/com/yxt/common/core/vo/TailBean.java | 59 ++ .../main/java/com/yxt/common/core/vo/Vo.java | 61 ++ .../core/result/ResultBeanOfEnumTest.java | 29 + .../yxt-common-core/yxt-common-core.iml | 96 +++ yxt-common/yxt-common.iml | 12 + yxt-parent/pom.xml | 449 +++++++++++++ yxt-parent/yxt-parent.iml | 12 + 91 files changed, 12029 insertions(+) create mode 100644 yxt-common/pom.xml create mode 100644 yxt-common/yxt-common-base/pom.xml create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/GloableException.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/JacksonConfig.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/KaptchaConfig.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/MybatisPlusConfig.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/RedisConfig.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/RedisUtil.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaBaseParam.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaException.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaType.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/ImageUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/RandomUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/CaptchaFactory.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/ICaptchaFactory.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/AbstractCaptcha.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/BlockPuzzleCaptcha.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/ClickWordCaptcha.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/FileBatchUploadComponent.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/FileUploadComponent.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/ImageUploadUtil.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/handler/GlobalExceptionHandler.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/utils/SpringUtil.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/web/FileController.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/service/MybatisBaseService.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/AjaxResult.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Base64.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/BeanMapUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/ConstantUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/DateUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Encodes.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Exceptions.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/ExportExcelUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/GlobalConstants.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpStatus.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpStatusEnum.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JPushServer.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JWTUtil.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JacobPDFConverter.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JsonUtilJackson.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/MsgWs.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/PagerUtil.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/PinYinUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/PropertiesLoader.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/QRCodeUtil.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/RegexUtil.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/StringRandom.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/StringUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/TencentCloudApiUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Tools.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/VerifyCodeUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/WafKit.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/WafRequestWrapper.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/WebUtil.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/WordUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/ZipUtils.java create mode 100644 yxt-common/yxt-common-base/src/main/resources/lib/jacob.jar create mode 100644 yxt-common/yxt-common-base/yxt-common-base.iml create mode 100644 yxt-common/yxt-common-core/pom.xml create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/api/BaseApi.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/constant/HttpStatus.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/domain/BaseEntity.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/domain/Entity.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/domain/EntityWithId.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/dto/Base64File.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/dto/Dto.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/query/PagerQuery.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/query/Query.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/result/AppResultData.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/result/FileUploadResult.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/result/IResultCodeMsg.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/result/ResultBean.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/result/ResultBeanOfEnum.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/utils/ExportEntityMap.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/utils/desensitized/DesensitizedUtils.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/utils/desensitized/Sensitive.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/utils/desensitized/SensitiveSerialize.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/utils/desensitized/SensitiveTypeEnum.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/vo/BlockPuzzleCaptchaVO.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/vo/CaptchaBaseVO.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/vo/ClickWordCaptchaVO.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/vo/PagerVo.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/vo/Tail.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/vo/TailBean.java create mode 100644 yxt-common/yxt-common-core/src/main/java/com/yxt/common/core/vo/Vo.java create mode 100644 yxt-common/yxt-common-core/src/test/java/com/yxt/common/core/result/ResultBeanOfEnumTest.java create mode 100644 yxt-common/yxt-common-core/yxt-common-core.iml create mode 100644 yxt-common/yxt-common.iml create mode 100644 yxt-parent/pom.xml create mode 100644 yxt-parent/yxt-parent.iml diff --git a/yxt-common/pom.xml b/yxt-common/pom.xml new file mode 100644 index 0000000..7e61524 --- /dev/null +++ b/yxt-common/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + + com.yxt + yxt-common + 0.0.1 + + yxt-common-core + yxt-common-base + + pom + 公共类及工具包项目yxt-common + 框架的公共项目,存放项目中用到的基础类、公共类及工具类。各项目根据需要引用对应子项目 + + + \ No newline at end of file diff --git a/yxt-common/yxt-common-base/pom.xml b/yxt-common/yxt-common-base/pom.xml new file mode 100644 index 0000000..bccda39 --- /dev/null +++ b/yxt-common/yxt-common-base/pom.xml @@ -0,0 +1,189 @@ + + + 4.0.0 + + com.yxt + yxt-parent + 0.0.1 + + + com.yxt + yxt-common-base + 0.0.1 + + + + com.yxt + yxt-common-core + 0.0.1 + + + + org.springframework.boot + spring-boot-starter-web + + + org.apache.commons + commons-lang3 + + + commons-beanutils + commons-beanutils + + + com.baomidou + mybatis-plus-boot-starter + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-data-redis + + + io.lettuce + lettuce-core + + + + + redis.clients + jedis + + + + com.auth0 + java-jwt + + + com.github.penggle + kaptcha + + + commons-io + commons-io + + + + org.apache.axis + axis + 1.4 + + + axis + axis-jaxrpc + 1.2.1 + + + + commons-discovery + commons-discovery + 0.5 + + + + wsdl4j + wsdl4j + 1.6.3 + + + + + commons-codec + commons-codec + + + com.alibaba + fastjson + 1.2.73 + + + org.apache.poi + poi + + + org.apache.poi + poi-ooxml + 3.14 + + + + + + com.google.zxing + core + 3.3.2 + + + + com.google.zxing + javase + 3.3.2 + + + + com.itextpdf + itextpdf + 5.4.3 + + + org.apache.httpcomponents + httpclient + + + org.apache.httpcomponents + httpclient + + + + + cn.jpush.api + jpush-client + 3.5.1 + + + cn.jpush.api + jiguang-common + 1.1.11 + + + io.netty + netty-all + 4.1.6.Final + compile + + + + com.belerweb + pinyin4j + 2.5.1 + + + + + cn.hutool + hutool-all + ${hutool.version} + + + + org.freemarker + freemarker + 2.3.29 + + + com.jacob + jacob + 1.18 + + + + + + \ No newline at end of file diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/GloableException.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/GloableException.java new file mode 100644 index 0000000..0eb3ae1 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/GloableException.java @@ -0,0 +1,33 @@ +package com.yxt.common.base.config; + +import com.yxt.common.core.result.ResultBean; +import org.springframework.http.HttpStatus; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.List; + +/** + * @author dimengzhe + * @date 2020/9/12 3:23 + * @description 全局异常处理 + */ +@RestControllerAdvice +public class GloableException { + + @ResponseStatus(HttpStatus.OK) + @ExceptionHandler(BindException.class) + public ResultBean handleBindException(BindException bindException) { + BindingResult bindingResult = bindException.getBindingResult(); + List fieldErrors = bindingResult.getFieldErrors(); + + for (FieldError fieldError : fieldErrors) { + return ResultBean.fireFail().setMsg(fieldError.getDefaultMessage()); + } + return null; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/JacksonConfig.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/JacksonConfig.java new file mode 100644 index 0000000..214d345 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/JacksonConfig.java @@ -0,0 +1,73 @@ +/********************************************************* + ********************************************************* + ******************** ******************* + ************* ************ + ******* _oo0oo_ ******* + *** o8888888o *** + * 88" . "88 * + * (| -_- |) * + * 0\ = /0 * + * ___/`---'\___ * + * .' \\| |// '. * + * / \\||| : |||// \ * + * / _||||| -:- |||||- \ * + * | | \\\ - /// | | * + * | \_| ''\---/'' |_/ | * + * \ .-\__ '-' ___/-. / * + * ___'. .' /--.--\ `. .'___ * + * ."" '< `.___\_<|>_/___.' >' "". * + * | | : `- \`.;`\ _ /`;.`/ - ` : | | * + * \ \ `_. \_ __\ /__ _/ .-` / / * + * =====`-.____`.___ \_____/___.-`___.-'===== * + * `=---=' * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *********__佛祖保佑__永无BUG__验收通过__钞票多多__********* + *********************************************************/ +package com.yxt.common.base.config; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; + +import java.io.IOException; + +/** + * Project: yxt-common
+ * File: JacksonConfig.java
+ * Class: com.yxt.common.base.config.JacksonConfig
+ * Description: <描述类的功能>.
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2020/8/24 21:24
+ * + * @author liupopo + * @version 1.0 + * @since 1.0 + */ +@Configuration +public class JacksonConfig { + @Bean + @Primary + @ConditionalOnMissingBean(ObjectMapper.class) + public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { + ObjectMapper objectMapper = builder.createXmlMapper(false).build(); + objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); + objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer() { + @Override + public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException, JsonProcessingException { + jsonGenerator.writeString(""); + } + }); + return objectMapper; + } + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/KaptchaConfig.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/KaptchaConfig.java new file mode 100644 index 0000000..7b901bd --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/KaptchaConfig.java @@ -0,0 +1,34 @@ +package com.yxt.common.base.config; + +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import java.util.Properties; + +/** + * @author dimengzhe + * @date 2020/9/11 16:45 + * @description + */ +@Component +public class KaptchaConfig { + + @Bean + public DefaultKaptcha getDefaultKaptcha() { + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + properties.put("kaptcha.border", "no"); + properties.put("kaptcha.textproducer.font.color", "black"); + properties.put("kaptcha.image.width", "150"); + properties.put("kaptcha.image.height", "40"); + properties.put("kaptcha.textproducer.font.size", "30"); + properties.put("kaptcha.session.key", "verifyCode"); + properties.put("kaptcha.textproducer.char.space", "5"); + Config config = new Config(properties); + defaultKaptcha.setConfig(config); + + return defaultKaptcha; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/MybatisPlusConfig.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/MybatisPlusConfig.java new file mode 100644 index 0000000..5614f0a --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/MybatisPlusConfig.java @@ -0,0 +1,68 @@ +/********************************************************* + ********************************************************* + ******************** ******************* + ************* ************ + ******* _oo0oo_ ******* + *** o8888888o *** + * 88" . "88 * + * (| -_- |) * + * 0\ = /0 * + * ___/`---'\___ * + * .' \\| |// '. * + * / \\||| : |||// \ * + * / _||||| -:- |||||- \ * + * | | \\\ - /// | | * + * | \_| ''\---/'' |_/ | * + * \ .-\__ '-' ___/-. / * + * ___'. .' /--.--\ `. .'___ * + * ."" '< `.___\_<|>_/___.' >' "". * + * | | : `- \`.;`\ _ /`;.`/ - ` : | | * + * \ \ `_. \_ __\ /__ _/ .-` / / * + * =====`-.____`.___ \_____/___.-`___.-'===== * + * `=---=' * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *********__佛祖保佑__永无BUG__验收通过__钞票多多__********* + *********************************************************/ +package com.yxt.common.base.config; + +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Project: yxt-common
+ * File: MybatisPlusConfig.java
+ * Class: com.yxt.common.base.config.MybatisPlusConfig
+ * Description: <描述类的功能>.
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2020/8/24 下午12:42
+ * + * @author popo + * @version 1.0 + * @since 1.0 + */ +@Configuration +public class MybatisPlusConfig { + /* + * 分页插件,自动识别数据库类型 多租户,请参考官网【插件扩展】 + */ +// @Bean +// public MybatisPlusInterceptor paginationInterceptor() { +// return new MybatisPlusInterceptor(); +// } + + @Bean + public PaginationInterceptor paginationInterceptor() { + PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); + // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false + // paginationInterceptor.setOverflow(false); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + // paginationInterceptor.setLimit(500); + // 开启 count 的 join 优化,只针对部分 left join + paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); + return paginationInterceptor; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/RedisConfig.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/RedisConfig.java new file mode 100644 index 0000000..8031726 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/RedisConfig.java @@ -0,0 +1,107 @@ +package com.yxt.common.base.config; + + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import redis.clients.jedis.JedisPoolConfig; + +/** + * @author dimengzhe + * @date 2020/9/18 19:37 + * @description + */ +@Configuration +public class RedisConfig { + + @Value("${spring.redis.host}") + private String host; + + @Value("${spring.redis.password}") + private String password; + + @Value("${spring.redis.port}") + private int port; + + @Value("${spring.redis.timeout}") + private int timeout; + + @Value("${spring.redis.jedis.pool.max-active}") + private int redisPoolMaxActive; + + @Value("${spring.redis.jedis.pool.max-wait}") + private int redisPoolMaxWait; + + @Value("${spring.redis.jedis.pool.max-idle}") + private int redisPoolMaxIdle; + + @Value("${spring.redis.jedis.pool.min-idle}") + private int redisPoolMinIdle; + @Value("${spring.redis.database}") + private int database; + + @Bean + public JedisPoolConfig getJedisPoolConfig() { + JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); + //最大空闲数 + jedisPoolConfig.setMaxIdle(redisPoolMaxIdle); + //最小空闲数 + jedisPoolConfig.setMinIdle(redisPoolMinIdle); + //最大建立连接等待时间 + jedisPoolConfig.setMaxWaitMillis(redisPoolMaxWait); + //连接池的最大数据库连接数 + jedisPoolConfig.setMaxTotal(redisPoolMaxActive); + return jedisPoolConfig; + } + + + @Bean + public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig) { + + JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig); + jedisConnectionFactory.setDatabase(database); + //IP地址 + jedisConnectionFactory.setHostName(host); + //如果redis设置有密码 + jedisConnectionFactory.setPassword(password); + //端口号 + jedisConnectionFactory.setPort(port); + //客户端超时时间单位是毫秒 + jedisConnectionFactory.setTimeout(timeout); +// jedisConnectionFactory.afterPropertiesSet(); //记得添加这行! + return jedisConnectionFactory; + } + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + // 使用Jackson2JsonRedisSerialize 替换默认序列化 + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); + ObjectMapper om = new ObjectMapper(); + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); + jackson2JsonRedisSerializer.setObjectMapper(om); + StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); + // key采用String的序列化方式 + //redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setKeySerializer(stringRedisSerializer); + // hash的key也采用String的序列化方式 + redisTemplate.setHashKeySerializer(stringRedisSerializer); + // value序列化方式采用jackson + // redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); + redisTemplate.setValueSerializer(stringRedisSerializer); + // hash的value序列化方式采用jackson + redisTemplate.setHashValueSerializer(stringRedisSerializer); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/RedisUtil.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/RedisUtil.java new file mode 100644 index 0000000..06dfea7 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/RedisUtil.java @@ -0,0 +1,322 @@ +package com.yxt.common.base.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.RedisStringCommands; +import org.springframework.data.redis.core.*; +import org.springframework.data.redis.core.types.Expiration; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.stereotype.Service; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * @author dimengzhe + * @date 2020/9/9 17:35 + * @description redis工具类 + */ +@Service +public class RedisUtil { + + @Autowired + private RedisTemplate redisTemplate; + + + /** + * 字符串类型:根据key设置value值,如果key中的value存在,那么返回false + * + * @param key + * @param value + * @return + */ + public Boolean setnx(final String key, final String value, final long expration, final TimeUnit timeUnit) { + return (Boolean) redisTemplate.execute(new RedisCallback() { + @Override + public Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException { + RedisSerializer redisSerializer = redisTemplate.getStringSerializer(); + byte keys[] = redisSerializer.serialize(key); + byte values[] = redisSerializer.serialize(value); + return redisConnection.set(keys, values, Expiration.from(expration, timeUnit), RedisStringCommands.SetOption.SET_IF_ABSENT); + } + }); + } + + /** + * 写入缓存 + * + * @param key + * @param value + * @return + */ + public boolean set(final String key, final String value) { + + boolean result = (boolean) redisTemplate.execute(new RedisCallback() { + @Override + public Boolean doInRedis(RedisConnection connection) throws DataAccessException { + RedisSerializer serializer = redisTemplate.getStringSerializer(); + connection.set(serializer.serialize(key), serializer.serialize(value)); + return true; + } + }); + return result; + } + + /** + * 写入缓存设置时效时间 + * + * @param key + * @param value + * @return + */ + public boolean set(final String key, Object value, Long expireTime) { + boolean result = false; + try { + ValueOperations operations = redisTemplate.opsForValue(); + operations.set(key, value); + redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); + result = true; + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + public boolean expire(String key, long expire) { + return redisTemplate.expire(key, expire, TimeUnit.SECONDS); + } + + /** + * 读取缓存 + * + * @param key + * @return + */ + public String get(final String key) { + String result = (String) redisTemplate.execute(new RedisCallback() { + @Override + public String doInRedis(RedisConnection connection) throws DataAccessException { + RedisSerializer serializer = redisTemplate.getStringSerializer(); + byte[] value = connection.get(serializer.serialize(key)); + return serializer.deserialize(value); + } + }); + return result; + } + + /** + * 正则获取key集合 + * + * @param pattern + * @return + */ + public Set keys(String pattern) { + Set keys = redisTemplate.keys(pattern); + return keys; + } + + + /** + * 批量删除对应的value + * + * @param keys + */ + public void remove(final String... keys) { + for (String key : keys) { + remove(key); + } + } + + /** + * 批量删除key + * + * @param pattern + */ + public void removePattern(final String pattern) { + Set keys = redisTemplate.keys(pattern); + if (keys.size() > 0) { + redisTemplate.delete(keys); + } + + } + + + public Long remove(final String key) { + return (Long) redisTemplate.execute(new RedisCallback() { + @Override + public Long doInRedis(RedisConnection redisConnection) throws DataAccessException { + RedisSerializer serializer = redisTemplate.getStringSerializer(); + byte keys[] = serializer.serialize(key); + return redisConnection.del(keys); + } + }); + } + + + /** + * 判断缓存中是否有对应的value + * + * @param key + * @return + */ + public boolean exists(final String key) { + return redisTemplate.hasKey(key); + } + + + /** + * 哈希 添加 + * + * @param key + * @param hashKey + * @param value + */ + public void hmSet(String key, Object hashKey, Object value) { + HashOperations hash = redisTemplate.opsForHash(); + hash.put(key, hashKey, value); + } + + /** + * 哈希获取数据 + * + * @param key + * @param hashKey + * @return + */ + public String hmGet(String key, Object hashKey) { + HashOperations hash = redisTemplate.opsForHash(); + return hash.get(key, hashKey); + } + + /** + * 获取哈希 keys + * + * @param key + * @return + */ + public Set hmGetKeys(String key) { + HashOperations hash = redisTemplate.opsForHash(); + return hash.keys(key); + } + + /** + * 删除集合中的key + * + * @param key + * @param hashKey + */ + public void hmDelete(String key, Object hashKey) { + HashOperations hash = redisTemplate.opsForHash(); + hash.delete(key, hashKey); + } + + /** + * 列表添加 + * + * @param k + * @param v + */ + public void lPush(String k, Object v) { + ListOperations list = redisTemplate.opsForList(); + list.rightPush(k, v); + } + + /** + * 列表获取 + * + * @param k + * @param l + * @param l1 + * @return + */ + public List lRange(String k, long l, long l1) { + ListOperations list = redisTemplate.opsForList(); + return list.range(k, l, l1); + } + + /** + * 集合添加 + * + * @param key + * @param value + */ + public void add(String key, Object value) { + SetOperations set = redisTemplate.opsForSet(); + set.add(key, value); + } + + /** + * 集合获取 + * + * @param key + * @return + */ + public Set setMembers(String key) { + SetOperations set = redisTemplate.opsForSet(); + return set.members(key); + } + + /** + * 有序集合添加 + * + * @param key + * @param value + * @param scoure + */ + public void zAdd(String key, Object value, double scoure) { + ZSetOperations zset = redisTemplate.opsForZSet(); + zset.add(key, value, scoure); + } + + /** + * 有序集合获取 + * + * @param key + * @param scoure + * @param scoure1 + * @return + */ + public Set rangeByScore(String key, double scoure, double scoure1) { + ZSetOperations zset = redisTemplate.opsForZSet(); + return zset.rangeByScore(key, scoure, scoure1); + } + + /** + * 实现命令:TTL key 以秒为单位,返回给定key的剩余生存时间 + * + * @param key + * @return + */ + public long ttl(String key) { + return redisTemplate.getExpire(key); + } + + /** + * @param keyPrefix: key前缀 + * @description: 根据前缀获取所有的符合该keyvalue值 + * @author: dimengzhe + * @date: 2021/11/6 16:16 + * @return: java.util.List + */ + public List getValuesByPrefix(String keyPrefix) { + List keys = getKeysByPrefix(keyPrefix); + List values = redisTemplate.opsForValue().multiGet(keys); + return (List) (List) values; + } + + /** + * @param keyPrefix: key前缀 + * @description: 根据前缀获取所有的符合该key的所有key值集合 + * @author: dimengzhe + * @date: 2021/11/6 16:17 + * @return: java.util.List + */ + public List getKeysByPrefix(String keyPrefix) { + Set keys = redisTemplate.keys(keyPrefix + "*"); + return Arrays.asList(keys.toArray(new String[0])); + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaBaseParam.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaBaseParam.java new file mode 100644 index 0000000..035ae89 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaBaseParam.java @@ -0,0 +1,23 @@ +package com.yxt.common.base.config.captcha; + +import java.io.Serializable; + +/** + * @author dimengzhe + * @date 2020/9/22 15:42 + * @description + */ + +public class CaptchaBaseParam implements Serializable { + + private String urlOrPath; + + public String getUrlOrPath() { + return urlOrPath; + } + + public void setUrlOrPath(String urlOrPath) { + this.urlOrPath = urlOrPath; + } + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaException.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaException.java new file mode 100644 index 0000000..a43ae4c --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaException.java @@ -0,0 +1,27 @@ +package com.yxt.common.base.config.captcha; + +/** + * @author dimengzhe + * @date 2020/9/22 15:36 + * @description + */ + +public class CaptchaException extends RuntimeException{ + private static final long serialVersionUID = -3401509188707909745L; + + public CaptchaException(){ + super(); + } + + public CaptchaException(String message){ + super(message); + } + + public CaptchaException(String message, Throwable cause){ + super(message, cause); + } + + public CaptchaException(Throwable cause){ + super(cause); + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaType.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaType.java new file mode 100644 index 0000000..96901c6 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/CaptchaType.java @@ -0,0 +1,44 @@ +package com.yxt.common.base.config.captcha; + +/** + * @author dimengzhe + * @date 2020/9/22 15:32 + * @description + */ + +public enum CaptchaType { + + /** + * 滑块拼图 + */ + + BLOCK_PUZZLE("BLOCK_PUZZLE", "滑块拼图"), + CLICK_WORD("CLICK_WORD", "点选文字"), + ; + + private String name; + + private String desc; + + + CaptchaType(String name, String desc) { + this.name = name; + this.desc = desc; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/ImageUtils.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/ImageUtils.java new file mode 100644 index 0000000..aa3837f --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/ImageUtils.java @@ -0,0 +1,116 @@ +package com.yxt.common.base.config.captcha; + + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import sun.misc.BASE64Decoder; + +import java.io.*; + +/** + * @author dimengzhe + * @date 2020/9/22 15:33 + * @description + */ +@Component +public class ImageUtils { + + /** + * 点选汉字 + */ + @Value("${image.login.path:static/upload/}") + private String imageLoginPath; + + /** + * 点选图片-原始图 + */ + @Value("${image.original.path:static/upload/}") + private String originalImagePath; + /** + * 点选图片-剪辑的小图片 + */ + @Value("${image.block.path:static/upload/}") + private String slidingBlockPath; + + /** + * 点选汉字 + * + * @return + */ + public String getClickWordBgPath() { +// String imagePath = "E:\\jlzx\\upload\\images\\pic-click"; + String imagePath = imageLoginPath; + File file = new File(imagePath); + String[] files = file.list(); + int randomNum = RandomUtils.getRandomInt(1, files.length); + + String path = files[randomNum]; + + return imagePath + "/" + path; + } + + /** + * 点选图片-原始图片 + * + * @return + */ + public String getBlockPuzzleBgPath() { +// String imagePath = "E:\\jlzx\\upload\\images\\jigsaw\\original"; + String imagePath = originalImagePath; + File file = new File(imagePath); + String[] files = file.list(); + int randomNum = RandomUtils.getRandomInt(1, files.length); + + String path = files[randomNum]; + + return imagePath + "/" + path; + } + + /** + * 点选图片-小图片 + * + * @return + */ + public String getBlockPuzzleJigsawPath() { +// String imagePath = "E:\\jlzx\\upload\\images\\jigsaw\\slidingBlock"; + String imagePath = slidingBlockPath; + File file = new File(imagePath); + String[] files = file.list(); + int randomNum = RandomUtils.getRandomInt(1, files.length); + + String path = files[randomNum]; + + return imagePath + "/" + path; + } + + public boolean GenerateImage(String imgData, String imgFilePath) throws IOException { // 对字节数组字符串进行Base64解码并生成图片 + if (imgData == null) { + // 图像数据为空 + return false; + } + + BASE64Decoder decoder = new BASE64Decoder(); + OutputStream out = null; + try { + out = new FileOutputStream(imgFilePath); + // Base64解码 + byte[] b = decoder.decodeBuffer(imgData); + for (int i = 0; i < b.length; ++i) { + // 调整异常数据 + if (b[i] < 0) { + b[i] += 256; + } + } + out.write(b); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + out.flush(); + out.close(); + return true; + } + } + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/RandomUtils.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/RandomUtils.java new file mode 100644 index 0000000..f795649 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/RandomUtils.java @@ -0,0 +1,32 @@ +package com.yxt.common.base.config.captcha; + +import java.util.Random; + +/** + * @author dimengzhe + * @date 2020/9/22 15:33 + * @description + */ + +public class RandomUtils { + + /** + * 获取随机中文 + * + * @return + */ + public static String getRandomHan(String hanZi) { + String ch = hanZi.charAt(new Random().nextInt(hanZi.length())) + ""; + return ch; + } + + /** + * 随机范围内数字 + * @param startNum + * @param endNum + * @return + */ + public static Integer getRandomInt(int startNum, int endNum) { + return new Random().nextInt(endNum-startNum) + startNum; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/CaptchaFactory.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/CaptchaFactory.java new file mode 100644 index 0000000..c0d962c --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/CaptchaFactory.java @@ -0,0 +1,24 @@ +package com.yxt.common.base.config.captcha.factory; + +import com.yxt.common.base.config.captcha.CaptchaType; +import com.yxt.common.base.config.captcha.factory.impl.AbstractCaptcha; +import com.yxt.common.base.config.captcha.factory.impl.BlockPuzzleCaptcha; +import com.yxt.common.base.config.captcha.factory.impl.ClickWordCaptcha; + +/** + * @author dimengzhe + * @date 2020/9/22 15:37 + * @description + */ + +public class CaptchaFactory implements ICaptchaFactory{ + @Override + public AbstractCaptcha getInstance(CaptchaType captchaType) { + if (CaptchaType.CLICK_WORD.getName().equals(captchaType.getName())){ + return new ClickWordCaptcha(); + } else if (CaptchaType.BLOCK_PUZZLE.getName().equals(captchaType.getName())) { + return new BlockPuzzleCaptcha(); + } + return null; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/ICaptchaFactory.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/ICaptchaFactory.java new file mode 100644 index 0000000..09048e4 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/ICaptchaFactory.java @@ -0,0 +1,15 @@ +package com.yxt.common.base.config.captcha.factory; + +import com.yxt.common.base.config.captcha.CaptchaType; +import com.yxt.common.base.config.captcha.factory.impl.AbstractCaptcha; + +/** + * @author dimengzhe + * @date 2020/9/22 15:38 + * @description + */ + +public interface ICaptchaFactory { + + AbstractCaptcha getInstance(CaptchaType captchaType); +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/AbstractCaptcha.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/AbstractCaptcha.java new file mode 100644 index 0000000..f65b502 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/AbstractCaptcha.java @@ -0,0 +1,105 @@ +package com.yxt.common.base.config.captcha.factory.impl; + +import com.yxt.common.base.config.captcha.CaptchaBaseParam; +import com.yxt.common.base.config.captcha.CaptchaException; +import com.yxt.common.core.vo.CaptchaBaseVO; +import org.apache.commons.lang3.StringUtils; +import sun.misc.BASE64Encoder; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.List; + + +/** + * @author dimengzhe + * @date 2020/9/22 15:38 + * @description + */ + +public abstract class AbstractCaptcha { + + protected static final String URL_PREFIX_HTTP = "http://"; + protected static final String URL_PREFIX_HTTPS = "https://"; + protected static final String IMAGE_TYPE_PNG = "png"; + + /** 滑块拼图图片地址 */ + private String jigsawUrlOrPath; + /** 点选文字 字体总个数 */ + private int wordTotalCount = 4; + /** 点选文字 字体颜色是否随机 */ + private boolean fontColorRandom = Boolean.TRUE; + + public abstract CaptchaBaseVO create(CaptchaBaseParam captchaParam); + + public abstract boolean verification(java.util.List pointList, List pointList1); + + /** + * + * 获取原生图片 + * @param urlOrPath + * @return + */ + protected static BufferedImage getBufferedImage (String urlOrPath) { + if (StringUtils.isBlank(urlOrPath)) { + throw new CaptchaException("urlOrPath is empty."); + } + BufferedImage sampleImage = null; + try { + if (urlOrPath.startsWith(URL_PREFIX_HTTP) || urlOrPath.startsWith(URL_PREFIX_HTTPS)) { + sampleImage = ImageIO.read(new URL(urlOrPath)); + } else { + sampleImage = ImageIO.read(new File(urlOrPath)); + } + } catch (IOException e ){ + throw new CaptchaException("urlOrPath is url or path error."); + } + return sampleImage; + } + + /** + * 图片转base64 字符串 + * @param templateImage + * @return + */ + protected String getImageToBase64Str (BufferedImage templateImage){ + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + ImageIO.write(templateImage, "jpg", baos); + } catch (IOException e) { + throw new CaptchaException("ImageIO.write is error", e); + } + byte[] bytes = baos.toByteArray(); + BASE64Encoder encoder = new sun.misc.BASE64Encoder(); + return encoder.encodeBuffer(bytes).trim(); + } + + public String getJigsawUrlOrPath() { + return jigsawUrlOrPath; + } + + public void setJigsawUrlOrPath(String jigsawUrlOrPath) { + this.jigsawUrlOrPath = jigsawUrlOrPath; + } + + public int getWordTotalCount() { + return wordTotalCount; + } + + public void setWordTotalCount(int wordTotalCount) { + this.wordTotalCount = wordTotalCount; + } + + public boolean isFontColorRandom() { + return fontColorRandom; + } + + public void setFontColorRandom(boolean fontColorRandom) { + this.fontColorRandom = fontColorRandom; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/BlockPuzzleCaptcha.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/BlockPuzzleCaptcha.java new file mode 100644 index 0000000..615b556 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/BlockPuzzleCaptcha.java @@ -0,0 +1,225 @@ +package com.yxt.common.base.config.captcha.factory.impl; + +import com.alibaba.fastjson.JSON; +import com.yxt.common.base.config.captcha.CaptchaBaseParam; +import com.yxt.common.base.config.captcha.CaptchaException; +import com.yxt.common.core.vo.BlockPuzzleCaptchaVO; +import com.yxt.common.core.vo.CaptchaBaseVO; +import org.apache.commons.lang3.StringUtils; +import sun.misc.BASE64Encoder; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.util.List; +import java.util.Random; + +/** + * @author dimengzhe + * @date 2020/9/22 15:44 + * @description 滑块拼图验证码 + */ + +public class BlockPuzzleCaptcha extends AbstractCaptcha { + @Override + public CaptchaBaseVO create(CaptchaBaseParam captchaParam) { + if (captchaParam == null + || StringUtils.isBlank(captchaParam.getUrlOrPath())) { + throw new CaptchaException("参数不正确,captchaParam:"+ JSON.toJSONString(captchaParam)); + } + if (StringUtils.isBlank(getJigsawUrlOrPath())){ + throw new CaptchaException("参数不正确,请设置jigsawUrlOrPath 参数"); + } + + //原生图片 + BufferedImage originalImage = getBufferedImage(captchaParam.getUrlOrPath()); + //抠图图片 + BufferedImage jigsawImage = getBufferedImage(getJigsawUrlOrPath()); + return pictureTemplatesCut(originalImage, jigsawImage); + } + + @Override + public boolean verification(List pointList, List pointList1) { + return false; + } + + /** + * 根据模板切图 + * + * @throws Exception + */ + public static CaptchaBaseVO pictureTemplatesCut(BufferedImage originalImage, BufferedImage jigsawImage){ + try { + BlockPuzzleCaptchaVO dataVO = new BlockPuzzleCaptchaVO(); + + int originalWidth = originalImage.getWidth(); + int originalHeight = originalImage.getHeight(); + int jigsawWidth = jigsawImage.getWidth(); + int jigsawHeight = jigsawImage.getHeight(); + + //随机生成拼图坐标 + Point point = generateJigsawPoint(originalWidth, originalHeight, jigsawWidth, jigsawHeight); + int x = (int)point.getX(); + int y = (int)point.getY(); + + //生成新的拼图图像 + BufferedImage newJigsawImage = new BufferedImage(jigsawWidth, jigsawHeight, jigsawImage.getType()); + Graphics2D graphics = newJigsawImage.createGraphics(); + graphics.setBackground(Color.white); + + int bold = 5; + BufferedImage subImage = originalImage.getSubimage(x, 0, jigsawWidth, jigsawHeight); + + // 获取拼图区域 + newJigsawImage = DealCutPictureByTemplate(subImage, jigsawImage, newJigsawImage); + + // 设置“抗锯齿”的属性 + graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics.setStroke(new BasicStroke(bold, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); + graphics.drawImage(newJigsawImage, 0, 0, null); + graphics.dispose(); + + ByteArrayOutputStream os = new ByteArrayOutputStream();//新建流。 + ImageIO.write(newJigsawImage, IMAGE_TYPE_PNG, os);//利用ImageIO类提供的write方法,将bi以png图片的数据模式写入流。 + byte[] jigsawImages = os.toByteArray(); + + // 源图生成遮罩 + byte[] oriCopyImages = DealOriPictureByTemplate(originalImage, jigsawImage, x, 0); + + BASE64Encoder encoder = new sun.misc.BASE64Encoder(); + dataVO.setOriginalImageBase64(encoder.encode(oriCopyImages)); + dataVO.setPoint(point); + dataVO.setJigsawImageBase64(encoder.encode(jigsawImages)); + return dataVO; + } catch (Exception e){ + throw new CaptchaException(e); + } + } + + /** + * 抠图后原图生成 + * + * @param oriImage + * @param templateImage + * @param x + * @param y + * @return + * @throws Exception + */ + private static byte[] DealOriPictureByTemplate(BufferedImage oriImage, BufferedImage templateImage, int x, + int y) throws Exception { + // 源文件备份图像矩阵 支持alpha通道的rgb图像 + BufferedImage ori_copy_image = new BufferedImage(oriImage.getWidth(), oriImage.getHeight(), BufferedImage.TYPE_4BYTE_ABGR); + // 源文件图像矩阵 + int[][] oriImageData = getData(oriImage); + // 模板图像矩阵 + int[][] templateImageData = getData(templateImage); + + //copy 源图做不透明处理 + for (int i = 0; i < oriImageData.length; i++) { + for (int j = 0; j < oriImageData[0].length; j++) { + int rgb = oriImage.getRGB(i, j); + int r = (0xff & rgb); + int g = (0xff & (rgb >> 8)); + int b = (0xff & (rgb >> 16)); + //无透明处理 + rgb = r + (g << 8) + (b << 16) + (255 << 24); + ori_copy_image.setRGB(i, j, rgb); + } + } + + for (int i = 0; i < templateImageData.length; i++) { + for (int j = 0; j < templateImageData[0].length - 5; j++) { + int rgb = templateImage.getRGB(i, j); + //对源文件备份图像(x+i,y+j)坐标点进行透明处理 + if (rgb != 16777215 && rgb <= 0) { + int rgb_ori = ori_copy_image.getRGB(x + i, y + j); + int r = (0xff & rgb_ori); + int g = (0xff & (rgb_ori >> 8)); + int b = (0xff & (rgb_ori >> 16)); + rgb_ori = r + (g << 8) + (b << 16) + (150 << 24); + ori_copy_image.setRGB(x + i, y + j, rgb_ori); + } else { + //do nothing + } + } + } + ByteArrayOutputStream os = new ByteArrayOutputStream();//新建流。 + ImageIO.write(ori_copy_image, "png", os);//利用ImageIO类提供的write方法,将bi以png图片的数据模式写入流。 + byte b[] = os.toByteArray();//从流中获取数据数组。 + return b; + } + + + /** + * 根据模板图片抠图 + * @param oriImage + * @param templateImage + * @param targetImage + * @return + * @throws Exception + */ + private static BufferedImage DealCutPictureByTemplate(BufferedImage oriImage, BufferedImage templateImage, + BufferedImage targetImage) throws Exception { + // 源文件图像矩阵 + int[][] oriImageData = getData(oriImage); + // 模板图像矩阵 + int[][] templateImageData = getData(templateImage); + // 模板图像宽度 + + for (int i = 0; i < templateImageData.length; i++) { + // 模板图片高度 + for (int j = 0; j < templateImageData[0].length; j++) { + // 如果模板图像当前像素点不是白色 copy源文件信息到目标图片中 + int rgb = templateImageData[i][j]; + if (rgb != 16777215 && rgb <= 0) { + targetImage.setRGB(i, j, oriImageData[i][j]); + } + } + } + return targetImage; + } + + /** + * 生成图像矩阵 + * @param + * @return + * @throws Exception + */ + private static int[][] getData(BufferedImage bimg){ + int[][] data = new int[bimg.getWidth()][bimg.getHeight()]; + for (int i = 0; i < bimg.getWidth(); i++) { + for (int j = 0; j < bimg.getHeight(); j++) { + data[i][j] = bimg.getRGB(i, j); + } + } + return data; + } + + /** + * 随机生成拼图坐标 + * @param originalWidth + * @param originalHeight + * @param jigsawWidth + * @param jigsawHeight + * @return + */ + private static Point generateJigsawPoint(int originalWidth, int originalHeight, int jigsawWidth, int jigsawHeight) { + Random random = new Random(); + int widthDifference = originalWidth - jigsawWidth; + int heightDifference = originalHeight - jigsawHeight; + int x, y = 0; + if (widthDifference <= 0) { + x = 5; + } else { + x = random.nextInt(originalWidth - jigsawWidth) + 5; + } + if (heightDifference <= 0) { + y = 5; + } else { + y = random.nextInt(originalHeight - jigsawHeight) + 5; + } + return new Point(x, y); + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/ClickWordCaptcha.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/ClickWordCaptcha.java new file mode 100644 index 0000000..5848d48 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/captcha/factory/impl/ClickWordCaptcha.java @@ -0,0 +1,148 @@ +package com.yxt.common.base.config.captcha.factory.impl; + +import com.alibaba.fastjson.JSON; +import com.yxt.common.base.config.captcha.CaptchaBaseParam; +import com.yxt.common.base.config.captcha.CaptchaException; +import com.yxt.common.base.config.captcha.RandomUtils; +import com.yxt.common.core.vo.CaptchaBaseVO; +import com.yxt.common.core.vo.ClickWordCaptchaVO; +import org.apache.commons.lang3.StringUtils; + +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author dimengzhe + * @date 2020/9/22 15:46 + * @description 点选文字验证码 + */ + +public class ClickWordCaptcha extends AbstractCaptcha { + + private static String HAN_ZI = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6"; + + private static String HAN_ZI_FONT = "宋体"; + + private static int HAN_ZI_SIZE = 30; + + private static int HAN_ZI_SIZE_HALF = 30 / 2; + + @Override + public CaptchaBaseVO create(CaptchaBaseParam captchaParam) { + if (captchaParam == null + || StringUtils.isBlank(captchaParam.getUrlOrPath())) { + throw new CaptchaException("参数不正确,captchaParam:" + JSON.toJSONString(captchaParam)); + } + BufferedImage bufferedImage = getBufferedImage(captchaParam.getUrlOrPath()); + return getImageData(bufferedImage); + } + + @Override + public boolean verification(List pointList, List pointList1) { + if (pointList == null + || pointList1 == null + || pointList.size() == 0 + || pointList.size() != pointList1.size()) { + throw new CaptchaException("点选文字验证码坐标信息为空或者不相等,pointList:" + JSON.toJSON(pointList) + ",pointList1:" + JSON.toJSONString(pointList1)); + } + + for (int i = 0; i < pointList.size(); i++) { + Point point = pointList.get(i); + Point point1 = pointList1.get(i); + int x = (int) point.getX(); + int y = (int) point.getY(); + + int x1 = (int) point1.getX(); + int y1 = (int) point1.getY(); + + if (Math.abs(x - x1) >= HAN_ZI_SIZE_HALF || Math.abs(y - y1) >= HAN_ZI_SIZE_HALF) { + return false; + } + } + return false; + } + + private CaptchaBaseVO getImageData(BufferedImage backgroundImage) { + ClickWordCaptchaVO dataVO = new ClickWordCaptchaVO(); + List wordList = new ArrayList(); + List pointList = new ArrayList(); + + Graphics backgroundGraphics = backgroundImage.getGraphics(); + int width = backgroundImage.getWidth(); + int height = backgroundImage.getHeight(); + + Font font = new Font(HAN_ZI_FONT, Font.BOLD, HAN_ZI_SIZE); + int wordCount = getWordTotalCount(); + //定义随机1到arr.length某一个字不参与校验 + int num = RandomUtils.getRandomInt(1, wordCount); + Set currentWords = new HashSet(); + for (int i = 0; i < wordCount; i++) { + String word; + do { + word = RandomUtils.getRandomHan(HAN_ZI); + currentWords.add(word); + } while (!currentWords.contains(word)); + + //随机字体坐标 + Point point = randomWordPoint(width, height, i, wordCount); + + //随机字体颜色 + if (isFontColorRandom()) { + backgroundGraphics.setColor(new Color(RandomUtils.getRandomInt(1, 255), RandomUtils.getRandomInt(1, 255), RandomUtils.getRandomInt(1, 255))); + } else { + backgroundGraphics.setColor(Color.BLACK); + } + //设置角度 + AffineTransform affineTransform = new AffineTransform(); + affineTransform.rotate(Math.toRadians(RandomUtils.getRandomInt(50, 85)), 0, 0); + Font rotatedFont = font.deriveFont(affineTransform); + backgroundGraphics.setFont(rotatedFont); + backgroundGraphics.drawString(word, (int) point.getX(), (int) point.getY()); + + if ((num - 1) != i) { + wordList.add(word); + pointList.add(point); + } + } + + //创建合并图片 + BufferedImage combinedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics combinedGraphics = combinedImage.getGraphics(); + combinedGraphics.drawImage(backgroundImage, 0, 0, null); + + dataVO.setOriginalImageBase64(getImageToBase64Str(backgroundImage)); + dataVO.setPointList(pointList); + dataVO.setWordList(wordList); + return dataVO; + } + + /** + * 随机字体循环排序下标 + * + * @param imageWidth 图片宽度 + * @param imageHeight 图片高度 + * @param wordSortIndex 字体循环排序下标(i) + * @param wordCount 字数量 + * @return + */ + private static Point randomWordPoint(int imageWidth, int imageHeight, int wordSortIndex, int wordCount) { + int avgWidth = imageWidth / (wordCount + 1); + int x, y; + if (avgWidth < HAN_ZI_SIZE_HALF) { + x = RandomUtils.getRandomInt(1, imageWidth); + } else { + if (wordSortIndex == 0) { + x = RandomUtils.getRandomInt(1, avgWidth * (wordSortIndex + 1)); + } else { + x = RandomUtils.getRandomInt(avgWidth * wordSortIndex, avgWidth * (wordSortIndex + 1)); + } + } + y = RandomUtils.getRandomInt(1, imageHeight - HAN_ZI_SIZE_HALF); + return new Point(x, y); + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/FileBatchUploadComponent.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/FileBatchUploadComponent.java new file mode 100644 index 0000000..de54149 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/FileBatchUploadComponent.java @@ -0,0 +1,164 @@ +package com.yxt.common.base.config.component; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import com.yxt.common.core.result.FileUploadResult; +import com.yxt.common.core.result.ResultBean; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @Description + * @Author liuguohui + * @Date 2021/10/25 + */ +@Component +public class FileBatchUploadComponent { + + private static final Logger L = LoggerFactory.getLogger(FileBatchUploadComponent.class); + + @Value("${image.upload.path:static/upload/}") + private String uploadPath; + + @Value("${image.url.prefix:http://120.46.131.15:8111/upload/}") + private String urlPrefix; + + @Autowired + private FileUploadComponent fileUploadComponent; + + /** + * 上传文件,会创建日期目录 + * @param files 上传的文件 + * @return + */ + public ResultBean batchUploadFile(MultipartFile[] files) { + return batchUploadFile(files, true, null); + } + + + /** + * 批量上传 + * @param files + * @param hasDateDir + * @param relativePath + * @return + */ + public ResultBean batchUploadFile( MultipartFile[] files, boolean hasDateDir, String relativePath) { + ResultBean rm = ResultBean.fireFail(); + + if (files.length > 9) { //最多只能上传9张图片 + return rm.setMsg("最多只能上传9张图片"); + } + + int index = 1; + List list = new ArrayList<>(); + for (MultipartFile file: files) { + if (file.getSize() == 0) { + return rm.setMsg("上传文件不能为空"); + } + //文件大小 +// long size = file.getSize(); +// String fileSize = getPrintSize(size); + // 文件名 + String fileName = file.getOriginalFilename(); + // 后缀名 + String suffixName = fileName.substring(fileName.lastIndexOf(".")); + if (suffixName.equals(".pdf")) { // pdf文件 + ResultBean resultBean = fileUploadComponent.uploadFile(file); + FileUploadResult uploadResult = resultBean.getData(); + String fullUrl = uploadResult.getFullUrl(); + list.add(fullUrl); + } else if(suffixName.equals(".png") || suffixName.equals(".jpg") || suffixName.equals(".jpeg") + || suffixName.equals(".bmp") || suffixName.equals(".gif") || suffixName.equals(".tiff")) { + // 图片宽度、高度 + String width = ""; + String height = ""; + try { + BufferedImage bufferedImage = ImageIO.read(file.getInputStream()); + if (bufferedImage != null) { // 证明上传的文件不是图片,获取图片流失败 + width = String.valueOf(bufferedImage.getWidth()); + height = String.valueOf(bufferedImage.getHeight()); + } + } catch (IOException e) { + e.printStackTrace(); + } + // 原文件名 + String prefixName = fileName.substring(0,fileName.indexOf(".")); + // 新文件名:文件原名称 + ‘-’ + 生成的时间戳 + String filePath = prefixName + "_" + dateFileName() + index + suffixName; + if (hasDateDir) { + String dateStr = DateUtil.format(new Date(), "yyyyMMdd"); + // 增加日期目录 + filePath = dateStr + "/" + filePath; + } + if (StringUtils.isNotBlank(relativePath)) { + // 增加指定目录 + filePath = relativePath + "/" + filePath; + } + // 上传后的文件含完整路径 + String path = uploadPath + filePath; + // 上传后的文件 + File destFile = new File(path); + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + try { + file.transferTo(destFile); + } catch (IOException e) { + e.printStackTrace(); + } + // 返回文件路劲 + String fullUrl = urlPrefix + filePath; + list.add(fullUrl); + } else { + return rm.setMsg("上传文件格式不正确"); + } + index++; + } + return rm.success().setData(list); + } + + private String dateFileName() { + return DateUtil.format(new Date(), "yyyyMMddHHmmssSSS") + RandomUtil.randomNumbers(3); + } + + public static String getPrintSize(long size) { + // 如果字节数少于1024,则直接以B为单位,否则先除于1024,后3位因太少无意义 + if (size < 1024) { + return String.valueOf(size) + "B"; + } else { + size = size / 1024; + } + // 如果原字节数除于1024之后,少于1024,则可以直接以KB作为单位 + // 因为还没有到达要使用另一个单位的时候 + // 接下去以此类推 + if (size < 1024) { + return String.valueOf(size) + "KB"; + } else { + size = size / 1024; + } + if (size < 1024) { + // 因为如果以MB为单位的话,要保留最后1位小数, + // 因此,把此数乘以100之后再取余 + size = size * 100; + return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + "MB"; + } else { + // 否则如果要以GB为单位的,先除于1024再作同样的处理 + size = size * 100 / 1024; + return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + "GB"; + } + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/FileUploadComponent.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/FileUploadComponent.java new file mode 100644 index 0000000..cb4a6dc --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/FileUploadComponent.java @@ -0,0 +1,447 @@ +/********************************************************* + ********************************************************* + ******************** ******************* + ************* ************ + ******* _oo0oo_ ******* + *** o8888888o *** + * 88" . "88 * + * (| -_- |) * + * 0\ = /0 * + * ___/`---'\___ * + * .' \\| |// '. * + * / \\||| : |||// \ * + * / _||||| -:- |||||- \ * + * | | \\\ - /// | | * + * | \_| ''\---/'' |_/ | * + * \ .-\__ '-' ___/-. / * + * ___'. .' /--.--\ `. .'___ * + * ."" '< `.___\_<|>_/___.' >' "". * + * | | : `- \`.;`\ _ /`;.`/ - ` : | | * + * \ \ `_. \_ __\ /__ _/ .-` / / * + * =====`-.____`.___ \_____/___.-`___.-'===== * + * `=---=' * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *********__佛祖保佑__永无BUG__验收通过__钞票多多__********* + *********************************************************/ +package com.yxt.common.base.config.component; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import com.yxt.common.base.utils.StringRandom; +import com.yxt.common.core.dto.Base64File; +import com.yxt.common.core.result.FileUploadResult; +import com.yxt.common.core.result.ResultBean; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Project: jbsc-commons
+ * File: FileUploadComponent.java
+ * Class: org.jbase.jbsc.commons.base.config.component.FileUploadComponent
+ * Description: <描述类的功能>.
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2020/9/17 上午11:58
+ * + * @author popo + * @version 1.0 + * @since 1.0 + */ +@Component +public class FileUploadComponent { + + private static final Logger L = LoggerFactory.getLogger(FileUploadComponent.class); + + @Value("${image.upload.path:static/upload/}") + private String uploadPath; + + @Value("${image.url.prefix:http://127.0.0.1:8080/upload/}") + private String urlPrefix; + + + /** + * 上传文件 + * + * @param file 上传的文件 + * @param hasDateDir 是否创建日期目录 + * @param relativePath 指定的目录 + * @return + */ + public ResultBean uploadFile(MultipartFile file, boolean hasDateDir, String relativePath) { + ResultBean rm = ResultBean.fireFail(); + //文件大小 + long size = file.getSize(); + String fileSize = getPrintSize(size); + // 文件名 + String fileName = file.getOriginalFilename(); + // 后缀名 + String suffixName = fileName.substring(fileName.lastIndexOf(".")); + //2021.10.16 截取文件后缀名以外的名字 + String prefixName = fileName.substring(0, fileName.indexOf(".")); + // 新文件名:文件原名称 + ‘-’ + 生成的时间戳 2021.10.16 + String filePath = prefixName + "_" + dateFileName() + suffixName; + if (hasDateDir) { + String dateStr = DateUtil.format(new Date(), "yyyyMMdd"); + // 增加日期目录 + filePath = dateStr + "/" + filePath; + } + if (StringUtils.isNotBlank(relativePath)) { + // 增加指定目录 + filePath = relativePath + "/" + filePath; + } + // 上传后的文件含完整路径 + String path = uploadPath + filePath; + // 上传后的文件 + File destFile = new File(path); + + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + + try { + file.transferTo(destFile); + } catch (IOException e) { + e.printStackTrace(); + } + + String fullUrl = urlPrefix + filePath; + + FileUploadResult fur = new FileUploadResult(fileName, filePath, fullUrl, fileSize); + + return rm.success().setData(fur); + } + + public ResultBean uploadFile2(MultipartFile file, boolean hasDateDir, String relativePath) { + ResultBean rm = ResultBean.fireFail(); + //文件大小 + long size = file.getSize(); + String fileSize = getPrintSize(size); + // 文件名 + String fileName = file.getOriginalFilename(); + // 后缀名 + String suffixName = fileName.substring(fileName.lastIndexOf(".")); + // 新文件名 + String filePath = dateFileName() + suffixName; + Date date = new Date(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat( + "yyyy/MM"); + String dir = simpleDateFormat.format(date); + SimpleDateFormat dateFormat = new SimpleDateFormat( + "yyyyMMddHHmmss"); + String disk_filename = dateFormat.format(date) + StringRandom.getRandomString(8); + if (hasDateDir) { +// String dateStr = DateUtil.format(new Date(), "yyyyMMdd"); + // 增加日期目录 +// filePath = dateStr + "/" + filePath; + filePath = "photo" + "/" + dir + "/" + filePath; + } + if (StringUtils.isNotBlank(relativePath)) { + // 增加指定目录 + filePath = relativePath + "/" + filePath; + } + // 上传后的文件含完整路径 + String path = uploadPath + filePath; + // 上传后的文件 + File destFile = new File(path); + + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + + try { + file.transferTo(destFile); + } catch (IOException e) { + e.printStackTrace(); + } + + String fullUrl = urlPrefix + filePath; + + FileUploadResult fur = new FileUploadResult(fileName, filePath, fullUrl, fileSize); + + return rm.success().setData(fur); + } + + + /** + * 上传文件,会创建日期目录 + * + * @param file 上传的文件 + * @return + */ + public ResultBean uploadFile(MultipartFile file) { + return uploadFile(file, true, null); + } + + public ResultBean uploadFile2(MultipartFile file) { + return uploadFile2(file, true, null); + } + + /** + * 上传文件,无指定目录 + * + * @param file 上传的文件 + * @param hasDateDir 是否创建日期目录 + * @return + */ + public ResultBean uploadFile(MultipartFile file, boolean hasDateDir) { + return uploadFile(file, hasDateDir, null); + } + + /** + * 上传文件到指定目录,不创建日期目录 + * + * @param file 上传的文件 + * @param relativePath 指定的目录 + * @return + */ + public ResultBean uploadFile(MultipartFile file, String relativePath) { + return uploadFile(file, false, relativePath); + } + + private String dateFileName() { + return DateUtil.format(new Date(), "yyyyMMddHHmmssSSS") + RandomUtil.randomNumbers(3); + } + + public String getUploadPath() { + return uploadPath; + } + + public String getUrlPrefix() { + return urlPrefix; + } + + + /** + * 通过路径获取文件 + * + * @param filePath + * @return + */ + public File findFileByPath(String filePath) { + String ablatePath = uploadPath + filePath; + File file = new File(ablatePath); + if (file.exists() && file.isFile()) { + return file; + } + return null; + } + + /** + * 通过路径获取文件(图片)的Base64字符串 + * + * @param filePath + * @return + */ + public String findBase64ByPath(String filePath) { + String base64 = null; + File file = findFileByPath(filePath); + if (file == null) { + return null; + } + byte[] bytes = new byte[(int) file.length()]; + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis); + bis.read(bytes); + base64 = org.apache.commons.codec.binary.Base64.encodeBase64String(bytes); + } catch (FileNotFoundException e) { + L.error("get img error", e); + e.printStackTrace(); + } catch (IOException e) { + L.error("get img error", e); + e.printStackTrace(); + } finally { + try { + fis.close(); + } catch (Exception e) { + L.error("close getImgBase64 error", e); + } + } + + return base64; + } + + /** + * 上传Base64 + * + * @param base64File 上传的Base64文件 + * @param hasDateDir 是否创建日期目录 + * @param relativePath 指定的目录 + * @return + */ + public ResultBean uploadBase64(Base64File base64File, boolean hasDateDir, String relativePath) { + ResultBean rb = ResultBean.fireFail(); + // 文件名 + String fileName = base64File.getName(); + String suffixName = base64File.getSuffix(); + long size = base64File.getSize(); + if (StringUtils.isBlank(suffixName)) { + // 后缀名 + suffixName = fileName.substring(fileName.lastIndexOf(".")); + } + // 新文件名 + String filePath = dateFileName() + suffixName; + if (hasDateDir) { + String dateStr = DateUtil.format(new Date(), "yyyyMMdd"); + // 增加日期目录 + filePath = dateStr + "/" + filePath; + } + if (StringUtils.isNotBlank(relativePath)) { + // 增加指定目录 + filePath = relativePath + "/" + filePath; + } + String fileSize = getPrintSize(size); + // 上传后的文件含完整路径 + String path = uploadPath + filePath; + // 上传后的文件 + File destFile = new File(path); + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + + if (base64ToFile(base64File.getBase64(), destFile)) { + String fullUrl = urlPrefix + filePath; + FileUploadResult fur = new FileUploadResult(fileName, filePath, fullUrl, fileSize); + return rb.success().setData(fur); + } + return rb.setMsg("文件上传失败!"); + } + + private boolean base64ToFile(String base64, File file) { + base64 = base64.substring(base64.indexOf(",") + 1); + BufferedOutputStream bos = null; + java.io.FileOutputStream fos = null; + try { + + byte[] bytes = org.apache.commons.codec.binary.Base64.decodeBase64(base64); + fos = new java.io.FileOutputStream(file); + bos = new BufferedOutputStream(fos); + bos.write(bytes); + return true; + } catch (Exception e) { + L.error("base64转文件失败", e); + return false; + } finally { + if (bos != null) { + try { + bos.close(); + } catch (IOException e) { + L.error("关闭文件流bos失败", e); + return false; + } + } + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + L.error("关闭文件流fos失败", e); + return false; + } + } + } + } + + /** + * 上传Base64,会创建日期目录 + * + * @param file 上传的Base64文件 + * @return + */ + public ResultBean uploadBase64(Base64File file) { + return uploadBase64(file, true, null); + } + + /** + * 上传Base64,无指定目录 + * + * @param file 上传的Base64文件 + * @param hasDateDir 是否创建日期目录 + * @return + */ + public ResultBean uploadBase64(Base64File file, boolean hasDateDir) { + return uploadBase64(file, hasDateDir, null); + } + + /** + * 上传Base64到指定目录,不创建日期目录 + * + * @param file 上传的Base64文件 + * @param relativePath 指定的目录 + * @return + */ + public ResultBean uploadBase64(Base64File file, String relativePath) { + return uploadBase64(file, false, relativePath); + } + + public static String getPrintSize(long size) { + // 如果字节数少于1024,则直接以B为单位,否则先除于1024,后3位因太少无意义 + if (size < 1024) { + return String.valueOf(size) + "B"; + } else { + size = size / 1024; + } + // 如果原字节数除于1024之后,少于1024,则可以直接以KB作为单位 + // 因为还没有到达要使用另一个单位的时候 + // 接下去以此类推 + if (size < 1024) { + return String.valueOf(size) + "KB"; + } else { + size = size / 1024; + } + if (size < 1024) { + // 因为如果以MB为单位的话,要保留最后1位小数, + // 因此,把此数乘以100之后再取余 + size = size * 100; + return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + "MB"; + } else { + // 否则如果要以GB为单位的,先除于1024再作同样的处理 + size = size * 100 / 1024; + return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + "GB"; + } + } + + /** + * @param path 图片网址路径 + * @param realPath 服务器内部真实路径(不能写顶级目录) + */ + public static void deleteFiles(String path, String realPath) { + //对path进行处理将网页地址转化为实际地址 + //获取文件的名字 + String originalFileName = path.substring(path.lastIndexOf("/") + 1); + //拼接新的地址 + String filePatn = realPath + path.substring(path.lastIndexOf("/") + 1); + File file = new File(filePatn); + //如果不是文件夹就直接删除该图片文件 + if (!file.isDirectory()) { + System.out.println(filePatn); + System.out.println(file.getName()); + file.delete(); + } else if (file.isDirectory()) { + //如果是文件夹是获取文件列表 + String[] filelist = file.list(); + //获取完成文件路径 + for (int j = 0; j < filelist.length; j++) { + File filessFile = new File(filePatn + "/" + filelist[j]); + System.out.println(filePatn + "/" + filelist[j]); + if (!filessFile.isDirectory()) { + filessFile.delete(); + } else if (filessFile.isDirectory()) { + //递归调用 + deleteFiles(filePatn + "/" + filelist[j], filePatn + "/"); + } + } + //最后删除该文件夹 + file.delete(); + } + } + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/ImageUploadUtil.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/ImageUploadUtil.java new file mode 100644 index 0000000..5a9e73f --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/component/ImageUploadUtil.java @@ -0,0 +1,103 @@ +package com.yxt.common.base.config.component; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; + +import javax.servlet.http.HttpServletRequest; +import javax.swing.*; +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * @author dimengzhe + * @date 2020/9/15 9:47 + * @description 上传图片 + */ +@Component +public class ImageUploadUtil { + + private static final DateFormat df = new SimpleDateFormat("yyyyMMdd"); + + @Autowired + private FileUploadComponent fileUploadComponent; + + /** + * 上传图片单张 + * + * @param request + * @return + */ + public Map imageUpLoad(HttpServletRequest request) { + Map map = new HashMap(); + try { + + MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request; + MultipartFile file = multiRequest.getFile("file"); + map = upload(file); + } catch (Exception e) { + System.out.println(e.getMessage()); + map.put("isSuccess", false); + } + return map; + } + + /** + * 上传图片 + * + * @param file + * @return + */ + public Map upload(MultipartFile file) { + // 文件名 + String fileName = file.getOriginalFilename(); + // 后缀名 + String suffixName = fileName.substring(fileName.lastIndexOf(".")); + //2021.10.16 截取文件后缀名以外的名字 + String prefixName = fileName.substring(0, fileName.indexOf(".")); + // 新文件名:文件原名称 + ‘-’ + 生成的时间戳 2021.10.16 + String filePath = dateFileName() + suffixName; + String dateStr = DateUtil.format(new Date(), "yyyyMMdd"); + // 增加日期目录 + filePath = dateStr + "/" + filePath; + Map map = new HashMap<>(); + // 上传后的文件含完整路径 + String upload = fileUploadComponent.getUploadPath(); + String path = upload + filePath; + // 上传后的文件 + File destFile = new File(path); + + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + + try { + file.transferTo(destFile); + } catch (IOException e) { + e.printStackTrace(); + } + + String fullUrl = fileUploadComponent.getUrlPrefix() + filePath; + ImageIcon imageIcon = new ImageIcon(path); + Image image = imageIcon.getImage(); + map.put("isSuccess", true); + map.put("url", fullUrl); + System.out.println(fullUrl); + map.put("width", image == null ? "" : image.getWidth(imageIcon.getImageObserver())); + map.put("height", image == null ? "" : image.getHeight(imageIcon.getImageObserver())); + return map; + } + + private String dateFileName() { + return DateUtil.format(new Date(), "yyyyMMddHHmmssSSS") + RandomUtil.randomNumbers(3); + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/handler/GlobalExceptionHandler.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..38c6064 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/handler/GlobalExceptionHandler.java @@ -0,0 +1,137 @@ +/********************************************************* + ********************************************************* + ******************** ******************* + ************* ************ + ******* _oo0oo_ ******* + *** o8888888o *** + * 88" . "88 * + * (| -_- |) * + * 0\ = /0 * + * ___/`---'\___ * + * .' \\| |// '. * + * / \\||| : |||// \ * + * / _||||| -:- |||||- \ * + * | | \\\ - /// | | * + * | \_| ''\---/'' |_/ | * + * \ .-\__ '-' ___/-. / * + * ___'. .' /--.--\ `. .'___ * + * ."" '< `.___\_<|>_/___.' >' "". * + * | | : `- \`.;`\ _ /`;.`/ - ` : | | * + * \ \ `_. \_ __\ /__ _/ .-` / / * + * =====`-.____`.___ \_____/___.-`___.-'===== * + * `=---=' * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *********__佛祖保佑__永无BUG__验收通过__钞票多多__********* + *********************************************************/ +package com.yxt.common.base.config.handler; + +import com.yxt.common.core.result.ResultBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.BindException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.NoHandlerFoundException; + +/** + * Project: jbsc-commons
+ * File: GlobalExceptionHandler.java
+ * Class: org.jbase.jbsc.commons.base.config.handler.GlobalExceptionHandler
+ * Description: <描述类的功能>.
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2020/9/17 上午10:34
+ * + * @author popo + * @version 1.0 + * @since 1.0 + */ +@RestControllerAdvice +public class GlobalExceptionHandler { + + private static final Logger L = LoggerFactory.getLogger(GlobalExceptionHandler.class); + + /** + * 路径错误 + * + * @param e + * @return + */ + @ExceptionHandler(NoHandlerFoundException.class) + public ResultBean handlerNoFoundException(Exception e) { + L.error(e.getMessage(), e); + return ResultBean.fireFail().setCode("404").setMsg("路径不存在,请检查路径是否正确"); + } + +//import org.springframework.security.access.AccessDeniedException; +//import org.springframework.security.authentication.AccountExpiredException; +//import org.springframework.security.core.userdetails.UsernameNotFoundException; +// /** +// * 没有授权 +// * +// * @param e +// * @return +// */ +// @ExceptionHandler(AccessDeniedException.class) +// public ResultBean handleAuthorizationException(AccessDeniedException e) { +// L.error(e.getMessage()); +// return ResultBean.fireFail().setCode("403").setMsg("没有权限,请联系管理员授权"); +// } +// +// /** +// * 登录超时 +// * +// * @param e +// * @return +// */ +// @ExceptionHandler(AccountExpiredException.class) +// public ResultBean handleAccountExpiredException(AccountExpiredException e) { +// L.error(e.getMessage(), e); +// return ResultBean.fireFail().setCode("50014").setMsg("账号登录超时:" + e.getMessage()); +// } +// +// /** +// * 用户名不存在 +// * +// * @param e +// * @return +// */ +// @ExceptionHandler(UsernameNotFoundException.class) +// public ResultBean handleUsernameNotFoundException(UsernameNotFoundException e) { +// L.error(e.getMessage(), e); +// return ResultBean.fireFail().setCode("50008").setMsg("用户名不存在:" + e.getMessage()); +// } + + /** + * 系统异常 + * + * @param e + * @return + */ + @ExceptionHandler(Exception.class) + public ResultBean handleException(Exception e) { + L.error(e.getMessage(), e); + return ResultBean.fireFail().setMsg("系统异常::" + e.getMessage()); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(BindException.class) + public ResultBean validatedBindException(BindException e) { + L.error(e.getMessage(), e); + String message = e.getAllErrors().get(0).getDefaultMessage(); + return ResultBean.fireFail().setCode("405").setMsg(message); + } + + /** + * 方法参数验证异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResultBean validExceptionHandler(MethodArgumentNotValidException e) { + L.error(e.getMessage(), e); + String message = e.getBindingResult().getFieldError().getDefaultMessage(); + return ResultBean.fireFail().setCode("405").setMsg(message); + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/utils/SpringUtil.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/utils/SpringUtil.java new file mode 100644 index 0000000..1de02b2 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/utils/SpringUtil.java @@ -0,0 +1,105 @@ +/********************************************************* + ********************************************************* + ******************** ******************* + ************* ************ + ******* _oo0oo_ ******* + *** o8888888o *** + * 88" . "88 * + * (| -_- |) * + * 0\ = /0 * + * ___/`---'\___ * + * .' \\| |// '. * + * / \\||| : |||// \ * + * / _||||| -:- |||||- \ * + * | | \\\ - /// | | * + * | \_| ''\---/'' |_/ | * + * \ .-\__ '-' ___/-. / * + * ___'. .' /--.--\ `. .'___ * + * ."" '< `.___\_<|>_/___.' >' "". * + * | | : `- \`.;`\ _ /`;.`/ - ` : | | * + * \ \ `_. \_ __\ /__ _/ .-` / / * + * =====`-.____`.___ \_____/___.-`___.-'===== * + * `=---=' * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *********__佛祖保佑__永无BUG__验收通过__钞票多多__********* + *********************************************************/ +package com.yxt.common.base.config.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * Project: yxt-common
+ * File: SpringUtil.java
+ * Class: com.yxt.common.base.config.utils.SpringUtil
+ * Description: <描述类的功能>.
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2020/8/24 21:31
+ * + * @author liupopo + * @version 1.0 + * @since 1.0 + */ +@Component +public class SpringUtil implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if (SpringUtil.applicationContext == null) { + SpringUtil.applicationContext = applicationContext; + } + } + + // 获取applicationContext + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + // 通过name获取 Bean. + public static Object getBean(String name) { + return getApplicationContext().getBean(name); + } + + // 通过class获取Bean. + public static T getBean(Class clazz) { + return getApplicationContext().getBean(clazz); + } + + // 通过name,以及Clazz返回指定的Bean + public static T getBean(String name, Class clazz) { + return getApplicationContext().getBean(name, clazz); + } + + /** + * 通过类型获取Spring容器中的对象 + * + * @param type + * @param + * @return + */ + public static Map getBeansOfType(Class type) { + Map beansOfType = getApplicationContext().getBeansOfType(type); + return beansOfType; + } + + /** + * 通过类型获取Spring容器中的对象 + * + * @param type + * @param includeNonSingletons + * @param allowEagerInit + * @param + * @return + */ + public static Map getBeansOfType(Class type, boolean includeNonSingletons, boolean allowEagerInit) { + Map beansOfType = getApplicationContext().getBeansOfType(type, includeNonSingletons, allowEagerInit); + return beansOfType; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/web/FileController.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/web/FileController.java new file mode 100644 index 0000000..9474215 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/config/web/FileController.java @@ -0,0 +1,216 @@ +/********************************************************* + ********************************************************* + ******************** ******************* + ************* ************ + ******* _oo0oo_ ******* + *** o8888888o *** + * 88" . "88 * + * (| -_- |) * + * 0\ = /0 * + * ___/`---'\___ * + * .' \\| |// '. * + * / \\||| : |||// \ * + * / _||||| -:- |||||- \ * + * | | \\\ - /// | | * + * | \_| ''\---/'' |_/ | * + * \ .-\__ '-' ___/-. / * + * ___'. .' /--.--\ `. .'___ * + * ."" '< `.___\_<|>_/___.' >' "". * + * | | : `- \`.;`\ _ /`;.`/ - ` : | | * + * \ \ `_. \_ __\ /__ _/ .-` / / * + * =====`-.____`.___ \_____/___.-`___.-'===== * + * `=---=' * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *********__佛祖保佑__永无BUG__验收通过__钞票多多__********* + *********************************************************/ +package com.yxt.common.base.config.web; + +import com.yxt.common.base.config.component.FileBatchUploadComponent; +import com.yxt.common.base.config.component.FileUploadComponent; +import com.yxt.common.base.utils.WebUtil; +import com.yxt.common.core.dto.Base64File; +import com.yxt.common.core.result.FileUploadResult; +import com.yxt.common.core.result.ResultBean; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; + +/** + * Project: jbsc-commons
+ * File: FileController.java
+ * Class: org.jbase.jbsc.commons.base.config.web.FileController
+ * Description: <描述类的功能>.
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2020/9/22 上午10:18
+ * + * @author popo + * @version 1.0 + * @since 1.0 + */ +@Api(tags = "文件上传和下载的通用控制方法") +@RestController("org.jbase.jbsc.commons.base.config.web.FileController") +@RequestMapping("/file") +public class FileController { + + private static final Logger L = LoggerFactory.getLogger(FileController.class); + + @Autowired + private FileUploadComponent fileUploadComponent; + @Autowired + private FileBatchUploadComponent batchUploadComponent; + + @ApiOperation(value = "上传文件") + @ApiImplicitParam(name = "file", value = "文件", required = true, dataType = "MultipartFile", dataTypeClass = MultipartFile.class) + @PostMapping("/upload") + public ResultBean uploadImage(@RequestParam(value = "file") MultipartFile file) { + ResultBean rb = ResultBean.fireFail(); + if (file == null || file.isEmpty()) { + return rb.setMsg("文件为空"); + } + + rb = fileUploadComponent.uploadFile(file); + return rb; + } + + + + @ApiOperation(value = "上传Base64到文件") + @PostMapping("/uploadBase64") + public ResultBean uploadUploadFileBase64(@RequestBody Base64File base64File) { + ResultBean rb = ResultBean.fireFail(); + rb = fileUploadComponent.uploadBase64(base64File); + return rb; + } + + @ApiOperation(value = "下载文件") + @ApiImplicitParams({ + @ApiImplicitParam(name = "filePath", value = "文件相对路径", required = true, dataType = "String", dataTypeClass = String.class), + @ApiImplicitParam(name = "outFileName", value = "下载的文件名", required = true, dataType = "String", dataTypeClass = String.class) + }) + @GetMapping("/download") + public ResultBean download(@RequestParam(value = "filePath") String filePath, @RequestParam(value = "outFileName") String outFileName) { + ResultBean rb = ResultBean.fireFail(); + + File file = fileUploadComponent.findFileByPath(filePath); + if (file == null) + return rb.setMsg("文件不存在"); + + HttpServletResponse response = WebUtil.getResponse(); + response.setContentType("application/x-download"); + try { + outFileName = new String(outFileName.getBytes(), "ISO-8859-1"); + response.setHeader("Content-Disposition", "attachment;filename=" + outFileName); + } catch (Exception e) { + e.printStackTrace(); + } + int length = 1024; + byte[] buffer = new byte[length]; + FileInputStream fis = null; + BufferedInputStream bis = null; + + OutputStream os = null; + try { + os = response.getOutputStream(); + fis = new FileInputStream(file); + bis = new BufferedInputStream(fis); + int i = bis.read(buffer); + while (i != -1) { + os.write(buffer); + buffer = new byte[length]; + i = bis.read(buffer); + } + } catch (Exception e) { + L.error("download error", e); + return rb.setMsg("下载出错!"); + } finally { + try { + bis.close(); + fis.close(); + } catch (IOException e) { + L.error("close inputstream error", e); + } + } + return rb.success(); + } + + + /** + * 获取base64图片数据 + * + * @param filePath + * @return + */ + @ApiOperation(value = "获取base64图片数据") + @ApiImplicitParam(name = "filePath", value = "文件相对路径", required = true, dataType = "String", dataTypeClass = String.class) + @GetMapping("/getImgBase64") + public Object getImgBase64(@RequestParam("filePath") String filePath) { + ResultBean rb = ResultBean.fireFail(); + String base64 = fileUploadComponent.findBase64ByPath(filePath); + if (base64 == null) + return rb.setMsg("文件不存在"); + return rb.success().setData(base64); + } + + /** + * 获取图片流 + * + * @param filePath + */ + @ApiOperation(value = "获取图片流") + @ApiImplicitParam(name = "filePath", value = "文件相对路径", required = true, dataType = "String", dataTypeClass = String.class) + @GetMapping("/getImgStream") + public ResultBean getImgStream(@RequestParam("filePath") String filePath) { + ResultBean rb = ResultBean.fireFail(); + File file = fileUploadComponent.findFileByPath(filePath); + if (file == null) + return rb.setMsg("文件不存在"); + + String fileName = file.getName(); + String suffixName = fileName.substring(fileName.lastIndexOf(".")); // 后缀名 + HttpServletResponse response = WebUtil.getResponse(); + response.setContentType("image/" + suffixName); + FileInputStream fis = null; + try { + OutputStream out = response.getOutputStream(); + fis = new FileInputStream(file); + byte[] b = new byte[fis.available()]; + fis.read(b); + out.write(b); + out.flush(); + } catch (Exception e) { + L.error("getImgStream error", e); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + L.error("close getImgStream error", e); + } + } + } + return rb.success(); + } + + @ApiOperation(value = "批量上传(手机)") + @ApiImplicitParam(name = "files", value = "文件", required = true, dataType = "MultipartFile",allowMultiple = true, dataTypeClass = MultipartFile.class) + @PostMapping("/batchUploadImage") + public ResultBean batchUploadImage(@RequestParam(value = "files") MultipartFile[] files) { + ResultBean rb = ResultBean.fireFail(); + if (files == null || files.length == 0) { + return rb.setMsg("文件为空"); + } + rb = batchUploadComponent.batchUploadFile(files); + return rb; + } + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/service/MybatisBaseService.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/service/MybatisBaseService.java new file mode 100644 index 0000000..689b03b --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/service/MybatisBaseService.java @@ -0,0 +1,416 @@ +/********************************************************* + ********************************************************* + ******************** ******************* + ************* ************ + ******* _oo0oo_ ******* + *** o8888888o *** + * 88" . "88 * + * (| -_- |) * + * 0\ = /0 * + * ___/`---'\___ * + * .' \\| |// '. * + * / \\||| : |||// \ * + * / _||||| -:- |||||- \ * + * | | \\\ - /// | | * + * | \_| ''\---/'' |_/ | * + * \ .-\__ '-' ___/-. / * + * ___'. .' /--.--\ `. .'___ * + * ."" '< `.___\_<|>_/___.' >' "". * + * | | : `- \`.;`\ _ /`;.`/ - ` : | | * + * \ \ `_. \_ __\ /__ _/ .-` / / * + * =====`-.____`.___ \_____/___.-`___.-'===== * + * `=---=' * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *********__佛祖保佑__永无BUG__验收通过__钞票多多__********* + *********************************************************/ +package com.yxt.common.base.service; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yxt.common.base.utils.PagerUtil; +import com.yxt.common.core.domain.BaseEntity; +import com.yxt.common.core.dto.Dto; +import com.yxt.common.core.query.PagerQuery; +import com.yxt.common.core.query.Query; +import com.yxt.common.core.vo.PagerVo; +import com.yxt.common.core.vo.Vo; +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; +import java.lang.reflect.ParameterizedType; +import java.util.*; + +/** + * Project: yxt-common
+ * File: MybatisBaseService.java
+ * Class: PACKAGE_NAME.MybatisBaseService
+ * Description: <描述类的功能>.
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2020/8/24 下午2:41
+ * + * @author popo + * @version 1.0 + * @since 1.0 + */ +public class MybatisBaseService, T> extends ServiceImpl { + + @SuppressWarnings("unchecked") + private T entity() { + T instance = null; + Class entityClass = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()) + .getActualTypeArguments()[1]; + try { + instance = entityClass.newInstance(); + } catch (InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return instance; + } + + /** + * 描述 : <描述函数实现的功能>.
+ *

+ * + * @param map + */ + protected Long checkId(Map map) { + Object object = map.get("id"); + if (object == null) + return 0L; + String sId = object.toString(); + if (StringUtils.isBlank(sId)) + return 0L; + Long id = Long.valueOf(sId); + return id; + } + + protected String checkSid(Map map) { + Object object = map.get("sid"); + if (object == null) + return null; + // if (StringUtils.isBlank(object.toString())) + // return null; + return object.toString(); + } + + /** + * 描述 : 将Map转换为实体对象.
+ *

+ * + * @param map + * @param t + * @return + */ + @SuppressWarnings("unchecked") + protected T map2entity(Map map, T t) { + map.remove("id"); + map.remove("sid"); + map.remove("createTime"); + map.remove("modifyTime"); + if (t instanceof BaseEntity) { + ((BaseEntity) t).setModifyTime(new Date()); + t = (T) (BaseEntity) t; + } + BeanUtil.fillBeanWithMapIgnoreCase(map, t, false); + return t; + } + + public int insert(T paramT) { + return baseMapper.insert(paramT); + } + + public int insert(Map map) { + T t = entity(); + t = map2entity(map, t); + return insert(t); + } + + public int deleteBySid(String sid) { + Map map = new HashMap<>(); + map.put("sid", sid); + return baseMapper.deleteByMap(map); + } + + /** + * 描述 : <描述函数实现的功能>.
+ *

+ * + * @param ids + * @return + */ + public int delByIds(String ids) { + String[] split = ids.split(","); + if (split.length < 1) { + return 0; + } else if (split.length == 1) { + return baseMapper.deleteById(Long.valueOf(ids)); + } else { + List list = new ArrayList<>(); + for (String id : split) { + list.add(Long.valueOf(id)); + } + return baseMapper.deleteBatchIds(list); + } + } + + /** + * 描述 : <描述函数实现的功能>.
+ *

+ * + * @param sids + * @return + */ + public int delBySids(String[] sids) { + if (sids == null || sids.length < 1) + return 0; + else if (sids.length == 1) { + String sid = sids[0]; + return deleteBySid(sid); + } else { + List list = new ArrayList<>(); + for (String sid : sids) { + list.add(sid); + } + QueryWrapper qw = new QueryWrapper<>(); + qw.in("sid", list); + return baseMapper.delete(qw); + } + } + + public int updateById(Map map) { + Long id = checkId(map); + if (id.equals(0L)) + return 0; + return updateById(map, id); + } + + public int updateById(Map map, Serializable id) { + T t = fetchById(id); + if (t == null) + return -1; + t = map2entity(map, t); + + if (t instanceof BaseEntity) { + if(((BaseEntity) t).getLockVersion()!=null) { + ((BaseEntity) t).setLockVersion(((BaseEntity) t).getLockVersion() + 1); + } + } + return baseMapper.updateById(t); + } + + public int updateBySid(Map map) { + String sid = checkSid(map); + if (StringUtils.isBlank(sid)) + return 0; + return updateBySid(map, sid); + } + + public int updateBySid(Dto dto, String sid) { + T t = fetchBySid(sid); + if (t == null) + return -1; + BeanUtil.copyProperties(dto,t); + if (t instanceof BaseEntity) { + if(((BaseEntity) t).getLockVersion()!=null) { + ((BaseEntity) t).setLockVersion(((BaseEntity) t).getLockVersion() + 1); + } + } + return baseMapper.updateById(t); + } + + public int updateBySid(Map map, String sid) { + T t = fetchBySid(sid); + if (t == null) + return -1; + t = map2entity(map, t); + + if (t instanceof BaseEntity) { + if(((BaseEntity) t).getLockVersion()!=null) { + ((BaseEntity) t).setLockVersion(((BaseEntity) t).getLockVersion() + 1); + } + } + return baseMapper.updateById(t); + } + + public int insertOrUpdateById(Map map) { + Long id = checkId(map); + if (id.equals(0L)) + return insert(map); + return updateById(map, id); + } + + public int insertOrUpdateBySid(Map map) { + String sid = checkSid(map); + if (StringUtils.isBlank(sid)) + return insert(map); + return updateBySid(map, sid); + } + + /** + * 描述 : <描述函数实现的功能>.
+ *

+ * + * @param id + * @return + */ + public T fetchById(Serializable id) { + return baseMapper.selectById(id); + } + + public T fetchBySid(String sid) { + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("sid", sid); + return baseMapper.selectOne(qw); + } + + /** + * 描述 : <描述函数实现的功能>.
+ *

+ * + * @param page + * @param params + * @return + */ + public IPage pagging(IPage page, Map params) { + QueryWrapper qw = defaultPageQueryWrapper(params); + return pagging(page, qw); + } + + /** + * 描述 : <描述函数实现的功能>.
+ *

+ * + * @param page + * @param qw + * @return + */ + public IPage pagging(IPage page, QueryWrapper qw) { + IPage selectPage = baseMapper.selectPage(page, qw); + if (selectPage.getPages() < selectPage.getCurrent()) { + page.setCurrent(selectPage.getPages()); + page.setTotal(selectPage.getTotal()); + selectPage = baseMapper.selectPage(page, qw); + } + return selectPage; + } + + public IPage> paggingMap(IPage> page, Map params) { + QueryWrapper qw = defaultPageQueryWrapper(params); + return paggingMap(page, qw); + } + + + public IPage> paggingMap(IPage> page, QueryWrapper qw) { + IPage> selectMapsPage = baseMapper.selectMapsPage(page, qw); + + if (selectMapsPage.getPages() < selectMapsPage.getCurrent()) { + page.setCurrent(selectMapsPage.getPages()); + page.setTotal(selectMapsPage.getTotal()); + selectMapsPage = baseMapper.selectMapsPage(page, qw); + } + + return selectMapsPage; + } + + /** + * 描述 : <描述函数实现的功能>.
+ *

+ * + * @param params + */ + private QueryWrapper defaultPageQueryWrapper(Map params) { + if (params == null || params.isEmpty()) + return Wrappers.emptyWrapper(); + + QueryWrapper qw = new QueryWrapper(); + for (String key : params.keySet()) { + qw.like(key, params.get(key)); + } + return qw; + } + + public IPage page(IPage page, Map params) { + QueryWrapper qw = defaultPageQueryWrapper(params); + return super.page(page, qw); + } + + public IPage> pageMaps(IPage> page, Map params) { + QueryWrapper qw = defaultPageQueryWrapper(params); + return super.pageMaps(page, qw); + } + + public PagerVo page(PagerQuery pagerQuery) { + Q params = pagerQuery.getParams(); + IPage page = PagerUtil.queryToPage(pagerQuery); + Map paramsMap = null; + if (params != null) + paramsMap = params.toMap(); + IPage pageResult = this.page(page, paramsMap); + PagerVo pv = PagerUtil.pageToVo(pageResult, null); + return pv; + } + + public PagerVo> pageMaps(PagerQuery pagerQuery) { + Q params = pagerQuery.getParams(); + IPage page = PagerUtil.queryToPage(pagerQuery); + Map paramsMap = null; + if (params != null) + paramsMap = params.toMap(); + IPage pageResult = this.page(page, paramsMap); + PagerVo> pv = PagerUtil.pageToVo(pageResult, new PagerVo<>()); + return pv; + } + + /** + * 查询与某一字段值相等的数据列表 + * + * @param filedName 字段名 + * @param filedValue 相等的值 + * @return + */ + public List listEqFiled(String filedName, String filedValue) { + QueryWrapper qw = new QueryWrapper<>(); + qw.eq(filedName, filedValue); + return list(qw); + } + + /** + * 查询与某一字段值相等,但不等于id的数据列表 + * + * @param filedName 字段名 + * @param filedValue 相等的值 + * @param id id的值 + * @return + */ + public List listEqFiledNeId(String filedName, String filedValue, Serializable id) { + QueryWrapper qw = new QueryWrapper<>(); + qw.eq(filedName, filedValue); + qw.ne("id", id); + return list(qw); + } + + /** + * 查询与某一字段值相等,但与另一字段的值不相等的数据列表 + * + * @param filedName 相等的字段名 + * @param filedValue 相等的值 + * @param neName 不相等的字段名 + * @param neValue 不相等的值 + * @return + */ + public List listEqFiledWithNe(String filedName, String filedValue, String neName, String neValue) { + QueryWrapper qw = new QueryWrapper<>(); + qw.eq(filedName, filedValue); + qw.ne(neName, neValue); + return list(qw); + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/AjaxResult.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/AjaxResult.java new file mode 100644 index 0000000..d527e5e --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/AjaxResult.java @@ -0,0 +1,142 @@ +package com.yxt.common.base.utils; + +import java.util.HashMap; + +/** + * @author dimengzhe + * @date 2020/9/18 9:12 + * @description 自定义响应结果 + */ + +public class AjaxResult extends HashMap { + private static final long serialVersionUID = 8563869641248167214L; + + /** + * 状态码 + */ + public static final String CODE_TAG = "code"; + + /** + * 返回内容 + */ + public static final String MSG_TAG = "msg"; + + /** + * 数据对象 + */ + public static final String DATA_TAG = "data"; + + /** + * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。 + */ + public AjaxResult() { + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param code 状态码 + * @param msg 返回内容 + */ + public AjaxResult(int code, String msg) { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param code 状态码 + * @param msg 返回内容 + * @param data 数据对象 + */ + public AjaxResult(int code, String msg, Object data) { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + if (StringUtils.isNotNull(data)) { + super.put(DATA_TAG, data); + } + } + + /** + * 返回成功消息 + * + * @return 成功消息 + */ + public static AjaxResult success() { + return AjaxResult.success("操作成功"); + } + + /** + * 返回成功数据 + * + * @return 成功消息 + */ + public static AjaxResult success(Object data) { + return AjaxResult.success("操作成功", data); + } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @return 成功消息 + */ + public static AjaxResult success(String msg) { + return AjaxResult.success(msg, null); + } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 成功消息 + */ + public static AjaxResult success(String msg, Object data) { + return new AjaxResult(HttpStatus.SUCCESS, msg, data); + } + + /** + * 返回错误消息 + * + * @return + */ + public static AjaxResult error() { + return AjaxResult.error("操作失败"); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static AjaxResult error(String msg) { + return AjaxResult.error(msg, null); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static AjaxResult error(String msg, Object data) { + return new AjaxResult(HttpStatus.ERROR, msg, data); + } + + /** + * 返回错误消息 + * + * @param code 状态码 + * @param msg 返回内容 + * @return 警告消息 + */ + public static AjaxResult error(int code, String msg) { + return new AjaxResult(code, msg, null); + } + + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Base64.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Base64.java new file mode 100644 index 0000000..0192a34 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Base64.java @@ -0,0 +1,250 @@ +package com.yxt.common.base.utils; + +/** + * @author dimengzhe + * @date 2020/9/18 9:39 + * @description Base64工具类 + */ + +public final class Base64 { + + static private final int BASELENGTH = 128; + static private final int LOOKUPLENGTH = 64; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int FOURBYTE = 4; + static private final int SIGN = -128; + static private final char PAD = '='; + static final private byte[] base64Alphabet = new byte[BASELENGTH]; + static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; + + static { + for (int i = 0; i < BASELENGTH; ++i) { + base64Alphabet[i] = -1; + } + for (int i = 'Z'; i >= 'A'; i--) { + base64Alphabet[i] = (byte) (i - 'A'); + } + for (int i = 'z'; i >= 'a'; i--) { + base64Alphabet[i] = (byte) (i - 'a' + 26); + } + + for (int i = '9'; i >= '0'; i--) { + base64Alphabet[i] = (byte) (i - '0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i <= 25; i++) { + lookUpBase64Alphabet[i] = (char) ('A' + i); + } + + for (int i = 26, j = 0; i <= 51; i++, j++) { + lookUpBase64Alphabet[i] = (char) ('a' + j); + } + + for (int i = 52, j = 0; i <= 61; i++, j++) { + lookUpBase64Alphabet[i] = (char) ('0' + j); + } + lookUpBase64Alphabet[62] = (char) '+'; + lookUpBase64Alphabet[63] = (char) '/'; + } + + private static boolean isWhiteSpace(char octect) { + return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); + } + + private static boolean isPad(char octect) { + return (octect == PAD); + } + + private static boolean isData(char octect) { + return (octect < BASELENGTH && base64Alphabet[octect] != -1); + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * @return Encoded Base64 array + */ + public static String encode(byte[] binaryData) { + if (binaryData == null) { + return null; + } + + int lengthDataBits = binaryData.length * EIGHTBIT; + if (lengthDataBits == 0) { + return ""; + } + + int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; + int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets; + char[] encodedData = null; + + encodedData = new char[numberQuartet * 4]; + + byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; + + int encodedIndex = 0; + int dataIndex = 0; + + for (int i = 0; i < numberTriplets; i++) { + b1 = binaryData[dataIndex++]; + b2 = binaryData[dataIndex++]; + b3 = binaryData[dataIndex++]; + + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); + + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; + } + + // form integral number of 6-bit groups + if (fewerThan24bits == EIGHTBIT) { + b1 = binaryData[dataIndex]; + k = (byte) (b1 & 0x03); + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; + encodedData[encodedIndex++] = PAD; + encodedData[encodedIndex++] = PAD; + } else if (fewerThan24bits == SIXTEENBIT) { + b1 = binaryData[dataIndex]; + b2 = binaryData[dataIndex + 1]; + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; + encodedData[encodedIndex++] = PAD; + } + return new String(encodedData); + } + + /** + * Decodes Base64 data into octects + * + * @param encoded string containing Base64 data + * @return Array containind decoded data. + */ + public static byte[] decode(String encoded) { + if (encoded == null) { + return null; + } + char[] base64Data = encoded.toCharArray(); + // remove white spaces + int len = removeWhiteSpace(base64Data); + + if (len % FOURBYTE != 0) { + // should be divisible by four + return null; + } + int numberQuadruple = (len / FOURBYTE); + if (numberQuadruple == 0) { + return new byte[0]; + } + byte[] decodedData = null; + byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; + char d1 = 0, d2 = 0, d3 = 0, d4 = 0; + int i = 0; + int encodedIndex = 0; + int dataIndex = 0; + decodedData = new byte[(numberQuadruple) * 3]; + for (; i < numberQuadruple - 1; i++) { + if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) + || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) { + return null; + } // if found "no data" just return null + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + b3 = base64Alphabet[d3]; + b4 = base64Alphabet[d4]; + decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); + } + + if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { + // if found "no data" just return null + return null; + } + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + + d3 = base64Data[dataIndex++]; + d4 = base64Data[dataIndex++]; + // Check if they are PAD characters + if (!isData((d3)) || !isData((d4))) { + if (isPad(d3) && isPad(d4)) { + // last 4 bits should be zero + if ((b2 & 0xf) != 0) { + return null; + } + byte[] tmp = new byte[i * 3 + 1]; + System.arraycopy(decodedData, 0, tmp, 0, i * 3); + tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); + return tmp; + } else if (!isPad(d3) && isPad(d4)) { + b3 = base64Alphabet[d3]; + // last 2 bits should be zero + if ((b3 & 0x3) != 0) { + return null; + } + byte[] tmp = new byte[i * 3 + 2]; + System.arraycopy(decodedData, 0, tmp, 0, i * 3); + tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + return tmp; + } else { + return null; + } + } else { // No PAD e.g 3cQl + b3 = base64Alphabet[d3]; + b4 = base64Alphabet[d4]; + decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); + + } + return decodedData; + } + + /** + * remove WhiteSpace from MIME containing encoded Base64 data. + * + * @param data the byte array of base64 data (with WS) + * @return the new length + */ + private static int removeWhiteSpace(char[] data) { + if (data == null) { + return 0; + } + + // count characters that's not whitespace + int newSize = 0; + int len = data.length; + for (int i = 0; i < len; i++) { + if (!isWhiteSpace(data[i])) { + data[newSize++] = data[i]; + } + } + return newSize; + } + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/BeanMapUtils.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/BeanMapUtils.java new file mode 100644 index 0000000..c44f5f2 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/BeanMapUtils.java @@ -0,0 +1,38 @@ +package com.yxt.common.base.utils; + +import org.springframework.cglib.beans.BeanMap; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author dimengzhe + * @date 2020/9/11 23:34 + * @description + */ + +public class BeanMapUtils { + /** + * 将对象属性转化为map结合 + */ + public static Map beanToMap(T bean) { + Map map = new HashMap<>(); + if (bean != null) { + BeanMap beanMap = BeanMap.create(bean); + for (Object key : beanMap.keySet()) { + map.put(key+"", beanMap.get(key)); + } + } + return map; + } + + /** + * 将map集合中的数据转化为指定对象的同名属性中 + */ + public static T mapToBean(Map map,Class clazz) throws Exception { + T bean = clazz.newInstance(); + BeanMap beanMap = BeanMap.create(bean); + beanMap.putAll(map); + return bean; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/ConstantUtils.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/ConstantUtils.java new file mode 100644 index 0000000..c90f405 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/ConstantUtils.java @@ -0,0 +1,405 @@ +package com.yxt.common.base.utils; + + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author dimengzhe + * @date 2021/3/13 11:35 + * @description 常量工具类 + */ + +public class ConstantUtils { + + public static String userAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"; + + public static final String DEF_CHATSET = "UTF-8"; + public static final int DEF_CONN_TIMEOUT = 30000; + public static final int DEF_READ_TIMEOUT = 30000; + /** + * 服务端地址 + */ +// public static String url = "https://cloud.tecshield.com"; + public static String url = "http://8.140.126.176:8080"; + /** + * 手机签名地址 + */ +// public static String url2 = "https://yzqmini.tecshield.com:8843/yizhengqian"; + public static String url2 = "http://110.249.155.83:7030/yizhengqian"; + + /** + * 签章解析地址 + */ + public static String parseUrl = url + "/signature/api/parseSignature"; + /** + * 数据签章地址 + */ + public static String signSealUrl = url + "/signature/api/signSeal"; + /** + * 获取证书授权码地址 + */ + public static String authCodeUrl = url + "/cert/api/authcode"; + /** + * 获取印章列表地址 + */ + public static String sealListUrl = url + "/seal/api/list"; + /** + * 对Client_Id进行授权地址 + */ + public static String oauthUrl = url + "/auth/oauth/token"; + /** + * 获取证书B64 + */ + public static String getCertB64Url = url + "/cert/api/get"; + /** + * 图片透明处理 + */ + public static String getHandleImgUrl = url + "/seal/api/handleImg"; + /** + * 新建印章 + */ + public static String addSealUrl = url + "/seal/api/add"; + /** + * 获取印章信息 + */ + public static String sealDetailsUrl = url + "/seal/api/seal/"; + + public static String sealParseDetailsUrl = url + "/signature/api/parseSeal"; + /** + * 印章注销 + */ + public static String disposeUrl = url + "/seal/api/dispose"; + /** + * 数据签章验证 + */ + public static String verifySignSealUrl = url + "/signature/api/verifySignSeal"; + /** + * 获取证书绑定有效期 + */ + public static String downloadUrl = url + "/cert/api/download"; + /** + * 创建证书 + */ + public static String addCertUrl = url + "/cert/api/add"; + /** + * 证书延期 + */ + public static String delayCaUrl = url + "/cert/api/delay"; + /** + * 修改证书密码 + */ + public static String changePasswordUrl = url + "/cert/api/changepassword"; + /** + * 证书注销 + */ + public static String disposeCaUrl = url + "/cert/api/dispose"; + + public static String caLoginUrl = url2 + "/interface/v1/login"; + + public static String createQrCodeUrl = url2 + "/interface/v1/createQrCode"; + + public static String handlerServiceUrl = url2 + "/api/v1/handlerService"; + + public static String lunxunGetResultUrl = url2 + "/interface/v1/lunxunGetResult"; + + + /** + * 请求头 + */ +// public static String AUTHORIZATION = "Basic bWFsaV90ZXN0OnlpemhlbmdxaWFu"; + //access token有效时长,单位秒 + public static long EXPIRES_IN = 0; + + public static String TOKEN_TYPE = "Bearer"; + public static String ACCESS_TOKEN = "access_token"; + + public static String GRANT_TYPE = "client_credentials"; + public static String SCOPE = "all"; + /** + * 账号 + */ + public static String CLIENT_ID = "hebca_yzq"; + /** + * 密码 + */ + public static String CLIENT_SECRET = "123456"; + /** + * 项目ID + */ + public static String APPID = "402883247a99b2bb017a9ecc4d8d00f6"; + + public static long EXPIRE_TIME = 20 * 24 * 60 * 60; + + public static int OPTYPE = 114; + public static int OPTYPE1 = 0; + public static int TRANSTYPE = 0; + + + public static String net(String strUrl, Map params, String method, String authorization) throws Exception { + HttpURLConnection conn = null; + BufferedReader reader = null; + String rs = null; + try { + StringBuffer sb = new StringBuffer(); + if (method == null || method.equals("GET")) { + strUrl = strUrl + "?" + urlencode(params); + } + URL url = new URL(strUrl); + conn = (HttpURLConnection) url.openConnection(); + if (method == null || method.equals("GET")) { + conn.setRequestMethod("GET"); + } else { + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + } +// conn.setRequestProperty("User-agent", userAgent); + conn.setRequestProperty("Authorization", authorization); + conn.setUseCaches(false); + conn.setConnectTimeout(DEF_CONN_TIMEOUT); + conn.setReadTimeout(DEF_READ_TIMEOUT); + conn.setInstanceFollowRedirects(false); + conn.connect(); + if (params != null && method.equals("POST")) { + try { + DataOutputStream out = new DataOutputStream(conn.getOutputStream()); + out.writeBytes(urlencode(params)); + } catch (Exception e) { + } + } + InputStream is = conn.getInputStream(); + reader = new BufferedReader(new InputStreamReader(is, DEF_CHATSET)); + String strRead = null; + while ((strRead = reader.readLine()) != null) { + sb.append(strRead); + } + rs = sb.toString(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (reader != null) { + reader.close(); + } + if (conn != null) { + conn.disconnect(); + } + } + return rs; + } + + public static String net2(String strUrl, Map params, String method, String authorization) throws Exception { + HttpURLConnection conn = null; + BufferedReader reader = null; + String rs = null; + try { + StringBuffer sb = new StringBuffer(); + if (method == null || method.equals("GET")) { + strUrl = strUrl + "?" + urlencode(params); + } + URL url = new URL(strUrl); + conn = (HttpURLConnection) url.openConnection(); + if (method == null || method.equals("GET")) { + conn.setRequestMethod("GET"); + } else { + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + } +// conn.setRequestProperty("User-agent", userAgent); + conn.setRequestProperty("I-Authorization", authorization); + conn.setUseCaches(false); + conn.setConnectTimeout(DEF_CONN_TIMEOUT); + conn.setReadTimeout(DEF_READ_TIMEOUT); + conn.setInstanceFollowRedirects(false); + conn.connect(); + if (params != null && method.equals("POST")) { + try { + DataOutputStream out = new DataOutputStream(conn.getOutputStream()); + out.writeBytes(urlencode(params)); + } catch (Exception e) { + } + } + InputStream is = conn.getInputStream(); + reader = new BufferedReader(new InputStreamReader(is, DEF_CHATSET)); + String strRead = null; + while ((strRead = reader.readLine()) != null) { + sb.append(strRead); + } + rs = sb.toString(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (reader != null) { + reader.close(); + } + if (conn != null) { + conn.disconnect(); + } + } + return rs; + } + + public static String net1(String strUrl, String method) throws Exception { + HttpURLConnection conn = null; + BufferedReader reader = null; + String rs = null; + try { + StringBuffer sb = new StringBuffer(); + URL url = new URL(strUrl); + conn = (HttpURLConnection) url.openConnection(); + if (method == null || method.equals("GET")) { + conn.setRequestMethod("GET"); + } + conn.setRequestProperty("User-agent", userAgent); + conn.setUseCaches(false); + conn.setConnectTimeout(DEF_CONN_TIMEOUT); + conn.setReadTimeout(DEF_READ_TIMEOUT); + conn.setInstanceFollowRedirects(false); + conn.connect(); + InputStream is = conn.getInputStream(); + reader = new BufferedReader(new InputStreamReader(is, DEF_CHATSET)); + String strRead = null; + while ((strRead = reader.readLine()) != null) { + sb.append(strRead); + } + rs = sb.toString(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (reader != null) { + reader.close(); + } + if (conn != null) { + conn.disconnect(); + } + } + return rs; + } + + /** + * 将map型转为请求参数型 + * + * @param data + * @return + */ + public static String urlencode(Map data) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry i : data.entrySet()) { + try { + sb.append(i.getKey()).append("=").append(URLEncoder.encode(i.getValue() + "", "UTF-8")).append("&"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + return sb.toString(); + } + + public static List castList(Object obj, Class clazz) { + List result = new ArrayList(); + if (obj instanceof List) { + for (Object o : (List) obj) { + result.add(clazz.cast(o)); + } + return result; + } + return null; + } + + // 获取String类型 + public static String getString(Map map, String keyName, String defaultValue) { + if (map == null) { + return defaultValue; + } + if (map.containsKey(keyName)) { + Object o = map.get(keyName); + if (o instanceof String) { + return (String) o; + } else { + return defaultValue; + } + } else { + return defaultValue; + } + } + + // 获取Integer + public static Integer getInteger(Map map, String keyName) { + if (map == null) { + return -1; + } + if (map.containsKey(keyName)) { + Object o = map.get(keyName); + if (o instanceof Integer) { + return (int) o; + } else { + return -1; + } + + } else { + return -1; + } + } + + //获取map类型 + public static Map getMap(Map map, String keyName) { + if (map == null) { + return new HashMap<>(); + } + if (map.containsKey(keyName)) { + Object o = map.get(keyName); + if (o instanceof Map) { + return (Map) o; + } else { + return new HashMap<>(); + } + + } else { + return new HashMap<>(); + } + } + + // 获取List类型 + public static List> getListData(Map map, String keyName) { + List> list = new ArrayList<>(); + if (map == null) { + return list; + } + if (map.containsKey(keyName)) { + Object o = map.get(keyName); + if (o instanceof List) { + for (int i = 0; i < ((List) o).size(); i++) { + Object o1 = ((List) o).get(i); + if (o1 instanceof Map) { + list.add((Map) o1); + } + } + } + } + return list; + } + + public static List getStringListData(Map map, String keyName) { + List list = new ArrayList<>(); + if (map == null) { + return list; + } + if (map.containsKey(keyName)) { + Object o = map.get(keyName); + if (o instanceof List) { + for (int i = 0; i < ((List) o).size(); i++) { + Object o1 = ((List) o).get(i); + if (o1 instanceof Integer) { + String a = String.valueOf(o1); + list.add(a); + } + } + } + } + return list; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/DateUtils.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/DateUtils.java new file mode 100644 index 0000000..1e155d5 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/DateUtils.java @@ -0,0 +1,588 @@ +package com.yxt.common.base.utils; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +/** + * 关于日期处理工具类. + * + * @author yxt_mtl + * @date 2020/11/10 10:54 + * @description + */ + +public class DateUtils { + + /** + * 获取两个时间间隔的x天x小时x分钟 + * + * @param startTime + * @param endTime + * @param format + * @return + * @throws Exception + */ + public static String dateDiff(String startTime, String endTime, + String format) throws Exception { + // 按照传入的格式生成一个simpledateformate对象 + SimpleDateFormat sd = new SimpleDateFormat(format); + long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数 + long nh = 1000 * 60 * 60;// 一小时的毫秒数 + long nm = 1000 * 60;// 一分钟的毫秒数 + //long ns = 1000;// 一秒钟的毫秒数 + long diff = 0; + try { + // 获得两个时间的毫秒时间差异 + diff = sd.parse(endTime).getTime() - sd.parse(startTime).getTime(); + } catch (Exception e) { + e.printStackTrace(); + } + long day = diff / nd;// 计算差多少天 + long hour = diff % nd / nh;// 计算差多少小时 + long min = diff % nd % nh / nm;// 计算差多少分钟 + // long sec = diff%nd%nh%nm/ns;//计算差多少秒//输出结果 + return (day + "天" + hour + "小时" + min + "分钟"); + + } + + /** + * 获取当前时间格式yyy-MM-dd HH:mm:ss时间字符串 + * + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static String getNowDateStr() { + return dateConvertStr(new Date(), "yyyy-MM-dd HH:mm:ss"); + } + + /** + * 获取当前时间格式yyy-MM-dd HH:mm时间字符串 + * + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static String getNowDateMinuteStr() { + return dateConvertStr(new Date(), "yyyy-MM-dd HH:mm"); + } + + /** + * 获取当前时间格式yyy-MM-dd时间字符串 + * + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static String getNowDateDayStr() { + return dateConvertStr(new Date(), "yyyy-MM-dd "); + } + + /** + * 将Date类型转换成yyy-MM-dd HH:mm:ss 字符串类型 + * + * @param Date date + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static String dateConvertStr(Date date) { + return dateConvertStr(date, "yyyy-MM-dd HH:mm:ss"); + } + + /** + * 将Date类型转换成yyy-MM-dd字符串类型 + * + * @param Date date + * @param String format 如:yyyy-MM-dd + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static String dateConvertDayStr(Date date) { + return dateConvertStr(date, "yyyy-MM-dd"); + } + + /** + * 将Date类型转换成字符串类型 + * + * @param Date date + * @param String format 如:yyyy-MM-dd HH:mm:ss + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static String dateConvertStr(Date date, String format) { + return (date == null) ? null : new SimpleDateFormat(format) + .format(date); + } + + /** + * 时间格式字符串转换成Date类型 + * + * @param String date + * @param String format 如:yyyy-MM-dd HH:mm:ss + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static Date dateStrConvertDate(String date, String format) { + try { + SimpleDateFormat simpledateformat = new SimpleDateFormat(format); + Date newdate = simpledateformat.parse(date); + return newdate; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + + /** + * 时间格式字符串转换成Date类型 + * + * @param String date + * @param String format 如:yyyy-MM-dd HH:mm:ss + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static Date dateStrConvertDateCST(String date, String format) { + try { + SimpleDateFormat simpledateformat = new SimpleDateFormat(format, + Locale.US); + Date newdate = simpledateformat.parse(date); + return newdate; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + + /** + * 根据日期获取当前为星期几 + * + * @param date + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static int getWeek(Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int weekno = cal.get(Calendar.DAY_OF_WEEK) - 1; + if (weekno == 0) + weekno = 7; + return weekno; + + } + + /** + * 计算两个时间间隔多少天,取绝对值 + * + * @param startday + * @param endday + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static int getIntervalDays(Date startday, Date endday) { + if (startday.after(endday)) { + Date cal = startday; + startday = endday; + endday = cal; + } + long sl = startday.getTime(); + long el = endday.getTime(); + long ei = el - sl; + return (int) (ei / (1000 * 60 * 60 * 24)); + } + + /** + * 计算两个时间间隔多少天,可能为负值 + * + * @param startday + * @param endday + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static int getDays(Date startday, Date endday) { + + long sl = startday.getTime(); + long el = endday.getTime(); + long ei = el - sl; + return (int) (ei / (1000 * 60 * 60 * 24)); + } + + /** + * 计算两个时间间隔分钟数,可能为负值 + * + * @param startday + * @param endday + * @return + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static int getMinutes(Date startday, Date endday) { + long sl = startday.getTime(); + long el = endday.getTime(); + long ei = el - sl; + return (int) (ei / (1000 * 60)); + + } + + /** + * 指定时间对象,根据日历的规则,为给定的日历字段添加或减去指定的时间量,返回时间对象 + * + * @param date Date类型 + * @param field int 日历字段,如:Calendar.DAY_OF_MONTH + * @param amount int 为字段添加的日期或时间量。 + * @return Date值 + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static Date getDate(Date date, int field, int amount) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.add(field, amount); + return cal.getTime(); + } + + /** + * 指定时间对象,根据日历的规则,为给定的日历字段添加或减去指定的天数,返回时间对象 + * + * @param date Date类型 + * @param day 天 int 为字段添加的日期或时间量。 + * @return Date值 + * @author: NQY + * @Createtime: Sep 14, 2012 + */ + public static Date getDateMonth(Date date, int day) { + return getDate(date, Calendar.MONTH, day); + } + + /** + * 获取指定时间在当年中的第几周 + * + * @param date Date类型 + * @return + * @author: NQY + * @Createtime: Aug 13, 2012 + */ + public static int getWeekNumber(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + return calendar.get(Calendar.WEEK_OF_YEAR); + + } + + /** + * 获取当前时间在当年中的第几周 + * + * @return + * @author: NQY + * @Createtime: Aug 13, 2012 + */ + public static int getWeekNumber() { + + return getWeekNumber(new Date()); + + } + + /** + * 通过传值跟当前时间比较(大于当前时间为true;小于当前时间为false) + * + * @param time String + * @return + */ + public static boolean getCompareDate(String time) { + boolean flag = false; + DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + try { + Date d = sdf.parse(time); + flag = new Date().before(d); + } catch (ParseException e) { + } + return flag; + } + + /** + * 获取指定日期所在周的周一 + * + * @return Date + * @Methods Name getMonday + */ + public static Date getMonday(Date date) { + Calendar cDay = Calendar.getInstance(); + cDay.setTime(date); + cDay.set(Calendar.DAY_OF_WEEK, 2);// 老外将周日定位第一天,周一取第二天 + return cDay.getTime(); + } + + /** + * 获取指定日期所在周日 + * + * @return Date + * @Methods Name getSunday + */ + public static Date getSunday(Date date) { + Calendar cDay = Calendar.getInstance(); + cDay.setTime(date); + if (Calendar.DAY_OF_WEEK == cDay.getFirstDayOfWeek()) { // 如果刚好是周日,直接返回 + return date; + } else {// 如果不是周日,加一周计算 + cDay.add(Calendar.DAY_OF_YEAR, 7); + cDay.set(Calendar.DAY_OF_WEEK, 1); + return cDay.getTime(); + } + } + + /** + * 得到本月第一天的日期 + * + * @return Date + * @Methods Name getFirstDayOfMonth + */ + public static Date getFirstDayOfMonth(Date date) { + Calendar cDay = Calendar.getInstance(); + cDay.setTime(date); + cDay.set(Calendar.DAY_OF_MONTH, 1); + return cDay.getTime(); + } + + /** + * 得到本月最后一天的日期 + * + * @return Date + * @Methods Name getLastDayOfMonth + */ + public static Date getLastDayOfMonth(Date date) { + Calendar cDay = Calendar.getInstance(); + cDay.setTime(date); + cDay.set(Calendar.DAY_OF_MONTH, + cDay.getActualMaximum(Calendar.DAY_OF_MONTH)); + return cDay.getTime(); + } + + /** + * 得到本季度第一天的日期 + * + * @return Date + * @Methods Name getFirstDayOfQuarter + */ + public static Date getFirstDayOfQuarter(Date date) { + Calendar cDay = Calendar.getInstance(); + cDay.setTime(date); + int curMonth = cDay.get(Calendar.MONTH); + if (curMonth >= Calendar.JANUARY && curMonth <= Calendar.MARCH) { + cDay.set(Calendar.MONTH, Calendar.JANUARY); + } + if (curMonth >= Calendar.APRIL && curMonth <= Calendar.JUNE) { + cDay.set(Calendar.MONTH, Calendar.APRIL); + } + if (curMonth >= Calendar.JULY && curMonth <= Calendar.AUGUST) { + cDay.set(Calendar.MONTH, Calendar.JULY); + } + if (curMonth >= Calendar.OCTOBER && curMonth <= Calendar.DECEMBER) { + cDay.set(Calendar.MONTH, Calendar.OCTOBER); + } + cDay.set(Calendar.DAY_OF_MONTH, + cDay.getActualMinimum(Calendar.DAY_OF_MONTH)); + return cDay.getTime(); + } + + /** + * 得到本季度最后一天的日期 + * + * @return Date + * @Methods Name getLastDayOfQuarter + */ + public static Date getLastDayOfQuarter(Date date) { + Calendar cDay = Calendar.getInstance(); + cDay.setTime(date); + int curMonth = cDay.get(Calendar.MONTH); + if (curMonth >= Calendar.JANUARY && curMonth <= Calendar.MARCH) { + cDay.set(Calendar.MONTH, Calendar.MARCH); + } + if (curMonth >= Calendar.APRIL && curMonth <= Calendar.JUNE) { + cDay.set(Calendar.MONTH, Calendar.JUNE); + } + if (curMonth >= Calendar.JULY && curMonth <= Calendar.AUGUST) { + cDay.set(Calendar.MONTH, Calendar.AUGUST); + } + if (curMonth >= Calendar.OCTOBER && curMonth <= Calendar.DECEMBER) { + cDay.set(Calendar.MONTH, Calendar.DECEMBER); + } + cDay.set(Calendar.DAY_OF_MONTH, + cDay.getActualMaximum(Calendar.DAY_OF_MONTH)); + return cDay.getTime(); + } + + // 根据出生日期生成年龄 + public static int getAgeByBirth(Date birthday) { + if (birthday == null) + return 0; + // 格式化传入的时间 + + Date parse = dateStrConvertDate(birthday.toString(), "yyyy-MM-dd"); + int age = 0; + try { + Calendar now = Calendar.getInstance(); + now.setTime(new Date()); // 当前时间 + + Calendar birth = Calendar.getInstance(); + birth.setTime(parse); // 传入的时间 + + // 如果传入的时间,在当前时间的后面,返回0岁 + if (birth.after(now)) { + age = 0; + } else { + age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR); + if (now.get(Calendar.DAY_OF_YEAR) > birth + .get(Calendar.DAY_OF_YEAR)) { + age += 1; + } + } + return age; + } catch (Exception e) { + return 0; + } + } + + public static double dateDiff1(String startTime, String endTime) { + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); + Date time; + Date time2; + String dff = ""; + try { + time = sdf.parse(startTime); + time2 = sdf.parse(endTime); + + Calendar instance = Calendar.getInstance(); + instance.setTime(time); + long timeInMillis1 = instance.getTimeInMillis(); + + Calendar instance2 = Calendar.getInstance(); + instance2.setTime(time2); + long timeInMillis2 = instance2.getTimeInMillis(); + + double hours = (timeInMillis2 - timeInMillis1) / 1000 / 60 / 60.0; + return hours; + } catch (ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return 0; + } + } + + /** + * 得到指定月的天数 + */ + public static int getMonthLastDay(int year, int month) { + Calendar a = Calendar.getInstance(); + a.set(Calendar.YEAR, year); + a.set(Calendar.MONTH, month - 1); + a.set(Calendar.DATE, 1);//把日期设置为当月第一天 + a.roll(Calendar.DATE, -1);//日期回滚一天,也就是最后一天 + int maxDate = a.get(Calendar.DATE); + return maxDate; + } + + + public static int getYearMonth(Date dt) {//传入日期 获取日期的年月 + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + int year = cal.get(Calendar.YEAR);//获取年份 + int month = cal.get(Calendar.MONTH);//获取月份 + return year * 100 + month;//返回年份乘以100加上月份的值,因为月份最多2位数,所以年份乘以100可以获取一个唯一的年月数值 + } + + + public static String getWeekOfDate(Date dt) {//获取周几; + String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}; + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + + int w = cal.get(Calendar.DAY_OF_WEEK) - 1; + if (w < 0) + w = 0; + + return weekDays[w]; + } + + /** + * 比较两个年月 的大小 s1 传参时间 ,s2当前时间 + */ + public static boolean compTime(Date s1, Date s2) {//比较两个年月 的大小 + Calendar cal = Calendar.getInstance(); + cal.setTime(s1); + int year = cal.get(Calendar.YEAR);//获取年份 + int month = cal.get(Calendar.MONTH);//获取月份 + int i1 = year * 100 + month;//返年份乘以100加上月份的值,因为月份最多2位数,所以年份乘以100可以获取一个唯一的年月数值 + + + Calendar cal1 = Calendar.getInstance(); + cal.setTime(s1); + int year1 = cal.get(Calendar.YEAR);//获取年份 + int month1 = cal.get(Calendar.MONTH);//获取月份 + int i2 = year1 * 100 + month1;//返年份乘以100加上月份的值,因为月份最多2位数,所以年份乘以100可以获取一个唯一的年月数值 + + return i1 < i2; + } + + + /** + * 比较时分的大小 + */ + public static boolean compTime1(String s1, String s2) {//比较时分的大小 + try { + if (s1.indexOf(":") < 0 || s1.indexOf(":") < 0) { + System.out.println("格式不正确"); + } else { + String[] array1 = s1.split(":"); + int total1 = Integer.valueOf(array1[0]) * 3600 + Integer.valueOf(array1[1]) * 60; + String[] array2 = s2.split(":"); + int total2 = Integer.valueOf(array2[0]) * 3600 + Integer.valueOf(array2[1]) * 60; + return total1 < total2; + } + } catch (NumberFormatException e) { + // TODO Auto-generated catch block + return true; + } + return false; + } + + + /** + * 比较时分秒的大小 + */ + public static boolean compTime2(String s1, String s2) {//比较时分秒的大小 + try { + if (s1.indexOf(":") < 0 || s1.indexOf(":") < 0) { + System.out.println("格式不正确"); + } else { + String[] array1 = s1.split(":"); + int total1 = Integer.valueOf(array1[0]) * 3600 + Integer.valueOf(array1[1]) * 60 + Integer.valueOf(array1[2]); + String[] array2 = s2.split(":"); + int total2 = Integer.valueOf(array2[0]) * 3600 + Integer.valueOf(array2[1]) * 60 + Integer.valueOf(array2[2]); + return total1 - total2 > 0 ? true : false; + } + } catch (NumberFormatException e) { + // TODO Auto-generated catch block + return true; + } + return false; + } + + public static final String parseDateToStr(final String format, final Date date) { + return new SimpleDateFormat(format).format(date); + } + + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Encodes.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Encodes.java new file mode 100644 index 0000000..9165c4f --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Encodes.java @@ -0,0 +1,188 @@ +package com.yxt.common.base.utils; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.tomcat.util.codec.binary.Base64; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * 封装各种格式的编码解码工具类. 1.Commons-Codec的 hex/base64 编码 2.自制的base62 编码 + * 3.Commons-Lang的xml/html escape 4.JDK提供的URLEncoder + * + * @author dimengzhe + * @date 2020/9/11 13:38 + * @description 编码解码工具类 + */ + +public class Encodes { + + private static final String DEFAULT_URL_ENCODING = "UTF-8"; + private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); + private static final String SALT="jlzx@yxt?"; + /** + * Hex编码. + */ + public static String encodeHex(byte[] input) { + return new String(Hex.encodeHex(input)); + } + + /** + * Hex解码. + */ + public static byte[] decodeHex(String input) { + try { + return Hex.decodeHex(input.toCharArray()); + } catch (DecoderException e) { + throw Exceptions.unchecked(e); + } + } + + /** + * Base64编码. + */ + public static String encodeBase64(byte[] input) { + return new String(Base64.encodeBase64(input)); + } + + /** + * Base64编码. + */ + public static String encodeBase64(String input) { + try { + return new String(Base64.encodeBase64(input.getBytes(DEFAULT_URL_ENCODING))); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + + /** + * Base64解码. + */ + public static byte[] decodeBase64(String input) { + return Base64.decodeBase64(input.getBytes()); + } + + /** + * Base64解码. + */ + public static String decodeBase64String(String input) { + try { + return new String(Base64.decodeBase64(input.getBytes()), DEFAULT_URL_ENCODING); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + + /** + * Base62编码。 + */ + public static String encodeBase62(byte[] input) { + char[] chars = new char[input.length]; + for (int i = 0; i < input.length; i++) { + chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)]; + } + return new String(chars); + } + + /** + * Html 转码. + */ + public static String escapeHtml(String html) { + return StringEscapeUtils.escapeHtml4(html); + } + + /** + * Html 解码. + */ + public static String unescapeHtml(String htmlEscaped) { + return StringEscapeUtils.unescapeHtml4(htmlEscaped); + } + + /** + * Xml 转码. + */ + public static String escapeXml(String xml) { + return StringEscapeUtils.escapeXml10(xml); + } + + /** + * Xml 解码. + */ + public static String unescapeXml(String xmlEscaped) { + return StringEscapeUtils.unescapeXml(xmlEscaped); + } + + /** + * URL 编码, Encode默认为UTF-8. + */ + public static String urlEncode(String part) { + try { + return URLEncoder.encode(part, DEFAULT_URL_ENCODING); + } catch (UnsupportedEncodingException e) { + throw Exceptions.unchecked(e); + } + } + + /** + * URL 解码, Encode默认为UTF-8. + */ + public static String urlDecode(String part) { + + try { + return URLDecoder.decode(part, DEFAULT_URL_ENCODING); + } catch (UnsupportedEncodingException e) { + throw Exceptions.unchecked(e); + } + } + + public static String md5(String str) { + return digest("MD5", str+SALT); + } + + public static String sha1(CharSequence cs) { + return digest("SHA1", cs); + } + + public static String digest(String algorithm, CharSequence cs) { + return digest(algorithm, StringUtils.getBytesUTF8(null == cs ? "" : cs), null, 1); + } + + public static String digest(String algorithm, byte[] bytes, byte[] salt, int iterations) { + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + if (salt != null) { + md.update(salt); + } + byte[] hashBytes = md.digest(bytes); + for (int i = 1; i < iterations; i++) { + md.reset(); + hashBytes = md.digest(hashBytes); + } + return fixedHexString(hashBytes); + } catch (NoSuchAlgorithmException e) { + throw Exceptions.unchecked(e); + } + } + + public static String fixedHexString(byte[] hashBytes) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < hashBytes.length; i++) { + sb.append(Integer.toString((hashBytes[i] & 0xFF) + 256, 16).substring(1)); + } + + return sb.toString(); + } + + public static String md5(String str, boolean isShort) { + if (isShort) { + return md5(str).substring(8, 24); + } + return md5(str); + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Exceptions.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Exceptions.java new file mode 100644 index 0000000..565cb48 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Exceptions.java @@ -0,0 +1,74 @@ +package com.yxt.common.base.utils; + +import javax.servlet.http.HttpServletRequest; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; + +/** + * 关于异常的工具类. + * + * @author dimengzhe + * @date 2020/9/11 13:44 + * @description + */ + +public class Exceptions { + + /** + * 将CheckedException转换为UncheckedException. + */ + public static RuntimeException unchecked(Throwable e) { + if ((e instanceof RuntimeException)) { + return (RuntimeException) e; + } + if ((e instanceof InvocationTargetException)) { + return unchecked(((InvocationTargetException) e).getTargetException()); + } + return new RuntimeException(e); + } + + /** + * 将ErrorStack转化为String. + */ + public static String getStackTraceAsString(Throwable e) { + if (e == null) { + return ""; + } + StringWriter stringWriter = new StringWriter(); + e.printStackTrace(new PrintWriter(stringWriter)); + return stringWriter.toString(); + } + + /** + * 判断异常是否由某些底层的异常引起. + */ + public static boolean isCausedBy(Exception ex, Class... causeExceptionClasses) { + Throwable cause = ex.getCause(); + while (cause != null) { + for (Class causeClass : causeExceptionClasses) { + if (causeClass.isInstance(cause)) { + return true; + } + } + cause = cause.getCause(); + } + return false; + } + + /** + * 在request中获取异常类 + * + * @param request + * @return + */ + public static Throwable getThrowable(HttpServletRequest request) { + Throwable ex = null; + if (request.getAttribute("exception") != null) { + ex = (Throwable) request.getAttribute("exception"); + } else if (request.getAttribute("javax.servlet.error.exception") != null) { + ex = (Throwable) request.getAttribute("javax.servlet.error.exception"); + } + return ex; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/ExportExcelUtils.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/ExportExcelUtils.java new file mode 100644 index 0000000..069943f --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/ExportExcelUtils.java @@ -0,0 +1,279 @@ +package com.yxt.common.base.utils; + +import com.yxt.common.core.utils.ExportEntityMap; +import org.apache.poi.hssf.usermodel.HeaderFooter; +import org.apache.poi.hssf.usermodel.*; +import org.apache.poi.ss.usermodel.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * @author dimengzhe + * @date 2020/9/30 17:02 + * @description + */ + +public class ExportExcelUtils { + + public static void export(String excelName, List list, Class c, HttpServletResponse response) { + // 设置日期格式 + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + // 设置默认文件名为当前时间:年月日时分秒 + if (excelName == null || excelName == "") { + excelName = df.format(new Date()).toString(); + } else { + excelName = excelName + df.format(new Date()).toString(); + } + // 设置response头信息 + response.reset(); + // 改成输出excel文件 + response.setContentType("application/vnd.ms-excel"); + // response.setHeader("Content-disposition", "attachment; filename=" +// + new String(excelName.getBytes("gb2312"), "ISO-8859-1") + ".xls"); + response.setHeader("Content-Disposition", "attachment;fileName=" + + excelName+".xls"); + + try { + //创建一个WorkBook,对应一个Excel文件 + HSSFWorkbook wb = new HSSFWorkbook(); + //在Workbook中,创建一个sheet,对应Excel中的工作薄(sheet) + HSSFSheet sheet = wb.createSheet(excelName); + //设置 边距、页眉、页脚 + HSSFPrintSetup printSetup = sheet.getPrintSetup(); + //打印方向,true:横向,false:纵向(默认) + printSetup.setLandscape(true); + printSetup.setHeaderMargin(0.2); + printSetup.setFooterMargin(0.2); + //设置打印缩放为88% + //printSetup.setScale((short) 55); + printSetup.setFitHeight((short) 0); + printSetup.setFitWidth((short) 1); + // printSetup.setLeftToRight(true);//列从左向右显示② + // 纸张 + printSetup.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE); + // 页边距(下) + sheet.setMargin(HSSFSheet.BottomMargin, (double) 0.8); + // 页边距(左) + sheet.setMargin(HSSFSheet.LeftMargin, (double) 0); + // 页边距(右) + sheet.setMargin(HSSFSheet.RightMargin, (double) 0); + // 页边距(上) + sheet.setMargin(HSSFSheet.TopMargin, (double) 0.8); + //设置打印页面为水平居中 + sheet.setHorizontallyCenter(true); + sheet.setVerticallyCenter(true); + sheet.setAutobreaks(false); + sheet.setFitToPage(false); + Footer footer = sheet.getFooter(); + //设置页数 + footer.setCenter("第" + HeaderFooter.page() + "页,共 " + HeaderFooter.numPages() + "页"); + Header header = sheet.getHeader(); + //自定义页眉,并设置页眉 左中右显示信息 + //居中 +// header.setCenter("Center Header"); + //靠左 + header.setLeft(HSSFHeader.font("宋体", "") + + HSSFHeader.fontSize((short) 16) + excelName + ".xls"); + //靠右 +// header.setRight(HSSFHeader.font("Stencil-Normal", "Italic") + +// HSSFHeader.fontSize((short) 16) + "Right w/ Stencil-Normal Italic font and size 16"); + + //创建单元格,并设置值表头 设置表头居中 + HSSFCellStyle style = wb.createCellStyle(); + //设置边框 + //下边框 + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + //上边框 + style.setBorderTop(BorderStyle.THIN); + //右边框 + style.setBorderRight(BorderStyle.THIN); + //自动换行 + //style.setWrapText(true); + //创建一个居中格式 + style.setAlignment(HorizontalAlignment.CENTER); + //上下居中 + style.setVerticalAlignment(VerticalAlignment.CENTER); + //设置字体 + HSSFFont font = wb.createFont(); + font.setFontName("宋体"); + + style.setFont(font); + // 填充工作表 + //获取需要转出的excel表头的map字段 + LinkedHashMap fieldMap = new LinkedHashMap<>(); + //循环注解里面的值 填入Link集合 + Field[] declaredFields = c.getDeclaredFields(); + + for (Field declaredField : declaredFields) { + //获取注解对象 + ExportEntityMap declaredAnnotation = declaredField.getDeclaredAnnotation(ExportEntityMap.class); + if (declaredAnnotation != null) { + fieldMap.put(declaredAnnotation.EnName(), declaredAnnotation.CnName()); + } + } + fillSheet(sheet, list, fieldMap, style); + //将文件输出 + OutputStream ouputStream = response.getOutputStream(); + wb.write(ouputStream); + ouputStream.flush(); + ouputStream.close(); + } catch (Exception e) { + System.err.println("导出Excel失败!"); + System.err.println(e.getMessage()); + } + } + + /** + * 根据字段名获取字段对象 + * + * @param fieldName 字段名 + * @param clazz 包含该字段的类 + * @return 字段 + */ + public static Field getFieldByName(String fieldName, Class clazz) { + //logger.info("根据字段名获取字段对象:getFieldByName()"); + // 拿到本类的所有字段 + Field[] selfFields = clazz.getDeclaredFields(); + // 如果本类中存在该字段,则返回 + for (Field field : selfFields) { + //如果本类中存在该字段,则返回 + if (field.getName().equals(fieldName)) { + return field; + } + } + // 否则,查看父类中是否存在此字段,如果有则返回 + Class superClazz = clazz.getSuperclass(); + if (superClazz != null && superClazz != Object.class) { + //递归 + return getFieldByName(fieldName, superClazz); + } + // 如果本类和父类都没有,则返回空 + return null; + } + + /** + * 根据字段名获取字段值 + * + * @param fieldName 字段名 + * @param o 对象 + * @return 字段值 + * @throws Exception 异常 + */ + public static Object getFieldValueByName(String fieldName, Object o) + throws Exception { + //logger.info("根据字段名获取字段值:getFieldValueByName()"); + Object value = null; + //根据字段名得到字段对象 + Field field = getFieldByName(fieldName, o.getClass()); + //如果该字段存在,则取出该字段的值 + if (field != null) { + //类中的成员变量为private,在类外边使用属性值,故必须进行此操作 + field.setAccessible(true); + //获取当前对象中当前Field的value + value = field.get(o); + } else { + throw new Exception(o.getClass().getSimpleName() + "类不存在字段名 " + + fieldName); + } + return value; + } + + /** + * 根据带路径或不带路径的属性名获取属性值,即接受简单属性名, + * 如userName等,又接受带路径的属性名,如student.department.name等 + * + * @param fieldNameSequence 带路径的属性名或简单属性名 + * @param o 对象 + * @return 属性值 + * @throws Exception 异常 + */ + public static Object getFieldValueByNameSequence(String fieldNameSequence, + Object o) throws Exception { + // logger.info("根据带路径或不带路径的属性名获取属性值,即接受简单属性名:getFieldValueByNameSequence()"); + Object value = null; + // 将fieldNameSequence进行拆分 + String[] attributes = fieldNameSequence.split("\\."); + if (attributes.length == 1) { + value = getFieldValueByName(fieldNameSequence, o); + } else { + // 根据数组中第一个连接属性名获取连接属性对象,如student.department.name + Object fieldObj = getFieldValueByName(attributes[0], o); + //截取除第一个属性名之后的路径 + String subFieldNameSequence = fieldNameSequence + .substring(fieldNameSequence.indexOf(".") + 1); + //递归得到最终的属性对象的值 + value = getFieldValueByNameSequence(subFieldNameSequence, fieldObj); + } + return value; + } + + /** + * 向工作表中填充数据 + * + * @param sheet excel的工作表名称 + * @param list 数据源 + * @param fieldMap 中英文字段对应关系的Map + * @param style 表格中的格式 + * @throws Exception 异常 + */ + public static void fillSheet(HSSFSheet sheet, List list, + LinkedHashMap fieldMap, HSSFCellStyle style) throws Exception { + //logger.info("向工作表中填充数据:fillSheet()"); + // 定义存放英文字段名和中文字段名的数组 + String[] enFields = new String[fieldMap.size()]; + String[] cnFields = new String[fieldMap.size()]; + // 填充数组 + int count = 0; + for (Map.Entry entry : fieldMap.entrySet()) { + enFields[count] = entry.getKey(); + cnFields[count] = entry.getValue(); + count++; + } + //存储最大列宽 + Map maxWidth = new HashMap<>(); + HSSFRow row = sheet.createRow((int) 0); + HSSFCell cell = null; + // 填充表头 + for (int i = 0; i < cnFields.length; i++) { + cell = row.createCell(i); + cell.setCellValue(cnFields[i]); + cell.setCellStyle(style); + sheet.autoSizeColumn(i); + //设置自适应宽高 + maxWidth.put(i, cell.getStringCellValue().getBytes().length * 256 + 200); + } + // 填充内容 + for (int index = 0; index < list.size(); index++) { + row = sheet.createRow(index + 1); + // 获取单个对象 + T item = list.get(index); + int j = 0; + for (int i = 0; i < enFields.length; i++) { + HSSFCell createCell = row.createCell(j); + Object objValue = getFieldValueByNameSequence(enFields[i], item); + String fieldValue = objValue == null ? "" : objValue.toString(); + cell = row.createCell(i); + createCell.setCellValue(fieldValue); + + int length = createCell.getStringCellValue().getBytes().length * 256 + 200; + //这里把宽度最大限制到15000 + if (length > 15000) { + length = 15000; + } + maxWidth.put(j, Math.max(length, maxWidth.get(j))); + j++; + createCell.setCellStyle(style); + } + } + + // 列宽自适应 + for (int i = 0; i < cnFields.length; i++) { + sheet.setColumnWidth(i, maxWidth.get(i)); + } + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/GlobalConstants.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/GlobalConstants.java new file mode 100644 index 0000000..e4cbb70 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/GlobalConstants.java @@ -0,0 +1,32 @@ +package com.yxt.common.base.utils; + +import org.springframework.beans.factory.annotation.Value; + +import java.util.Collections; +import java.util.Map; + +/** + * @author dimengzhe + * @date 2020/9/10 9:25 + * @description + */ + +public class GlobalConstants { + + private static Map map = Collections.emptyMap(); + + public static Object get(String key) { + return map.get(key); + } + + public static void set(String key, Object obj) { + map.put(key, obj); + } + + public static String image_url_prefix = "http://120.46.131.15:8111/upload"; + public static String image_upload_path = "D:\\\\anrui\\\\upload\\\\"; + public static String cms_template_path; + public static String Real_Path_Root = "/"; + public static String audio_path; + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpStatus.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpStatus.java new file mode 100644 index 0000000..98b4587 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpStatus.java @@ -0,0 +1,15 @@ +package com.yxt.common.base.utils; + +/** + * @author dimengzhe + * @date 2020/9/18 9:26 + * @description + */ + +public class HttpStatus { + + public static final int SUCCESS = 200; + public static final int ERROR = 100; + + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpStatusEnum.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpStatusEnum.java new file mode 100644 index 0000000..617f258 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpStatusEnum.java @@ -0,0 +1,69 @@ +package com.yxt.common.base.utils; + +/** + * @author 10095 + * @version 1.0 + * @Description: http请求结果枚举类 + * @date 2022/02/25 + */ +public enum HttpStatusEnum { + + /** + * http 状态码 + */ + SUCCESS("200", "操作成功"), + CREATED("201", "已创建"), + ACCEPTED("202", "已接受"), + NON_AUTHORITATIVE_INFORMATION("203", "非授权信息"), + NO_CONTENT("204", "无内容"), + RESET_CONTENT("205", "重置内容"), + PARTIAL_CONTENT("206", "部分内容"), + ERROR("400", "操作失败"), + AUTH_ERROR("401", "未授权"), + FORBIDDEN("403", "禁止"), + NOT_FOUND("404", "资源不存在"), + METHOD_NOT_ALLOWED("405", "方法禁用"), + NOT_ACCEPTABLE("406", "不接受"), + PROXY_AUTHENTICATION_REQUIRED("407", "需要代理授权"), + REQUEST_TIMEOUT("408", "请求超时"), + CONFLICT("409", "冲突"), + GONE("410", "已删除"), + LENGTH_REQUIRED("411", "需要有效长度"), + PRECONDITION_FAILED("412", "未满足前提条件"), + REQUEST_ENTITY_TOO_LARGE("413", "请求实体过大"), + REQUEST_URI_TOO_LONG("414", "请求的 URI 过长"), + UNSUPPORTED_MEDIA_TYPE("415", "不支持的媒体类型"), + REQUESTED_RANGE_NOT_SATISFIABLE("416", "请求范围不符合要求"), + EXPECTATION_FAILED("417", "未满足期望值"), + SYSTEM_ERROR("500", "服务器异常,请稍后再试"), + NOT_IMPLEMENTED("501", "尚未实施"), + BAD_GATEWAY("502", "错误网关"), + SERVICE_UNAVAILABLE("503", "服务不可用"), + GATEWAY_TIMEOUT("504", "上游服务器超时"), + HTTP_VERSION_NOT_SUPPORTED("505", "HTTP 版本不受支持"), + + /* + * 自己定义的状态码 + */ + CRM_ERROR_EXIST("511", "该手机号客户已是您的客户,请跳转至信息维护"), + CRM_ERROR_NOTBELONG("512", "不是当前用户的客户"), + CRM_ERROR_WXEXIST("513", "该微信号客户已是您的客户,如需更改,请到客户信息中修改"), + ; + + + private String code; + private String msg; + + HttpStatusEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } + + public String getCode() { + return code; + } + + public String getMsg() { + return msg; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpUtils.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpUtils.java new file mode 100644 index 0000000..f401e11 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/HttpUtils.java @@ -0,0 +1,100 @@ +package com.yxt.common.base.utils; + +import org.apache.http.HttpEntity; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.util.Map; + +/** + * @author dimengzhe + * @date 2021/7/1 14:23 + * @description + */ + +public class HttpUtils { + + /** + * 向指定 URL 发送POST方法的请求(数据格式为json) + * + * @param url 发送请求的 URL + * @param resultOne 请求头参数集合 + * @param json 请求参数,请求参数为json的形式。 + * @return 所代表远程资源的响应结果 + */ + public static String sendPost(String url, Map resultOne, String json) { + CloseableHttpClient httpClient = null; + CloseableHttpResponse httpResponse = null; + String result = ""; + // 创建httpClient实例 + httpClient = HttpClients.createDefault(); + // 创建httpPost远程连接实例 + HttpPost httpPost = new HttpPost(url); + + // 配置请求参数实例 + RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)// 设置连接主机服务超时时间 + .setConnectionRequestTimeout(35000)// 设置连接请求超时时间 + .setSocketTimeout(60000)// 设置读取数据连接超时时间 + .build(); + // 为httpPost实例设置配置 + httpPost.setConfig(requestConfig); + // 设置请求头 + httpPost.addHeader("Authorization", resultOne.get("Authorization")); + httpPost.addHeader("Content-Type", resultOne.get("Content-Type")); + httpPost.addHeader("Host", resultOne.get("Host")); + httpPost.addHeader("X-TC-Timestamp", resultOne.get("X-TC-Timestamp")); + httpPost.addHeader("X-TC-Version", resultOne.get("X-TC-Version")); + httpPost.addHeader("X-TC-Action", resultOne.get("X-TC-Action")); + httpPost.addHeader("X-TC-Region", resultOne.get("X-TC-Region")); + + ContentType contentType = ContentType.create("application/json"); + // 为httpPost设置封装好的请求参数 + try { + //设置参数的content-type格式 + httpPost.setEntity(new StringEntity(json, contentType)); + //此方式参数content-type为application/x-www-form-urlencoded,源码中默认实现的 + //httpPost.setEntity(new UrlEncodedFormEntity(nvps,"utf-8")); + } catch (Exception e) { + e.printStackTrace(); + } + try { + // httpClient对象执行post请求,并返回响应参数对象 + httpResponse = httpClient.execute(httpPost); +// // 从响应对象中获取响应内容 + HttpEntity entity = httpResponse.getEntity(); + result = EntityUtils.toString(entity); + + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + // 关闭资源 + if (null != httpResponse) { + try { + httpResponse.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != httpClient) { + try { + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return result; + } + + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JPushServer.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JPushServer.java new file mode 100644 index 0000000..cdac8a4 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JPushServer.java @@ -0,0 +1,239 @@ +package com.yxt.common.base.utils; + +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jpush.api.JPushClient; +import cn.jpush.api.push.PushResult; +import cn.jpush.api.push.model.*; +import cn.jpush.api.push.model.audience.Audience; +import cn.jpush.api.push.model.notification.*; +import com.google.gson.JsonObject; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Description 极光推送 + * @Author liuguohui + * @Date 2021/9/2 + */ +public class JPushServer { + + protected static final String APP_KEY = "a46600903b1e0815dc8ed550"; + protected static final String MASTER_SECRET = "e619b4b223298d717e98d071"; + protected static final String URIACTIVITY = "com.anrui.android.activity.MessageTypeDetailsActivity"; + protected static final Map thirdPartyChannel = third_party_channelMap(); + + public static final String TAG = "tag_api"; + + public static void main(String[] args) { + String title = "标题2"; + String content = "内容2"; + String msg_type = "4598b44e-52df-4d83-b012-4db1ea7e5ed7"; + String name = "系统消息"; +// sendPushAll(title, content, msg_type, name); // 广播 + sendPushAlias(title, content, msg_type, name, "23","26","66"); // 别名 + } + + /** + * 推送请求下发通道 的数据 + * @return + */ + private static Map third_party_channelMap(){ + Map thirdPartyChannel = new HashMap<>(); + JsonObject xiaomiObj = new JsonObject(); + JsonObject huaweiObj = new JsonObject(); + JsonObject oppoObj = new JsonObject(); + JsonObject vivoObj = new JsonObject(); + JsonObject meizuObj = new JsonObject(); + JsonObject fcmObj = new JsonObject(); + // secondary_push 表示推送优先走极光,极光不在线再走厂商,厂商作为辅助; + xiaomiObj.addProperty("distribution","secondary_push"); + huaweiObj.addProperty("distribution","secondary_push"); + oppoObj.addProperty("distribution","secondary_push"); + vivoObj.addProperty("distribution","secondary_push"); +// meizuObj.addProperty("distribution","secondary_push"); +// fcmObj.addProperty("distribution","secondary_push"); + thirdPartyChannel.put("xiaomi", xiaomiObj); + thirdPartyChannel.put("huawei", huaweiObj); + thirdPartyChannel.put("oppo", oppoObj); + thirdPartyChannel.put("vivo", vivoObj); +// thirdPartyChannel.put("meizu", meizuObj); +// thirdPartyChannel.put("fcm", fcmObj); + return thirdPartyChannel; + } + + /** + * 消息推送(广播) + * @param title 标题 + * @param content 内容 + * @param msg_type 消息类别 + */ + public static void sendPushAll(String title, String content, String msg_type, String name) { + ClientConfig clientConfig = ClientConfig.getInstance(); + final JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, clientConfig); + Map extras = new HashMap<>(); + extras.put("class_name", URIACTIVITY); + extras.put("msg_type", msg_type); + extras.put("name", name); +// String authCode = ServiceHelper.getBasicAuthorization(APP_KEY, MASTER_SECRET); + // 在这里您可以使用 NativeHttpClient 或 NettyHttpClient 或 ApacheHttpClient。 + // 调用 setHttpClient 设置 httpClient, + // 如果不调用此方法,默认 httpClient 将使用 NativeHttpClient。 +// ApacheHttpClient httpClient = new ApacheHttpClient(authCode, null, clientConfig); +// NettyHttpClient httpClient =new NettyHttpClient(authCode, null, clientConfig); +// jpushClient.getPushClient().setHttpClient(httpClient); + + // 对于推送,您需要做的就是构建 PushPayload 对象。 + final PushPayload payload = buildPushObject_android_and_iosAll(title, content, URIACTIVITY, extras); +// PushPayload payload = buildPushObject_all_alias_alert(); + try { + PushResult result = jpushClient.sendPush(payload); + System.out.println("Got result - " + result); + // 如果使用 NettyHttpClient,需要手动调用 close 方法退出进程 + // jpushClient.close(); + } catch (APIConnectionException e) { + System.out.println("Connection error. Should retry later. "+e); + System.out.println("Sendno: " + payload.getSendno()); + + } catch (APIRequestException e) { + System.out.println("Error response from JPush server. Should review and fix it. "+ e); + System.out.println("HTTP Status: " + e.getStatus()); + System.out.println("Error Code: " + e.getErrorCode()); + System.out.println("Error Message: " + e.getErrorMessage()); + System.out.println("Msg ID: " + e.getMsgId()); + System.out.println("Sendno: " + payload.getSendno()); + } + } + + /** + * 消息推送(使用别名) + * @param title 标题 + * @param content 内容 + * @param msg_type 消息类别 + */ + public static void sendPushAlias(String title, String content, String msg_type, String name, String... alias) { + Map extras = new HashMap<>(); + extras.put("class_name", URIACTIVITY); + extras.put("msg_type", msg_type); + extras.put("name", name); + ClientConfig clientConfig = ClientConfig.getInstance(); + final JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, clientConfig); + + final PushPayload payload = buildPushObject_android_and_iosAlias(title, content, URIACTIVITY, extras, alias); + try { + PushResult result = jpushClient.sendPush(payload); + System.out.println("Got result - " + result); + // 如果使用 NettyHttpClient,需要手动调用 close 方法退出进程 + // jpushClient.close(); + } catch (APIConnectionException e) { + System.out.println("Connection error. Should retry later. "+e); + System.out.println("Sendno: " + payload.getSendno()); + + } catch (APIRequestException e) { + System.out.println("Error response from JPush server. Should review and fix it. "+ e); + System.out.println("HTTP Status: " + e.getStatus()); + System.out.println("Error Code: " + e.getErrorCode()); + System.out.println("Error Message: " + e.getErrorMessage()); + System.out.println("Msg ID: " + e.getMsgId()); + System.out.println("Sendno: " + payload.getSendno()); + } + } + + /** + * (广播) + * @param title 标题 + * @param content 内容 + * @param uriActivity url + * @param extras 扩展字段 + * @return + */ + private static PushPayload buildPushObject_android_and_iosAll(String title, String content, String uriActivity, Map extras) { + return PushPayload.newBuilder() + .setPlatform(Platform.android_ios()) // 推送平台设置 + .setAudience(Audience.all()) // 推送设备指定(所有) +// .setMessage(Message.newBuilder() // 消息内容体。 +// .setMsgContent(content) +// .build()) + .setNotification(Notification.newBuilder() // 消息内容体。 + .setAlert(content) // 通知内容 + .addPlatformNotification(AndroidNotification.newBuilder() // 安卓 + .setTitle(title) // 通知标题 + .addExtras(extras) // 扩展字段 + .setUriActivity(uriActivity) // 指定跳转页面 + .setUriAction(uriActivity) // 指定跳转页面 + .build()) + .addPlatformNotification(IosNotification.newBuilder() // ios + .incrBadge(1) + .addExtra("extra_key", "extra_value") + .build()) + .build()) +// .setSMS(SMS.newBuilder() +// .setDelayTime(1000) +// .setTempID(2000) +// .addPara("Test", 1) +// .setActiveFilter(true) +// .build()) +// .setNotification3rd(Notification3rd.newBuilder() // 自定义消息转厂商通知内容体。与 message 一起使用 +// .setContent("Hi, JPush") +// .setTitle("msg testing") +// .setChannelId("channel1001") +// .setUriActivity("cn.jpush.android.ui.OpenClickActivity") +// .setUriAction("cn.jpush.android.intent.CONNECTION") +// .setBadgeAddNum(1) +// .setBadgeClass("com.test.badge.MainActivity") +// .setSound("sound") +// .addExtra("news_id", 124) +// .addExtra("my_key", "a value") +// .build()) + .setInappMessage(InappMessage.newBuilder() + .setInappMessage(true) + .build()) + .setOptions(Options.newBuilder() // 推送参数 + .setThirdPartyChannelV2(thirdPartyChannel) // 推送请求下发通道 + .setApnsProduction(false) + .setTimeToLive(43200) + .build()) + .build(); + } + + /** + * (别名) + * @param title 标题 + * @param content 内容 + * @param uriActivity url + * @param extras 扩展字段 + * @return + */ + private static PushPayload buildPushObject_android_and_iosAlias(String title, String content, String uriActivity, Map extras, String... alias) { + return PushPayload.newBuilder() + .setPlatform(Platform.android_ios()) // 推送平台设置 + .setAudience(Audience.alias(alias)) // 推送设备指定(别名) +// .setMessage(Message.newBuilder() // 消息内容体。 +// .setMsgContent(content) +// .build()) + .setNotification(Notification.newBuilder() // 消息内容体。 + .setAlert(content) // 通知内容 + .addPlatformNotification(AndroidNotification.newBuilder() // 安卓 + .setTitle(title) // 通知标题 + .addExtras(extras) // 扩展字段 + .setUriActivity(uriActivity) // 指定跳转页面 + .setUriAction(uriActivity) // 指定跳转页面 + .build()) + .addPlatformNotification(IosNotification.newBuilder() // ios + .incrBadge(1) + .addExtra("extra_key", "extra_value") + .build()) + .build()) + .setInappMessage(InappMessage.newBuilder() + .setInappMessage(true) + .build()) + .setOptions(Options.newBuilder() // 推送参数 + .setThirdPartyChannelV2(thirdPartyChannel) // 推送请求下发通道 + .setApnsProduction(false) + .setTimeToLive(43200) + .build()) + .build(); + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JWTUtil.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JWTUtil.java new file mode 100644 index 0000000..09de1e1 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JWTUtil.java @@ -0,0 +1,54 @@ +package com.yxt.common.base.utils; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; + +@Data +@Slf4j +public class JWTUtil { + + //private static final String TOKEN_SECRET = "eyJhbGciOiJIUzI1NiJ9"; + private static final String TOKEN_SECRET = "yXtJLzxh2bGciO5iJIUzI1NiJ9"; + private static final String ISS = "WBK"; + private static final String USERNO = "userNo"; + // private static final Long TIME = 60 * 1000L; // 1min + private static final Long TIME = 24 * 3600 * 1000L; // 1天 + + //创建Token + public static String create(String userNo) { + try { + return JWT + .create() + .withIssuer(ISS) + .withClaim(USERNO, userNo) + .withExpiresAt(new Date(System.currentTimeMillis() + TIME)) + .sign(Algorithm.HMAC256(TOKEN_SECRET)); + } catch (Exception e) { + log.error("JWT生成失败", e); + return e.getMessage(); + } + } + + //解析Token + public static DecodedJWT verify(String token) throws Exception { + return JWT + .require(Algorithm.HMAC256(TOKEN_SECRET)) + .withIssuer(ISS) + .build() + .verify(token); + } + + //根据解析生成的Token返回userNo + public static Long getUserNo(DecodedJWT decodedJWT) { + return Long.parseLong(decodedJWT.getClaim(USERNO).asString()); + } + + public static String getUserSid(DecodedJWT decodedJWT) { + return decodedJWT.getClaim(USERNO).asString(); + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JacobPDFConverter.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JacobPDFConverter.java new file mode 100644 index 0000000..71625ab --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JacobPDFConverter.java @@ -0,0 +1,114 @@ +/* +package com.yxt.common.base.utils; + +import com.jacob.activeX.ActiveXComponent; +import com.jacob.com.ComFailException; +import com.jacob.com.ComThread; +import com.jacob.com.Dispatch; +import org.springframework.stereotype.Component; + +import java.io.File; + +*/ +/** + * @author dimengzhe + * @date 2020/12/31 15:18 + * @description + *//* + +@Component +public class JacobPDFConverter { + + private static final int wdFormatPDF = 17; + static final int wdDoNotSaveChanges = 0;// 不保存待定的更改。 + + public static void wordToPdf(String wordpath, String pdfpath) { + System.out.println("启动Word..."); + long start = System.currentTimeMillis(); + ActiveXComponent app = null; + try { + //打开word应用程序 + app = new ActiveXComponent("Word.Application"); + //设置应用操作是文档不在明面上显示,只在后台静默处理。 + app.setProperty("Visible", false); + //获得文档集合,用来操作我们需要处理的文档. + Dispatch docs = app.getProperty("Documents").toDispatch(); + System.out.println("打开文档..." + wordpath); + //打开word文档 + Dispatch doc = Dispatch.call(docs, + "Open", + // FileName + wordpath, + // ConfirmConversions + false, + // ReadOnly + true + ).toDispatch(); + System.out.println("转换文档到PDF..." + pdfpath); + File tofile = new File(pdfpath); + //创建存放pdf的文件夹 + if (tofile.exists()) { + tofile.delete(); + } + //将word另存为pdf + Dispatch.call(doc, + "SaveAs", + // FileName + pdfpath, + wdFormatPDF); + //关闭word文档 + Dispatch.call(doc, "Close", false); + long end = System.currentTimeMillis(); + System.out.println("转换完成..用时:" + (end - start) + "ms."); + } catch (Exception e) { + System.out.println("========Error:文档转换失败:" + e.getMessage()); + } finally { + if (app != null){ + app.invoke("Quit", wdDoNotSaveChanges); + } + } + } + + + public static void word2PDF(String inputFile, String pdfFile) { + ActiveXComponent app = null; + Dispatch doc = null; + try { + ComThread.InitSTA(); + //打开word应用程序 + app = new ActiveXComponent("Word.Application"); + //设置word不可见 + app.setProperty("Visible", false); + //获得word中所有打开的文档,返回Documents对象 + Dispatch docs = app.getProperty("Documents").toDispatch(); + //调用Documents对象中Open方法打开文档,并返回打开的文档对象Document + doc = Dispatch.call(docs, + "Open", + inputFile, + false, + true + ).toDispatch(); + Dispatch.call(doc, + "ExportAsFixedFormat", + pdfFile, + //word保存为pdf格式宏,值为17 + wdFormatPDF + ); + } catch (ComFailException e) { + + } catch (Exception e) { + + } finally { + if (doc != null) { + //关闭文档 + Dispatch.call(doc, "Close", false); + } + if (app != null) { + //关闭word应用程序 + app.invoke("Quit", 0); + } + ComThread.Release(); + } + } +} +*/ diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JsonUtilJackson.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JsonUtilJackson.java new file mode 100644 index 0000000..a749499 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/JsonUtilJackson.java @@ -0,0 +1,110 @@ +/********************************************************* + ********************************************************* + ******************** ******************* + ************* ************ + ******* _oo0oo_ ******* + *** o8888888o *** + * 88" . "88 * + * (| -_- |) * + * 0\ = /0 * + * ___/`---'\___ * + * .' \\| |// '. * + * / \\||| : |||// \ * + * / _||||| -:- |||||- \ * + * | | \\\ - /// | | * + * | \_| ''\---/'' |_/ | * + * \ .-\__ '-' ___/-. / * + * ___'. .' /--.--\ `. .'___ * + * ."" '< `.___\_<|>_/___.' >' "". * + * | | : `- \`.;`\ _ /`;.`/ - ` : | | * + * \ \ `_. \_ __\ /__ _/ .-` / / * + * =====`-.____`.___ \_____/___.-`___.-'===== * + * `=---=' * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *********__佛祖保佑__永无BUG__验收通过__钞票多多__********* + *********************************************************/ +package com.yxt.common.base.utils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.CollectionLikeType; + +/** + * Project: yxt-common
+ * File: JsonUtilJackson.java
+ * Class: com.yxt.common.base.utils.JsonUtilJackson
+ * Description: <描述类的功能>.
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2020/8/24 21:33
+ * + * @author liupopo + * @version 1.0 + * @since 1.0 + */ +public abstract class JsonUtilJackson { + + private static ObjectMapper MAPPER = new ObjectMapper(); + + public static Map str2map(String jsonStr) { + // JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, Object.class); + // 如果是Map类型 mapper.getTypeFactory().constructParametricType(HashMap.class,String.class, Bean.class); + JavaType javaType = MAPPER.getTypeFactory().constructParametricType(HashMap.class, String.class, Object.class); + Map map = null; + try { + map = MAPPER.readValue(jsonStr, javaType); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return map; + } + + public static List> str2list(String jsonStr) { + CollectionLikeType type = MAPPER.getTypeFactory().constructCollectionLikeType(List.class, Map.class); + List> listMap = null; + try { + listMap = MAPPER.readValue(jsonStr, type); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + // ObjectMapper mapper = new ObjectMapper(); + // JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, Object.class); + // //如果是Map类型 mapper.getTypeFactory().constructParametricType(HashMap.class,String.class, Bean.class); + // List lst = (List)mapper.readValue(jsonString, javaType); + return listMap; + } + + public static String obj2str(Object obj) { + String mjson = null; + try { + MAPPER.setSerializationInclusion(Include.ALWAYS); + mjson = MAPPER.writeValueAsString(obj); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return mjson; + } + + public static String obj2str(Object obj, Include inc) { + String mjson = null; + try { + MAPPER.setSerializationInclusion(inc); + mjson = MAPPER.writeValueAsString(obj); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return mjson; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/MsgWs.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/MsgWs.java new file mode 100644 index 0000000..34a17de --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/MsgWs.java @@ -0,0 +1,64 @@ +package com.yxt.common.base.utils; + +import org.apache.axis.client.Call; +import org.apache.axis.client.Service; +import org.apache.axis.encoding.XMLType; + +import javax.xml.namespace.QName; + +/** + * @author dimengzhe + * @date 2020/9/11 8:59 + * @description 发送短信调用接口 + */ +public class MsgWs { + private static String msgSign="【计量业务应用平台】"; +// private static String msgtitle="河北省计量业务应用平台提醒:"; + public static String MSG_NEWPWD="用户,您好!您的新密码为:"; + public static String MSG_VERIFY = "用户,您好!您注册的单位已审核通过,管理员的密码为:"; + public static String MSG_VERIFY_NO = "用户,您好!您注册的单位未审核通过,未通过原因:"; + public static String MSG_VERIFY_ONE = "用户,您好!您所填写的基本信息未通过。请及时登录系统修改。"; + + public static String MSG_USER_VERIFY = "用户,您好!您注册的个人信息已审核通过"; + public static String MSG_USER_VERIFY_NO = "用户,您好!您注册的个人信息未审核通过,未通过原因:"; + public static String MSG_ORG_STAFF = "尊敬的用户,您好!您绑定的单位已审核通过,可登陆系统进行查看"; + public static String MSG_USING = "尊敬的用户,您好!有待确认的单位信息需确认,请及时确认信息"; + + public static String MSG_OA_FILE_SEND = "用户,您好!协同办公中您收到一份文件,请查阅:"; + public static String SendWaitWorkMsg(String mobile, String msg) { + try { + + String urlname = "http://sdk1.mb345.com/ws/LinkWS.asmx"; + String soapActionURI = "http://tempuri.org/BatchSend"; + Service s = new Service(); + Call call = (Call) s.createCall(); + call.setTimeout(new Integer(5000)); + call.setUseSOAPAction(true); + call.setSOAPActionURI(soapActionURI); + // wsdl中接口名称 + call.setOperationName(new QName("http://tempuri.org/", "BatchSend")); + call.setTargetEndpointAddress(urlname); + call.addParameter(new QName("http://tempuri.org/", "CorpID"), XMLType.XSD_STRING, + javax.xml.rpc.ParameterMode.IN); + call.addParameter(new QName("http://tempuri.org/", "Pwd"), XMLType.XSD_STRING, + javax.xml.rpc.ParameterMode.IN); + call.addParameter(new QName("http://tempuri.org/", "Mobile"), XMLType.XSD_STRING, + javax.xml.rpc.ParameterMode.IN); + call.addParameter(new QName("http://tempuri.org/", "Content"), XMLType.XSD_STRING, + javax.xml.rpc.ParameterMode.IN); + call.addParameter(new QName("http://tempuri.org/", "Cell"), XMLType.XSD_STRING, + javax.xml.rpc.ParameterMode.IN); + call.addParameter(new QName("http://tempuri.org/", "SendTime"), XMLType.XSD_STRING, + javax.xml.rpc.ParameterMode.IN); +// String[] fn01 = {"YXT010045", "yuxintonghygl", mobile, msgtitle+msg+msgSign, "", ""}; +// String[] fn01 = {"YXT010045", "yuxintonghygl", mobile, msg+msgSign, "", ""}; + String[] fn01 = {"YXT004914", "hbsjljszx@0202", mobile, msg+msgSign, "", ""}; + String val = (String) call.invoke(fn01); + return val; + + } catch (Exception e) { + return e.getMessage(); + + } + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/PagerUtil.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/PagerUtil.java new file mode 100644 index 0000000..97b0540 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/PagerUtil.java @@ -0,0 +1,102 @@ +/********************************************************* + ********************************************************* + ******************** ******************* + ************* ************ + ******* _oo0oo_ ******* + *** o8888888o *** + * 88" . "88 * + * (| -_- |) * + * 0\ = /0 * + * ___/`---'\___ * + * .' \\| |// '. * + * / \\||| : |||// \ * + * / _||||| -:- |||||- \ * + * | | \\\ - /// | | * + * | \_| ''\---/'' |_/ | * + * \ .-\__ '-' ___/-. / * + * ___'. .' /--.--\ `. .'___ * + * ."" '< `.___\_<|>_/___.' >' "". * + * | | : `- \`.;`\ _ /`;.`/ - ` : | | * + * \ \ `_. \_ __\ /__ _/ .-` / / * + * =====`-.____`.___ \_____/___.-`___.-'===== * + * `=---=' * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *********__佛祖保佑__永无BUG__验收通过__钞票多多__********* + *********************************************************/ +package com.yxt.common.base.utils; + +import java.util.ArrayList; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yxt.common.core.query.PagerQuery; +import com.yxt.common.core.vo.PagerVo; +import com.yxt.common.core.vo.Vo; + +/** + * Project: jbsc-commons
+ * File: PagerUtil.java
+ * Class: org.jbase.jbsc.commons.base.utils.PagerUtil
+ * Description: <描述类的功能>.
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2020/9/22 上午9:35
+ * + * @author popo + * @version 1.0 + * @since 1.0 + */ +public abstract class PagerUtil { + + public static IPage queryToPage(PagerQuery pq) { + IPage page = new Page<>(); + page.setSize(pq.getSize()).setCurrent(pq.getCurrent()); + return page; + } + + public static PagerVo pageToVo(IPage pr, PagerVo pv) { + if (pv == null) + pv = new PagerVo(); + pv.setCurrent(pr.getCurrent()).setSize(pr.getSize()) + .setTotal(pr.getTotal()).setPages(pr.getPages()) + .setRecords(pr.getRecords()); + return pv; + } + + /** + * 转换pagerVo + * + * @param soure + * @param clazz + * @return + */ + public static PagerVo switchPagerVo( + PagerVo soure) { + if (soure == null) + return null; + + PagerVo target = new PagerVo<>(); + target.setCurrent(soure.getCurrent()).setPages(soure.getPages()) + .setSize(soure.getSize()).setTotal(soure.getTotal()); + target.setRecords(new ArrayList()); + + return target; + } + + /* + * public static PagerVo pageVoToVo(PagerVo pvs, PagerVo + * pvt) { if (pvt == null) pvt = new PagerVo(); + * pvt.setCurrent(pvs.getCurrent + * ()).setSize(pvs.getSize()).setTotal(pvs.getTotal + * ()).setPages(pvs.getPages()); + * + * for(int i=0;i DYZMAP = setDYZMap(); + + private static Map setDYZMap(){ + Map map = new HashMap<>(); + map.put("仇","QIU"); + map.put("柏", "BO"); + map.put("牟", "MU"); + map.put("颉", "XIE"); + map.put("解", "XIE"); + map.put("尉", "YU"); + map.put("奇", "JI"); + map.put("单", "SHAN"); + map.put("谌", "SHEN"); + map.put("乐", "YUE"); + map.put("召", "SHAO"); + map.put("朴", "PIAO"); + map.put("区", "OU"); + map.put("查", "ZHA"); + map.put("曾", "ZENG"); + map.put("缪", "MIAO"); + map.put("晟", "CHENG"); + map.put("员", "YUN"); + map.put("贠", "YUN"); + map.put("黑", "HE"); + map.put("重", "CHONG"); + map.put("秘", "BI"); + map.put("冼", "XIAN"); + map.put("折", "SHE"); + map.put("翟", "ZHAI"); + map.put("盖", "GE"); + map.put("万俟", "MOQI"); + map.put("尉迟", "YUCHI"); + return map; + } + + + + /** + * 返回字符串的拼音 + * @param str + * @return + */ + public static String[] getCharPinYinString(String str) { + if (str == null || str.length() < 1) { + return null; + } + List result = new ArrayList(); + //对字符串中的记录逐个分析 + for (int i = 0; i < str.length(); i++) { + result = getCharPinYinString(str.charAt(i), result); + } + return result.toArray(new String[result.size()]); + } + + /** + * 将字符c的拼音拼接到list中的记录中 + * @param c + * @param list + * @return + */ + private static List getCharPinYinString(char c, List list) { + String[] strs = getCharPinYinString(c); + List result = new ArrayList(); + // strs去重(多音字) + strs = disdinctStr(strs); + + //如果解析出的拼音为空,判断字符C是否为英文字母,如果是英文字母则添加值拼音结果中 + if (strs == null) { + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + c = c <= 91 ? (char)(c + 32) : c; + if (list == null || list.size() == 0) { + result.add(c + ""); + } else { + for (String s : list) { + result.add(s + c); + } + } + return result; + } + return list; + } + //将字符C的拼音首和已存在的拼音首组合成新的记录 + for (String str : strs) { + if (list == null || list.size() == 0) { + result.add(str); + } else { + for (String s : list) { + result.add(s + str); + } + } + } + return result; + } + + /** + * 返回汉字的拼音 + * @param c + * @return + */ + public static String[] getCharPinYinString(char c) { + try { + //返回字符C的拼音 + return PinyinHelper.toHanyuPinyinStringArray(c, format); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 返回字符串的拼音的首字母 + * @param str + * @return + */ + public static String[] getCharPinYinChar(String str) { + if (str == null || str.length() < 1) { + return null; + } + List result = new ArrayList(); + //对字符串中的记录逐个分析 + for (int i = 0; i < str.length(); i++) { + result = getCharPinYinChar(str.charAt(i), result); + } + return result.toArray(new String[result.size()]); + } + + /** + * 将字符c的拼音首字母拼接到list中的记录中 + * @param c + * @param list + * @return + */ + private static List getCharPinYinChar(char c, List list) { + char[] chars = getCharPinYinChar(c); + List result = new ArrayList(); + //如果解析出的拼音为空,判断字符C是否为英文字母,如果是英文字母则添加值拼音结果中 + if (chars == null) { + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + c = c < 91 ? (char)(c + 32) : c; + if (list == null || list.size() == 0) { + result.add(c + ""); + } else { + for (String s : list) { + result.add(s + c); + } + } + return result; + } + return list; + } + //将字符C的拼音首字母和已存在的拼音首字母组合成新的记录 + for (char ch : chars) { + if (list == null || list.size() == 0) { + result.add(ch + ""); + } else { + for (String s : list) { + result.add(s + ch); + } + } + } + return result; + } + + /** + * 返回汉字拼音首字母 + * @param c + * @return + */ + public static char[] getCharPinYinChar(char c) { + //字符C的拼音 + String[] strs = getCharPinYinString(c); + if (strs != null) { + //截取拼音的首字母 + char[] chars = new char[strs.length]; + for(int i = 0; i arrStream = Arrays.stream(str); + List arrList = arrStream.distinct().collect(Collectors.toList()); + str = new String[arrList.size()]; + arrList.toArray(str); + return str; + } + + /** + * 判断传入的字符串是否为中文,将中文的转换为拼音 + * @param name + * @return + */ + public static String getPinYinName(String name){ + char[] nameArray = name.toCharArray(); + String newName = ""; + for (int i = 0; i < nameArray.length; i++) { + if (Character.toString(nameArray[i]).matches("^[\u4e00-\u9fa5]+$")) { // 如果字符是中文,则将中文转为汉语拼音 + String[] pinYinString = PinYinUtils.getCharPinYinString(nameArray[i]); + // strs去重(多音字) + pinYinString = disdinctStr(pinYinString); + String pinYinStr = StringUtils.join(pinYinString); + newName = newName + pinYinStr; + }else { + newName = newName + Character.toString(nameArray[i]); + } + } + return newName; + } + + /** + * 返回字符串的拼音的首字母(包括多音字) + * @param str + * @return + */ + public static String getCharDuoPinYinChar(String str) { + if (str == null || str.length() < 1) { + return null; + } + char firstChar = str.toCharArray()[0]; + if(Character.toString(firstChar).matches("^[\u4e00-\u9fa5]+$")){ // 为中文 + char[] charPinYinChar = getCharPinYinChar(firstChar); + String result = ""; + if (DYZMAP.containsKey(Character.toString(firstChar))) { + result = DYZMAP.get(Character.toString(firstChar)).toString().substring(0, 1); + }else { + result = StringUtils.join(charPinYinChar[0]); + } + return result.toUpperCase(); + }else if(Character.toString(firstChar).matches("^[a-zA-Z]")){ // 为英文字母 + return Character.toString(firstChar).toUpperCase(); + }else { // 特殊符号 + return "#"; + } + } + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/PropertiesLoader.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/PropertiesLoader.java new file mode 100644 index 0000000..ec793b4 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/PropertiesLoader.java @@ -0,0 +1,147 @@ +package com.yxt.common.base.utils; + +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; + +import java.io.IOException; +import java.io.InputStream; +import java.util.NoSuchElementException; +import java.util.Properties; + +/** + * Properties文件载入工具类. 可载入多个properties文件, 相同的属性在最后载入的文件中的值将会覆盖之前的值,但以System的Property优先. + * + * @author dimengzhe + * @version 2020/9/10 9:22 + */ +public class PropertiesLoader { + + private static Logger logger = LoggerFactory.getLogger(PropertiesLoader.class); + + private static ResourceLoader resourceLoader = new DefaultResourceLoader(); + + private final Properties properties; + + public PropertiesLoader(String... resourcesPaths) { + properties = loadProperties(resourcesPaths); + } + + public Properties getProperties() { + return properties; + } + + /** + * 取出Property,但以System的Property优先,取不到返回空字符串. + */ + private String getValue(String key) { + String systemProperty = System.getProperty(key); + if (systemProperty != null) { + return systemProperty; + } + if (properties.containsKey(key)) { + return properties.getProperty(key); + } + return ""; + } + + /** + * 取出String类型的Property,但以System的Property优先,如果都为Null则抛出异常. + */ + public String getProperty(String key) { + String value = getValue(key); + if (value == null) { + throw new NoSuchElementException(); + } + return value; + } + + /** + * 取出String类型的Property,但以System的Property优先.如果都为Null则返回Default值. + */ + public String getProperty(String key, String defaultValue) { + String value = getValue(key); + return value != null ? value : defaultValue; + } + + /** + * 取出Integer类型的Property,但以System的Property优先.如果都为Null或内容错误则抛出异常. + */ + public Integer getInteger(String key) { + String value = getValue(key); + if (value == null) { + throw new NoSuchElementException(); + } + return Integer.valueOf(value); + } + + /** + * 取出Integer类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容错误则抛出异常 + */ + public Integer getInteger(String key, Integer defaultValue) { + String value = getValue(key); + return value != null ? Integer.valueOf(value) : defaultValue; + } + + /** + * 取出Double类型的Property,但以System的Property优先.如果都为Null或内容错误则抛出异常. + */ + public Double getDouble(String key) { + String value = getValue(key); + if (value == null) { + throw new NoSuchElementException(); + } + return Double.valueOf(value); + } + + /** + * 取出Double类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容错误则抛出异常 + */ + public Double getDouble(String key, Integer defaultValue) { + String value = getValue(key); + return value != null ? Double.valueOf(value) : defaultValue; + } + + /** + * 取出Boolean类型的Property,但以System的Property优先.如果都为Null抛出异常,如果内容不是true/false则返回false. + */ + public Boolean getBoolean(String key) { + String value = getValue(key); + if (value == null) { + throw new NoSuchElementException(); + } + return Boolean.valueOf(value); + } + + /** + * 取出Boolean类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容不为true/false则返回false. + */ + public Boolean getBoolean(String key, boolean defaultValue) { + String value = getValue(key); + return value != null ? Boolean.valueOf(value) : defaultValue; + } + + /** + * 载入多个文件, 文件路径使用Spring Resource格式. + */ + private Properties loadProperties(String... resourcesPaths) { + Properties props = new Properties(); + + for (String location : resourcesPaths) { + InputStream is = null; + try { + Resource resource = resourceLoader.getResource(location); + is = resource.getInputStream(); + props.load(is); + } catch (IOException ex) { + logger.info("Could not load properties from path:" + location + ", " + ex.getMessage()); + } finally { + IOUtils.closeQuietly(is); + } + } + return props; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/QRCodeUtil.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/QRCodeUtil.java new file mode 100644 index 0000000..8df860f --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/QRCodeUtil.java @@ -0,0 +1,255 @@ +package com.yxt.common.base.utils; + +import com.google.zxing.*; +import com.google.zxing.client.j2se.BufferedImageLuminanceSource; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.imageio.ImageIO; +import javax.swing.filechooser.FileSystemView; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +/** + * @author dimengzhe + * @date 2020/11/3 15:05 + * @description + */ +@Component +@Slf4j +public class QRCodeUtil { + + + /** + * CODE_WIDTH:二维码宽度,单位像素 + * CODE_HEIGHT:二维码高度,单位像素 + * FRONT_COLOR:二维码前景色,0x000000 表示黑色 + * BACKGROUND_COLOR:二维码背景色,0xFFFFFF 表示白色 + * 演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白 + */ + private static final int CODE_WIDTH = 400; + private static final int CODE_HEIGHT = 400; + private static final int FRONT_COLOR = 0x000000; + private static final int BACKGROUND_COLOR = 0xFFFFFF; + + + /** + * @param codeContent 二维码参数内容,如果是一个网页地址,如 https://www.baidu.com/ 则 微信扫一扫会直接进入此地址, 如果是一些参数,如 + * 1541656080837,则微信扫一扫会直接回显这些参数值 + * @param codeImgFileSaveDir 二维码图片保存的目录,如 D:/codes + * @param fileName 二维码图片文件名称,带格式,如 123.png + */ + public static void createCodeToFile(String codeContent, File codeImgFileSaveDir, String fileName) { + try { + if (codeContent == null || "".equals(codeContent)) { + log.info("二维码内容为空,不进行操作..."); + return; + } + codeContent = codeContent.trim(); + if (codeImgFileSaveDir == null || codeImgFileSaveDir.isFile()) { + codeImgFileSaveDir = FileSystemView.getFileSystemView().getHomeDirectory(); + log.info("二维码图片存在目录为空,默认放在桌面..."); + } + if (!codeImgFileSaveDir.exists()) { + codeImgFileSaveDir.mkdirs(); + log.info("二维码图片存在目录不存在,开始创建..."); + } + if (fileName == null || "".equals(fileName)) { + fileName = System.currentTimeMillis() + ".png"; + log.info("二维码图片文件名为空,随机生成 png 格式图片..."); + } + + BufferedImage bufferedImage = getBufferedImage(codeContent); + + /* + * javax.imageio.ImageIO:java扩展的图像IO + * write(RenderedImage im, String formatName, File output) + * im:待写入的图像, formatName:图像写入的格式,output:写入的图像文件,文件不存在时会自动创建 + */ + File codeImgFile = new File(codeImgFileSaveDir, fileName); + ImageIO.write(bufferedImage, "png", codeImgFile); + + log.info("二维码图片生成成功:" + codeImgFile.getPath()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + /** + * 生成二维码并输出到输出流, 通常用于输出到网页上进行显示 + * 输出到网页与输出到磁盘上的文件中,区别在于最后一句 ImageIO.write + * write(RenderedImage im,String formatName,File output):写到文件中 + * write(RenderedImage im,String formatName,OutputStream output):输出到输出流中 + * + * @param codeContent :二维码内容 + * @param outputStream :输出流,比如 HttpServletResponse 的 getOutputStream + */ + public static void createCodeToOutputStream(String codeContent, OutputStream outputStream) { + try { + if (codeContent == null || "".equals(codeContent.trim())) { + log.info("二维码内容为空,不进行操作..."); + return; + } + codeContent = codeContent.trim(); + + BufferedImage bufferedImage = getBufferedImage(codeContent); + /* + * 区别就是以一句,输出到输出流中,如果第三个参数是 File,则输出到文件中 + */ + ImageIO.write(bufferedImage, "png", outputStream); + log.info("二维码图片生成到输出流成功..."); + } catch (Exception e) { + e.printStackTrace(); + log.error("发生错误: {}!", e.getMessage()); + } + } + + + private static BufferedImage getBufferedImage(String codeContent) throws WriterException { + /* + * com.google.zxing.EncodeHintType:编码提示类型,枚举类型 + * EncodeHintType.CHARACTER_SET:设置字符编码类型 + * EncodeHintType.ERROR_CORRECTION:设置误差校正 + * ErrorCorrectionLevel:误差校正等级,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction + * 不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的 + * EncodeHintType.MARGIN:设置二维码边距,单位像素,值越小,二维码距离四周越近 + */ + Map hints = new HashMap(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); + hints.put(EncodeHintType.MARGIN, 1); + + /* + * MultiFormatWriter:多格式写入,这是一个工厂类,里面重载了两个 encode 方法,用于写入条形码或二维码 + * encode(String contents,BarcodeFormat format,int width, int height,Map hints) + * contents:条形码/二维码内容 + * format:编码类型,如 条形码,二维码 等 + * width:码的宽度 + * height:码的高度 + * hints:码内容的编码类型 + * BarcodeFormat:枚举该程序包已知的条形码格式,即创建何种码,如 1 维的条形码,2 维的二维码 等 + * BitMatrix:位(比特)矩阵或叫2D矩阵,也就是需要的二维码 + */ + MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); + BitMatrix bitMatrix = multiFormatWriter.encode(codeContent, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints); + + /* + * java.awt.image.BufferedImage:具有图像数据的可访问缓冲图像,实现了 RenderedImage 接口 + * BitMatrix 的 get(int x, int y) 获取比特矩阵内容,指定位置有值,则返回true,将其设置为前景色,否则设置为背景色 + * BufferedImage 的 setRGB(int x, int y, int rgb) 方法设置图像像素 + * x:像素位置的横坐标,即列 + * y:像素位置的纵坐标,即行 + * rgb:像素的值,采用 16 进制,如 0xFFFFFF 白色 + */ + BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR); + for (int x = 0; x < CODE_WIDTH; x++) { + for (int y = 0; y < CODE_HEIGHT; y++) { + bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR); + } + } + return bufferedImage; + } + + + /** + * 根据本地二维码图片解析二维码内容 注:图片必须是二维码图片,但也可以是微信用户二维码名片,上面有名称、头像也是可以的) + * + * @param file 本地二维码图片文件,如 E:\\logs\\2.jpg + * @return + * @throws Exception + */ + public static String parseQRCodeByFile(File file) { + String resultStr = null; + if (file == null || file.isDirectory() || !file.exists()) { + return resultStr; + } + try { + /* + * ImageIO的BufferedImage read(URL input)方法用于读取网络图片文件转为内存缓冲图像 + * 同理还有:read(File input)、read(InputStream input)、、read(ImageInputStream stream) + */ + BufferedImage bufferedImage = ImageIO.read(file); + /* + * com.google.zxing.client.j2se.BufferedImageLuminanceSource:缓冲图像亮度源 + * 将 java.awt.image.BufferedImage 转为 zxing 的 缓冲图像亮度源 + * 关键就是下面这几句:HybridBinarizer 用于读取二维码图像数据,BinaryBitmap 二进制位图 + */ + BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(bufferedImage); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + Hashtable hints = new Hashtable(); + hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); + /* + * 如果图片不是二维码图片,则 decode 抛异常:com.google.zxing.NotFoundException + * MultiFormatWriter 的 encode 用于对内容进行编码成 2D 矩阵 + * MultiFormatReader 的 decode 用于读取二进制位图数据 + */ + Result result = new MultiFormatReader().decode(bitmap, hints); + resultStr = result.getText(); + } catch (IOException e) { + e.printStackTrace(); + } catch (NotFoundException e) { + e.printStackTrace(); + log.error("图片非二维码图片, 路径是: {}!", file.getPath()); + } + return resultStr; + } + + + /** + * 根据网络二维码图片解析二维码内容, 区别仅仅在于 ImageIO.read(url); 这一个重载的方法) + * + * @param url 二维码图片网络地址,如 https://res.wx.qq.com/mpres/htmledition/images/mp_qrcode3a7b38.gif + * @return + * @throws Exception + */ + public static String parseQRCodeByUrl(URL url) { + String resultStr = null; + if (url == null) { + return resultStr; + } + try { + /* + * ImageIO 的 BufferedImage read(URL input) 方法用于读取网络图片文件转为内存缓冲图像 + * 同理还有:read(File input)、read(InputStream input)、、read(ImageInputStream stream) + * 如果图片网络地址错误,比如不能访问,则 read 抛异常:javax.imageio.IIOException: Can't get input stream from URL! + */ + BufferedImage bufferedImage = ImageIO.read(url); + /* + * com.google.zxing.client.j2se.BufferedImageLuminanceSource:缓冲图像亮度源 + * 将 java.awt.image.BufferedImage 转为 zxing 的 缓冲图像亮度源 + * 关键就是下面这几句:HybridBinarizer 用于读取二维码图像数据,BinaryBitmap 二进制位图 + */ + BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(bufferedImage); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + Hashtable hints = new Hashtable(); + /* + * 如果内容包含中文,则解码的字符集格式应该和编码时一致 + */ + hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); + /* + * 如果图片不是二维码图片,则 decode 抛异常:com.google.zxing.NotFoundException + * MultiFormatWriter 的 encode 用于对内容进行编码成 2D 矩阵 + * MultiFormatReader 的 decode 用于读取二进制位图数据 + */ + Result result = new MultiFormatReader().decode(bitmap, hints); + resultStr = result.getText(); + } catch (IOException e) { + e.printStackTrace(); + log.error("二维码图片地址错误, 地址是: {}!", url); + } catch (NotFoundException e) { + e.printStackTrace(); + log.error("图片非二维码图片, 地址是: {}!", url); + } + return resultStr; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/RegexUtil.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/RegexUtil.java new file mode 100644 index 0000000..1ee2b89 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/RegexUtil.java @@ -0,0 +1,220 @@ +package com.yxt.common.base.utils; + +import org.apache.commons.lang3.StringUtils; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.GregorianCalendar; +import java.util.Hashtable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author dimengzhe + * @date 2020/8/28 9:22 + * @description 常用正则验证工具类 + */ + +public class RegexUtil { + + /** + * 正则表达式: 验证手机号 + */ + public static final String REGEX_MOBILE = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$"; + + /** + * 验证邮箱 + */ + public static final String REGEX_EMAIL = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"; + /** + * 验证汉字 + */ + public static final String REGEX_CHINESE = "^[\u4e00-\u9fa5],{0,}$"; + /** + * 验证身份证 + */ + public static final String REGEX_ID_CARD = "(^\\d{18}$)|(^\\d{15}$)"; + + /** + * 验证手机号 + * + * @param mobile 手机号 + * @return + */ + public static boolean isMobile(String mobile) { + return StringUtils.isNotBlank(mobile) && Pattern.matches(REGEX_MOBILE, mobile); + } + + /** + * 验证邮箱 + * + * @param email 邮箱证号 + * @return + */ + public static boolean isEmail(String email) { + return StringUtils.isNotBlank(email) && Pattern.matches(REGEX_EMAIL, email); + } + + /** + * 验证汉字 + * + * @param chinese 汉字 + * @return + */ + public static boolean isChinese(String chinese) { + return StringUtils.isNotBlank(chinese) && Pattern.matches(REGEX_CHINESE, chinese); + } + + /** + * 验证身份证号 + * + * @param idCard 身份证号 + * @return + */ + public static boolean isIDCard(String idCard) { + return StringUtils.isNotBlank(idCard) && Pattern.matches(REGEX_ID_CARD, idCard); + } + + /** + * 严格验证身份证号是否正确 + * + * @param IDStr 身份证号 + * @return + * @throws ParseException + */ + public static String IDCardValidate(String IDStr) throws ParseException { + IDStr = IDStr.toLowerCase(); + String errorInfo = ""; + String[] ValCodeArr = {"1", "0", "x", "9", "8", "7", "6", "5", "4", + "3", "2"}; + String[] Wi = {"7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", + "9", "10", "5", "8", "4", "2"}; + String Ai = ""; + + if ((IDStr.length() != 15) && (IDStr.length() != 18)) { + errorInfo = "身份证号码长度应为15位或18位。"; + return errorInfo; + } + + if (IDStr.length() == 18) { + Ai = IDStr.substring(0, 17); + } else if (IDStr.length() == 15) { + Ai = IDStr.substring(0, 6) + "19" + IDStr.substring(6, 15); + } + if (!isNumeric(Ai)) { + errorInfo = "身份证15位号码都应为数字 ; 18位号码除最后一位外,都应为数字。"; + return errorInfo; + } + + String strYear = Ai.substring(6, 10); + String strMonth = Ai.substring(10, 12); + String strDay = Ai.substring(12, 14); + if (!isDate(strYear + "-" + strMonth + "-" + strDay)) { + errorInfo = "身份证生日无效。"; + return errorInfo; + } + GregorianCalendar gc = new GregorianCalendar(); + SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd"); + if ((gc.get(1) - Integer.parseInt(strYear) > 150) + || (gc.getTime().getTime() + - s.parse(strYear + "-" + strMonth + "-" + strDay) + .getTime() < 0L)) { + errorInfo = "身份证生日不在有效范围。"; + return errorInfo; + } + if ((Integer.parseInt(strMonth) > 12) + || (Integer.parseInt(strMonth) == 0)) { + errorInfo = "身份证月份无效"; + return errorInfo; + } + if ((Integer.parseInt(strDay) > 31) || (Integer.parseInt(strDay) == 0)) { + errorInfo = "身份证日期无效"; + return errorInfo; + } + + Hashtable h = GetAreaCode(); + if (h.get(Ai.substring(0, 2)) == null) { + errorInfo = "身份证地区编码错误。"; + return errorInfo; + } + + int TotalmulAiWi = 0; + for (int i = 0; i < 17; i++) { + TotalmulAiWi = TotalmulAiWi + + Integer.parseInt(String.valueOf(Ai.charAt(i))) + * Integer.parseInt(Wi[i]); + } + int modValue = TotalmulAiWi % 11; + String strVerifyCode = ValCodeArr[modValue]; + Ai = Ai + strVerifyCode; + + if (IDStr.length() == 18) { + if (!Ai.equals(IDStr)) { + errorInfo = "身份证无效,不是合法的身份证号码"; + return errorInfo; + } + } else { + return ""; + } + + + return ""; + } + + private static Hashtable GetAreaCode() { + Hashtable hashtable = new Hashtable(); + hashtable.put("11", "北京"); + hashtable.put("12", "天津"); + hashtable.put("13", "河北"); + hashtable.put("14", "山西"); + hashtable.put("15", "内蒙古"); + hashtable.put("21", "辽宁"); + hashtable.put("22", "吉林"); + hashtable.put("23", "黑龙江"); + hashtable.put("31", "上海"); + hashtable.put("32", "江苏"); + hashtable.put("33", "浙江"); + hashtable.put("34", "安徽"); + hashtable.put("35", "福建"); + hashtable.put("36", "江西"); + hashtable.put("37", "山东"); + hashtable.put("41", "河南"); + hashtable.put("42", "湖北"); + hashtable.put("43", "湖南"); + hashtable.put("44", "广东"); + hashtable.put("45", "广西"); + hashtable.put("46", "海南"); + hashtable.put("50", "重庆"); + hashtable.put("51", "四川"); + hashtable.put("52", "贵州"); + hashtable.put("53", "云南"); + hashtable.put("54", "西藏"); + hashtable.put("61", "陕西"); + hashtable.put("62", "甘肃"); + hashtable.put("63", "青海"); + hashtable.put("64", "宁夏"); + hashtable.put("65", "新疆"); + hashtable.put("71", "台湾"); + hashtable.put("81", "香港"); + hashtable.put("82", "澳门"); + hashtable.put("91", "国外"); + return hashtable; + } + + private static boolean isNumeric(String str) { + Pattern pattern = Pattern.compile("[0-9]*"); + Matcher isNum = pattern.matcher(str); + + return isNum.matches(); + } + + public static boolean isDate(String strDate) { + Pattern pattern = Pattern + .compile("^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1-2][0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$"); + Matcher m = pattern.matcher(strDate); + + return m.matches(); + } + + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/StringRandom.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/StringRandom.java new file mode 100644 index 0000000..f1a03cd --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/StringRandom.java @@ -0,0 +1,27 @@ +package com.yxt.common.base.utils; + +import java.util.Random; + +/** + * 生成随机字符串 + * @author yxt_mtl + * + * + */ +public class StringRandom { + /** + * 随机生成字符串-规避I,l,O,o,0,1容易混淆的字符 + * @param length用户要求产生字符串的长度 + * @return + */ + public static String getRandomString(int length){ + String str="abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; + Random random=new Random(); + StringBuffer sb=new StringBuffer(); + for(int i=0;i", "<$1>"); + } + + /** + * 替换为手机识别的HTML,去掉样式及属性,保留回车。 + * + * @param txt + * @return + */ + public static String toHtml(String txt) { + if (txt == null) { + return ""; + } + return replace(replace(Encodes.escapeHtml(txt), "\n", "
"), "\t", "    "); + } + + /** + * 缩略字符串(不区分中英文字符) + * + * @param str 目标字符串 + * @param length 截取长度 + * @return + */ + public static String abbr(String str, int length) { + if (str == null) { + return ""; + } + try { + StringBuilder sb = new StringBuilder(); + int currentLength = 0; + for (char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()) { + currentLength += String.valueOf(c).getBytes("GBK").length; + if (currentLength <= length - 3) { + sb.append(c); + } else { + sb.append("..."); + break; + } + } + return sb.toString(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return ""; + } + + public static String abbr2(String param, int length) { + if (param == null) { + return ""; + } + StringBuffer result = new StringBuffer(); + int n = 0; + char temp; + boolean isCode = false; // 是不是HTML代码 + boolean isHTML = false; // 是不是HTML特殊字符,如  + for (int i = 0; i < param.length(); i++) { + temp = param.charAt(i); + if (temp == '<') { + isCode = true; + } else if (temp == '&') { + isHTML = true; + } else if (temp == '>' && isCode) { + n = n - 1; + isCode = false; + } else if (temp == ';' && isHTML) { + isHTML = false; + } + try { + if (!isCode && !isHTML) { + n += String.valueOf(temp).getBytes("GBK").length; + } + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + if (n <= length - 3) { + result.append(temp); + } else { + result.append("..."); + break; + } + } + // 取出截取字符串中的HTML标记 + String temp_result = result.toString().replaceAll("(>)[^<>]*(]*/?>", + ""); + // 去掉成对的HTML标记 + temp_result = temp_result.replaceAll("<([a-zA-Z]+)[^<>]*>(.*?)", "$2"); + // 用正则表达式取出标记 + Pattern p = Pattern.compile("<([a-zA-Z]+)[^<>]*>"); + Matcher m = p.matcher(temp_result); + List endHTML = new ArrayList(); + while (m.find()) { + endHTML.add(m.group(1)); + } + // 补全不成对的HTML标记 + for (int i = endHTML.size() - 1; i >= 0; i--) { + result.append(""); + } + return result.toString(); + } + + /** + * 转换为Double类型 + */ + public static Double toDouble(Object val) { + if (val == null) { + return 0D; + } + try { + return Double.valueOf(trim(val.toString())); + } catch (Exception e) { + return 0D; + } + } + + /** + * 转换为Float类型 + */ + public static Float toFloat(Object val) { + return toDouble(val).floatValue(); + } + + /** + * 转换为Long类型 + */ + public static Long toLong(Object val) { + return toDouble(val).longValue(); + } + + /** + * 转换为Integer类型 + */ + public static Integer toInteger(Object val) { + return toLong(val).intValue(); + } + + /** + * 转换为BigDecimal类型 + */ + public static BigDecimal toBigDecimal(String val) { + if (StringUtils.isBlank(val)) { + return null; + } + BigDecimal bd = new BigDecimal(val); + return bd; + } + + /** + * 获得用户远程地址 + */ + public static String getRemoteAddr(HttpServletRequest request) { + String remoteAddr = request.getHeader("X-Real-IP"); + if (isNotBlank(remoteAddr)) { + remoteAddr = request.getHeader("X-Forwarded-For"); + } else if (isNotBlank(remoteAddr)) { + remoteAddr = request.getHeader("Proxy-Client-IP"); + } else if (isNotBlank(remoteAddr)) { + remoteAddr = request.getHeader("WL-Proxy-Client-IP"); + } + return remoteAddr != null ? remoteAddr : request.getRemoteAddr(); + } + + /** + * 驼峰命名法工具 + * + * @return toCamelCase(" hello_world ") == "helloWorld" + * toCapitalizeCamelCase("hello_world") == "HelloWorld" + * toUnderScoreCase("helloWorld") = "hello_world" + */ + public static String toCamelCase(String s) { + if (s == null) { + return null; + } + + s = s.toLowerCase(); + + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == SEPARATOR) { + upperCase = true; + } else if (upperCase) { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } else { + sb.append(c); + } + } + + return sb.toString(); + } + + /** + * 驼峰命名法工具 + * + * @return toCamelCase(" hello_world ") == "helloWorld" + * toCapitalizeCamelCase("hello_world") == "HelloWorld" + * toUnderScoreCase("helloWorld") = "hello_world" + */ + public static String toCapitalizeCamelCase(String s) { + if (s == null) { + return null; + } + s = toCamelCase(s); + return s.substring(0, 1).toUpperCase() + s.substring(1); + } + + /** + * 驼峰命名法工具 + * + * @return toCamelCase(" hello_world ") == "helloWorld" + * toCapitalizeCamelCase("hello_world") == "HelloWorld" + * toUnderScoreCase("helloWorld") = "hello_world" + */ + public static String toUnderScoreCase(String s) { + if (s == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + boolean nextUpperCase = true; + + if (i < (s.length() - 1)) { + nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); + } + + if ((i > 0) && Character.isUpperCase(c)) { + if (!upperCase || !nextUpperCase) { + sb.append(SEPARATOR); + } + upperCase = true; + } else { + upperCase = false; + } + + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 如果不为空,则设置值 + * + * @param target + * @param source + */ + public static void setValueIfNotBlank(String target, String source) { + if (isNotBlank(source)) { + target = source; + } + } + + /** + * 转换为JS获取对象值,生成三目运算返回结果 + * + * @param objectString 对象串 例如:row.user.id + * 返回:!row?'':!row.user?'':!row.user.id?'':row.user.id + */ + public static String jsGetVal(String objectString) { + StringBuilder result = new StringBuilder(); + StringBuilder val = new StringBuilder(); + String[] vals = split(objectString, "."); + for (int i = 0; i < vals.length; i++) { + val.append("." + vals[i]); + result.append("!" + (val.substring(1)) + "?'':"); + } + result.append(val.substring(1)); + return result.toString(); + } + + public static byte[] getBytesUTF8(CharSequence cs) { + try { + return cs.toString().getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw Exceptions.unchecked(e); + } + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/TencentCloudApiUtils.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/TencentCloudApiUtils.java new file mode 100644 index 0000000..52dadea --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/TencentCloudApiUtils.java @@ -0,0 +1,429 @@ +package com.yxt.common.base.utils; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.xml.bind.DatatypeConverter; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.TimeZone; + +/** + * 错误示例: + * { + * "Response": { + * "Error": { + * "Code": "AuthFailure.SignatureFailure", + * "Message": "The provided credentials could not be validated. Please check your signature is correct." + * }, + * "RequestId": "e6e433fe-1baf-4fa9-ae28-3f37b3fb01f1"* } + * } + *

+ * 正确示例: + * { + * "Response": { + * "TextDetections": [{ + * "DetectedText": "\"宇信通交流赛\"乒乓球大竞技", + * "Confidence": 99, + * "ItemPolygon": { + * "X": 67, + * "Y": 125, + * "Width": 538, + * "Height": 44 + * }, + * "Polygon": [{ + * "X": 67, + * "Y": 125 + * }, { + * "X": 605, + * "Y": 125 + * }, { + * "X": 605, + * "Y": 169 + * }, { + * "X": 67, + * "Y": 169 + * }], + * "AdvancedInfo": "{\"Parag\":{\"ParagNo\":1}}"* }, { + * "DetectedText": "2019.07", + * "Confidence": 99, + * "ItemPolygon": { + * "X": 421, + * "Y": 227, + * "Width": 132, + * "Height": 26* }, + * "Polygon": [{ + * "X": 421, + * "Y": 227 + * }, { + * "X": 553, + * "Y": 227 + * }, { + * "X": 553, + * "Y": 253 + * }, { + * "X": 421, + * "Y": 253 + * }], + * "AdvancedInfo": "{\"Parag\":{\"ParagNo\":2}} " + * }, { + * "DetectedText": "主办单位:乒娱网需事组委合", + * "Confidence": 96, + * "ItemPolygon": { + * "X": 227, + * "Y": 362, + * "Width": 386, + * "Heig 33 + * }, + * "Polygon": [{ + * "X": 227, + * " 362 + * }, { + * "X": 613, + * " 362 + * }, { + * "X": 613, + * " 395 + * }, { + * "X": 227, + * " 395 + * }], + * "AdvancedInfo": "{\"Parag\":{\"ParagNo 3}}" + * }], + * "Language": "zh", + * "Angel": 359.989990234375, + * "PdfPageSize": 0, + * "RequestId": "0e3be269-081d-4037-aa5a-9717de 4aa6" + * } + * } + */ +public class TencentCloudApiUtils { + + + /** + * 实体 通过 Action字段取值为命名 + */ + public enum TencentApi { + // 通用印刷体识别(支持区域:北京,广州,香港,首尔,上海,多伦多) + GeneralBasicOCR(HTTPRequestMethod.POST_JSON, "ocr.tencentcloudapi.com", "ocr", "2018-11-19"), + // 增值税发票识别(支持区域:北京,广州,香港,上海,多伦多) + VatInvoiceOCR(HTTPRequestMethod.POST_JSON, "ocr.tencentcloudapi.com", "ocr", "2018-11-19"), + // 增值税发票核验(支持区域:北京,广州,香港,上海,多伦多) + VatInvoiceVerify(HTTPRequestMethod.POST_JSON, "ocr.tencentcloudapi.com", "ocr", "2018-11-19"), + // 驾驶证识别(支持区域:北京,广州,香港,上海,多伦多) + DriverLicenseOCR(HTTPRequestMethod.POST_JSON, "ocr.tencentcloudapi.com", "ocr", "2018-11-19"), + // 车辆VIN码识别(支持区域:北京,广州,香港,上海,多伦多) + VinOCR(HTTPRequestMethod.POST_JSON, "ocr.tencentcloudapi.com", "ocr", "2018-11-19"), + // 行驶证识别(支持区域:北京,广州,香港,上海,多伦多) + VehicleLicenseOCR(HTTPRequestMethod.POST_JSON, "ocr.tencentcloudapi.com", "ocr", "2018-11-19"), + // 车牌识别(支持区域:北京,广州,香港,上海,多伦多) + LicensePlateOCR(HTTPRequestMethod.POST_JSON, "ocr.tencentcloudapi.com", "ocr", "2018-11-19"), + // 身份证识别(支持区域:北京,广州,香港,上海,多伦多) + IDCardOCR(HTTPRequestMethod.POST_JSON, "ocr.tencentcloudapi.com", "ocr", "2018-11-19"), + // 护照识别(港澳台地区及境外护照)(支持区域:广州、新加坡) + MLIDPassportOCR(HTTPRequestMethod.POST_JSON, "ocr.tencentcloudapi.com", "ocr", "2018-11-19"), + // 港澳台通行证识别(支持区域:北京、广州、香港、上海、多伦多) + PermitOCR(HTTPRequestMethod.POST_JSON, "ocr.tencentcloudapi.com", "ocr", "2018-11-19"); + + private final HTTPRequestMethod method; + private final String domaiName; + private final String prodect; + private final String version; + + TencentApi(HTTPRequestMethod method, String domaiName, String prodect, String version) { + this.method = method; + this.domaiName = domaiName; + this.prodect = prodect; + this.version = version; + } + } + + // 请求类型 + private enum HTTPRequestMethod { + // content-type 必须和实际发送的相符合,有些编程语言网络库即使未指定也会自动添加 charset 值, + // 如果签名时和发送时不一致,服务器会返回签名校验失败 + GET("GET", "application/x-www-form-urlencoded"), + POST_JSON("POST", "content-type:application/json"), + POST_FORM("POST", "content-type:multipart/form-data; charset=utf-8"); + + private final String name; + private final String contentType; + + + HTTPRequestMethod(String name, String contentType) { + this.name = name; + this.contentType = contentType; + } + + } + + // 区域 + public enum Region { + BeiJing("ap-beijing"), + GuangZhou("ap-guangzhou"), + HongKong("ap-hongkong"), + Seoul("ap-seoul"), + ShangHai("ap-shanghai"), + Toronto("na-toronto"); + + private String path; + + Region(String path) { + this.path = path; + } + } + + // 目前仅支持postJson请求,默认北京 + public static Result2 buildHeaders(TencentApi api, String requestPayload) { + return buildHeaders(api.method, api, Region.BeiJing, requestPayload); + } + + // 目前仅支持postJson请求 + public static Result2 buildHeaders(TencentApi api, Region apiRegion, String requestPayload) { + return buildHeaders(api.method, api, apiRegion, requestPayload); + } + + /** + * 组装v3签名请求头 + * + * @param method HTTP 请求方法(GET、POST) + * @param api 接口的Api相关信息 + * @param apiRegion 地域列表 + * @param requestPayload 请求参数 如:json : {"aaa":"aaa"} + */ + private static Result2 buildHeaders(HTTPRequestMethod method, TencentApi api, Region apiRegion, String requestPayload) { + + // 腾讯云秘钥 + String SecretId = "AKIDHqFKF3rEet44qTmBIEzvhIQRH8uZNkGJ"; + String SecretKey = "0zpau31tbCgosoiT3TimeT1KVVNSPOg1"; + // 签名算法,目前固定取该值 + String algorithm = "TC3-HMAC-SHA256"; + // UTC 标准时间的日期 + String utcTimeStr = getUTCTime(); + // Unix时间戳 + String unixTimestamp = getUnixTimestamp(); + + /*************** 步骤 1:拼接规范请求串 *************/ + // CanonicalQueryString: 发起 HTTP 请求 URL 中的查询字符串,对于 POST 请求,固定为空字符串"",对于 GET 请求,则为 URL 中问号(?)后面的字符串内容,例如:Limit=10&Offset=0。 + // 注意:CanonicalQueryString 需要参考 RFC3986 进行 URLEncode,字符集 UTF8,推荐使用编程语言标准库,所有特殊字符均需编码,大写形式。 + String CanonicalQueryString = ""; + + if ("GET".equals(method.name())) { + try { + CanonicalQueryString = URLEncoder.encode(requestPayload, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return new Result2(false, e.toString()); + } + + // 目前GET请求未调通 + return new Result2(false, "未完善POST_FORM方式"); + } + + if ("POST_FORM".equals(method.name())) { + return new Result2(false, "未完善POST_FORM方式"); + } + + String CanonicalHeaders = method.contentType + "\nhost:" + api.domaiName + "\n"; + + // 对 HTTP 请求正文做 SHA256 哈希,然后十六进制编码, + // 最后编码串转换成小写字母。对于 GET 请求,RequestPayload 固定为空字符串 + Result hashRequest = getHashRequest("GET".equals(method.name()) ? "" : requestPayload); + if (!hashRequest.success) { + return new Result2(false, hashRequest.result); + } + String HashedRequestPayload = hashRequest.result; + + /** + * POST + * / + * + * content-type:application/json; charset=utf-8 + * host:cvm.tencentcloudapi.com + * + * content-type;host + * 35e9c5b0e3ae67532d3c9f17ead6c90222632e5b1ff7f6e89887f1398934f064 + */ + String CanonicalRequest = + method.name + '\n' + + "/" + '\n' + + CanonicalQueryString + '\n' + + CanonicalHeaders + '\n' + + "content-type;host\n" + + HashedRequestPayload; + + System.out.println("拼接规范请求串" + CanonicalRequest); + + /*************** 步骤 2:拼接待签名字符串 *************/ + + // 前述步骤拼接所得规范请求串的哈希值 + Result hashCanonicalRequest = getHashRequest(CanonicalRequest); + if (!hashCanonicalRequest.success) { + return new Result2(false, hashCanonicalRequest.result); + } + String HashedCanonicalRequest = hashCanonicalRequest.result; + + /** + * TC3-HMAC-SHA256 + * 1551113065 + * 2019-02-25/cvm/tc3_request + * 5ffe6a04c0664d6b969fab9a13bdab201d63ee709638e2749d62a09ca18d7031 + */ + String StringToSign = + algorithm + "\n" + + unixTimestamp + '\n' + + utcTimeStr + "/" + api.prodect + "/tc3_request\n" + + HashedCanonicalRequest; + + System.out.println("拼接待签名字符串" + StringToSign); + + /************** 步骤 3:计算签名 *************/ + + String Signature; + + try { + byte[] secretDate = hmac256(("TC3" + SecretKey).getBytes(StandardCharsets.UTF_8), utcTimeStr); + byte[] secretService = hmac256(secretDate, api.prodect); + byte[] secretSigning = hmac256(secretService, "tc3_request"); + Signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, StringToSign)).toLowerCase(); + } catch (Exception e) { + e.printStackTrace(); + return new Result2(false, e.toString()); + } + + System.out.println("计算签名" + Signature); + + /********* 步骤 4:拼接 Authorization *************/ + + // TC3-HMAC-SHA256 Credential=AKIDz8krbsJ5yKBZQpn74WFkmLPx3*******/2019-02-25/cvm/tc3_request, SignedHeaders=content-type;host, Signature=2230eefd229f582d8b1b891af7107b91597240707d778ab3738f756258d7652c + String authorization = algorithm + " " + + "Credential=" + SecretId + "/" + utcTimeStr + "/" + api.prodect + "/" + "tc3_request" + ", " + + "SignedHeaders=content-type;host, " + + "Signature=" + Signature; + + System.out.println("拼接 Authorization" + authorization); + + HashMap headers = new HashMap<>(); + headers.put("Authorization", authorization); + headers.put("Content-Type", method.contentType.replace("content-type:", "")); + headers.put("Host", api.domaiName); + // 当前 UNIX 时间戳,可记录发起 API 请求的时间。例如 1529223702。 + // 注意:如果与服务器时间相差超过5分钟,会引起签名过期错误。 + headers.put("X-TC-Timestamp", unixTimestamp); + // 操作的 API 的版本。取值参考接口文档中入参公共参数 Version 的说明。例如云服务器的版本 2017-03-12。 + headers.put("X-TC-Version", api.version); + // 操作的接口名称。取值参考接口文档中输入参数公共参数 Action 的说明。 + // 例如云服务器的查询实例列表接口,取值为 DescribeInstances。 + headers.put("X-TC-Action", api.name()); + // 地域参数,用来标识希望操作哪个地域的数据。 + // 接口接受的地域取值参考接口文档中输入参数公共参数 Region 的说明。 + // 注意:某些接口不需要传递该参数,接口文档中会对此特别说明,此时即使传递该参数也不会生效。 + headers.put("X-TC-Region", apiRegion.path); + return new Result2(true, headers); + } + + // 生成HMACSHA256 + public static byte[] hmac256(byte[] key, String msg) throws Exception { + Mac mac = Mac.getInstance("HmacSHA256"); + SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm()); + mac.init(secretKeySpec); + return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8)); + } + + // 获取 UTC 标准时间的日期 + private static String getUTCTime() { + // yyyy-MM-dd HH:mm:ss + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + sdf.setTimeZone(TimeZone.getTimeZone("gmt")); + String gmtTime = sdf.format(new Date()); + return gmtTime; + } + + // 当前时间 UNIX 时间戳,精确到秒 + private static String getUnixTimestamp() { +// return "1625125488"; + return Long.toString(System.currentTimeMillis() / 1000L); + } + + // 获取 HASH_REQUEST + private static Result getHashRequest(String s) { + MessageDigest messageDigest; + String encodeStr = ""; + try { + messageDigest = MessageDigest.getInstance("SHA-256"); + messageDigest.update(s.getBytes(StandardCharsets.UTF_8)); + + StringBuilder sb = new StringBuilder(); + String temp = null; + for (byte aByte : messageDigest.digest()) { + temp = Integer.toHexString(aByte & 0xFF); + if (temp.length() == 1) { + // 1得到一位的进行补0操作 + sb.append("0"); + } + sb.append(temp); + } + encodeStr = sb.toString().toLowerCase(); + } catch (Exception e) { + e.printStackTrace(); + return new Result(false, e.toString()); + } + return new Result(true, encodeStr); + } + + static class Result { + private final boolean success; + private final String result; + + public Result(boolean success, String result) { + this.success = success; + this.result = result; + } + + public boolean isSuccess() { + return success; + } + + public String getResult() { + return result; + } + } + + /** + * 最终结果 + * 正确 sucess + * 错误 取errorMsg + */ + public static class Result2 { + private final boolean success; + private String errorMsg; + private HashMap result; + + public Result2(boolean success, String errorMsg) { + this.success = success; + this.errorMsg = errorMsg; + } + + public Result2(boolean success, HashMap result) { + this.success = success; + this.result = result; + } + + public boolean isSuccess() { + return success; + } + + public HashMap getResult() { + return result; + } + + public String getErrorMsg() { + return errorMsg; + } + } + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Tools.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Tools.java new file mode 100644 index 0000000..0f50a30 --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/Tools.java @@ -0,0 +1,23 @@ +package com.yxt.common.base.utils; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author dimengzhe + * @date 2020/9/11 11:34 + * @description + */ + +public class Tools { + + public static final String CODE_SUCCESS = "200"; + public static final String CODE_FAIL = "100"; + + public static Map setRetCode(String code, String details) { + Map map = new HashMap<>(); + map.put("code", code); + map.put("details", details); + return map; + } +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/VerifyCodeUtils.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/VerifyCodeUtils.java new file mode 100644 index 0000000..c333d4c --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/VerifyCodeUtils.java @@ -0,0 +1,227 @@ +package com.yxt.common.base.utils; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Random; + +/** + * @author dimengzhe + * @date 2020/9/22 14:41 + * @description + */ + +public class VerifyCodeUtils { + + // 使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符 + public static final String VERIFY_CODES = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ"; + + private static Random random = new SecureRandom(); + + /** + * 使用系统默认字符源生成验证码 + * + * @param verifySize 验证码长度 + * @return + */ + public static String generateVerifyCode(int verifySize) + { + return generateVerifyCode(verifySize, VERIFY_CODES); + } + + /** + * 使用指定源生成验证码 + * + * @param verifySize 验证码长度 + * @param sources 验证码字符源 + * @return + */ + public static String generateVerifyCode(int verifySize, String sources) + { + if (sources == null || sources.length() == 0) + { + sources = VERIFY_CODES; + } + int codesLen = sources.length(); + Random rand = new Random(System.currentTimeMillis()); + StringBuilder verifyCode = new StringBuilder(verifySize); + for (int i = 0; i < verifySize; i++) + { + verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1))); + } + return verifyCode.toString(); + } + + /** + * 输出指定验证码图片流 + * + * @param w + * @param h + * @param os + * @param code + * @throws IOException + */ + public static void outputImage(int w, int h, OutputStream os, String code) throws IOException + { + int verifySize = code.length(); + BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + Random rand = new Random(); + Graphics2D g2 = image.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Color[] colors = new Color[5]; + Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, + Color.ORANGE, Color.PINK, Color.YELLOW }; + float[] fractions = new float[colors.length]; + for (int i = 0; i < colors.length; i++) + { + colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)]; + fractions[i] = rand.nextFloat(); + } + Arrays.sort(fractions); + + g2.setColor(Color.GRAY);// 设置边框色 + g2.fillRect(0, 0, w, h); + + Color c = getRandColor(200, 250); + g2.setColor(c);// 设置背景色 + g2.fillRect(0, 2, w, h - 4); + + // 绘制干扰线 + Random random = new Random(); + g2.setColor(getRandColor(160, 200));// 设置线条的颜色 + for (int i = 0; i < 20; i++) + { + int x = random.nextInt(w - 1); + int y = random.nextInt(h - 1); + int xl = random.nextInt(6) + 1; + int yl = random.nextInt(12) + 1; + g2.drawLine(x, y, x + xl + 40, y + yl + 20); + } + + // 添加噪点 + // 噪声率 + float yawpRate = 0.05f; + int area = (int) (yawpRate * w * h); + for (int i = 0; i < area; i++) + { + int x = random.nextInt(w); + int y = random.nextInt(h); + int rgb = getRandomIntColor(); + image.setRGB(x, y, rgb); + } + // 使图片扭曲 + shear(g2, w, h, c); + + g2.setColor(getRandColor(100, 160)); + int fontSize = h - 4; + Font font = new Font("Algerian", Font.ITALIC, fontSize); + g2.setFont(font); + char[] chars = code.toCharArray(); + for (int i = 0; i < verifySize; i++) + { + AffineTransform affine = new AffineTransform(); + affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), + (w / verifySize) * i + fontSize / 2, h / 2); + g2.setTransform(affine); + g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10); + } + + g2.dispose(); + ImageIO.write(image, "jpg", os); + } + + private static Color getRandColor(int fc, int bc) + { + if (fc > 255) { + fc = 255; + } + if (bc > 255) { + bc = 255; + } + int r = fc + random.nextInt(bc - fc); + int g = fc + random.nextInt(bc - fc); + int b = fc + random.nextInt(bc - fc); + return new Color(r, g, b); + } + + private static int getRandomIntColor() + { + int[] rgb = getRandomRgb(); + int color = 0; + for (int c : rgb) + { + color = color << 8; + color = color | c; + } + return color; + } + + private static int[] getRandomRgb() + { + int[] rgb = new int[3]; + for (int i = 0; i < 3; i++) + { + rgb[i] = random.nextInt(255); + } + return rgb; + } + + private static void shear(Graphics g, int w1, int h1, Color color) + { + shearX(g, w1, h1, color); + shearY(g, w1, h1, color); + } + + private static void shearX(Graphics g, int w1, int h1, Color color) + { + + int period = random.nextInt(2); + + boolean borderGap = true; + int frames = 1; + int phase = random.nextInt(2); + + for (int i = 0; i < h1; i++) + { + double d = (double) (period >> 1) + * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames); + g.copyArea(0, i, w1, 1, (int) d, 0); + if (borderGap) + { + g.setColor(color); + g.drawLine((int) d, i, 0, i); + g.drawLine((int) d + w1, i, w1, i); + } + } + + } + + private static void shearY(Graphics g, int w1, int h1, Color color) + { + + int period = random.nextInt(40) + 10; // 50; + + boolean borderGap = true; + int frames = 20; + int phase = 7; + for (int i = 0; i < w1; i++) + { + double d = (double) (period >> 1) + * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames); + g.copyArea(i, 0, 1, h1, 0, (int) d); + if (borderGap) + { + g.setColor(color); + g.drawLine(i, (int) d, i, 0); + g.drawLine(i, (int) d + h1, i, h1); + } + + } + } + +} diff --git a/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/WafKit.java b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/WafKit.java new file mode 100644 index 0000000..73de2eb --- /dev/null +++ b/yxt-common/yxt-common-base/src/main/java/com/yxt/common/base/utils/WafKit.java @@ -0,0 +1,120 @@ +/********************************************************* + ********************************************************* + ******************** ******************* + ************* ************ + ******* _oo0oo_ ******* + *** o8888888o *** + * 88" . "88 * + * (| -_- |) * + * 0\ = /0 * + * ___/`---'\___ * + * .' \\| |// '. * + * / \\||| : |||// \ * + * / _||||| -:- |||||- \ * + * | | \\\ - /// | | * + * | \_| ''\---/'' |_/ | * + * \ .-\__ '-' ___/-. / * + * ___'. .' /--.--\ `. .'___ * + * ."" '< `.___\_<|>_/___.' >' "". * + * | | : `- \`.;`\ _ /`;.`/ - ` : | | * + * \ \ `_. \_ __\ /__ _/ .-` / / * + * =====`-.____`.___ \_____/___.-`___.-'===== * + * `=---=' * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *********__佛祖保佑__永无BUG__验收通过__钞票多多__********* + *********************************************************/ +package com.yxt.common.base.utils; + +import java.util.regex.Pattern; + +/** + * Project: jbsc-commons
+ * File: WafKit.java
+ * Class: org.jbase.jbsc.commons.base.utils.WafKit
+ * Description: Web防火墙工具类
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2020/9/22 上午11:53
+ * + * @author popo + * @version 1.0 + * @since 1.0 + */ +public class WafKit { + + /** + * @param value 待处理内容 + * @return + * @Description 过滤XSS脚本内容 + */ + public static String stripXSS(String value) { + String rlt = null; + + if (null != value) { + // NOTE: It's highly recommended to use the ESAPI library and uncomment the following line to + // avoid encoded attacks. + // value = ESAPI.encoder().canonicalize(value); + + // Avoid null characters + rlt = value.replaceAll("", ""); + + // Avoid anything between script tags + Pattern scriptPattern = Pattern.compile("", Pattern.CASE_INSENSITIVE); + rlt = scriptPattern.matcher(rlt).replaceAll(""); + + + // Remove any lonesome tag + scriptPattern = Pattern.compile("", Pattern.CASE_INSENSITIVE); + rlt = scriptPattern.matcher(rlt).replaceAll(""); + + // Remove any lonesome