Commit ae8f5bcf by zhangyang

Merge branch 'master' into feature/1006066

# Conflicts:
#	pcloud-common-core/src/main/java/com/pcloud/common/core/constant/MQTopicProducer.java
parents dfb215bd be516cae
**Pcloud Common Pom 3.x**
* Upgrade Spring Boot to 2.x
* Upgrade Spring Cloud to Hoxton.SR11
## 各环境不同版本打包命令
```sh
-Dreversion=3.1.0-SNAPSHOT
mvn clean install -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=指定版本号
```
\ No newline at end of file
@echo off
call mvn eclipse:clean
call pause
call mvn -Ptest clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U
call mvn -Puat clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.0-RELEASE
call mvn -Pperf clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.1-SNAPSHOT
call mvn -Pprod clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.1-RELEASE
call mvn -Ptsrpd clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.2-RELEASE
@pause
\ No newline at end of file
call mvn -Ptest clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U
@pause
\ No newline at end of file
call mvn clean install -Denforcer.skip=true -Dmaven.test.skip=true -U
call pause
\ No newline at end of file
......@@ -5,7 +5,7 @@
<parent>
<groupId>com.pcloud.common</groupId>
<artifactId>pcloud-common-parent</artifactId>
<version>2.1.0-RELEASE</version>
<version>3.1.0-SNAPSHOT</version>
</parent>
<artifactId>pcloud-common-config</artifactId>
......@@ -16,7 +16,7 @@
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
call mvn -Ptest clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U
call mvn -Puat clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.0-RELEASE
call mvn -Pperf clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.1-SNAPSHOT
call mvn -Pprod clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.1-RELEASE
call mvn -Ptsrpd clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.2-RELEASE
@pause
\ No newline at end of file
call mvn -Ptest clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U
@pause
\ No newline at end of file
call mvn -Ptest clean install -Denforcer.skip=true -Dmaven.test.skip=true -U
call pause
\ No newline at end of file
......@@ -5,65 +5,44 @@
<parent>
<groupId>com.pcloud.common</groupId>
<artifactId>pcloud-common-parent</artifactId>
<version>2.1.0-RELEASE</version>
<version>3.1.0-SNAPSHOT</version>
</parent>
<artifactId>pcloud-common-core</artifactId>
<packaging>jar</packaging>
<version>${pcloud-common-core.version}</version>
<version>${reversion}</version>
<name>pcloud-common-core</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<universe-springcloud-monitor-starter.version>1.0.1-SNAPSHOT</universe-springcloud-monitor-starter.version>
<universe-dbmonitor-starter.version>1.0.1-SNAPSHOT</universe-dbmonitor-starter.version>
<universe-monitorlog-logback-starter.version>1.0.1-SNAPSHOT</universe-monitorlog-logback-starter.version>
<universe-error-alarm.version>3.0.1-SNAPSHOT</universe-error-alarm.version>
</properties>
<dependencies>
<dependency>
<groupId>com.pcloud.common</groupId>
<artifactId>pcloud-common</artifactId>
<version>${pcloud-common.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<version>${reversion}</version>
</dependency>
<dependency>
<groupId>com.pcloud.universe</groupId>
<artifactId>universe-springcloud-monitor-starter</artifactId>
<version>${universe-springcloud-monitor-starter.version}</version>
</dependency>
<dependency>
<groupId>com.pcloud.universe</groupId>
<artifactId>universe-dbmonitor-starter</artifactId>
<version>${universe-dbmonitor-starter.version}</version>
</dependency>
<dependency>
<groupId>com.pcloud.universe</groupId>
<artifactId>universe-monitorlog-logback-starter</artifactId>
<version>${universe-monitorlog-logback-starter.version}</version>
</dependency>
<!-- Database connect Begin -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!-- Database connect End -->
<!-- Mysql Driver Begin -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Mysql Driver End -->
<!-- Jackson Begin -->
<dependency>
......@@ -71,6 +50,17 @@
<artifactId>jackson-mapper-asl</artifactId>
</dependency>
<!-- Jackson End -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>com.pcloud.universe</groupId>
<artifactId>universe-error-alarm</artifactId>
<version>${universe-error-alarm.version}</version>
</dependency>
</dependencies>
</project>
package com.pcloud.common.core.aspect;
import com.pcloud.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.util.ResourceUtils;
import redis.clients.util.JedisClusterCRC16;
import redis.clients.util.SafeEncoder;
import java.io.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 添加监控,查看
*/
//@Component
//@Aspect
@Slf4j
public class JedisClusterAspect {
//需要统计的方法调用次数
private Map<String, ConcurrentHashMap<String, AtomicInteger>> solfDistributedMap = new ConcurrentHashMap<>();
private Map<String, ConcurrentHashMap<String, AtomicInteger>> tempMap = new ConcurrentHashMap<>();
private LFU<String, String> cache = new LFU<>(10000);
public JedisClusterAspect() {
//初始化redis操作
new PringLogThread().start();
}
@Pointcut("execution(* redis.clients.jedis.JedisCluster.*(..))")
public void pointcut() {
}
class PringLogThread extends Thread {
@Override
public void run() {
String path = getResourceBasePath() + File.separator + "redislog" + File.separator;
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
while (true) {
BufferedWriter out = null;
try {
Thread.sleep(60*60 * 1000);
tempMap.putAll(solfDistributedMap);
solfDistributedMap.clear();
String fileName = "hotkey" + DateUtils.getYmdHmsTime() + ".log";
out = new BufferedWriter(new FileWriter(path + fileName));
for (Map.Entry<String, ConcurrentHashMap<String, AtomicInteger>> entry : tempMap.entrySet()) {
for (Map.Entry<String, AtomicInteger> childEntry : entry.getValue().entrySet()) {
out.write("key前缀:"+entry.getKey() + ",节点:" + childEntry.getKey());
out.write(",调用次数:" + childEntry.getValue());
out.newLine();
}
}
tempMap.clear();
Map<String, LFU<String, String>.HitRate> hotMap = cache.getHotKeyMap();
for (Map.Entry<String, LFU<String, String>.HitRate> entry : hotMap.entrySet()) {
LFU<String, String>.HitRate hitRate = entry.getValue();
out.write("key:" + hitRate.getKey() + ",槽位:" + hitRate.getV() + ",次数:" + hitRate.getHitCount());
out.newLine();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
}
}
}
}
}
@AfterReturning(value = "pointcut()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
Object[] obj = joinPoint.getArgs();
String key = obj[0].toString();
setSoltDistributed(key);
cache.put(key, getNodeName(key));
int randomInt = RandomUtils.nextInt(1,101);
//100里面1个数,小于等于10的概率就是10%
if(randomInt<10){
log.warn("采样hotkey methodName {} key {}",methodName,key);
}
if(key.startsWith("readercenter")){
log.warn("统计增长比较快的key methodName {} key {}",methodName,key);
}
}
private String getNodeName(String key){
int slot = JedisClusterCRC16.getSlot(SafeEncoder.encode(key));
String nodeName = "";
if (slot >= 0 && slot <= 4095) {
nodeName = "firstNode";
} else if (slot >= 4096 && slot <= 8191) {
nodeName = "secondNode";
} else if (slot >= 8192 && slot <= 12287) {
nodeName = "thirdNode";
} else if (slot > 12288 && slot <= 16383) {
nodeName = "fourthNode";
}
return nodeName;
}
/**
* 计算key的分布
*
* @param key
*/
private void setSoltDistributed(String key) {
String[] keys = key.split(":");
if (keys.length < 2) {
return;
}
String keyPrefix = key.substring(0, key.lastIndexOf(":"));
String nodeName = getNodeName(key);
ConcurrentHashMap<String, AtomicInteger> map = solfDistributedMap.get(keyPrefix);
if (map == null) {
map = new ConcurrentHashMap<String, AtomicInteger>();
solfDistributedMap.put(keyPrefix,map);
}
AtomicInteger count = map.get(nodeName);
if (count == null) {
count = new AtomicInteger(1);
} else {
count.getAndIncrement();
}
map.put(nodeName, count);
}
private static String getResourceBasePath() {
// 获取跟目录
File path = null;
try {
path = new File(ResourceUtils.getURL("classpath:").getPath());
} catch (FileNotFoundException e) {
// nothing to do
}
if (path == null || !path.exists()) {
path = new File("");
}
String pathStr = path.getAbsolutePath();
// 如果是在eclipse中运行,则和target同级目录,如果是jar部署到服务器,则默认和jar包同级
pathStr = pathStr.replace("\\target\\classes", "");
return pathStr;
}
public void addMissCount(ConcurrentHashMap<String, AtomicInteger> map, String key) {
AtomicInteger missCount = map.get(key);
if (missCount == null) {
missCount = new AtomicInteger(1);
} else {
missCount.getAndIncrement();
}
map.put(key, missCount);
}
}
......@@ -476,16 +476,21 @@ public class MQTopicProducer {
public static final String FISSION_POSTER_SUBSCRIBE = "topic.fissionPosterSubscribe";
/**
* 服务消息预警
*/
public static final String ALERT_MESSAGE_COUNT = "topic.alertMessageCount";
/**
* 会员活动书刊配置
*/
public static final String MEMBER_ACTIVITY_BOOK_SET = "topic.memberActivityBookSet";
/**
* 新读者关注
*/
public static final String READER_SUBSCRIBE = "topic.subscribe";
/**
* 服务消息预警
*/
public static final String ALERT_MESSAGE_COUNT = "topic.alertMessageCount";
/**
* 文本转语音
*/
public static final String TEXT_TO_SPEACH = "topic.textToSpeach";
}
......@@ -362,6 +362,10 @@ public class ProductTypeConstant {
*/
public static final String SPECIAL = "SPECIAL";
/**
* 图书订购
*/
public static final String BOOK_ORDER_APP = "BOOK_ORDER_APP";
/**
* 热门作品类型
......@@ -392,7 +396,7 @@ public class ProductTypeConstant {
EF, VIDEO_COURSE, PRETESTAPP, AUDIO_RESOURCE, QA_APP, EBOOK_APP, AUDIO_MAGIC, TEACH_RESOURCE_APP,
COURSE_WARE, TEST_PAPER_APP, MATCH_LISTEN, WORD_DICTATION, STROKE_ORDER_APP, IMAGE_APP, MEMBER_APP,
ARTICLE_READING, ENGLISH_WALKMAN, ORAL_EVALUATION, PBSTORY, PDF_APP, WORD_APP, SUBJECTNOTE_APP, BM, BOOK_CLICK_APP,
DRAW_APP, COLD_KNOWLEDGE, SPECIAL};
DRAW_APP, COLD_KNOWLEDGE, SPECIAL, BOOK_ORDER_APP};
/**
* 数据平台埋点型作品
......
......@@ -213,5 +213,5 @@ public class SMSTemplateConstant {
/**
* 服务${serveName}剩余使用数量已不足20%, 请及时充值。
*/
public static final String ALERT_MESSAGE_COUNT = "SMS_21061100006";
public static final String ALERT_MESSAGE_COUNT = "SMS_21092600006";
}
......@@ -41,6 +41,10 @@ public class DataSourceConfig {
public static final String SESSION_FACTORY_NAME = "sqlSessionFactory";
public static final String SESSION_TEMPLATE_NAME = "sqlSessionTemplate";
static {
System.setProperty("druid.mysql.usePingMethod","false");
}
private String url;
private String type;
......@@ -118,6 +122,7 @@ public class DataSourceConfig {
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setFilters(filtersNew);
datasource.setConnectionProperties(connectionPropertiesNew);
datasource.setKeepAlive(true);
// datasource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
ArrayList<String> arr = new ArrayList<>();
arr.add("set names utf8mb4;");
......
......@@ -35,10 +35,10 @@ public class SendMessageDto implements Serializable{
*/
private String phoneAreaCode;
/*
签名
/**
* 签名
*/
private String signature;
private String signature;
public String getSignature() {
return signature;
......
......@@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
......@@ -18,6 +19,7 @@ import com.alibaba.fastjson.JSONObject;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.permission.Permission;
import com.pcloud.common.utils.SessionUtil;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
/**
*
......@@ -40,6 +42,12 @@ public class GlobalHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler instanceof ResourceHttpRequestHandler
|| handler instanceof BasicErrorController) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
if (method.isAnnotationPresent(Permission.class)) {
......@@ -58,11 +66,9 @@ public class GlobalHandlerInterceptor implements HandlerInterceptor {
}
}
}
if (!flag)
if (!flag) {
throw BizException.PERMISSION_NOT_FOUND;
LOGGER.info("【权限验证】调用--" + method.getName() + "--方法,token为-->" + token);
} else {
LOGGER.info("【权限验证】调用--" + method.getName() + "--方法,不需要权限。");
}
}
return true;
}
......
......@@ -4,9 +4,7 @@ import com.pcloud.universe.monitor.provider.MonitorInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.pcloud.common.core.interceptor.GlobalHandlerInterceptor;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
*
......@@ -16,7 +14,7 @@ import com.pcloud.common.core.interceptor.GlobalHandlerInterceptor;
* @版本:1.0
*/
@Configuration
public class GlobalWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
public class GlobalWebMvcConfigurerAdapter implements WebMvcConfigurer {
@Value("${spring.application.name}")
private String appCode;
......@@ -27,7 +25,12 @@ public class GlobalWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
/**
* 监控埋点日志拦截器,需要在第一个
*/
registry.addInterceptor(new MonitorInterceptor(appCode));
registry.addInterceptor(new MonitorInterceptor(appCode))
.excludePathPatterns("/**/*.css", "/**/*.js",
"/**/*.jpg", "/**/*.png", "/**/*.gif", "/**/*.ico", "/**/*.tif", "/**/*.svg",
"/**/*.jpeg", "/**/*.bmp", "/**/*.tiff", "/**/*.wav", "/**/*.mp3", "/**/*.mp4",
"/**/*.html", "/**/*.htm"
);
registry.addInterceptor(new GlobalHandlerInterceptor());
}
......
......@@ -50,4 +50,14 @@ public class MQExchangeConstants {
*/
public static final String CHANNEL_DELAY_ROUTING_KEY = "channel.routingkey.delay";
/**
*wxwork 延时队列交换机
*/
public static final String WXWORK_DELAYED_EXCHANGE = "wxwork.exchange.delay";
/**
* wxwork 延时队列 routing key
*/
public static final String WXWORK_DELAY_ROUTING_KEY = "wxwork.routingkey.delay";
}
......@@ -27,4 +27,10 @@ public class MQQueueConstants {
*/
public static final String CHANNEL_IMMEDIATE_QUEUE_FOR_DELAY = "channel." + IMMEDIATE_QUEUE_FOR_DELAY;
/**
* wxwork延时队列
*/
public static final String WXWORK_IMMEDIATE_QUEUE_FOR_DELAY = "wxwork." + IMMEDIATE_QUEUE_FOR_DELAY;
}
......@@ -2,7 +2,6 @@ package com.pcloud.common.core.mybatis.cache.redis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.exceptions.JedisConnectionException;
/**
* ClassName: CachePool <br/>
......@@ -43,20 +42,7 @@ public class CachePool {
@SuppressWarnings("deprecation")
public Jedis getJedis() {
Jedis jedis = null;
boolean borrowOrOprSuccess = true;
try {
jedis = pool.getResource();
} catch (JedisConnectionException e) {
borrowOrOprSuccess = false;
if (jedis != null)
pool.returnBrokenResource(jedis);
} finally {
if (borrowOrOprSuccess)
pool.returnResource(jedis);
}
jedis = pool.getResource();
return jedis;
return pool.getResource();
}
public JedisSentinelPool getJedisPool() {
......
package com.pcloud.common.core.mybatis.cache.redis;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import com.pcloud.common.utils.cache.redis.SerializeUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.cache.Cache;
import com.pcloud.common.utils.cache.redis.SerializeUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.exceptions.JedisConnectionException;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @描述:Mybatis 接口 实现 redis 功能 类<br/>
* <per>
......@@ -51,26 +49,11 @@ public class RedisCache implements Cache {
return this.id;
}
@SuppressWarnings("deprecation")
@Override
public int getSize() {
Jedis jedis = null;
JedisSentinelPool jedisPool = null;
int result = 0;
boolean borrowOrOprSuccess = true;
try {
jedis = CachePool.getInstance().getJedis();
jedisPool = CachePool.getInstance().getJedisPool();
result = Integer.valueOf(jedis.dbSize().toString());
} catch (JedisConnectionException e) {
borrowOrOprSuccess = false;
if (jedis != null)
jedisPool.returnBrokenResource(jedis);
} finally {
if (borrowOrOprSuccess)
jedisPool.returnResource(jedis);
}
return result;
Jedis jedis = CachePool.getInstance().getJedis();
return Integer.parseInt(jedis.dbSize().toString());
}
......@@ -81,22 +64,12 @@ public class RedisCache implements Cache {
log.debug("putObject:" + key.hashCode() + "=" + value);
if (log.isInfoEnabled())
log.info("put to redis sql :" + key.toString());
Jedis jedis = null;
JedisSentinelPool jedisPool = null;
boolean borrowOrOprSuccess = true;
try {
jedis = CachePool.getInstance().getJedis();
jedisPool = CachePool.getInstance().getJedisPool();
Jedis jedis = CachePool.getInstance().getJedis();
jedis.set(SerializeUtils.serialize(key.hashCode()), SerializeUtils.serialize(value));
} catch (JedisConnectionException e) {
borrowOrOprSuccess = false;
if (jedis != null)
jedisPool.returnBrokenResource(jedis);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (borrowOrOprSuccess)
jedisPool.returnResource(jedis);
}
}
......@@ -110,20 +83,9 @@ public class RedisCache implements Cache {
boolean borrowOrOprSuccess = true;
try {
jedis = CachePool.getInstance().getJedis();
jedisPool = CachePool.getInstance().getJedisPool();
System.out.println(key.hashCode());
System.out.println(SerializeUtils.serialize(key.hashCode()));
System.out.println(jedis.get(SerializeUtils.serialize(key.hashCode())));
value = SerializeUtils.unSerialize(jedis.get(SerializeUtils.serialize(key.hashCode())));
} catch (JedisConnectionException e) {
borrowOrOprSuccess = false;
if (jedis != null)
jedisPool.returnBrokenResource(jedis);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (borrowOrOprSuccess)
jedisPool.returnResource(jedis);
}
if (log.isDebugEnabled())
log.debug("getObject:" + key.hashCode() + "=" + value);
......@@ -141,15 +103,8 @@ public class RedisCache implements Cache {
jedis = CachePool.getInstance().getJedis();
jedisPool = CachePool.getInstance().getJedisPool();
value = jedis.expire(SerializeUtils.serialize(key.hashCode()), 0);
} catch (JedisConnectionException e) {
borrowOrOprSuccess = false;
if (jedis != null)
jedisPool.returnBrokenResource(jedis);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (borrowOrOprSuccess)
jedisPool.returnResource(jedis);
}
if (log.isDebugEnabled())
log.debug("getObject:" + key.hashCode() + "=" + value);
......@@ -168,12 +123,7 @@ public class RedisCache implements Cache {
jedis.flushDB();
jedis.flushAll();
} catch (JedisConnectionException e) {
borrowOrOprSuccess = false;
if (jedis != null)
jedisPool.returnBrokenResource(jedis);
} finally {
if (borrowOrOprSuccess)
jedisPool.returnResource(jedis);
e.printStackTrace();
}
}
......
......@@ -5,9 +5,8 @@ import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
import com.pcloud.common.utils.cache.redis.JedisClusterUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
......@@ -15,13 +14,10 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import lombok.extern.slf4j.Slf4j;
/**
* 自定义灰度发布规则 2019-11-19 by david
*/
@Slf4j
@Service
public class GrayRule extends ZoneAvoidanceRule {
/**
......
package com.pcloud.common.core.tools;
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
import io.micrometer.spring.autoconfigure.MeterRegistryConfigurer;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import org.springframework.cloud.netflix.hystrix.EnableHystrix;
//import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.core.env.Environment;
import org.springframework.web.client.RestTemplate;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
* Created by zengqiang on 17-11-16.
*/
//@EnableHystrix
//@EnableHystrixDashboard
@Configuration
public class CommonBeans {
private static Logger LOGGER = LoggerFactory.getLogger(CommonBeans.class);
@Autowired
private Environment environment;
private long timeout = 10;
@Bean
public ProcessorMetrics processorMetrics() {
return new ProcessorMetrics();
}
@Bean
public JvmGcMetrics jvmGcMetrics() {
return new JvmGcMetrics();
}
@Bean
public JvmThreadMetrics jvmThreadMetrics() {
return new JvmThreadMetrics();
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
@Primary
MeterRegistryConfigurer configurer() {
try {
InetAddress inetAddress = getLocalInetAddress();
String host = null == inetAddress ? "unknown" : inetAddress.getHostName() + "/" + inetAddress.getHostAddress();
return registry -> {
registry.config().commonTags("host/ip", host);
};
} catch (Exception e) {
LOGGER.error("create MeterRegistryConfigurer error", e);
return null;
}
}
/**
* 取当前系统站点本地地址 linux下 和 window下可用
*
* @return
*/
public InetAddress getLocalInetAddress() {
InetAddress ia = null, inetAddress = null;
try {
for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) {
NetworkInterface networkInterface = interfaces.nextElement();
if (networkInterface.isLoopback() || networkInterface.isVirtual() || !networkInterface.isUp()) {
continue;
}
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
ia = addresses.nextElement();
if (ia instanceof Inet4Address) {
inetAddress = ia;
}
}
}
} catch (SocketException e) {
return null;
}
return inetAddress;
}
@Bean
public GracefulShutdownConnector gracefulShutdown() {
return new GracefulShutdownConnector();
}
@Bean
public EmbeddedServletContainerCustomizer tomcatCustomizer(@Autowired GracefulShutdownConnector connector) {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
((TomcatEmbeddedServletContainerFactory) container)
.addConnectorCustomizers(connector);
}
}
};
}
class GracefulShutdownConnector implements TomcatConnectorCustomizer,
ApplicationListener<ContextClosedEvent> {
private volatile Connector connector;
@Override
public void customize(Connector connector) {
this.connector = connector;
}
@Override
public void onApplicationEvent(ContextClosedEvent event) {
if (environment.containsProperty("shutdownTimeout")) {
timeout = environment.getProperty("shutdownTimeout", Long.class);
}
this.connector.pause();
Executor executor = this.connector.getProtocolHandler().getExecutor();
if (executor instanceof ThreadPoolExecutor) {
try {
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
threadPoolExecutor.shutdown();
if (!threadPoolExecutor.awaitTermination(timeout, TimeUnit.SECONDS)) {
LOGGER.warn("Tomcat thread pool did not shut down gracefully within "
+ timeout + " seconds. Proceeding with forceful shutdown");
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
}
package com.pcloud.common.core.zipkin;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import java.util.BitSet;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 自定义采样率Sampler
*/
@Slf4j
public class PercentageLocalSampler implements Sampler {
//采样率最小值
private static final Float MIN_PERCENTAGE = 0.0f;
//采样率最大值
private static final Float MAX_PERCENTAGE = 1.0f;
private Map<String, BitSet> sampleDecisionsMap;
//本地采样器
private final SamplerLocalProperties configuration;
private Float globalPercentage;
private static final String all = "all";
//替换访问地址前缀正则表达式
private static final String regex = "^(http://www\\.|http://|www\\.|http:)";
//uri访问次数
private final Map<String, AtomicInteger> concurrentSampleCount;
//刷新本地采样器和读取采样器配置使用读写锁,该场景读大于写,后期可优化为类似eureka注册表多级缓存
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//读锁
ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
//写锁
ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
public PercentageLocalSampler(SamplerLocalProperties configuration) {
this.configuration = configuration;
sampleDecisionsMap = buildRandomBit();
concurrentSampleCount = new ConcurrentHashMap<>();
concurrentSampleCount.put(all, new AtomicInteger(0));
}
public Map<String, AtomicInteger> getConcurrentSampleCount() {
return this.concurrentSampleCount;
}
@Override
public boolean isSampled(Span currentSpan) {
try {
readLock.lock();
if (currentSpan == null) {
return false;
}
// 获取span中的请求uri
String uri = currentSpan.getName();
uri = uri.replaceFirst(regex, "");
AtomicInteger count = this.concurrentSampleCount.get(all);
// 获取全局的bitSet
BitSet bitSet = this.sampleDecisionsMap.get(all);
// 获取全局的采样率
float percentage = this.configuration.getPercentage();
for (UriSampleProperties sampleProperties : configuration.getUriSamples()) {
// 正则匹配
if (uri.matches(sampleProperties.getUriRegex())) {
//匹配上了自定义采样率的正则
// 多个线程会有并发问题,加个局部锁
synchronized (this) {
// 判断当前uri是否在map中
if (!concurrentSampleCount.containsKey(uri)) {
concurrentSampleCount.put(uri, new AtomicInteger(0));
}
}
// 获取当前URI对应的访问次数
count = concurrentSampleCount.get(uri);
// 获取当前URI对应的bitSet
bitSet = sampleDecisionsMap.get(sampleProperties.getUriRegex());
// 获取当前URI对应的采样率
percentage = sampleProperties.getUriPercentage();
break;
}
}
log.warn("replace uri {} , percentage {}", uri, percentage);
// 如果采样率是0 ,直接返回false
if (percentage == MIN_PERCENTAGE) {
return false;
} else if (percentage == MAX_PERCENTAGE) { // 如果采样率是1 ,那么直接返回true
return true;
}
synchronized (this) {
// 访问次数加1
final int i = count.getAndIncrement();
// 判断当前的访问 次数是否在 bitSet中,存在则返回true
boolean result = bitSet.get(i);
// 等于99的时候,重新设置为0
if (i == 99) {
count.set(0);
}
return result;
}
} finally {
readLock.unlock();
}
}
private static BitSet randomBitSet(int size, int cardinality, Random rnd) {
BitSet result = new BitSet(size);
int[] chosen = new int[cardinality];
int i;
for (i = 0; i < cardinality; ++i) {
chosen[i] = i;
result.set(i);
}
for (; i < size; ++i) {
int j = rnd.nextInt(i + 1);
if (j < cardinality) {
result.clear(chosen[j]);
result.set(i);
chosen[j] = i;
}
}
return result;
}
private Map<String, BitSet> buildRandomBit() {
Map<String, BitSet> map = new ConcurrentHashMap<>();
int size = 100;
// 设置全局的采样率
int outOf100 = (int) (configuration.getPercentage() * size);
map.put(all, randomBitSet(size, outOf100, new Random()));
if (CollectionUtils.isNotEmpty(configuration.getUriSamples())) {
for (UriSampleProperties sampleProperties : configuration.getUriSamples()) {
// 设置个性化的采样率
map.put(sampleProperties.getUriRegex(), randomBitSet(size,
(int) (sampleProperties.getUriPercentage() * size), new Random()));
}
}
return map;
}
public void initPercentage(SamplerLocalProperties samplerRemoteProperties) {
try {
writeLock.lock();
configuration.setPercentage(samplerRemoteProperties.getPercentage());
configuration.setUriSamples(samplerRemoteProperties.getUriSamples());
sampleDecisionsMap = buildRandomBit();
} finally {
writeLock.unlock();
}
}
public SamplerLocalProperties getConfiguration() {
return configuration;
}
}
package com.pcloud.common.core.zipkin;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.pcloud.common.utils.string.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Component;
import java.util.*;
/**
* 刷新本地采样率
*/
@Slf4j
@Component
public class RefreshSamplerLocalProperties implements ApplicationContextAware, InitializingBean {
@Autowired(required = false)
private List<PropertySourceLocator> propertySourceLocators = new ArrayList<>();
@Autowired(required = false)
private PercentageLocalSampler percentageLocalSampler;
//线程休眠时间
private static final Long REFRESH_SLEEP_TIME = 60 * 1000L;
//个性化采样率map的key
private static final String SPRING_ZIPKIN_URISAMPLEMAPJSONSTR = "spring.zipkin.uriSampleMapJsonStr";
//个性化设置全局采样率的key
private static final String SPRING_ZIPKIN_GLOBALPERCENTAGE = "spring.zipkin.globalPercentage";
//容器上下文
private ApplicationContext applicationContext;
//个性化采样率默认值
private static final String DEFAULT_URISAMPLEMAPJSONSTR = "{}";
//全局采样率默认值
private static final Float DEFAULT_GLOBALPERCENTAGE = 0.01f;
private Environment environment;
private static final String STATUS_DELIMITER="-";
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
environment = applicationContext.getEnvironment();
}
@Override
public void afterPropertiesSet() throws Exception {
new RefreshRequest().start();
}
public void setPropertySourceLocators(
Collection<PropertySourceLocator> propertySourceLocators) {
this.propertySourceLocators = new ArrayList<>(propertySourceLocators);
}
/**
* 读取git配置文件线程
*/
class RefreshRequest extends Thread {
@Override
public void run() {
while (true) {
try {
for (PropertySourceLocator locator : propertySourceLocators) {
PropertySource<?> source = null;
source = locator.locate(environment);
if (source == null) {
continue;
}
float globalPercentage = source.getProperty(SPRING_ZIPKIN_GLOBALPERCENTAGE) != null ? Float.parseFloat(source.getProperty(SPRING_ZIPKIN_GLOBALPERCENTAGE).toString()) : DEFAULT_GLOBALPERCENTAGE;
String uriSampleMapJsonStr = source.getProperty(SPRING_ZIPKIN_URISAMPLEMAPJSONSTR) != null ? source.getProperty(SPRING_ZIPKIN_URISAMPLEMAPJSONSTR).toString() : DEFAULT_URISAMPLEMAPJSONSTR;
log.warn("读取git配置文件 globalPercentage {} ,globalPercentageJsonStr {}", globalPercentage, uriSampleMapJsonStr);
if (!uriSampleMapJsonStr.equals(DEFAULT_URISAMPLEMAPJSONSTR)) {
loadSamplerProperties(globalPercentage,uriSampleMapJsonStr);
}
}
Thread.sleep(REFRESH_SLEEP_TIME);
} catch (Exception e) {
log.error("刷新采样率异常 {}", e);
}
}
}
}
/**
* 刷新PercentageLocalSampler
*
* @param globalPercentage 全局采样率
* @param uriSampleMapJsonStr url正则表达式和个性化采样率
*/
public void loadSamplerProperties(Float globalPercentage, String uriSampleMapJsonStr) {
//获取容器的percentageLocalSampler
if (null == percentageLocalSampler) {
percentageLocalSampler = (PercentageLocalSampler) applicationContext.getBean("percentageLocalSampler");
}
SamplerLocalProperties samplerLocalProperties = percentageLocalSampler.getConfiguration();
SamplerLocalProperties samplerRemoteLocalProperties = new SamplerLocalProperties();
//全局采样率配置更新
if (globalPercentage != null && globalPercentage != DEFAULT_GLOBALPERCENTAGE) {
samplerRemoteLocalProperties.setPercentage(globalPercentage);
}
if (!StringUtil.isEmpty(uriSampleMapJsonStr) && !uriSampleMapJsonStr.equals(DEFAULT_URISAMPLEMAPJSONSTR)) {
List<UriSampleProperties> uriSamples = new ArrayList<>();
Map<Float, ArrayList<String>> uriSampleMap = (HashMap<Float, ArrayList<String>>) JSON.parseObject(uriSampleMapJsonStr, new TypeReference<HashMap<Float, ArrayList<String>>>() {
});
if (uriSampleMap != null && uriSampleMap.size() > 0) {
for (Map.Entry<Float, ArrayList<String>> entry : uriSampleMap.entrySet()) {
float percentage = entry.getKey();
for (String uri : entry.getValue()) {
UriSampleProperties uriSampleProperties = new UriSampleProperties();
uriSampleProperties.setUriPercentage(percentage);
uriSampleProperties.setUriRegex(uri);
uriSamples.add(uriSampleProperties);
}
}
}
samplerRemoteLocalProperties.setUriSamples(uriSamples);
}
if(!getPercentageSamplerHashCode(samplerRemoteLocalProperties).equals(getPercentageSamplerHashCode(samplerLocalProperties))){
log.warn("更新采样率 globalPercentage {} ,globalPercentageJsonStr {}", globalPercentage, uriSampleMapJsonStr);
percentageLocalSampler.initPercentage(samplerRemoteLocalProperties);
}
}
/**
* 计算计算hash值
*
* @param samplerLocalProperties
* @return
*/
public static String getPercentageSamplerHashCode(SamplerLocalProperties samplerLocalProperties) {
StringBuffer reconcileHashCode = new StringBuffer((samplerLocalProperties.getPercentage() + STATUS_DELIMITER));
for (UriSampleProperties uriSampleProperties : samplerLocalProperties.getUriSamples()) {
reconcileHashCode.append(uriSampleProperties.getUriRegex().hashCode() + STATUS_DELIMITER);
reconcileHashCode.append((uriSampleProperties.getUriPercentage() + STATUS_DELIMITER));
}
return reconcileHashCode.toString();
}
}
package com.pcloud.common.core.zipkin;
import java.util.ArrayList;
import java.util.List;
/**
* 本地采样器集合
*/
public class SamplerLocalProperties {
//采样器集合
private List<UriSampleProperties> uriSamples = new ArrayList<>(10);
//全局采样率
private float percentage = 0.1f;
public List<UriSampleProperties> getUriSamples() {
return uriSamples;
}
public void setUriSamples(List<UriSampleProperties> uriSamples) {
this.uriSamples = uriSamples;
}
public float getPercentage() {
return percentage;
}
public void setPercentage(float percentage) {
this.percentage = percentage;
}
}
package com.pcloud.common.core.zipkin;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
/**
* 本地取样器
*/
public class UriSampleProperties {
//url正则表达式表达式
private String uriRegex;
//采样率
private float uriPercentage = 0.01f;
public String getUriRegex() {
return uriRegex;
}
public void setUriRegex(String uriRegex) {
this.uriRegex = uriRegex;
}
public float getUriPercentage() {
return uriPercentage;
}
public void setUriPercentage(float uriPercentage) {
this.uriPercentage = uriPercentage;
}
}
package com.pcloud.common.core.zipkin;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 重新配置自定义采样率
*/
@Configuration
@AutoConfigureBefore(RefreshSamplerLocalProperties.class)
public class ZipkinConfig {
//ZipkinAutoConfiguration使用@ConditionalOnMissingBean注解的,也就是容器中不存在这个Bean的时候,才初始化他自己默认的配置,可以重写他的配置
@Bean
public Sampler percentageLocalSampler(){
SamplerLocalProperties samplerLocalProperties = new SamplerLocalProperties();
return new PercentageLocalSampler(samplerLocalProperties);
}
}
call mvn -Ptest clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U
call mvn -Puat clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.0-RELEASE
call mvn -Pperf clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.1-SNAPSHOT
call mvn -Pprod clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.1-RELEASE
call mvn -Ptsrpd clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.2-RELEASE
@pause
\ No newline at end of file
call mvn -Ptest clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U
@pause
\ No newline at end of file
call mvn -Ptest clean install -Denforcer.skip=true -Dmaven.test.skip=true -U
call pause
\ No newline at end of file
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.pcloud.common</groupId>
<artifactId>pcloud-common-parent</artifactId>
<version>3.1.0-SNAPSHOT</version>
</parent>
<artifactId>pcloud-common-lang</artifactId>
<packaging>jar</packaging>
<version>${reversion}</version>
<name>pcloud-common-lang</name>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
</project>
package com.pcloud.common.dto;
import java.io.Serializable;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
/**
* @描述:服务响应实体类
* @作者:shichunshan
* @创建时间:2016年5月17日,下午1:53:02 @版本:1.0
*/
@JsonInclude(value = Include.NON_NULL)
public class ResponseDto<T> implements Serializable {
/**
*
*/
private static final long serialVersionUID = -9004186626234235043L;
/**
* 默认操作成功,成功代码
*/
private static final int SUCCESS = 0;
/**
* 默认成功消息
*/
private static final String SUCCESS_MSG = "操作成功!";
/**
* 错误码
*/
private int errCode;
/**
* 消息
*/
private String message;
/**
* 数据
*/
private T data;
/**
* 生产者名称
*/
private String produceAppName;
/**
* 生产者IP
*/
private String produceIp;
/**
* 生产者类名
*/
private String produceClassName;
/**
* 生产者方法名
*/
private String produceMethodName;
/**
* 默认成功
*/
public ResponseDto() {
super();
this.errCode = SUCCESS;
this.message = SUCCESS_MSG;
}
/**
* @param errCode
* @param message
*/
public ResponseDto(int errCode, String message) {
super();
this.errCode = errCode;
this.message = message;
}
/**
* @param errCode
* @param message
* @param data
*/
public ResponseDto(int errCode, String message, T data) {
super();
this.errCode = errCode;
this.message = message;
this.data = data;
}
/**
* 默认成功
*
* @param data
*/
public ResponseDto(T data) {
super();
this.errCode = SUCCESS;
this.message = SUCCESS_MSG;
this.data = data;
}
public int getErrCode() {
return errCode;
}
public void setErrCode(int errCode) {
this.errCode = errCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getProduceAppName() {
return produceAppName;
}
public void setProduceAppName(String produceAppName) {
this.produceAppName = produceAppName;
}
public String getProduceClassName() {
return produceClassName;
}
public void setProduceClassName(String produceClassName) {
this.produceClassName = produceClassName;
}
public String getProduceMethodName() {
return produceMethodName;
}
public void setProduceMethodName(String produceMethodName) {
this.produceMethodName = produceMethodName;
}
public String getProduceIp() {
return produceIp;
}
public void setProduceIp(String produceIp) {
this.produceIp = produceIp;
}
@Override
public String toString() {
return "ResponseDto -> " + JSON.toJSONString(this);
}
}
call mvn -Ptest clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U
call mvn -Puat clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.0-RELEASE
call mvn -Pperf clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.1-SNAPSHOT
call mvn -Pprod clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.1-RELEASE
call mvn -Ptsrpd clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.2-RELEASE
@pause
\ No newline at end of file
call mvn -Ptest clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U
@pause
\ No newline at end of file
call mvn -Ptest clean install -Denforcer.skip=true -Dmaven.test.skip=true -U
call pause
\ No newline at end of file
......@@ -6,25 +6,24 @@
<parent>
<groupId>com.pcloud.common</groupId>
<artifactId>pcloud-common-parent</artifactId>
<version>2.1.0-RELEASE</version>
<version>3.1.0-SNAPSHOT</version>
</parent>
<artifactId>pcloud-common</artifactId>
<packaging>jar</packaging>
<version>${pcloud-common.version}</version>
<version>${reversion}</version>
<name>pcloud-common</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.pcloud.common</groupId>
<artifactId>pcloud-common-config</artifactId>
<version>${pcloud-common-config.version}</version>
<artifactId>pcloud-common-lang</artifactId>
<version>${reversion}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
......@@ -49,31 +48,27 @@
<!-- Spring Cloud Begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-turbine</artifactId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
......@@ -83,24 +78,7 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-spring-legacy</artifactId>
<version>1.0.0-rc.2</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-influx</artifactId>
<version>1.0.0-rc.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
......@@ -119,6 +97,10 @@
<artifactId>cglib</artifactId>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
......@@ -417,6 +399,11 @@
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
</dependency>
</dependencies>
</project>
package com.pcloud.common.config;
import com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
@EnableNacosConfig
@NacosPropertySource(dataId = "eureka.yml", first = true)
@NacosPropertySource(dataId = "db-default.yml")
@NacosPropertySource(dataId = "universe-monitor.yml")
@NacosPropertySource(dataId = "rabbitmq.yml")
@NacosPropertySource(dataId = "redis.properties")
public class BaseConfig {
}
package com.pcloud.common.config;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import org.springframework.stereotype.Component;
@Component
public class NacosConfigServiceInstance {
private static ConfigService SERVICE;
@NacosInjected
public void setConfigService(ConfigService configService) throws NacosException {
if (SERVICE == null) {
SERVICE = configService;
}
PublicConfig.loadPublicSystem(configService);
}
public static ConfigService getInstance() {
return SERVICE;
}
}
......@@ -3,50 +3,94 @@
*/
package com.pcloud.common.config;
import java.util.Map;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import com.alibaba.nacos.spring.util.NacosUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import com.pcloud.common.utils.ResourceUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 环境配置基础类
* @author diseng
*
*/
*/
@Configuration
@NacosPropertySource(dataId = "public_user.properties")
public class PublicConfig {
/**
* 系统文件配置 加载。
*/
public static Map<String, String> PUBLIC_USER = ResourceUtils.getResource("public_user").getMap();
private static Logger LOGGER = LoggerFactory.getLogger(PublicConfig.class);
/**
* 系统文件配置 加载。
*/
public static Map<String, String> PUBLIC_SYSTEM = ResourceUtils.getResource("public_system").getMap();
@Value("${IS_DEV_STATUS}")
public void setIsDevStatus(Boolean v) {
IS_DEV_STATUS = v;
}
@Value("${PWD_TIMES_USE_KAPTCHA}")
public void setPwdTimesUseKaptcha(Integer v) {
PWD_TIMES_USE_KAPTCHA = v;
}
@Value("${IS_USE_KAPTCHA}")
public void setIsUseKaptcha(Boolean v) {
IS_USE_KAPTCHA = v;
}
@Value("${PWD_ERROR_LIMIT_TIME}")
public void setPwdErrorLimitTime(Integer v) {
PWD_ERROR_LIMIT_TIME = v;
}
@Value("${PWD_ERROR_LIMIT_TIMES}")
public void setPwdErrorLimitTimes(Integer v) {
PWD_ERROR_LIMIT_TIMES = v;
}
/**
* 密码错误限制次数
*/
public final static Integer PWD_ERROR_LIMIT_TIMES = Integer.parseInt(PUBLIC_USER.get("PWD_ERROR_LIMIT_TIMES"));
public static Integer PWD_ERROR_LIMIT_TIMES;
/**
* 密码错误限制时间(分钟)
*/
public final static Integer PWD_ERROR_LIMIT_TIME = Integer.parseInt(PUBLIC_USER.get("PWD_ERROR_LIMIT_TIME"));
public static Integer PWD_ERROR_LIMIT_TIME;
/**
* 门户是否使用验证码 配合密码错误次数值使用
*/
public final static boolean IS_USE_KAPTCHA = Boolean.parseBoolean(PUBLIC_USER.get("IS_USE_KAPTCHA"));
public static boolean IS_USE_KAPTCHA;
/**
* 密码错误次数值 将 出现验证码,如果值为0 则永远不会出现验证码
*/
public final static Integer PWD_TIMES_USE_KAPTCHA = Integer.parseInt(PUBLIC_USER.get("PWD_TIMES_USE_KAPTCHA"));
public static Integer PWD_TIMES_USE_KAPTCHA;
/**
* 是否开发状态
*/
public final static boolean IS_DEV_STATUS = Boolean.parseBoolean(PUBLIC_USER.get("IS_DEV_STATUS"));
public static boolean IS_DEV_STATUS;
/**
* 系统文件配置 加载。
*/
public static Map<String, String> PUBLIC_SYSTEM = new HashMap<>();
public static void loadPublicSystem(ConfigService configService) throws NacosException {
String config = configService.getConfig("public_system.properties", Constants.DEFAULT_GROUP, Constants.RECV_WAIT_TIMEOUT);
Map<String, Object> p = NacosUtils.toProperties(config);
p.forEach((k, v) -> {
PUBLIC_SYSTEM.put(k, v.toString());
});
LOGGER.info("public system loaded completed, size={}", PUBLIC_SYSTEM.size());
}
}
package com.pcloud.common.constant;
import cn.hutool.core.util.StrUtil;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import com.pcloud.common.utils.FileUtils;
......@@ -15,7 +15,7 @@ import com.pcloud.common.utils.string.StringUtil;
* @date:2018年6月25日,下午7:30:21
*/
@Component("aliyunConstant")
@PropertySource(value = { "classpath:aliyun.properties" })
@NacosPropertySource(dataId = "aliyun.properties")
public class AliyunConstant {
/**
......
package com.pcloud.common.constant;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
......@@ -14,7 +14,7 @@ import java.util.List;
* @Date: 2019/11/25 14:28
*/
@Component("appLabelConstant")
@PropertySource(value = { "classpath:app_label.properties" })
@NacosPropertySource(dataId = "app_label.properties")
public class AppLabelConstant {
public static final String GRADE1 = "一年级";
......
package com.pcloud.common.utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestContextHolderUtil {
private RequestContextHolderUtil() {}
public static HttpServletRequest getRequest() {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return requestAttributes.getRequest();
}
public static HttpServletResponse getResponse() {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return requestAttributes.getResponse();
}
}
......@@ -14,8 +14,8 @@ import java.util.ResourceBundle;
* @创建时间:2016年3月10日,上午11:46:33
* @版本:1.0
*/
public class ResourceUtils {
private ResourceBundle resourceBundle;
class ResourceUtils {
private ResourceBundle resourceBundle;
private ResourceUtils(String resource) {
resourceBundle = ResourceBundle.getBundle(resource);
......@@ -26,7 +26,7 @@ private ResourceBundle resourceBundle;
* @param resource 资源
* @return 解析
*/
public static ResourceUtils getResource(String resource) {
static ResourceUtils getResource(String resource) {
return new ResourceUtils(resource);
}
......@@ -36,7 +36,7 @@ private ResourceBundle resourceBundle;
* @param args value中参数序列,参数:{0},{1}...,{n}
* @return
*/
public String getValue(String key, Object... args) {
String getValue(String key, Object... args) {
String temp = resourceBundle.getString(key);
return MessageFormat.format(temp, args);
}
......@@ -45,7 +45,7 @@ private ResourceBundle resourceBundle;
* 获取所有资源的Map表示
* @return 资源Map
*/
public Map<String, String> getMap() {
Map<String, String> getMap() {
Map<String, String> map = new HashMap<String, String>();
for(String key: resourceBundle.keySet()) {
map.put(key, resourceBundle.getString(key));
......
......@@ -245,7 +245,6 @@ public class ResponseHandleUtil {
}
ResponseDto<?> body = (ResponseDto<?>) entity.getBody();
if (body == null) {
LOGGER.warn("【请求NULL】ResponseDto==null");
return null;
}
if (body.getErrCode() != 0) {
......@@ -335,20 +334,9 @@ public class ResponseHandleUtil {
*/
public static <T> ResponseEntity<ResponseDto<T>> toResponse(T data) {
if (null == data) {
LOGGER.warn("null data object");
return null;
}
ResponseDto<T> body = new ResponseDto<>(data);
try {
// body.setProduceAppName(Application.APP_NAME);
// body.setProduceIp(NginxUtils.getLocalAddress());
// StackTraceElement stackTraceElement = new Exception().getStackTrace()[1];
// body.setProduceClassName(stackTraceElement.getClassName());
// body.setProduceMethodName(stackTraceElement.getMethodName());
} catch (Exception e) {
LOGGER.warn("【内部接口】封装返回类型失败:" + e.getMessage(), e);
}
return new ResponseEntity<>(body, HttpStatus.OK);
return new ResponseEntity<>(new ResponseDto<>(data), HttpStatus.OK);
}
}
\ No newline at end of file
......@@ -216,7 +216,7 @@ public class OssUtils {
LOGGER.error("【aliOSS】上传文件失败:" + e.getMessage(), e);
throw new FileException(FileException.FILE_UPLOAD_FAILURE, "上传文件失败");
} finally {
client.close();
// client.close();
}
//oss%2Ftranscode%2Faudio%2Fmp3%2Ftest_20200529150529182.mp3
if (!StringUtil.isEmpty(ossFileDO.getObject()) && ossFileDO.getObject().contains("%2F")) {
......@@ -255,7 +255,7 @@ public class OssUtils {
LOGGER.error("【aliOSS】上传文件失败:" + e.getMessage(), e);
throw new FileException(FileException.FILE_UPLOAD_FAILURE, "上传文件失败");
} finally {
ossClient.close();
// ossClient.close();
}
//oss%2Ftranscode%2Faudio%2Fmp3%2Ftest_20200529150529182.mp3
if (!StringUtil.isEmpty(ossFileDO.getObject()) && ossFileDO.getObject().contains("%2F")) {
......@@ -293,7 +293,7 @@ public class OssUtils {
LOGGER.error("【aliOSS】下载文件失败:" + e.getMessage(), e);
throw new FileException(FileException.FILE_UPLOAD_FAILURE, "上传文件失败");
} finally {
ossClient.close();
// ossClient.close();
}
return result;
}
......@@ -1276,7 +1276,7 @@ public class OssUtils {
ObsClient ossClient = getOSSClient(bucketName);
ObjectMetadata objectMetadata = ossClient.getObjectMetadata(bucketName, objectKey);
// 关闭client
ossClient.close();
// ossClient.close();
return objectMetadata;
}
......@@ -1315,7 +1315,7 @@ public class OssUtils {
os.close();
}
if (ossClient != null) {
ossClient.close();
// ossClient.close();
}
} catch (Exception e) {
LOGGER.error("【aliOSS】下载文件,关闭文件流失败:" + e.getMessage(), e);
......@@ -1756,7 +1756,7 @@ public class OssUtils {
FileUtils.deleteFile(localPath);
LOGGER.error("【aliOSS】图片处理API:" + e.getMessage(), e);
} finally {
ossClient.close();
// ossClient.close();
}
return localPath;
}
......@@ -1886,7 +1886,7 @@ public class OssUtils {
FileUtils.creatFiles(localPath);
ObsObject obsObject = ossClient.getObject(request);
obsObjectToLocalFile(localPath, obsObject);
ossClient.close();
// ossClient.close();
// 上传处理后的图片,并删除本地文件
UploadResultInfo uploadResultInfo = uploadLocalFile4CustomName(localPath, fileName);
FileUtils.deleteFile(localPath);
......@@ -1926,12 +1926,23 @@ public class OssUtils {
return Math.round(result);
}
private static final Map<String, ObsClient> OBS_CLIENT_MAP = new HashMap<>();
/**
* 获取OSS客户端
*/
private static ObsClient getOSSClient(String bucketName) {
return new ObsClient(AliyunConstant.MAIN_ACCESS_KEY_ID,
AliyunConstant.MAIN_ACCESS_KEY_SECRET, AliyunConstant.getOSSEndPoint(bucketName));
if (OBS_CLIENT_MAP.get(bucketName) == null) {
synchronized (OssUtils.class) {
if (OBS_CLIENT_MAP.get(bucketName) == null) {
long start = System.currentTimeMillis();
OBS_CLIENT_MAP.put(bucketName, new ObsClient(AliyunConstant.MAIN_ACCESS_KEY_ID,
AliyunConstant.MAIN_ACCESS_KEY_SECRET, AliyunConstant.getOSSEndPoint(bucketName)));
LOGGER.warn("ObsClient created,bucket={},cost={}", bucketName, System.currentTimeMillis() - start);
}
}
}
return OBS_CLIENT_MAP.get(bucketName);
}
/**
......@@ -1942,7 +1953,7 @@ public class OssUtils {
ObsClient ossClient = getOSSClient(bucketName);
boolean found = ossClient.doesObjectExist(bucketName, objectKey);
// 关闭client
ossClient.close();
// ossClient.close();
return found;
}
......
package com.pcloud.common.utils.cache.redis;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import com.pcloud.common.utils.string.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -11,13 +9,13 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.pcloud.common.utils.string.StringUtil;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
/**
*
* @描述:redis集群初始化
......@@ -27,7 +25,6 @@ import redis.clients.jedis.JedisCluster;
*/
@Configuration
@EnableCaching
@PropertySource(value = "classpath:redis.properties")
public class JedisClusterConfig {
/**
......@@ -38,6 +35,9 @@ public class JedisClusterConfig {
@Value("${redis.cluster.host}")
private String host;
@Value("${redis.cluster.password}")
private String password;
@Value("${redis.cluster.timeout}")
private int timeout;
......@@ -75,6 +75,7 @@ public class JedisClusterConfig {
@Bean
public GenericObjectPoolConfig jedisPoolConfig() {
LOGGER.info("【redis】JedisPool注入成功,<START>");
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxTotal(maxTotal);
poolConfig.setMinIdle(minIdle);
......@@ -90,8 +91,22 @@ public class JedisClusterConfig {
*/
@Bean
public JedisCluster JedisClusterFactory() {
LOGGER.info("【redis】JedisCluster创建,<START>");
return new JedisCluster(parseHostAndPort(), timeout, maxRedirections, jedisPoolConfig());
LOGGER.info("【redis】JedisCluster创建,{},=>{}<=]", timeout, password);
try {
JedisCluster jc = new JedisCluster(parseHostAndPort(), timeout, timeout, maxRedirections, StringUtils.trimToNull(password), jedisPoolConfig());
LOGGER.info("【redis】JedisCluster创建,echo={}", jc.echo("Echo Successfully."));
return jc;
} catch (Exception e) {
LOGGER.info("【redis】JedisCluster创建无密重试,{},=>{}<=],message={}", timeout, password, e.getMessage());
JedisCluster jc = new JedisCluster(parseHostAndPort(), timeout, maxRedirections, jedisPoolConfig());
LOGGER.info("【redis】JedisCluster创建无密重试,echo={}", jc.echo("Echo Successfully."));
return jc;
}
}
/**
......
......@@ -23,6 +23,7 @@ import com.pcloud.common.utils.string.StringUtil;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.params.SetParams;
/**
* @描述:redis集群API
......@@ -160,7 +161,7 @@ public class JedisClusterUtils {
public static boolean set(String key, String value, String nxxx, String expx, Integer seconds) {
try {
seconds = Optional.ofNullable(seconds).orElse(60);
String result = jedisCluster.set(key, value, nxxx, expx, seconds);
String result = jedisCluster.set(key, value, SetParams.setParams().nx().ex(seconds));
return "OK".equalsIgnoreCase(result);
} catch (Exception e) {
LOGGER.warn("jedis缓存保存失败:" + e.getMessage(), e);
......@@ -174,7 +175,7 @@ public class JedisClusterUtils {
public static boolean lock(String key, Integer seconds) {
try {
seconds = Optional.ofNullable(seconds).orElse(60);
String result = jedisCluster.set(key, String.valueOf(System.currentTimeMillis()), "NX", "EX", seconds);
String result = jedisCluster.set(key, String.valueOf(System.currentTimeMillis()), SetParams.setParams().nx().ex(seconds));
return "OK".equalsIgnoreCase(result);
} catch (Exception e) {
LOGGER.warn("jedis缓存保存失败:" + e.getMessage(), e);
......@@ -186,8 +187,8 @@ public class JedisClusterUtils {
/**
* 保存一个字符串到redis中,长期有效
*
* @param objecKey 键
* @param objecValue 缓存对象
* @param key 键
* @param value 缓存对象
* @return
*/
public static boolean setObject(Object key, Object value) {
......@@ -203,8 +204,8 @@ public class JedisClusterUtils {
/**
* 保存一个字符串到redis中并指定过期时间
*
* @param objecKey 键
* @param objecValue 缓存对象
* @param key 键
* @param value 缓存对象
* @param seconds 时间,如果为null,则使用默认时间30分钟
* @return
*/
......@@ -275,7 +276,7 @@ public class JedisClusterUtils {
/**
* 根据缓存键获取Redis缓存中的对象.<br/>
*
* @param objecKey 键
* @param key 键
* @return
*/
public static Object getObject(Object key) {
......@@ -501,7 +502,6 @@ public class JedisClusterUtils {
* 根据缓存键获取Redis缓存中的Map.<br/>
*
* @param key
* @param fields 具体的map键
* @return
*/
public static Map<String, String> hgetAll(String key) {
......@@ -614,7 +614,6 @@ public class JedisClusterUtils {
* 根据缓存键删除map中的指定键值
*
* @param key 缓存键
* @param field map键值
* @return 删除成功返回1,失败返回0
*/
public static Boolean hdel(String key, String... fields) {
......@@ -712,7 +711,6 @@ public class JedisClusterUtils {
* 添加内容到指定key的list中,先进后出(左放置)
*
* @param key
* @param field
* @param value
* @return
*/
......@@ -764,7 +762,6 @@ public class JedisClusterUtils {
* 添加内容到指定key的list中,先进先出(从右放置)
*
* @param key
* @param field
* @param value
* @return
*/
......@@ -799,7 +796,6 @@ public class JedisClusterUtils {
* 添加内容到指定key的list中,先进先出(从右放置)
*
* @param key
* @param field
* @param value
* @return
*/
......@@ -1013,7 +1009,7 @@ public class JedisClusterUtils {
}
return null;
}
/**
* 删除指定元素
* 该命令用于从key对应的list中,移除前count次出现 的值为value的元素。count参数有三种情况:
......@@ -1173,7 +1169,7 @@ public class JedisClusterUtils {
* 根据clazz和key获取对应的map
*
* @param key
* @param clazz
* @param vClazz
* @return
*/
@SuppressWarnings("unchecked")
......
......@@ -9,6 +9,8 @@ import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -16,6 +18,8 @@ import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.utils.NumberUtil;
import com.pcloud.common.utils.string.StringUtil;
import javax.servlet.http.HttpServletRequest;
/**
* @描述:cooike内容解析工具类
* @作者:songx
......@@ -118,6 +122,21 @@ public class Cookie {
public static final String USER_LABEL = "userLabel";
public static final String COOKIE_USER_INFO = "userInfo";
public static String getCookieUserInfo(HttpServletRequest request) {
javax.servlet.http.Cookie[] cc = request.getCookies();
if (ArrayUtils.isEmpty(cc)) {
return StringUtil.EMPTY;
}
for (javax.servlet.http.Cookie c : cc) {
if (StringUtils.equalsIgnoreCase(c.getName(), COOKIE_USER_INFO)) {
return c.getValue();
}
}
return StringUtil.EMPTY;
}
/**
* cookie 信息處理
* @param userInfo
......@@ -126,17 +145,13 @@ public class Cookie {
*/
public static Map<String, Object> getUserInfo(String userInfo) throws BizException {
if (StringUtil.isEmpty(userInfo)) {
LOGGER.warn("Cookie解析失败:userInfo==NULL");
throw BizException.COOKIE_IS_ILLICIT;
}
try {
userInfo = URLDecoder.decode(userInfo, "UTF-8");
LOGGER.info("Cookie的内容如下:" + String.valueOf(userInfo));
} catch (UnsupportedEncodingException e) {
LOGGER.error("Cookie解析失败:" + e.getMessage(), e);
throw BizException.COOKIE_IS_ILLICIT;
LOGGER.info("Cookie的内容如下:{}" , userInfo);
} catch (Exception e) {
LOGGER.error("Cookie解析失败:" + e.getMessage(), e);
LOGGER.error("Cookie解析失败:{}" , e.getMessage(), e);
throw BizException.COOKIE_IS_ILLICIT;
}
Map<String, Object> userInfos = new HashMap<>();
......@@ -297,18 +312,14 @@ public class Cookie {
* @throws BizException
*/
public static String getString(String userInfo, String type) throws BizException {
if (StringUtil.isEmpty(userInfo)) {
LOGGER.error("Cookie解析失败:userInfo==NULL");
if (StringUtil.isBlank(userInfo)) {
throw BizException.COOKIE_IS_ILLICIT;
}
try {
userInfo = URLDecoder.decode(userInfo, "UTF-8");
LOGGER.info("Cookie的内容如下:" + String.valueOf(userInfo));
} catch (UnsupportedEncodingException e) {
LOGGER.error("Cookie解析失败:" + e.getMessage(), e);
throw new BizException(BizException.COOKIE_IS_ILLICIT);
LOGGER.info("Cookie的内容如下:{}", userInfo);
} catch (Exception e) {
LOGGER.error("Cookie解析失败:" + e.getMessage(), e);
LOGGER.warn("Cookie解析失败:userInfo={},type={},err:{}", userInfo, type , e.getMessage(), e);
throw new BizException(BizException.COOKIE_IS_ILLICIT);
}
String[] userInfoArry = userInfo.split("&");
......@@ -316,7 +327,7 @@ public class Cookie {
if (userInfoArry[i].contains(type)) {
String[] ids = userInfoArry[i].split("=");
String id = ids[ids.length - 1];
return StringUtil.isEmpty(id) || "undefined".equalsIgnoreCase(id) || "null".equalsIgnoreCase(id) || type.equalsIgnoreCase(id)? null : id;
return StringUtil.isBlank(id) || "undefined".equalsIgnoreCase(id) || "null".equalsIgnoreCase(id) || type.equalsIgnoreCase(id)? null : id;
}
}
return null;
......
package com.pcloud.common.utils.encrypt;
import com.pcloud.common.exceptions.BizException;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public class AESUtil {
private AESUtil() {
}
private static final String KEY_AES = "AES";
private static final String DEFAULT_KEY = "~dcg@rays$2021^&";
private static Cipher ENCRYPT_CIPHER = null;
private static Cipher DECRYPT_CIPHER = null;
/**
* 使用固定密钥加密
* @param src 待加密数据
* @return 加密后数据
*/
public static String fixedLongEncrypt(final long src) {
return fixedEncrypt(String.valueOf(src));
}
/**
* 使用固定密钥解密
* @param encrypted 待解密数据
* @return 解密后结果
*/
public static long fixedLongDecrypt(final String encrypted) {
return Long.parseLong(fixedDecrypt(encrypted));
}
/**
* 使用固定密钥加密
* @param src 待加密数据
* @return 加密后数据
*/
public static String fixedEncrypt(final String src) {
if (StringUtils.isBlank(src)) {
return src;
}
try {
byte[] encrypted = getEncryptCipherInstance().doFinal(src.getBytes());
return byte2hex(encrypted);
} catch (Throwable t) {
throw new BizException("aes encrypt failed,src=" + src, t);
}
}
/**
* 使用固定密钥解密
* @param encrypted 待解密数据
* @return 解密后结果
*/
public static String fixedDecrypt(final String encrypted) {
if (StringUtils.isBlank(encrypted)) {
return encrypted;
}
try {
byte[] b = hex2byte(encrypted);
if (b == null) {
throw new BizException("aes decrypt failed,src=" + encrypted);
}
byte[] original = getDecryptCipherInstance().doFinal(b);
return new String(original, StandardCharsets.UTF_8);
} catch (Throwable t) {
throw new BizException("aes decrypt failed,src=" + encrypted, t);
}
}
private static Cipher getEncryptCipherInstance() {
if (ENCRYPT_CIPHER == null) {
synchronized (AESUtil.class) {
if (ENCRYPT_CIPHER == null) {
try {
byte[] raw = DEFAULT_KEY.getBytes();
SecretKeySpec spec = new SecretKeySpec(raw, KEY_AES);
ENCRYPT_CIPHER = Cipher.getInstance(KEY_AES);
ENCRYPT_CIPHER.init(Cipher.ENCRYPT_MODE, spec);
} catch (Throwable t) {
ENCRYPT_CIPHER = null;
throw new BizException("aes cipher init failed", t);
}
}
}
}
return ENCRYPT_CIPHER;
}
private static Cipher getDecryptCipherInstance() {
if (DECRYPT_CIPHER == null) {
synchronized (AESUtil.class) {
if (DECRYPT_CIPHER == null) {
try {
byte[] raw = DEFAULT_KEY.getBytes();
SecretKeySpec spec = new SecretKeySpec(raw, KEY_AES);
DECRYPT_CIPHER = Cipher.getInstance(KEY_AES);
DECRYPT_CIPHER.init(Cipher.DECRYPT_MODE, spec);
} catch (Throwable t) {
DECRYPT_CIPHER = null;
throw new BizException("aes cipher init failed", t);
}
}
}
}
return DECRYPT_CIPHER;
}
private static byte[] hex2byte(String strhex) {
int l = strhex.length();
if (l % 2 == 1) {
return null;
}
byte[] b = new byte[l / 2];
for (int i = 0; i != l / 2; i++) {
b[i] = (byte) Integer.parseInt(strhex.substring(i * 2, i * 2 + 2),
16);
}
return b;
}
private static String byte2hex(byte[] b) {
StringBuilder hs = new StringBuilder();
String tmp = "";
for (byte value : b) {
tmp = (Integer.toHexString(value & 0XFF));
if (tmp.length() == 1) {
hs.append("0").append(tmp);
} else {
hs.append(tmp);
}
}
return hs.toString().toUpperCase();
}
}
......@@ -20,6 +20,19 @@ import org.apache.commons.lang.StringUtils;
public class NginxUtils {
/**
* 优先获取X-Real-IP
* @param request Request
* @return IP
*/
public static String getXRealIp(HttpServletRequest request) {
String ip = request.getHeader("X-Real-IP");
if (StringUtils.isNotBlank(ip) && !"unKnown".equalsIgnoreCase(ip)) {
return ip;
}
return getClientIp(request);
}
/**
* 在很多应用下都可能有需要将用户的真实IP记录下来,这时就要获得用户的真实IP地址,在JSP里,获取客户端的IP地
* 址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的。但是在通过了Apache,Squid等
* 反向代理软件就不能获取到客户端的真实IP地址了。
......
/*
* Copyright 2013-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.netflix.feign;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
/**
* Annotation for interfaces declaring that a REST client with that interface should be
* created (e.g. for autowiring into another component). If ribbon is available it will be
* used to load balance the backend requests, and the load balancer can be configured
* using a <code>@RibbonClient</code> with the same name (i.e. value) as the feign client.
*
* @author Spencer Gibb
* @author Venil Noronha
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@org.springframework.cloud.openfeign.FeignClient
public @interface FeignClient {
/**
* The name of the service with optional protocol prefix. Synonym for {@link #name()
* name}. A name must be specified for all clients, whether or not a url is provided.
* Can be specified as property key, eg: ${propertyKey}.
*/
@AliasFor("name")
String value() default "";
/**
* The service id with optional protocol prefix. Synonym for {@link #value() value}.
*
* @deprecated use {@link #name() name} instead
*/
@Deprecated
String serviceId() default "";
/**
* The service id with optional protocol prefix. Synonym for {@link #value() value}.
*/
@AliasFor("value")
String name() default "";
/**
* Sets the <code>@Qualifier</code> value for the feign client.
*/
String qualifier() default "";
/**
* An absolute URL or resolvable hostname (the protocol is optional).
*/
String url() default "";
/**
* Whether 404s should be decoded instead of throwing FeignExceptions
*/
boolean decode404() default false;
/**
* A custom <code>@Configuration</code> for the feign client. Can contain override
* <code>@Bean</code> definition for the pieces that make up the client, for instance
* {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
*
* @see FeignClientsConfiguration for the defaults
*/
Class<?>[] configuration() default {};
/**
* Fallback class for the specified Feign client interface. The fallback class must
* implement the interface annotated by this annotation and be a valid spring bean.
*/
Class<?> fallback() default void.class;
/**
* Define a fallback factory for the specified Feign client interface. The fallback
* factory must produce instances of fallback classes that implement the interface
* annotated by {@link FeignClient}. The fallback factory must be a valid spring
* bean.
*
* @see feign.hystrix.FallbackFactory for details.
*/
Class<?> fallbackFactory() default void.class;
/**
* Path prefix to be used by all method-level mappings. Can be used with or without
* <code>@RibbonClient</code>.
*/
String path() default "";
/**
* Whether to mark the feign proxy as a primary bean. Defaults to true.
*/
boolean primary() default true;
}
package com.pcloud.common.utils;
import com.pcloud.common.utils.encrypt.AESUtil;
import org.junit.Assert;
import org.junit.Test;
public class AESUtilTest {
@Test
public void testAll() {
exec("!@#$%^");
exec("abcdefg");
exec("123456");
exec("123456efg");
exec("我是中国人");
exec(9632587L);
exec(Long.MAX_VALUE);
}
private void exec(String src) {
String e = AESUtil.fixedEncrypt(src);
String d = AESUtil.fixedDecrypt(e);
Assert.assertEquals(d, src);
}
private void exec(long src) {
String e = AESUtil.fixedLongEncrypt(src);
long d = AESUtil.fixedLongDecrypt(e);
Assert.assertEquals(d, src);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="threshold" value="debug" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%t]: %c:%L - %m%n" />
</layout>
</appender>
<!-- Application Loggers -->
<logger name="com.pcloud">
<level value="debug" />
</logger>
<!-- Root Logger -->
<root>
<priority value="debug" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
\ No newline at end of file
call mvn -Ptest clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U
call mvn -Puat clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.0-RELEASE
call mvn -Pperf clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.1-SNAPSHOT
call mvn -Pprod clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.1-RELEASE
call mvn -Ptsrpd clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U -Dreversion=3.1.2-RELEASE
@pause
\ No newline at end of file
call mvn clean source:jar deploy -Denforcer.skip=true -Dmaven.test.skip=true -U
@pause
\ No newline at end of file
call mvn clean install -Denforcer.skip=true -Dmaven.test.skip=true -U
call pause
\ No newline at end of file
......@@ -6,32 +6,24 @@
<parent>
<groupId>com.pcloud.common</groupId>
<artifactId>pcloud-common-parent</artifactId>
<version>2.1.0-RELEASE</version>
<version>3.1.0-SNAPSHOT</version>
</parent>
<artifactId>pcloud-solr</artifactId>
<packaging>jar</packaging>
<version>${pcloud-solr.version}</version>
<version>${reversion}</version>
<name>pcloud-solr</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.pcloud.common</groupId>
<artifactId>pcloud-common-config</artifactId>
<version>${pcloud-common-config.version}</version>
</dependency>
<!-- solr add by gaop at 2018-4-23 11:33:47 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
<version>${spring.data.solr.version}</version>
</dependency>
<!-- Spring Cloud Begin -->
......@@ -39,35 +31,31 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- Spring Cloud End -->
<!-- Common Dependency Begin -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.18</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.38</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<!-- Common Dependency End -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
</dependency>
</dependencies>
</project>
package com.pcloud.solr;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.MapUtils;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
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.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Description solr全文检索工具类
* @author PENG
* @date 2018/4/23
*/
@Component("solrUtils")
@PropertySource(value = "classpath:public_system.properties")
@NacosPropertySource(dataId = "solr7.properties")
public class SolrUtils {
private static Logger LOGGER = LoggerFactory.getLogger(SolrUtils.class);
......@@ -38,6 +36,7 @@ public class SolrUtils {
private static final SimpleDateFormat UTC_FULL_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
private static String defaultCollection;
private static String hosts;
protected static CloudSolrClient solrClient;
......@@ -545,11 +544,36 @@ public class SolrUtils {
@Value("${solr.default.collection}")
public void setDefaultCollection(String defaultCollection) {
SolrUtils.defaultCollection = defaultCollection;
initSolrClient(SolrUtils.hosts, SolrUtils.defaultCollection);
}
@Autowired
public void setSolrClient(SolrClient solrClient) {
SolrUtils.solrClient = (CloudSolrClient) solrClient;
SolrUtils.solrClient.setDefaultCollection(defaultCollection);
@Value("${solr.cloud.host}")
public void setSolrCloudHost(String hosts) {
SolrUtils.hosts = hosts;
initSolrClient(SolrUtils.hosts, SolrUtils.defaultCollection);
}
private void initSolrClient(String hosts, String defaultCollection) {
if (StringUtils.isBlank(hosts) || StringUtils.isBlank(defaultCollection)) {
return;
}
if (SolrUtils.solrClient != null) {
return;
}
try {
List<String> hs = Lists.newArrayList(StringUtils.split(hosts, ','));
CloudSolrClient client = new CloudSolrClient.Builder(hs).build();
client.setDefaultCollection(defaultCollection);
LOGGER.warn("SolrClient==>hosts:{}\tdefaultCollection={}\t{}", hosts, defaultCollection, client);
LOGGER.warn("SolrClient Ping==>{}", client.ping(defaultCollection));
SolrUtils.solrClient = client;
SolrUtils.defaultCollection = defaultCollection;
} catch (SolrServerException | IOException e) {
LOGGER.error("SolrClient initialized failed,{}", e.getMessage(), e);
throw new RuntimeException("SolrClient initialized failed");
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment