From 75fb7b9eda5a8c6f9c60d3221955754c14fac777 Mon Sep 17 00:00:00 2001 From: JiyangTang <18010816106@163.com> Date: Mon, 3 Jul 2023 11:41:50 +0800 Subject: [PATCH] =?UTF-8?q?job=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ncementsDto.java => AnnouncementsDto.java} | 2 +- .../admin/schedule/EdgeXNoticeSchedule.java | 81 ------ .../admin/schedule/NoticeSchedule.java | 110 ++++++++ .../common/annotation/Sensitive.java | 28 +++ .../common/constants/CacheConstant.java | 2 +- .../serialize/SensitiveJsonSerializer.java | 57 +++++ .../common/serialize/SensitiveStrategy.java | 50 ++++ .../serialize/SystemSettingProperties.java | 60 +++++ .../baogutang/common/utils/Base64Utils.java | 235 ++++++++++++++++++ .../baogutang/common/utils/CommonUtils.java | 37 +++ .../top/baogutang/common/utils/ImageUtil.java | 182 ++++++++++++++ 11 files changed, 761 insertions(+), 83 deletions(-) rename baogutang-admin/src/main/java/top/baogutang/admin/domain/{EdgeXAnnouncementsDto.java => AnnouncementsDto.java} (91%) delete mode 100644 baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java create mode 100644 baogutang-admin/src/main/java/top/baogutang/admin/schedule/NoticeSchedule.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/annotation/Sensitive.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/serialize/SensitiveJsonSerializer.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/serialize/SensitiveStrategy.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/serialize/SystemSettingProperties.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/utils/Base64Utils.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/utils/CommonUtils.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/utils/ImageUtil.java diff --git a/baogutang-admin/src/main/java/top/baogutang/admin/domain/EdgeXAnnouncementsDto.java b/baogutang-admin/src/main/java/top/baogutang/admin/domain/AnnouncementsDto.java similarity index 91% rename from baogutang-admin/src/main/java/top/baogutang/admin/domain/EdgeXAnnouncementsDto.java rename to baogutang-admin/src/main/java/top/baogutang/admin/domain/AnnouncementsDto.java index 98816c4..88ac786 100644 --- a/baogutang-admin/src/main/java/top/baogutang/admin/domain/EdgeXAnnouncementsDto.java +++ b/baogutang-admin/src/main/java/top/baogutang/admin/domain/AnnouncementsDto.java @@ -11,7 +11,7 @@ import java.util.Date; * @date: 2023/06/16 : 12:09 */ @Data -public class EdgeXAnnouncementsDto implements Serializable { +public class AnnouncementsDto implements Serializable { private static final long serialVersionUID = 2069054276884655439L; diff --git a/baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java b/baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java deleted file mode 100644 index 49a5747..0000000 --- a/baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java +++ /dev/null @@ -1,81 +0,0 @@ -package top.baogutang.admin.schedule; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.cloud.context.config.annotation.RefreshScope; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import top.baogutang.admin.domain.EdgeXAnnouncementsDto; -import top.baogutang.admin.services.IWxMsgPushService; -import top.baogutang.admin.utils.DingTalkMsgPushUtils; -import top.baogutang.common.domain.Page; -import top.baogutang.common.domain.Results; -import top.baogutang.common.properties.WxMsgPushProperties; -import top.baogutang.common.utils.HttpUtils; - -import javax.annotation.Resource; -import java.util.Objects; -import java.util.concurrent.TimeUnit; - -import static top.baogutang.common.constants.CacheConstant.MSG_PUSH_PREFIX_KEY; - -/** - * @description: EDGEX公告 - * @author: nikooh - * @date: 2023/06/16 : 11:41 - */ -@Slf4j -@Component -@RefreshScope -public class EdgeXNoticeSchedule { - - @Resource - private IWxMsgPushService wxMsgPushService; - - @Resource - private WxMsgPushProperties wxMsgPushProperties; - - @Resource - private RedisTemplate redisTemplate; - - @Resource - private DingTalkMsgPushUtils dingTalkMsgPushUtils; - - @Value("${dingtalk.baogutang.agentId}") - private String agentId; - - private static final String REQUEST_URL = "https://art-api.edge-x.cn/api/v1/art/announcements?pageNum=1&pageSize=1"; - - /** - * 每分钟查询edgeX公告 - */ - @Scheduled(cron = "0 0/1 * * * ? ") - public void edgeXNotice() { - Results> results = HttpUtils.get(REQUEST_URL, new TypeReference>>() { - }); - log.info(">>>>>>>>>>请求获取edgeX公告返回数据:{}<<<<<<<<<<", JSON.toJSONString(results)); - if (Objects.isNull(results)) { - return; - } - if (!Boolean.TRUE.equals(results.isSuccess())) { - return; - } - if (Objects.isNull(results.getData()) || CollectionUtils.isEmpty(results.getData().getList())) { - return; - } - EdgeXAnnouncementsDto announcementsDto = results.getData().getList().get(0); - String cacheKey = String.format(MSG_PUSH_PREFIX_KEY, announcementsDto.getId()); - - Boolean result = redisTemplate.opsForValue().setIfAbsent(cacheKey, 1, 5, TimeUnit.DAYS); - if (Boolean.TRUE.equals(result)) { - String content = "# " + announcementsDto.getTitle() + "\n\n![](" + announcementsDto.getCover() + ")\n\n> 点击下方链接查看更多详情:\n\n[查看详情](" + "https://app.edge-x.cn/#/noticeDetail?noticeId=" + announcementsDto.getId() + ")"; - dingTalkMsgPushUtils.robotMarkdownMsgPush(announcementsDto.getTitle(), content); -// wxMsgPushService.msgPush(Message.CONTENT_TYPE_HTML, announcementsDto.getTitle(), announcementsDto.getContent(), wxMsgPushProperties.getTopicIds()); - } - } - -} diff --git a/baogutang-admin/src/main/java/top/baogutang/admin/schedule/NoticeSchedule.java b/baogutang-admin/src/main/java/top/baogutang/admin/schedule/NoticeSchedule.java new file mode 100644 index 0000000..e2f2e54 --- /dev/null +++ b/baogutang-admin/src/main/java/top/baogutang/admin/schedule/NoticeSchedule.java @@ -0,0 +1,110 @@ +package top.baogutang.admin.schedule; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import top.baogutang.admin.domain.AnnouncementsDto; +import top.baogutang.admin.services.IWxMsgPushService; +import top.baogutang.admin.utils.DingTalkMsgPushUtils; +import top.baogutang.common.domain.Page; +import top.baogutang.common.domain.Results; +import top.baogutang.common.properties.WxMsgPushProperties; +import top.baogutang.common.utils.HttpUtils; + +import javax.annotation.Resource; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import static top.baogutang.common.constants.CacheConstant.MSG_PUSH_PREFIX_KEY; + +/** + * @description: EDGEX公告 + * @author: nikooh + * @date: 2023/06/16 : 11:41 + */ +@Slf4j +@Component +@RefreshScope +public class NoticeSchedule { + + @Resource + private IWxMsgPushService wxMsgPushService; + + @Resource + private WxMsgPushProperties wxMsgPushProperties; + + @Resource + private RedisTemplate redisTemplate; + + @Resource + private DingTalkMsgPushUtils dingTalkMsgPushUtils; + + @Value("${dingtalk.baogutang.agentId}") + private String agentId; + + private static final String EDGE_X_REQUEST_URL = "https://art-api.edge-x.cn/api/v1/art/announcements?pageNum=1&pageSize=1"; + private static final String EDGE_REQUEST_URL = "https://art-api.heishiapp.com/api/v1/art/announcements?pageNum=1&pageSize=1"; + + /** + * 每分钟查询edgeX公告 + */ + @Scheduled(cron = "0 0/1 * * * ? ") + public void edgeXNotice() { + Results> results = HttpUtils.get(EDGE_X_REQUEST_URL, new TypeReference>>() { + }); + log.info(">>>>>>>>>>请求获取edgeX公告返回数据:{}<<<<<<<<<<", JSON.toJSONString(results)); + if (Objects.isNull(results)) { + return; + } + if (!Boolean.TRUE.equals(results.isSuccess())) { + return; + } + if (Objects.isNull(results.getData()) || CollectionUtils.isEmpty(results.getData().getList())) { + return; + } + AnnouncementsDto announcementsDto = results.getData().getList().get(0); + String cacheKey = String.format(MSG_PUSH_PREFIX_KEY, "edge_x", announcementsDto.getId()); + + Boolean result = redisTemplate.opsForValue().setIfAbsent(cacheKey, 1, 5, TimeUnit.DAYS); + if (Boolean.TRUE.equals(result)) { + String content = "# EDGE-X-" + announcementsDto.getTitle() + "\n\n![](" + announcementsDto.getCover() + ")\n\n> 点击下方链接查看更多详情:\n\n[查看详情](" + "https://app.edge-x.cn/#/noticeDetail?noticeId=" + announcementsDto.getId() + ")"; + dingTalkMsgPushUtils.robotMarkdownMsgPush(announcementsDto.getTitle(), content); +// wxMsgPushService.msgPush(Message.CONTENT_TYPE_HTML, announcementsDto.getTitle(), announcementsDto.getContent(), wxMsgPushProperties.getTopicIds()); + } + } + + /** + * 每分钟查询edge公告 + */ + @Scheduled(cron = "0 0/1 * * * ? ") + public void edgeNotice() { + Results> results = HttpUtils.get(EDGE_REQUEST_URL, new TypeReference>>() { + }); + log.info(">>>>>>>>>>请求获取edge公告返回数据:{}<<<<<<<<<<", JSON.toJSONString(results)); + if (Objects.isNull(results)) { + return; + } + if (!Boolean.TRUE.equals(results.isSuccess())) { + return; + } + if (Objects.isNull(results.getData()) || CollectionUtils.isEmpty(results.getData().getList())) { + return; + } + AnnouncementsDto announcementsDto = results.getData().getList().get(0); + String cacheKey = String.format(MSG_PUSH_PREFIX_KEY, "edge", announcementsDto.getId()); + + Boolean result = redisTemplate.opsForValue().setIfAbsent(cacheKey, 1, 5, TimeUnit.DAYS); + if (Boolean.TRUE.equals(result)) { + String content = "# EDGE-" + announcementsDto.getTitle() + "\n\n![](" + announcementsDto.getCover() + ")\n\n> 点击下方链接查看更多详情:\n\n[查看详情](" + "https://activities-h5.heishiapp.com/#/noticeDetail?noticeId=" + announcementsDto.getId() + ")"; + dingTalkMsgPushUtils.robotMarkdownMsgPush(announcementsDto.getTitle(), content); +// wxMsgPushService.msgPush(Message.CONTENT_TYPE_HTML, announcementsDto.getTitle(), announcementsDto.getContent(), wxMsgPushProperties.getTopicIds()); + } + } + +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/annotation/Sensitive.java b/baogutang-common/src/main/java/top/baogutang/common/annotation/Sensitive.java new file mode 100644 index 0000000..5e49008 --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/annotation/Sensitive.java @@ -0,0 +1,28 @@ +package top.baogutang.common.annotation; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import top.baogutang.common.serialize.SensitiveJsonSerializer; +import top.baogutang.common.serialize.SensitiveStrategy; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * 敏感注解 + * + * @author liushuai(liushuai711 @ gmail.com) + * @version v4.0 + * @Description: + * @since 2021/9/10 16:45 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@JacksonAnnotationsInside +@JsonSerialize(using = SensitiveJsonSerializer.class) +public @interface Sensitive { + SensitiveStrategy strategy(); +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/constants/CacheConstant.java b/baogutang-common/src/main/java/top/baogutang/common/constants/CacheConstant.java index 9b20152..6ba5c51 100644 --- a/baogutang-common/src/main/java/top/baogutang/common/constants/CacheConstant.java +++ b/baogutang-common/src/main/java/top/baogutang/common/constants/CacheConstant.java @@ -30,7 +30,7 @@ public class CacheConstant { /** * 消息推送 */ - public static final String MSG_PUSH_PREFIX_KEY = "top:baogutang:msg:push:%d:"; + public static final String MSG_PUSH_PREFIX_KEY = "top:baogutang:msg:push:%s:%d:"; public static final Integer ENABLE = 0; diff --git a/baogutang-common/src/main/java/top/baogutang/common/serialize/SensitiveJsonSerializer.java b/baogutang-common/src/main/java/top/baogutang/common/serialize/SensitiveJsonSerializer.java new file mode 100644 index 0000000..6de7b6b --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/serialize/SensitiveJsonSerializer.java @@ -0,0 +1,57 @@ +package top.baogutang.common.serialize; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import top.baogutang.common.annotation.Sensitive; + +import java.io.IOException; +import java.util.Objects; + +/** + * 敏感信息序列化时 过滤 + * + * @author liushuai(liushuai711 @ gmail.com) + * @version v4.0 + * @Description: + * @since 2021/9/10 16:46 + */ +public class SensitiveJsonSerializer extends JsonSerializer + implements ContextualSerializer, ApplicationContextAware { + private SensitiveStrategy strategy; + + /** + * 系统配置 + */ + private SystemSettingProperties systemSettingProperties; + + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + // 字段序列化处理 + gen.writeString(strategy.desensitizer().apply(value)); + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { + //获取敏感枚举 + Sensitive annotation = property.getAnnotation(Sensitive.class); + //如果有敏感注解,则加入脱敏规则 + if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) { + this.strategy = annotation.strategy(); + return this; + } + return prov.findValueSerializer(property.getType(), property); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + systemSettingProperties = applicationContext.getBean(SystemSettingProperties.class); + } + +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/serialize/SensitiveStrategy.java b/baogutang-common/src/main/java/top/baogutang/common/serialize/SensitiveStrategy.java new file mode 100644 index 0000000..db3cfd9 --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/serialize/SensitiveStrategy.java @@ -0,0 +1,50 @@ +package top.baogutang.common.serialize; + +import java.util.function.Function; + +/** + * 敏感策略枚举 + * + * @author liushuai(liushuai711 @ gmail.com) + * @version v4.0 + * @Description: + * @since 2021/9/10 16:46 + */ + +public enum SensitiveStrategy { + /** + * Username sensitive strategy. + */ + USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")), + /** + * Id card sensitive type. + */ + ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")), + /** + * Phone sensitive type. + */ + PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")), + /** + * Email sensitive type. + */ + EMAIL(s -> s.replaceAll("(^\\w)[^@]*(@.*$)", "$1****$2")), + /** + * Name sensitive type. + */ + NAME(s -> s.replaceAll("^(.{3}).+(.{3})$", "$1*****$2")), + /** + * Address sensitive type. + */ + ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****")); + + + private final Function desensitizer; + + SensitiveStrategy(Function desensitizer) { + this.desensitizer = desensitizer; + } + + public Function desensitizer() { + return desensitizer; + } +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/serialize/SystemSettingProperties.java b/baogutang-common/src/main/java/top/baogutang/common/serialize/SystemSettingProperties.java new file mode 100644 index 0000000..395ecd3 --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/serialize/SystemSettingProperties.java @@ -0,0 +1,60 @@ +package top.baogutang.common.serialize; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * 系统设置 + * + * @author Chopper + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "baogutang.system") +public class SystemSettingProperties { + + + /** + * 是否是演示站点 + */ + private Boolean isDemoSite = false; + + /** + * 测试模式 + * 验证码短信为6个1 + */ + private Boolean isTestModel = false; + + /** + * 脱敏级别: + * 0:不做脱敏处理 + * 1:管理端用户手机号等信息脱敏 + * 2:商家端信息脱敏(为2时,表示管理端,商家端同时脱敏) + *

+ * PS: + */ + private Integer sensitiveLevel = 0; + + + public Boolean getDemoSite() { + if (isDemoSite == null) { + return false; + } + return isDemoSite; + } + + public Boolean getTestModel() { + if (isTestModel == null) { + return false; + } + return isTestModel; + } + + public Integer getSensitiveLevel() { + if (sensitiveLevel == null) { + return 0; + } + return sensitiveLevel; + } +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/utils/Base64Utils.java b/baogutang-common/src/main/java/top/baogutang/common/utils/Base64Utils.java new file mode 100644 index 0000000..d04d037 --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/utils/Base64Utils.java @@ -0,0 +1,235 @@ +package top.baogutang.common.utils; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * Base64编码 + * + * @author looly + * @since 3.2.0 + */ +public class Base64Utils { + + private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + /** + * 标准编码表 + */ + private static final byte[] STANDARD_ENCODE_TABLE = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' + }; + /** + * URL安全的编码表,将 + 和 / 替换为 - 和 _ + */ + private static final byte[] URL_SAFE_ENCODE_TABLE = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '-', '_' + }; + + //-------------------------------------------------------------------- encode + + /** + * 编码为Base64,非URL安全的 + * + * @param arr 被编码的数组 + * @param lineSep 在76个char之后是CRLF还是EOF + * @return 编码后的bytes + */ + public static byte[] encode(byte[] arr, boolean lineSep) { + return encode(arr, lineSep, false); + } + + /** + * 编码为Base64,URL安全的 + * + * @param arr 被编码的数组 + * @param lineSep 在76个char之后是CRLF还是EOF + * @return 编码后的bytes + * @since 3.0.6 + */ + public static byte[] encodeUrlSafe(byte[] arr, boolean lineSep) { + return encode(arr, lineSep, true); + } + + /** + * base64编码 + * + * @param source 被编码的base64字符串 + * @return 被加密后的字符串 + */ + public static String encode(CharSequence source) { + return encode(source, DEFAULT_CHARSET); + } + + /** + * base64编码,URL安全 + * + * @param source 被编码的base64字符串 + * @return 被加密后的字符串 + * @since 3.0.6 + */ + public static String encodeUrlSafe(CharSequence source) { + return encodeUrlSafe(source, DEFAULT_CHARSET); + } + + /** + * base64编码 + * + * @param source 被编码的base64字符串 + * @param charset 字符集 + * @return 被加密后的字符串 + */ + public static String encode(CharSequence source, Charset charset) { + return encode(bytes(source, charset)); + } + + /** + * base64编码,URL安全的 + * + * @param source 被编码的base64字符串 + * @param charset 字符集 + * @return 被加密后的字符串 + * @since 3.0.6 + */ + public static String encodeUrlSafe(CharSequence source, Charset charset) { + return encodeUrlSafe(bytes(source, charset)); + } + + /** + * base64编码 + * + * @param source 被编码的base64字符串 + * @return 被加密后的字符串 + */ + public static String encode(byte[] source) { + return str(encode(source, false), DEFAULT_CHARSET); + } + + /** + * base64编码,URL安全的 + * + * @param source 被编码的base64字符串 + * @return 被加密后的字符串 + * @since 3.0.6 + */ + public static String encodeUrlSafe(byte[] source) { + return str(encodeUrlSafe(source, false), DEFAULT_CHARSET); + } + + /** + * 编码为Base64
+ * 如果isMultiLine为true,则每76个字符一个换行符,否则在一行显示 + * + * @param arr 被编码的数组 + * @param isMultiLine 在76个char之后是CRLF还是EOF + * @param isUrlSafe 是否使用URL安全字符,一般为false + * @return 编码后的bytes + */ + public static byte[] encode(byte[] arr, boolean isMultiLine, boolean isUrlSafe) { + if (null == arr) { + return null; + } + + int len = arr.length; + if (len == 0) { + return new byte[0]; + } + + int evenlen = (len / 3) * 3; + int cnt = ((len - 1) / 3 + 1) << 2; + int destlen = cnt + (isMultiLine ? (cnt - 1) / 76 << 1 : 0); + byte[] dest = new byte[destlen]; + + byte[] encodeTable = isUrlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE; + + for (int s = 0, d = 0, cc = 0; s < evenlen; ) { + int i = (arr[s++] & 0xff) << 16 | (arr[s++] & 0xff) << 8 | (arr[s++] & 0xff); + + dest[d++] = encodeTable[(i >>> 18) & 0x3f]; + dest[d++] = encodeTable[(i >>> 12) & 0x3f]; + dest[d++] = encodeTable[(i >>> 6) & 0x3f]; + dest[d++] = encodeTable[i & 0x3f]; + + if (isMultiLine && ++cc == 19 && d < destlen - 2) { + dest[d++] = '\r'; + dest[d++] = '\n'; + cc = 0; + } + } + + //剩余位数 + int left = len - evenlen; + if (left > 0) { + int i = ((arr[evenlen] & 0xff) << 10) | (left == 2 ? ((arr[len - 1] & 0xff) << 2) : 0); + + dest[destlen - 4] = encodeTable[i >> 12]; + dest[destlen - 3] = encodeTable[(i >>> 6) & 0x3f]; + + if (isUrlSafe) { + //在URL Safe模式下,=为URL中的关键字符,不需要补充。空余的byte位要去掉。 + int urlSafeLen = destlen - 2; + if (2 == left) { + dest[destlen - 2] = encodeTable[i & 0x3f]; + urlSafeLen += 1; + } + byte[] urlSafeDest = new byte[urlSafeLen]; + System.arraycopy(dest, 0, urlSafeDest, 0, urlSafeLen); + return urlSafeDest; + } else { + dest[destlen - 2] = (left == 2) ? encodeTable[i & 0x3f] : (byte) '='; + dest[destlen - 1] = '='; + } + } + return dest; + } + + /** + * 编码字符串 + * + * @param str 字符串 + * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 + * @return 编码后的字节码 + */ + public static byte[] bytes(CharSequence str, Charset charset) { + if (str == null) { + return null; + } + + if (null == charset) { + return str.toString().getBytes(); + } + return str.toString().getBytes(charset); + } + + /** + * 解码字节码 + * + * @param data 字符串 + * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 + * @return 解码后的字符串 + */ + public static String str(byte[] data, Charset charset) { + if (data == null) { + return null; + } + + if (null == charset) { + return new String(data); + } + return new String(data, charset); + } + +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/utils/CommonUtils.java b/baogutang-common/src/main/java/top/baogutang/common/utils/CommonUtils.java new file mode 100644 index 0000000..fadf3aa --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/utils/CommonUtils.java @@ -0,0 +1,37 @@ +package top.baogutang.common.utils; + +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +/** + * 通用工具 + * @author Chopper + */ +public class CommonUtils { + + public static final String BASE_NUMBER = "0123456789"; + + /** + * 以UUID重命名 + * @param fileName 文件名称 + * @return 格式化名称 + */ + public static String rename(String fileName) { + String extName = fileName.substring(fileName.lastIndexOf(".")); + return UUID.randomUUID().toString().replace("-", "") + extName; + } + + + /** + * 随机6位数生成 + */ + public static String getRandomNum() { + StringBuilder sb = new StringBuilder(6); + for (int i = 0; i < 6; i++) { + int num = ThreadLocalRandom.current().nextInt(BASE_NUMBER.length()); + sb.append(BASE_NUMBER.charAt(num)); + } + return sb.toString(); + } + +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/utils/ImageUtil.java b/baogutang-common/src/main/java/top/baogutang/common/utils/ImageUtil.java new file mode 100644 index 0000000..0616267 --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/utils/ImageUtil.java @@ -0,0 +1,182 @@ +package top.baogutang.common.utils; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.IOException; + +/** + * ImageUtil + * + * @author niko + * @version v1.0 + * 2020-11-17 14:50 + */ +public class ImageUtil { + + /** + * 添加水印 + * + * @param oriImage 原图 + * @param text 文字 + * @throws IOException 流操作异常 + */ + public static void addWatermark(BufferedImage oriImage, String text) { + Graphics2D graphics2D = oriImage.createGraphics(); + //设置水印文字颜色 + graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + //设置水印文字Font + graphics2D.setColor(Color.black); + //设置水印文字透明度 + graphics2D.setFont(new Font("宋体", Font.BOLD, 30)); + //第一参数->设置的内容,后面两个参数->文字在图片上的坐标位置(x,y) + graphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.4f)); + graphics2D.drawString(text, 10, 40); + graphics2D.dispose(); + } + + + /** + * 干扰图 + * + * @param oriImage 原图 + * @param templateImage 模板图 + * @param x 随机扣取坐标X + * @param y 随机扣取坐标y + */ + public static void interfereTemplate(BufferedImage oriImage, BufferedImage templateImage, + int x, int y) { + //临时数组遍历用于高斯模糊存周边像素值 + int[][] matrix = new int[3][3]; + int[] values = new int[9]; + + int xLength = templateImage.getWidth(); + int yLength = templateImage.getHeight(); + //模板图像宽度 + for (int i = 0; i < xLength; i++) { + //模板图片高度 + for (int j = 0; j < yLength; j++) { + //如果模板图像当前像素点不是透明色 copy源文件信息到目标图片中 + int rgb = templateImage.getRGB(i, j); + if (rgb < 0) { + //抠图区域高斯模糊 + readPixel(oriImage, x + i, y + j, values); + fillMatrix(matrix, values); + oriImage.setRGB(x + i, y + j, avgMatrix(matrix)); + } + + //防止数组越界判断 + if (i == (xLength - 1) || j == (yLength - 1)) { + continue; + } + int rightRgb = templateImage.getRGB(i + 1, j); + int downRgb = templateImage.getRGB(i, j + 1); + //描边处理,,取带像素和无像素的界点,判断该点是不是临界轮廓点,如果是设置该坐标像素是白色 + boolean rgbImage = ((rgb >= 0 && rightRgb < 0) + || (rgb < 0 && rightRgb >= 0) + || (rgb >= 0 && downRgb < 0) + || (rgb < 0 && downRgb >= 0)); + } + } + } + + /** + * @param oriImage 原图 + * @param templateImage 模板图 + * @param newImage 新抠出的小图 + * @param x 随机扣取坐标X + * @param y 随机扣取坐标y + */ + public static void cutByTemplate(BufferedImage oriImage, BufferedImage templateImage, BufferedImage newImage, + int x, int y) { + //临时数组遍历用于高斯模糊存周边像素值 + int[][] matrix = new int[3][3]; + int[] values = new int[9]; + + int xLength = templateImage.getWidth(); + int yLength = templateImage.getHeight(); + //模板图像宽度 + for (int i = 0; i < xLength; i++) { + //模板图片高度 + for (int j = 0; j < yLength; j++) { + //如果模板图像当前像素点不是透明色 copy源文件信息到目标图片中 + int rgb = templateImage.getRGB(i, j); + if (rgb < 0) { + newImage.setRGB(i, j, oriImage.getRGB(x + i, y + j)); + + //抠图区域高斯模糊 + readPixel(oriImage, x + i, y + j, values); + fillMatrix(matrix, values); + oriImage.setRGB(x + i, y + j, avgMatrix(matrix)); + } + + //防止数组越界判断 + if (i == (xLength - 1) || j == (yLength - 1)) { + continue; + } + int rightRgb = templateImage.getRGB(i + 1, j); + int downRgb = templateImage.getRGB(i, j + 1); + //描边处理,,取带像素和无像素的界点,判断该点是不是临界轮廓点,如果是设置该坐标像素是白色 + boolean rgbImage = ((rgb >= 0 && rightRgb < 0) + || (rgb < 0 && rightRgb >= 0) + || (rgb >= 0 && downRgb < 0) + || (rgb < 0 && downRgb >= 0)); + + if (rgbImage) { + newImage.setRGB(i, j, Color.GRAY.getRGB()); + } + } + } + } + + public static void readPixel(BufferedImage img, int x, int y, int[] pixels) { + int xStart = x - 1; + int yStart = y - 1; + int current = 0; + for (int i = xStart; i < 3 + xStart; i++) { + for (int j = yStart; j < 3 + yStart; j++) { + int tx = i; + if (tx < 0) { + tx = -tx; + + } else if (tx >= img.getWidth()) { + tx = x; + } + int ty = j; + if (ty < 0) { + ty = -ty; + } else if (ty >= img.getHeight()) { + ty = y; + } + pixels[current++] = img.getRGB(tx, ty); + + } + } + } + + public static void fillMatrix(int[][] matrix, int[] values) { + int filled = 0; + for (int[] x : matrix) { + for (int j = 0; j < x.length; j++) { + x[j] = values[filled++]; + } + } + } + + public static int avgMatrix(int[][] matrix) { + int r = 0; + int g = 0; + int b = 0; + for (int[] x : matrix) { + for (int j = 0; j < x.length; j++) { + if (j == 1) { + continue; + } + Color c = new Color(x[j]); + r += c.getRed(); + g += c.getGreen(); + b += c.getBlue(); + } + } + return new Color(r / 8, g / 8, b / 8).getRGB(); + } +}