job修改
This commit is contained in:
parent
ed92db8b91
commit
75fb7b9eda
@ -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;
|
||||
|
||||
@ -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<String, Object> 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<Page<EdgeXAnnouncementsDto>> results = HttpUtils.get(REQUEST_URL, new TypeReference<Results<Page<EdgeXAnnouncementsDto>>>() {
|
||||
});
|
||||
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 + ")\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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<String, Object> 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<Page<AnnouncementsDto>> results = HttpUtils.get(EDGE_X_REQUEST_URL, new TypeReference<Results<Page<AnnouncementsDto>>>() {
|
||||
});
|
||||
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 + ")\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<Page<AnnouncementsDto>> results = HttpUtils.get(EDGE_REQUEST_URL, new TypeReference<Results<Page<AnnouncementsDto>>>() {
|
||||
});
|
||||
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 + ")\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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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<String>
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<String, String> desensitizer;
|
||||
|
||||
SensitiveStrategy(Function<String, String> desensitizer) {
|
||||
this.desensitizer = desensitizer;
|
||||
}
|
||||
|
||||
public Function<String, String> desensitizer() {
|
||||
return desensitizer;
|
||||
}
|
||||
}
|
||||
@ -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时,表示管理端,商家端同时脱敏)
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@ -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<br>
|
||||
* 如果isMultiLine为<code>true</code>,则每76个字符一个换行符,否则在一行显示
|
||||
*
|
||||
* @param arr 被编码的数组
|
||||
* @param isMultiLine 在76个char之后是CRLF还是EOF
|
||||
* @param isUrlSafe 是否使用URL安全字符,一般为<code>false</code>
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user