java同步器
commit
1d9bbd839d
@ -0,0 +1,35 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
docus-services/docus-services-system1/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
*.log
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
mvnw*
|
||||
*.cmd
|
||||
*.mvn
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
logs*
|
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>docus-collector-server</artifactId>
|
||||
<groupId>com.docus</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>api-prototype</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<name>Archetype - api-prototype</name>
|
||||
<packaging>jar</packaging>
|
||||
<dependencies>
|
||||
<!--ehcache-->
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache.internal</groupId>
|
||||
<artifactId>ehcache-core</artifactId>
|
||||
<version>2.10.2</version>
|
||||
</dependency>
|
||||
<!-- 分页插件pagehelper -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper</artifactId>
|
||||
<version>5.2.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-autoconfigure</artifactId>
|
||||
<version>1.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>2.1.4</version>
|
||||
</dependency>
|
||||
<!--mybatis -p1us通用接口插件-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
<!--mybatis -pTus通用生成插件-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-generator</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,13 @@
|
||||
package com.docus.api.prototype;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class ApiPrototypeApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ApiPrototypeApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.docus.api.prototype.actuator;
|
||||
|
||||
import org.springframework.boot.actuate.trace.http.HttpTrace;
|
||||
import org.springframework.boot.actuate.trace.http.InMemoryHttpTraceRepository;
|
||||
|
||||
public class ApiHttpTraceRepository extends InMemoryHttpTraceRepository {
|
||||
|
||||
@Override
|
||||
public void add(HttpTrace trace) {
|
||||
|
||||
if (trace.getRequest() != null && trace.getRequest().getUri() != null
|
||||
&& trace.getRequest().getUri().getPath() != null && trace.getRequest().getUri().getPath().startsWith("/actuator")) {
|
||||
//排除/actuator请求
|
||||
return;
|
||||
} else {
|
||||
super.add(trace);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.docus.api.prototype.actuator.endpoints;
|
||||
|
||||
import com.docus.api.prototype.log.RequestLog;
|
||||
import com.docus.api.prototype.log.RequestLogManager;
|
||||
import com.docus.api.prototype.web.response.RawResponse;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Endpoint(id = "requestLog")
|
||||
public class RequestLogEndpoint {
|
||||
@ReadOperation
|
||||
public List<RequestLog> requestLog() {
|
||||
RequestLogManager traceLogStat = RequestLogManager.getInstance();
|
||||
List<RequestLog> list = new ArrayList();
|
||||
list.addAll(traceLogStat.getExceptionTraces().values());
|
||||
list.addAll(traceLogStat.getElapsedTimeTraces().values());
|
||||
list.addAll(traceLogStat.getSqlCountTraces().values());
|
||||
list.addAll(traceLogStat.getManualTracks().values());
|
||||
list.sort((o1, o2) -> o2.getLogTime().compareTo(o1.getLogTime()));
|
||||
return list;
|
||||
}
|
||||
|
||||
@RawResponse
|
||||
@ReadOperation
|
||||
public String getLogContent(@Selector Integer logIndex) {
|
||||
if (logIndex != null && logIndex > 0) {
|
||||
RequestLog traceLog = RequestLogManager.getInstance().getTraceLog(logIndex);
|
||||
String filePath = traceLog.getLogFilePath();
|
||||
File file = new File(filePath);
|
||||
if (file.exists()) {
|
||||
try {
|
||||
return FileUtils.readFileToString(file, "UTF-8");
|
||||
} catch (IOException e) {
|
||||
return "读取日志文件失败," + e.getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
return "日志文件不存在 ";
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.docus.api.prototype.cache;
|
||||
|
||||
public enum CacheAction {
|
||||
FETCH,
|
||||
CLEAR
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.docus.api.prototype.cache;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.docus.api.prototype.cache.impl.CacheImpl;
|
||||
|
||||
@Aspect
|
||||
public class CacheAop {
|
||||
private final CacheProxy cacheProxy;
|
||||
|
||||
public CacheAop() {
|
||||
cacheProxy = new CacheProxy();
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
private CacheImpl cacheImpl;
|
||||
|
||||
@Around(value = "@annotation(cache)")
|
||||
public Object around(ProceedingJoinPoint joinPoint, Cache cache) throws Throwable {
|
||||
CacheContext cacheContext = new CacheContext(joinPoint);
|
||||
cacheProxy.proxy(cacheContext, cache, cacheImpl);
|
||||
return cacheContext.getReturnValue();
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.docus.api.prototype.cache;
|
||||
|
||||
public enum CacheImpl {
|
||||
REDIS,
|
||||
EHCACHE
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.docus.api.prototype.cache;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
//支持多个annotation
|
||||
@Target({ ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface Caches {
|
||||
Cache[] value();
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.docus.api.prototype.cache;
|
||||
|
||||
import com.docus.api.prototype.cache.impl.CacheImpl;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@Aspect
|
||||
public class CachesAop {
|
||||
private final CacheProxy cacheProxy;
|
||||
|
||||
public CachesAop() {
|
||||
cacheProxy = new CacheProxy();
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
private CacheImpl cacheImpl;
|
||||
|
||||
@Around(value = "@annotation(caches)")
|
||||
public Object around(ProceedingJoinPoint joinPoint, Caches caches) throws Throwable {
|
||||
CacheContext cacheContext = new CacheContext(joinPoint);
|
||||
if (caches.value() != null && caches.value().length > 0) {
|
||||
for (Cache cache : caches.value()) {
|
||||
cacheProxy.proxy(cacheContext, cache, cacheImpl);
|
||||
}
|
||||
|
||||
}
|
||||
return cacheContext.getReturnValue();
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.docus.api.prototype.cache.impl;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public interface CacheImpl {
|
||||
|
||||
Object get(String group, String key, Type type);
|
||||
|
||||
void set(String group, String key, Object value, int duration, TimeUnit timeUnit);
|
||||
|
||||
void clear(String group, String key);
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.docus.api.prototype.cache.impl;
|
||||
|
||||
import com.docus.api.prototype.web.response.ApiException;
|
||||
import com.docus.api.prototype.web.response.ExceptionCode;
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Element;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class EhcacheImpl implements CacheImpl {
|
||||
@Autowired(required = false)
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private Cache getCacheGroup(String group) {
|
||||
Cache cache = cacheManager.getCache(group);
|
||||
if (cache == null) {
|
||||
throw new ApiException(ExceptionCode.InternalError.getCode(), "ehcache缓存" + group + "未配置");
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(String group, String key, Type type) {
|
||||
Cache cache = getCacheGroup(group);
|
||||
Element element = cache.get(key);
|
||||
return element == null ? null : element.getObjectValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String group, String key, Object value, int duration, TimeUnit timeUnit) {
|
||||
Cache cache = getCacheGroup(group);
|
||||
int durationSeconds = (int) timeUnit.toSeconds(duration);
|
||||
cache.put(new Element(key, value, durationSeconds, durationSeconds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(String group, String key) {
|
||||
Cache cache = getCacheGroup(group);
|
||||
cache.remove(key);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.docus.api.prototype.cache.impl;
|
||||
|
||||
import com.docus.api.prototype.utils.JsonUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RedisCacheImpl implements CacheImpl {
|
||||
|
||||
@Autowired(required = false)
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
public String getKey(String group, String key) {
|
||||
return "Cache:" + group + ":" + key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(String group, String key, Type type) {
|
||||
String value = stringRedisTemplate.opsForValue().get(getKey(group, key));
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
return null;
|
||||
}
|
||||
if (type instanceof ParameterizedType) {
|
||||
//泛型
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
|
||||
List<Class> parameterClasses = new ArrayList<>();
|
||||
for (Type actualTypeArgument : actualTypeArguments) {
|
||||
parameterClasses.add((Class) actualTypeArgument);
|
||||
}
|
||||
return JsonUtils.fromJson(value, (Class) parameterizedType.getRawType(), parameterClasses.toArray(new Class[parameterClasses.size()]));
|
||||
}
|
||||
return JsonUtils.fromJson(value, (Class) type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String group, String key, Object value, int duration, TimeUnit timeUnit) {
|
||||
stringRedisTemplate.opsForValue().set(getKey(group, key), JsonUtils.toJson(value), duration, timeUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(String group, String key) {
|
||||
stringRedisTemplate.delete(getKey(group, key));
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.docus.api.prototype.cloud.feign;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.docus.api.prototype.web.response.ApiException;
|
||||
import feign.FeignException;
|
||||
import feign.Response;
|
||||
import feign.Util;
|
||||
import feign.codec.Decoder;
|
||||
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Objects;
|
||||
|
||||
//feign处理统一输出和异常
|
||||
public class FeignResponseDecoder extends ResponseEntityDecoder {
|
||||
public FeignResponseDecoder(Decoder decoder) {
|
||||
super(decoder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(Response response, Type type) throws IOException, FeignException {
|
||||
String body;
|
||||
//response. body默认是InputStreamBody , 加了Feign 1og之后转为ByteArrayBody
|
||||
if (response.body().length() == null && response.body().asInputStream().available() > 0) {
|
||||
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
|
||||
body = new String(bodyData);
|
||||
} else {
|
||||
body = response.body().toString();
|
||||
}
|
||||
if (!StringUtils.isEmpty(body)) {
|
||||
JSONObject responseobject = JSON.parseObject(body);
|
||||
if (responseobject.containsKey("code")) {
|
||||
Integer code = responseobject.getInteger("code");
|
||||
if (!Objects.equals(0, code)) {
|
||||
String message = responseobject.getString("message");
|
||||
throw new ApiException(code, message);
|
||||
}
|
||||
String result = responseobject.getString("result");
|
||||
if (result == null || "null".equalsIgnoreCase(result)) {
|
||||
return null;
|
||||
}
|
||||
response = response.toBuilder().body(result, Charset.forName("UTF-8")).build();
|
||||
}
|
||||
}
|
||||
return super.decode(response, type);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.docus.api.prototype.common;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class IgnoreCaseMap<V> extends HashMap<String, V> {
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
V v = super.get(key);
|
||||
if (v == null && key != null) {
|
||||
for (String k : keySet()) {
|
||||
if (key.toString().equalsIgnoreCase(k)) {
|
||||
return get(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getOrDefault(Object key, V defaultValue) {
|
||||
V v = get(key);
|
||||
return v == null ? defaultValue : v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
|
||||
return get(key) != null;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.docus.api.prototype.config;
|
||||
|
||||
import com.docus.api.prototype.web.CommonController;
|
||||
import com.docus.api.prototype.web.monitor.RequestLogController;
|
||||
import com.docus.api.prototype.actuator.ApiHttpTraceRepository;
|
||||
import com.docus.api.prototype.actuator.AppInfoContributor;
|
||||
import com.docus.api.prototype.actuator.endpoints.RequestLogEndpoint;
|
||||
import com.docus.api.prototype.redis.RedisStringService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(ApiProperties.class)
|
||||
public class ApiAutoConfig {
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public RequestLogController requestLogController() {
|
||||
return new RequestLogController();
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public CommonController commonController() {
|
||||
return new CommonController();
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public AppInfoContributor logInfoContributo() {
|
||||
return new AppInfoContributor();
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public RedisStringService redisStringService() {
|
||||
return new RedisStringService();
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public ApiHttpTraceRepository apiHttpTraceRepository() {
|
||||
ApiHttpTraceRepository apiHttpTraceRepository = new ApiHttpTraceRepository();
|
||||
// ;默认500条
|
||||
apiHttpTraceRepository.setCapacity(500);
|
||||
return apiHttpTraceRepository;
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public RequestLogEndpoint requestLogEndpoint() {
|
||||
return new RequestLogEndpoint();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.docus.api.prototype.config;
|
||||
|
||||
import com.docus.api.prototype.cache.CacheAop;
|
||||
import com.docus.api.prototype.cache.CachesAop;
|
||||
import com.docus.api.prototype.cache.impl.CacheImpl;
|
||||
import com.docus.api.prototype.cache.impl.EhcacheImpl;
|
||||
import com.docus.api.prototype.cache.impl.RedisCacheImpl;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class CacheConfig {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = CacheAop.class)
|
||||
@ConditionalOnProperty(value = {"api. enable-cache"}, havingValue = "true")
|
||||
public CacheAop cacheAop() {
|
||||
return new CacheAop();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = CachesAop.class)
|
||||
@ConditionalOnProperty(value = {" api. enable-cache"}, havingValue = "true")
|
||||
public CachesAop cachesAop() {
|
||||
return new CachesAop();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = CacheImpl.class)
|
||||
@ConditionalOnProperty(value = {"api.cache-impl"}, havingValue = "REDIS")
|
||||
public CacheImpl redisCacheImpl() {
|
||||
return new RedisCacheImpl();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = CacheImpl.class)
|
||||
@ConditionalOnProperty(value = {"api. cache-imp1"}, havingValue = "EHCACHE")
|
||||
public CacheImpl ehcacheImpl() {
|
||||
return new EhcacheImpl();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.docus.api.prototype.config;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator;
|
||||
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
public class CustomDataSourceHealthContributor extends DataSourceHealthContributorAutoConfiguration {
|
||||
private String defaultQuery = "select 1 from dual";
|
||||
|
||||
public CustomDataSourceHealthContributor(Map<String, DataSource> dataSources, ObjectProvider<DataSourcePoolMetadataProvider> metadataProviders) {
|
||||
super(dataSources, metadataProviders);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractHealthIndicator createIndicator(DataSource source) {
|
||||
DataSourceHealthIndicator indicator = (DataSourceHealthIndicator) super.createIndicator(source);
|
||||
if (!StringUtils.hasText(indicator.getQuery())) {
|
||||
indicator.setQuery(defaultQuery);
|
||||
}
|
||||
return indicator;
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.docus.api.prototype.config;
|
||||
|
||||
import com.docus.api.prototype.cloud.feign.FeignResponseDecoder;
|
||||
import com.docus.api.prototype.utils.DateTimeUtils;
|
||||
import feign.Request;
|
||||
import feign.codec.Decoder;
|
||||
import feign.optionals.OptionalDecoder;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.cloud.openfeign.FeignFormatterRegistrar;
|
||||
import org.springframework.cloud.openfeign.support.SpringDecoder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
@Configuration
|
||||
public class SpringCloudConfig {
|
||||
@Autowired
|
||||
private ApiProperties apiProperties;
|
||||
|
||||
//feign发起get调用时对时间类型参数转换
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public FeignFormatterRegistrar localDataTimeFormatRegister() {
|
||||
FeignFormatterRegistrar formatterRegistrar = new FeignFormatterRegistrar() {
|
||||
@Override
|
||||
public void registerFormatters(FormatterRegistry registry) {
|
||||
registry.addConverter(new Converter<LocalDateTime, String>() {
|
||||
@Override
|
||||
public String convert(LocalDateTime source) {
|
||||
return DateTimeUtils.dateTimeDisplay(source);
|
||||
}
|
||||
});
|
||||
registry.addConverter(new Converter<LocalDate, String>() {
|
||||
@Override
|
||||
public String convert(LocalDate source) {
|
||||
return source.toString();
|
||||
}
|
||||
});
|
||||
registry.addConverter(new Converter<LocalTime, String>() {
|
||||
@Override
|
||||
public String convert(LocalTime source) {
|
||||
return source.toString();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return formatterRegistrar;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
private ObjectFactory<HttpMessageConverters> messageConverters;
|
||||
|
||||
//feign统一输出体响应拦截
|
||||
@ConditionalOnMissingBean(value = Decoder.class)
|
||||
@ConditionalOnProperty(value = "api.feign-decode-global-response", havingValue = "true")
|
||||
@Bean
|
||||
public Decoder feignResponseDecoder() {
|
||||
return new OptionalDecoder(
|
||||
new FeignResponseDecoder(new SpringDecoder(this.messageConverters)));
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean(value = Request.Options.class)
|
||||
public Request.Options options() {
|
||||
return new Request.Options(apiProperties.getFeignConnectionTimeoutMillis(), apiProperties.getFeignReadTimeoutMillis());
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.docus.api.prototype.db;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class BaseDomain implements Serializable {
|
||||
|
||||
@TableId(value = "ID", type = IdType.UUID)
|
||||
private String id;
|
||||
|
||||
@TableField("CREATE_TIME")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.docus.api.prototype.db;
|
||||
|
||||
import com.docus.api.prototype.db.enums.IIntegerEnum;
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.EnumTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
//mybatis枚举类型分发
|
||||
public class EnumTypeHandlerDispatch<E extends Enum<E>> extends BaseTypeHandler<E> {
|
||||
private BaseTypeHandler<E> typeHandler;
|
||||
|
||||
public EnumTypeHandlerDispatch(Class<E> type) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Type argument. cannot be nu11");
|
||||
}
|
||||
if (IIntegerEnum.class.isAssignableFrom(type)) {
|
||||
//如果实现了IIntegerEnum,使用自定义的转换器
|
||||
typeHandler = new IntegerEnumHandler(type);
|
||||
} else {
|
||||
//默认转换器
|
||||
typeHandler = new EnumTypeHandler<>(type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws
|
||||
SQLException {
|
||||
typeHandler.setNonNullParameter(ps, i, parameter, jdbcType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||
return typeHandler.getNullableResult(rs, columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||
return typeHandler.getNullableResult(rs, columnIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||
return typeHandler.getNullableResult(cs, columnIndex);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.docus.api.prototype.db;
|
||||
|
||||
import com.docus.api.prototype.db.enums.IIntegerEnum;
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
//mybatis枚举类型转换
|
||||
public class IntegerEnumHandler<E extends IIntegerEnum> extends BaseTypeHandler<E> {
|
||||
private final Class<E> type;
|
||||
|
||||
public IntegerEnumHandler(Class<E> type) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Type argument. cannot. be nu11");
|
||||
}
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
|
||||
if (jdbcType == null) {
|
||||
ps.setInt(i, parameter.getValue());
|
||||
} else {
|
||||
ps.setObject(i, parameter.getValue(), jdbcType.TYPE_CODE); //1 / see r3589
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||
String s = rs.getString(columnName);
|
||||
return s == null ? null : IIntegerEnum.fromValue(type, Integer.parseInt(s));
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||
String s = rs.getString(columnIndex);
|
||||
return s == null ? null : IIntegerEnum.fromValue(type, Integer.parseInt(s));
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||
String s = cs.getString(columnIndex);
|
||||
return s == null ? null : IIntegerEnum.fromValue(type, Integer.parseInt(s));
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.docus.api.prototype.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class KeyGenerator implements IKeyGenerator {
|
||||
public static String genId() {
|
||||
return UUID.randomUUID().toString().replace("-", "").toUpperCase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String executeSql(String incrementerName) {
|
||||
return genId();
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.docus.api.prototype.db;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
//排序定义
|
||||
public class Sort {
|
||||
private List<SortItem> sortByProperties = new ArrayList<>();
|
||||
|
||||
// 隐藏构造函数
|
||||
private Sort() {
|
||||
}
|
||||
|
||||
public static Sort byAsc(String property) {
|
||||
return new Sort().thenByAsc(property);
|
||||
}
|
||||
|
||||
public static Sort byDesc(String property) {
|
||||
return new Sort().thenByDesc(property);
|
||||
}
|
||||
|
||||
public Sort thenByAsc(String property) {
|
||||
sortByProperties.add(new SortItem(property, Direction.ASC));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Sort thenByDesc(String property) {
|
||||
sortByProperties.add(new SortItem(property, Direction.DESC));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public List<SortItem> getSortList() {
|
||||
//复制、只读
|
||||
List<SortItem> copyList = new ArrayList<>(sortByProperties);
|
||||
return Collections.unmodifiableList(copyList);
|
||||
}
|
||||
|
||||
public class SortItem {
|
||||
private String property;
|
||||
private Direction direction;
|
||||
|
||||
private SortItem(String property, Direction direction) {
|
||||
this.property = property;
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public Direction getDirection() {
|
||||
return direction;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Direction {
|
||||
ASC, DESC;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.docus.api.prototype.db;
|
||||
|
||||
//当前的租户信息
|
||||
public class TenantContext {
|
||||
//租户
|
||||
private Object tenant;
|
||||
//是否禁用租户过滤
|
||||
private boolean isDisabledTenant = false;
|
||||
|
||||
//租户ID
|
||||
public Object getTenant() {
|
||||
return tenant;
|
||||
}
|
||||
|
||||
private void setTenant(Object tenant) {
|
||||
this.tenant = tenant;
|
||||
}
|
||||
|
||||
//当前是否禁用租户过滤(访问后失效)
|
||||
public boolean isDisabledTenant() {
|
||||
if (isDisabledTenant) {
|
||||
isDisabledTenant = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//临时禁用租户过滤(仅生效一-次)
|
||||
public void disableTenant() {
|
||||
isDisabledTenant = true;
|
||||
}
|
||||
|
||||
//线程变量
|
||||
private static final ThreadLocal<TenantContext> current = new ThreadLocal<>();
|
||||
|
||||
//荻取当前銭程的reques tContext
|
||||
public static TenantContext get() {
|
||||
return current.get();
|
||||
}
|
||||
|
||||
//清除线程变量
|
||||
public static void clear() {
|
||||
current.remove();
|
||||
}
|
||||
|
||||
//初始化
|
||||
public static void init(Object tenant) {
|
||||
current.remove();
|
||||
TenantContext tenantContext = new TenantContext();
|
||||
tenantContext.setTenant(tenant);
|
||||
current.set(tenantContext);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.docus.api.prototype.db.enums;
|
||||
|
||||
public class EnumItemView {
|
||||
|
||||
private Integer value;
|
||||
private String display;
|
||||
|
||||
public EnumItemView() {
|
||||
}
|
||||
|
||||
public EnumItemView(Integer value, String display) {
|
||||
this.value = value;
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Integer value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
public void setDisplay(String display) {
|
||||
this.display = display;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.docus.api.prototype.db.enums;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IEnum;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public interface IIntegerEnum extends IEnum {
|
||||
|
||||
//枚举值,存储到数据库
|
||||
|
||||
@Override
|
||||
Integer getValue();
|
||||
|
||||
//*用于显示的枚举描述
|
||||
String getDisplay();
|
||||
|
||||
static <T extends IIntegerEnum> T fromValue(Class<T> enumType, Integer value) {
|
||||
for (T object : enumType.getEnumConstants()) {
|
||||
if (Objects.equals(value, object.getValue())) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No. enum value 。" + value + "of " + enumType.getCanonicalName());
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.docus.api.prototype.db.interceptor;
|
||||
|
||||
import org.apache.ibatis.executor.Executor;
|
||||
import org.apache.ibatis.mapping.MappedStatement;
|
||||
import org.apache.ibatis.mapping.SqlCommandType;
|
||||
import org.apache.ibatis.plugin.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
//★数据变更(包含add、update、 delete )拦截器示例
|
||||
@Intercepts(@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}))
|
||||
public class UpdateInterceptor implements Interceptor {
|
||||
@Override
|
||||
public Object intercept(Invocation invocation) throws Throwable {
|
||||
Object proceed = invocation.proceed();
|
||||
//process之后add对象的id会赋值
|
||||
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
|
||||
Object param = invocation.getArgs()[1];
|
||||
if (param instanceof Map) {
|
||||
|
||||
}
|
||||
if (mappedStatement.getSqlCommandType() == SqlCommandType.INSERT) {
|
||||
//新增
|
||||
} else if (mappedStatement.getSqlCommandType() == SqlCommandType.UPDATE) {
|
||||
//修改
|
||||
} else if (mappedStatement.getSqlCommandType() == SqlCommandType.DELETE) {
|
||||
//删除
|
||||
}
|
||||
return proceed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object plugin(Object target) {
|
||||
if (target instanceof Executor) {
|
||||
return Plugin.wrap(target, this);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperties(Properties properties) {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.docus.api.prototype.db.mapwrapper;
|
||||
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.apache.ibatis.reflection.wrapper.MapWrapper;
|
||||
|
||||
import java.util.Map;
|
||||
//key全部转换成大写
|
||||
public class MyCustomWrapper extends MapWrapper {
|
||||
public MyCustomWrapper(MetaObject metaObject, Map<String, Object> map) {
|
||||
super(metaObject, map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findProperty(String name, boolean useCamelCaseMapping) {
|
||||
return name == null?"":name.toUpperCase();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.docus.api.prototype.db.mapwrapper;
|
||||
|
||||
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
//缺少conver处理启动报错
|
||||
@Component
|
||||
@ConfigurationPropertiesBinding
|
||||
public class ObjectWrapperFactoryConverter implements Converter<String, ObjectWrapperFactory> {
|
||||
@Override
|
||||
public ObjectWrapperFactory convert(String source) {
|
||||
try {
|
||||
return (ObjectWrapperFactory) Class.forName(source).newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.docus.api.prototype.db.type.handler;
|
||||
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.apache.ibatis.type.MappedTypes;
|
||||
|
||||
import java.sql.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
//用于兼容gbase localdatetime 转换
|
||||
@MappedTypes(value = LocalDateTime.class)
|
||||
public class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {
|
||||
|
||||
//驱动是否原生支持
|
||||
private Boolean isJdbcSupport;
|
||||
|
||||
private boolean getIsJdbcSupport(ResultSet rs, String columnName) {
|
||||
if (isJdbcSupport == null) {
|
||||
try {
|
||||
rs.getObject(columnName, LocalDateTime.class);
|
||||
isJdbcSupport = true;
|
||||
} catch (Exception e) {
|
||||
isJdbcSupport = false;
|
||||
}
|
||||
}
|
||||
return isJdbcSupport;
|
||||
}
|
||||
|
||||
private boolean getIsJdbcSupport(CallableStatement cs, int columnIndex) {
|
||||
if (isJdbcSupport == null) {
|
||||
try {
|
||||
cs.getObject(columnIndex, LocalDateTime.class);
|
||||
isJdbcSupport = true;
|
||||
} catch (Exception e) {
|
||||
isJdbcSupport = false;
|
||||
}
|
||||
}
|
||||
return isJdbcSupport;
|
||||
}
|
||||
|
||||
private boolean getIsJdbcSupport(ResultSet rs, int columnIndex) {
|
||||
if (isJdbcSupport == null) {
|
||||
try {
|
||||
rs.getObject(columnIndex, LocalDateTime.class);
|
||||
isJdbcSupport = true;
|
||||
} catch (Exception e) {
|
||||
isJdbcSupport = false;
|
||||
}
|
||||
}
|
||||
return isJdbcSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement ps, int i, LocalDateTime localDateTime, JdbcType jdbcType) throws SQLException {
|
||||
if (isJdbcSupport != null && isJdbcSupport) {
|
||||
ps.setObject(i, localDateTime);
|
||||
} else {
|
||||
ps.setObject(i, Timestamp.valueOf(localDateTime));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
|
||||
if (getIsJdbcSupport(resultSet, columnName)) {
|
||||
return resultSet.getObject(columnName, LocalDateTime.class);
|
||||
} else {
|
||||
Timestamp timestamp = resultSet.getTimestamp(columnName);
|
||||
return timestamp == null ? null : timestamp.toLocalDateTime();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
|
||||
if (getIsJdbcSupport(resultSet, columnIndex)) {
|
||||
return resultSet.getObject(columnIndex, LocalDateTime.class);
|
||||
} else {
|
||||
Timestamp timestamp = resultSet.getTimestamp(columnIndex);
|
||||
return timestamp == null ? null : timestamp.toLocalDateTime();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
|
||||
if (getIsJdbcSupport(callableStatement, columnIndex)) {
|
||||
return callableStatement.getObject(columnIndex, LocalDateTime.class);
|
||||
} else {
|
||||
Timestamp timestamp = callableStatement.getTimestamp(columnIndex);
|
||||
return timestamp == null ? null : timestamp.toLocalDateTime();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.docus.api.prototype.db.type.handler;
|
||||
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.apache.ibatis.type.MappedTypes;
|
||||
|
||||
import java.sql.*;
|
||||
import java.time.LocalDate;
|
||||
|
||||
//用于兼容gbase LocalDate 转换
|
||||
@MappedTypes(value = LocalDate.class)
|
||||
public class LocalDateTypeHandler extends BaseTypeHandler<LocalDate> {
|
||||
|
||||
//驱动是否原生支持
|
||||
private Boolean isJdbcSupport;
|
||||
|
||||
private boolean getIsJdbcSupport(ResultSet rs, String columnName) {
|
||||
if (isJdbcSupport == null) {
|
||||
try {
|
||||
rs.getObject(columnName, LocalDate.class);
|
||||
isJdbcSupport = true;
|
||||
} catch (Exception e) {
|
||||
isJdbcSupport = false;
|
||||
}
|
||||
}
|
||||
return isJdbcSupport;
|
||||
}
|
||||
|
||||
private boolean getIsJdbcSupport(CallableStatement cs, int columnIndex) {
|
||||
if (isJdbcSupport == null) {
|
||||
try {
|
||||
cs.getObject(columnIndex, LocalDate.class);
|
||||
isJdbcSupport = true;
|
||||
} catch (Exception e) {
|
||||
isJdbcSupport = false;
|
||||
}
|
||||
}
|
||||
return isJdbcSupport;
|
||||
}
|
||||
|
||||
private boolean getIsJdbcSupport(ResultSet rs, int columnIndex) {
|
||||
if (isJdbcSupport == null) {
|
||||
try {
|
||||
rs.getObject(columnIndex, LocalDate.class);
|
||||
isJdbcSupport = true;
|
||||
} catch (Exception e) {
|
||||
isJdbcSupport = false;
|
||||
}
|
||||
}
|
||||
return isJdbcSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement ps, int i, LocalDate localDate, JdbcType jdbcType) throws SQLException {
|
||||
if (isJdbcSupport != null && isJdbcSupport) {
|
||||
ps.setObject(i, localDate);
|
||||
} else {
|
||||
ps.setObject(i, Date.valueOf(localDate));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
|
||||
if (getIsJdbcSupport(resultSet, columnName)) {
|
||||
return resultSet.getObject(columnName, LocalDate.class);
|
||||
} else {
|
||||
Date date = resultSet.getDate(columnName);
|
||||
return date == null ? null : date.toLocalDate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
|
||||
if (getIsJdbcSupport(resultSet, columnIndex)) {
|
||||
return resultSet.getObject(columnIndex, LocalDate.class);
|
||||
} else {
|
||||
Date date = resultSet.getDate(columnIndex);
|
||||
return date == null ? null : date.toLocalDate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
|
||||
if (getIsJdbcSupport(callableStatement, columnIndex)) {
|
||||
return callableStatement.getObject(columnIndex, LocalDate.class);
|
||||
} else {
|
||||
Date date = callableStatement.getDate(columnIndex);
|
||||
return date == null ? null : date.toLocalDate();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.docus.api.prototype.db.type.handler;
|
||||
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.apache.ibatis.type.MappedTypes;
|
||||
|
||||
import java.sql.*;
|
||||
import java.time.LocalTime;
|
||||
|
||||
//用于兼容gbase LocalTime 转换
|
||||
@MappedTypes(value = LocalTime.class)
|
||||
public class LocalTimeTypeHandler extends BaseTypeHandler<LocalTime> {
|
||||
|
||||
//驱动是否原生支持
|
||||
private Boolean isJdbcSupport;
|
||||
|
||||
private boolean getIsJdbcSupport(ResultSet rs, String columnName) {
|
||||
if (isJdbcSupport == null) {
|
||||
try {
|
||||
rs.getObject(columnName, LocalTime.class);
|
||||
isJdbcSupport = true;
|
||||
} catch (Exception e) {
|
||||
isJdbcSupport = false;
|
||||
}
|
||||
}
|
||||
return isJdbcSupport;
|
||||
}
|
||||
|
||||
private boolean getIsJdbcSupport(CallableStatement cs, int columnIndex) {
|
||||
if (isJdbcSupport == null) {
|
||||
try {
|
||||
cs.getObject(columnIndex, LocalTime.class);
|
||||
isJdbcSupport = true;
|
||||
} catch (Exception e) {
|
||||
isJdbcSupport = false;
|
||||
}
|
||||
}
|
||||
return isJdbcSupport;
|
||||
}
|
||||
|
||||
private boolean getIsJdbcSupport(ResultSet rs, int columnIndex) {
|
||||
if (isJdbcSupport == null) {
|
||||
try {
|
||||
rs.getObject(columnIndex, LocalTime.class);
|
||||
isJdbcSupport = true;
|
||||
} catch (Exception e) {
|
||||
isJdbcSupport = false;
|
||||
}
|
||||
}
|
||||
return isJdbcSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement ps, int i, LocalTime LocalTime, JdbcType jdbcType) throws SQLException {
|
||||
if (isJdbcSupport != null && isJdbcSupport) {
|
||||
ps.setObject(i, LocalTime);
|
||||
} else {
|
||||
ps.setObject(i, Time.valueOf(LocalTime));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTime getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
|
||||
if (getIsJdbcSupport(resultSet, columnName)) {
|
||||
return resultSet.getObject(columnName, LocalTime.class);
|
||||
} else {
|
||||
Time time = resultSet.getTime(columnName);
|
||||
return time == null ? null : time.toLocalTime();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTime getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
|
||||
if (getIsJdbcSupport(resultSet, columnIndex)) {
|
||||
return resultSet.getObject(columnIndex, LocalTime.class);
|
||||
} else {
|
||||
Time time = resultSet.getTime(columnIndex);
|
||||
return time == null ? null : time.toLocalTime();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTime getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
|
||||
if (getIsJdbcSupport(callableStatement, columnIndex)) {
|
||||
return callableStatement.getObject(columnIndex, LocalTime.class);
|
||||
} else {
|
||||
Time time = callableStatement.getTime(columnIndex);
|
||||
return time == null ? null : time.toLocalTime();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package com.docus.api.prototype.log;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
//web request 请求跟踪log
|
||||
public class RequestLog {
|
||||
//日志类型
|
||||
private RequestLogType logType;
|
||||
//开始时间
|
||||
private LocalDateTime logTime;
|
||||
//索引
|
||||
private Integer logIndex;
|
||||
//请求url
|
||||
private String requestUrl;
|
||||
//log文件路径
|
||||
private String logFilePath;
|
||||
//异常类型
|
||||
private String exceptionType;
|
||||
//异常消息
|
||||
private String exceptionMessage;
|
||||
//耗时
|
||||
private Integer elapsedTime;
|
||||
//调用sql次数
|
||||
private Integer sqlCount;
|
||||
|
||||
public RequestLogType getLogType() {
|
||||
return logType;
|
||||
}
|
||||
|
||||
public void setLogType(RequestLogType logType) {
|
||||
this.logType = logType;
|
||||
}
|
||||
|
||||
public LocalDateTime getLogTime() {
|
||||
return logTime;
|
||||
}
|
||||
|
||||
public void setLogTime(LocalDateTime logTime) {
|
||||
this.logTime = logTime;
|
||||
}
|
||||
|
||||
public Integer getLogIndex() {
|
||||
return logIndex;
|
||||
}
|
||||
|
||||
public void setLogIndex(Integer logIndex) {
|
||||
this.logIndex = logIndex;
|
||||
}
|
||||
|
||||
public String getRequestUrl() {
|
||||
return requestUrl;
|
||||
}
|
||||
|
||||
public void setRequestUrl(String requestUrl) {
|
||||
this.requestUrl = requestUrl;
|
||||
}
|
||||
|
||||
public String getLogFilePath() {
|
||||
return logFilePath;
|
||||
}
|
||||
|
||||
public void setLogFilePath(String logFilePath) {
|
||||
this.logFilePath = logFilePath;
|
||||
}
|
||||
|
||||
public String getExceptionType() {
|
||||
return exceptionType;
|
||||
}
|
||||
|
||||
public void setExceptionType(String exceptionType) {
|
||||
this.exceptionType = exceptionType;
|
||||
}
|
||||
|
||||
public String getExceptionMessage() {
|
||||
return exceptionMessage;
|
||||
}
|
||||
|
||||
public void setExceptionMessage(String exceptionMessage) {
|
||||
this.exceptionMessage = exceptionMessage;
|
||||
}
|
||||
|
||||
public Integer getElapsedTime() {
|
||||
return elapsedTime;
|
||||
}
|
||||
|
||||
public void setElapsedTime(Integer elapsedTime) {
|
||||
this.elapsedTime = elapsedTime;
|
||||
}
|
||||
|
||||
public Integer getSqlCount() {
|
||||
return sqlCount;
|
||||
}
|
||||
|
||||
public void setSqlCount(Integer sqlCount) {
|
||||
this.sqlCount = sqlCount;
|
||||
}
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
package com.docus.api.prototype.log;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
//tracelog 分类管理器
|
||||
public class RequestLogManager {
|
||||
private static final RequestLogManager INSTANCE = new RequestLogManager();
|
||||
|
||||
public static RequestLogManager getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
//开始统计时间
|
||||
private LocalDateTime beginStatTime;
|
||||
//索引计数器
|
||||
private AtomicInteger traceIndex;
|
||||
//异常logs
|
||||
private Map<Integer, RequestLog> exceptionTraces;
|
||||
//数据库调用logs
|
||||
private Map<Integer, RequestLog> sqlCountTraces;
|
||||
//#Rf 7ogs
|
||||
private Map<Integer, RequestLog> elapsedTimeTraces;
|
||||
//手动跟踪1ogs
|
||||
private Map<Integer, RequestLog> manualTracks;
|
||||
//异常类型统计
|
||||
private Map<Type, AtomicInteger> exceptionTypeStat;
|
||||
|
||||
private RequestLogManager() {
|
||||
beginStatTime = LocalDateTime.now();
|
||||
traceIndex = new AtomicInteger(0);
|
||||
exceptionTraces = new ConcurrentHashMap<>();
|
||||
sqlCountTraces = new ConcurrentHashMap<>();
|
||||
elapsedTimeTraces = new ConcurrentHashMap<>();
|
||||
manualTracks = new ConcurrentHashMap<>();
|
||||
exceptionTypeStat = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public void addExceptionTrace(String requestUrl, String logFilePath, Exception exception) {
|
||||
int index = traceIndex.incrementAndGet();
|
||||
RequestLog traceLog = new RequestLog();
|
||||
traceLog.setLogType(RequestLogType.Exception);
|
||||
traceLog.setLogIndex(index);
|
||||
traceLog.setRequestUrl(requestUrl);
|
||||
Class<? extends Exception> exceptionType = exception.getClass();
|
||||
traceLog.setExceptionType(exceptionType.getTypeName());
|
||||
traceLog.setExceptionMessage(exception.getMessage());
|
||||
traceLog.setLogFilePath(logFilePath);
|
||||
exceptionTraces.put(index, traceLog);
|
||||
if (!exceptionTypeStat.containsKey(exceptionType)) {
|
||||
exceptionTypeStat.putIfAbsent(exceptionType, new AtomicInteger(0));
|
||||
}
|
||||
exceptionTypeStat.get(exceptionType).addAndGet(1);
|
||||
}
|
||||
|
||||
public void addSq1CountTrace(String requestUrl, String logFilePath, Integer sqlCount) {
|
||||
int index = traceIndex.incrementAndGet();
|
||||
RequestLog traceLog = new RequestLog();
|
||||
traceLog.setLogType(RequestLogType.HeavySql);
|
||||
traceLog.setLogIndex(index);
|
||||
traceLog.setRequestUrl(requestUrl);
|
||||
traceLog.setSqlCount(sqlCount);
|
||||
traceLog.setLogFilePath(logFilePath);
|
||||
sqlCountTraces.put(index, traceLog);
|
||||
}
|
||||
|
||||
public void addElapsedTrace(String requestUrl, String logFilePath, Integer elapsedTime) {
|
||||
int index = traceIndex.incrementAndGet();
|
||||
RequestLog traceLog = new RequestLog();
|
||||
traceLog.setLogType(RequestLogType.SlowRequest);
|
||||
traceLog.setLogIndex(index);
|
||||
traceLog.setRequestUrl(requestUrl);
|
||||
traceLog.setElapsedTime(elapsedTime);
|
||||
traceLog.setLogFilePath(logFilePath);
|
||||
elapsedTimeTraces.put(index, traceLog);
|
||||
}
|
||||
|
||||
public void addManualTrace(String requestUrl, String logFi1ePath) {
|
||||
int index = traceIndex.incrementAndGet();
|
||||
RequestLog traceLog = new RequestLog();
|
||||
traceLog.setLogType(RequestLogType.ManualTrack);
|
||||
traceLog.setLogIndex(index);
|
||||
traceLog.setRequestUrl(requestUrl);
|
||||
traceLog.setLogFilePath(logFi1ePath);
|
||||
manualTracks.put(index, traceLog);
|
||||
}
|
||||
|
||||
public LocalDateTime getBeginStatTime() {
|
||||
return beginStatTime;
|
||||
}
|
||||
|
||||
public Map<Integer, RequestLog> getExceptionTraces() {
|
||||
return exceptionTraces;
|
||||
}
|
||||
|
||||
public Map<Integer, RequestLog> getSqlCountTraces() {
|
||||
return sqlCountTraces;
|
||||
}
|
||||
|
||||
public Map<Integer, RequestLog> getElapsedTimeTraces() {
|
||||
return elapsedTimeTraces;
|
||||
}
|
||||
|
||||
public Map<Integer, RequestLog> getManualTracks() {
|
||||
return manualTracks;
|
||||
}
|
||||
|
||||
public RequestLog getTraceLog(Integer index) {
|
||||
if (this.exceptionTraces.containsKey(index)) {
|
||||
return this.exceptionTraces.get(index);
|
||||
}
|
||||
if (this.elapsedTimeTraces.containsKey(index)) {
|
||||
return this.elapsedTimeTraces.get(index);
|
||||
}
|
||||
if (this.sqlCountTraces.containsKey(index)) {
|
||||
return this.sqlCountTraces.get(index);
|
||||
}
|
||||
if (this.manualTracks.containsKey(index)) {
|
||||
return this.manualTracks.get(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//*获取各异常数量,按倒序排序
|
||||
public Map<Type, AtomicInteger> getTopExceptionType() {
|
||||
List<Map.Entry<Type, AtomicInteger>> list = new ArrayList<>(exceptionTypeStat.entrySet());
|
||||
//然后通过比较器来实现排序
|
||||
list.sort((o1, o2) -> Integer.compare(o2.getValue().get(), o1.getValue().get()));
|
||||
Map<Type, AtomicInteger> result = new LinkedHashMap<>();
|
||||
for (Map.Entry<Type, AtomicInteger> entry : list) {
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.docus.api.prototype.log;
|
||||
|
||||
import com.docus.api.prototype.db.enums.IIntegerEnum;
|
||||
|
||||
public enum RequestLogType implements IIntegerEnum {
|
||||
Exception(1, " 请求异常"),
|
||||
SlowRequest(2, " 请求缓慢"),
|
||||
HeavySql(3, "SQL 频繁调用"),
|
||||
ManualTrack(4, "手动跟踪");
|
||||
private Integer value;
|
||||
private String display;
|
||||
|
||||
RequestLogType(Integer value, String display) {
|
||||
this.value = value;
|
||||
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplay() {
|
||||
|
||||
return display;
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
package com.docus.api.prototype.security;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
|
||||
public class EncryptUtils {
|
||||
|
||||
private static final String CHAREST_UTF8 = "utf-8";
|
||||
|
||||
public static String aesEncrypt(String original, String privateKey) {
|
||||
try {
|
||||
Cipher cipher = getAesCipher(privateKey, Cipher.ENCRYPT_MODE);
|
||||
byte[] byteContent = original.getBytes(CHAREST_UTF8);
|
||||
byte[] result = cipher.doFinal(byteContent);
|
||||
return base64(result);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String aesDecrypt(String content, String privateKey) {
|
||||
try {
|
||||
Cipher cipher = getAesCipher(privateKey, Cipher.DECRYPT_MODE);
|
||||
byte[] byteContent = Base64.getDecoder().decode(content);
|
||||
byte[] result = cipher.doFinal(byteContent);
|
||||
return new String(result, CHAREST_UTF8);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Cipher getAesCipher(String privateKey, int decryptMode) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
||||
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
|
||||
random.setSeed(privateKey.getBytes());
|
||||
keyGenerator.init(128, random);
|
||||
SecretKey secretKey = keyGenerator.generateKey();
|
||||
byte[] enCodeFormat = secretKey.getEncoded();
|
||||
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES");
|
||||
cipher.init(decryptMode, key);
|
||||
return cipher;
|
||||
}
|
||||
|
||||
public static String md5ToBase64(String original) {
|
||||
try {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
byte[] byteContent = original.getBytes(CHAREST_UTF8);
|
||||
byte[] digest = md5.digest(byteContent);
|
||||
return base64(digest);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String md5To32(String original) {
|
||||
try {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5 ");
|
||||
byte[] byteContent = original.getBytes(CHAREST_UTF8);
|
||||
byte[] digest = md5.digest(byteContent);
|
||||
StringBuilder hexValue = new StringBuilder();
|
||||
for (byte aDigest : digest) {
|
||||
int val = ((int) aDigest) & 0xff;
|
||||
if (val < 16)
|
||||
hexValue.append("0");
|
||||
hexValue.append(Integer.toHexString(val));
|
||||
}
|
||||
return hexValue.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static String md5To16(String original) {
|
||||
String md5 = md5To32(original);
|
||||
if (md5.length() > 24) {
|
||||
return md5.substring(8, 24);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String base64(String original) {
|
||||
if (original == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return base64(original.getBytes(CHAREST_UTF8));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String base64(byte[] original) {
|
||||
try {
|
||||
return Base64.getEncoder().encodeToString(original);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String base64Decode(String base64Code) {
|
||||
if (base64Code == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new String(Base64.getDecoder().decode(base64Code));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
package com.docus.api.prototype.utils;
|
||||
|
||||
import com.docus.api.prototype.web.response.ApiException;
|
||||
import com.docus.api.prototype.web.response.ExceptionCode;
|
||||
import com.docus.api.prototype.utils.enums.DateTypeEnum;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
//时间工具类
|
||||
public class DateTimeUtils {
|
||||
|
||||
//时间格式化yyyy-MM-dd
|
||||
public static String dateDisplay(LocalDateTime dateTime) {
|
||||
if (dateTime == null) {
|
||||
return null;
|
||||
}
|
||||
return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||
}
|
||||
|
||||
//时间格式化yyyy-MM-dd HH:mm:ss
|
||||
public static String dateTimeDisplay(LocalDateTime dateTime) {
|
||||
if (dateTime == null) {
|
||||
return null;
|
||||
}
|
||||
return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
}
|
||||
|
||||
public static String format(LocalDateTime dateTime, String pattern) {
|
||||
return dateTime.format(DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
//long毫秒转成localdatetime
|
||||
public static LocalDateTime formatTime(long time) {
|
||||
return LocalDateTime.ofInstant(Instant.ofEpochMilli(time), TimeZone.getDefault().toZoneId());
|
||||
}
|
||||
|
||||
//localdatetime转成long毫秒
|
||||
public static long toTime(LocalDateTime dateTime) {
|
||||
return dateTime.toInstant(OffsetDateTime.now().getOffset()).toEpochMilli();
|
||||
}
|
||||
|
||||
//字符串转localdatetime
|
||||
public static LocalDateTime toLocalDateTime(String str) {
|
||||
if (!StringUtils.hasText(str)) {
|
||||
return null;
|
||||
}
|
||||
if (str.contains("T")) {
|
||||
if (str.contains("+")) {
|
||||
//1 2017-12-22708:09: 15.9467651+08:00
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
return LocalDateTime.parse(str, formatter);
|
||||
} else {
|
||||
//1/2018- 11-29T07:09:51.775Z
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
|
||||
return LocalDateTime.parse(str, formatter);
|
||||
}
|
||||
}
|
||||
str = str.replaceAll("[-/\\._: ]", "");
|
||||
if (str.length() == 8) {
|
||||
LocalDate date = toLocalDate(str);
|
||||
return date == null ? null : date.atTime(0, 0);
|
||||
|
||||
} else if (str.length() == 14) {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(" yyyyMMddHHmmss");
|
||||
return LocalDateTime.parse(str, formatter);
|
||||
} else if (str.length() == 17) {
|
||||
//带亳秒的没点号会出错,手动加点号
|
||||
str = str.substring(0, 14) + "." + str.substring(14);
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss.SSS");
|
||||
return LocalDateTime.parse(str, formatter);
|
||||
}
|
||||
throw new IllegalArgumentException(str + " could : not : parse to LocalDateTime");
|
||||
}
|
||||
|
||||
public static LocalDate toLocalDate(String str) {
|
||||
if (!StringUtils.hasText(str)) {
|
||||
return null;
|
||||
}
|
||||
if (str.length() >= 8) {
|
||||
str = str.replaceAll("[-/\\._]", "");
|
||||
}
|
||||
if (str.length() == 6 && !str.startsWith("20")) {
|
||||
str = "20" + str;
|
||||
}
|
||||
if (str.length() == 8) {
|
||||
return LocalDate.parse(str, DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||
|
||||
}
|
||||
throw new IllegalArgumentException(str + " could not. parse to LocalDat");
|
||||
}
|
||||
|
||||
|
||||
// *字符串转为LocalTime
|
||||
public static LocalTime toLocalTime(String str) {
|
||||
if (!StringUtils.hasText(str)) {
|
||||
return null;
|
||||
} else {
|
||||
str = str.trim();
|
||||
}
|
||||
if (str.length() == 5) {
|
||||
return LocalTime.parse(str + ":00", DateTimeFormatter.ofPattern("HH:mm:ss"));
|
||||
}
|
||||
if (str.length() == 8) {
|
||||
return LocalTime.parse(str, DateTimeFormatter.ofPattern("HH: mm:ss"));
|
||||
}
|
||||
throw new IllegalArgumentException(str + " could not. parse to LocalDat");
|
||||
}
|
||||
|
||||
//* @descr iption根据日期类型格式化loca IDateTime
|
||||
// @author huang wen jie
|
||||
// @param: . dateType
|
||||
//*. @param: 1oca ÍDateTime
|
||||
//*. @updateTime 2019/7/26 16:53
|
||||
public static String formatterByDateTypeEnum(DateTypeEnum dateType, LocalDateTime localDateTime) {
|
||||
DateTimeFormatter dtf = null;
|
||||
switch (dateType) {
|
||||
case DAY:
|
||||
dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
break;
|
||||
case MONTH:
|
||||
dtf = DateTimeFormatter.ofPattern("yyyy-MM");
|
||||
break;
|
||||
case YEAR:
|
||||
dtf = DateTimeFormatter.ofPattern("yyyy");
|
||||
break;
|
||||
}
|
||||
return localDateTime.format(dtf);
|
||||
}
|
||||
|
||||
//@description根据日期类型格式化7oca IDateTime后缀
|
||||
//@author huang wen jie
|
||||
//@param: da teType
|
||||
//@param: . loca ÍDateTime
|
||||
//@updateTime 2019/7/26 19:05
|
||||
public static LocalDateTime formatterBeginSuffixByDateTypeEnum(DateTypeEnum dateType, LocalDateTime localDateTime) {
|
||||
String dateTime = formatterByDateTypeEnum(dateType, localDateTime);
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
switch (dateType) {
|
||||
case DAY:
|
||||
return LocalDateTime.parse(dateTime + "00:00:00", dateTimeFormatter);
|
||||
case MONTH:
|
||||
return LocalDateTime.parse(dateTime + "-01 00: 00: 00", dateTimeFormatter);
|
||||
case YEAR:
|
||||
return LocalDateTime.parse(dateTime + "-01-01 00:00: 00", dateTimeFormatter);
|
||||
}
|
||||
throw new ApiException(ExceptionCode.ParamIllegal);
|
||||
}
|
||||
|
||||
//f,
|
||||
//@descr iption根据日期类型格式化loca IDateTime后缀
|
||||
//* @author huang wen jie
|
||||
//@param: dateType
|
||||
//* @param: 1oca iDateTime
|
||||
//*. @upda teTime 201917/26 19:056
|
||||
public static LocalDateTime formatterEndSuffixByDateTypeEnum(DateTypeEnum dateType, LocalDateTime localDateTime) {
|
||||
String dateTime = formatterByDateTypeEnum(dateType, localDateTime);
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
switch (dateType) {
|
||||
case DAY:
|
||||
return LocalDateTime.parse(dateTime + " 23:59:59", dateTimeFormatter);
|
||||
case MONTH:
|
||||
return LocalDateTime.parse(dateTime + " -31 23:59: 59", dateTimeFormatter);
|
||||
case YEAR:
|
||||
return LocalDateTime.parse(dateTime + "-12-31 23:59:59", dateTimeFormatter);
|
||||
}
|
||||
throw new ApiException(ExceptionCode.ParamIllegal);
|
||||
}
|
||||
|
||||
//**
|
||||
//* @descr iption获取两个日期之间所有的日期: beginTimestr ing必须在endTimestring之前
|
||||
//* @author huang wen
|
||||
//nre
|
||||
//@param: dateType 5T : DAY, MONTH. YEAR
|
||||
// @param: beginTime
|
||||
// @param: endT ime
|
||||
// * @updateTime 2019/7/29 11:49
|
||||
public static List<String> getBetweenBeginEndDateList(DateTypeEnum dateType, LocalDateTime beginTime, LocalDateTime endTime) {
|
||||
if (beginTime.isAfter(endTime)) {
|
||||
throw new ApiException(ExceptionCode.ParamIllegal.getCode(), "开始时间必须小于结束时间 ! ");
|
||||
}
|
||||
List<String> betweenBeginEndDateList = new LinkedList<>();
|
||||
String beginTimeString = formatterByDateTypeEnum(dateType, beginTime);
|
||||
String endTimeString = formatterByDateTypeEnum(dateType, endTime);
|
||||
betweenBeginEndDateList.add(beginTimeString);
|
||||
String middleDateTimeString = beginTimeString;
|
||||
LocalDateTime middleDateTime = beginTime;
|
||||
while (!middleDateTimeString.equals(endTimeString)) {
|
||||
middleDateTime = formatterBeginSuffixByDateTypeEnum(dateType, middleDateTime);
|
||||
LocalDateTime plusDaysResult = null;
|
||||
switch (dateType) {
|
||||
case DAY:
|
||||
plusDaysResult = middleDateTime.plusDays(1L);
|
||||
break;
|
||||
case MONTH:
|
||||
plusDaysResult = middleDateTime.plusMonths(1L);
|
||||
break;
|
||||
case YEAR:
|
||||
plusDaysResult = middleDateTime.plusYears(1L);
|
||||
break;
|
||||
}
|
||||
middleDateTimeString = DateTimeUtils.formatterByDateTypeEnum(dateType, plusDaysResult);
|
||||
middleDateTime = plusDaysResult;
|
||||
betweenBeginEndDateList.add(middleDateTimeString);
|
||||
}
|
||||
return betweenBeginEndDateList;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
LocalDateTime time = LocalDateTime.now();
|
||||
String localTime = df.format(time);
|
||||
LocalDateTime ldt = LocalDateTime.parse("2017-09-20 17:07 :05", df);
|
||||
LocalDateTime ldt2 = LocalDateTime.parse("2018-10-28 17 :07:05", df);
|
||||
List<String> betweenBeginEndDateList = getBetweenBeginEndDateList(DateTypeEnum.YEAR, ldt, ldt2);
|
||||
betweenBeginEndDateList.forEach(o -> {
|
||||
System.out.println(o);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
package com.docus.api.prototype.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class GpsConstants {
|
||||
|
||||
//PI道
|
||||
public static final double PI = 3.14159265358979324;
|
||||
//. *卷球长半婆(米)WE5-84标准
|
||||
public static final double RADIUS = 6378140;
|
||||
//。第一個心率平方e2 6E5-84标准
|
||||
public static final double EE = 0.00669437999013;
|
||||
//行政区城一>城市苦全对映村
|
||||
public static final Map<Integer, String> ADMIN_MAP;
|
||||
//城市书全林->行政区划映射
|
||||
public static final Map<String, Integer> CITY_MAP;
|
||||
|
||||
static {
|
||||
ADMIN_MAP = new HashMap<>();
|
||||
ADMIN_MAP.put(110000, "北京市");
|
||||
ADMIN_MAP.put(120000, "天津市");
|
||||
ADMIN_MAP.put(130000, "河北省");
|
||||
ADMIN_MAP.put(130100, "河北省石家庄市");
|
||||
ADMIN_MAP.put(130102, "河北省石家庄市長安区");
|
||||
ADMIN_MAP.put(130104, " 河北省石家庄市椦西区");
|
||||
ADMIN_MAP.put(130105, "河北省 石家庄市新年区");
|
||||
ADMIN_MAP.put(130107, " 河北省石家庄市井陸斫区");
|
||||
ADMIN_MAP.put(130108, "河北省石家庄市裕年区 ");
|
||||
ADMIN_MAP.put(130109, "河北省 石家庄市藁城区");
|
||||
ADMIN_MAP.put(130110, "河北省石 家庄市鹿泉区");
|
||||
ADMIN_MAP.put(130111, "河北省石家庄市索城区");
|
||||
ADMIN_MAP.put(130121, "河北省石家庄市井陸具");
|
||||
ADMIN_MAP.put(130123, "河北省石家庄市正定具");
|
||||
ADMIN_MAP.put(130125, "河北省石家庄市行唐具");
|
||||
ADMIN_MAP.put(130126, "河北省石家庄市炙寿具");
|
||||
ADMIN_MAP.put(130127, "河北省石家庄市高邑具");
|
||||
ADMIN_MAP.put(130128, "河北省 石家庄市深浄具");
|
||||
ADMIN_MAP.put(130129, "河北省石家庄市賛皇具");
|
||||
ADMIN_MAP.put(130130, "河北省石家庄市无板 具");
|
||||
ADMIN_MAP.put(130131, "河北省石家庄市平山昼");
|
||||
ADMIN_MAP.put(130132, "河北省石家庄市元氏基");
|
||||
ADMIN_MAP.put(130133, "河北省石家庄市逖具");
|
||||
ADMIN_MAP.put(130183, "河北省石家庄市晉州市");
|
||||
ADMIN_MAP.put(130184, "河北省石家庄市新禾市");
|
||||
ADMIN_MAP.put(130200, "河北省唐山市");
|
||||
ADMIN_MAP.put(130202, "河北省唐山市路南区");
|
||||
ADMIN_MAP.put(130203, "河北省唐山市路北区");
|
||||
ADMIN_MAP.put(130204, "河北省唐山市古冶区");
|
||||
ADMIN_MAP.put(130205, "河北省 唐山市升平区");
|
||||
ADMIN_MAP.put(130207, "河北省唐山市率南区");
|
||||
ADMIN_MAP.put(130208, "河北省唐山市半淘区");
|
||||
ADMIN_MAP.put(130209, "河北省唐山市曹妃旬区");
|
||||
ADMIN_MAP.put(130223, "河北省唐山市漆基");
|
||||
ADMIN_MAP.put(130224, "河北省 唐山市漆南基");
|
||||
ADMIN_MAP.put(130225, "河北省唐山市示亭基");
|
||||
ADMIN_MAP.put(130227, "河北省唐山市迂西具");
|
||||
ADMIN_MAP.put(130229, "河北省唐山市玉田具");
|
||||
ADMIN_MAP.put(130281, "河北省唐山市遵化市");
|
||||
ADMIN_MAP.put(130283, " 河北省唐山市迂安市");
|
||||
ADMIN_MAP.put(130300, "河北省秦皇島市");
|
||||
ADMIN_MAP.put(130302, "河北省秦皇島市海港区");
|
||||
ADMIN_MAP.put(130303, "河北省秦皇島市山海美区");
|
||||
ADMIN_MAP.put(130304, "河北省秦皇島市北戴河区");
|
||||
ADMIN_MAP.put(130306, "河北省秦皇島市旡宇区");
|
||||
ADMIN_MAP.put(130321, "河北省秦皇島市青尤満族自治具");
|
||||
ADMIN_MAP.put(130322, "河北省秦皇島市昌黎昼");
|
||||
ADMIN_MAP.put(130324, "河北省秦皇島市戸尤具");
|
||||
ADMIN_MAP.put(130400, "河北省邯鄲市");
|
||||
ADMIN_MAP.put(130402, "河北省邯鄲市邯山区");
|
||||
ADMIN_MAP.put(130403, "河北省邯鄲市丛台区");
|
||||
ADMIN_MAP.put(130404, "河北省邯郸市复兴区");
|
||||
ADMIN_MAP.put(130406, "河北省邯郸市峰峰矿区");
|
||||
ADMIN_MAP.put(130421, "河北省 邯郸市邯郸县");
|
||||
ADMIN_MAP.put(130423, "河北省邯郸市临漳县");
|
||||
ADMIN_MAP.put(130424, "河北省邯郸市成安县");
|
||||
ADMIN_MAP.put(130425, "河北省邯郸市大名县");
|
||||
ADMIN_MAP.put(130426, "河北省 邯郸市涉县 ");
|
||||
ADMIN_MAP.put(130427, "河北省邯郸市磁县");
|
||||
ADMIN_MAP.put(130428, "河北省邯郸市肥乡县");
|
||||
ADMIN_MAP.put(130429, "河北省邯郸市永年县");
|
||||
ADMIN_MAP.put(130430, "河北省邯郸市邱县");
|
||||
ADMIN_MAP.put(130431, " 河北省邯郸市鸡泽县");
|
||||
ADMIN_MAP.put(130432, "河北省邯郸市广平县");
|
||||
ADMIN_MAP.put(130433, "河北省邯郸市馆陶县");
|
||||
ADMIN_MAP.put(130434, " 河北省邯郸市魏县");
|
||||
ADMIN_MAP.put(130435, "河北省邯郸市曲周县");
|
||||
ADMIN_MAP.put(130481, "河北省邯鄭市武安市");
|
||||
ADMIN_MAP.put(130500, "河北省邢台市");
|
||||
ADMIN_MAP.put(130502, "河北省邢台市桥东区");
|
||||
ADMIN_MAP.put(130503, "河北省邢台市桥西区");
|
||||
ADMIN_MAP.put(130521, " 河北省邢台市邢台县");
|
||||
ADMIN_MAP.put(130522, "河北省邢台市临城县");
|
||||
ADMIN_MAP.put(130523, "河北省邢台市内丘县");
|
||||
ADMIN_MAP.put(130524, "河北省邢台市柏乡县");
|
||||
ADMIN_MAP.put(130525, "河北省邢台市隆尧县");
|
||||
ADMIN_MAP.put(130526, "河北省邢台市任县");
|
||||
ADMIN_MAP.put(130527, "河北省邢台市南和县");
|
||||
ADMIN_MAP.put(130528, "河北省邢台市宁晋县 ");
|
||||
ADMIN_MAP.put(130529, "河北省邢台市巨鹿县");
|
||||
ADMIN_MAP.put(130530, "河北省邢台市新河县");
|
||||
ADMIN_MAP.put(130531, " 河北省邢台市广宗县");
|
||||
ADMIN_MAP.put(130532, "河北省邢台市平乡县");
|
||||
ADMIN_MAP.put(130533, "河北省邢台市威县");
|
||||
ADMIN_MAP.put(130534, "河北省邢台市清河县");
|
||||
ADMIN_MAP.put(130535, "河北省邢台市临西县");
|
||||
ADMIN_MAP.put(130581, "河北省邢台市南宫市");
|
||||
ADMIN_MAP.put(130582, "河北省邢台市沙河市");
|
||||
ADMIN_MAP.put(130600, "河北省保定市");
|
||||
ADMIN_MAP.put(130602, "河北省保定市竞秀区");
|
||||
ADMIN_MAP.put(130606, "河北省保定市莲池区");
|
||||
ADMIN_MAP.put(130607, "河北省 保定市满城区");
|
||||
ADMIN_MAP.put(130608, "河北省 保定市清苑区");
|
||||
ADMIN_MAP.put(130609, "河北省保定市徐水区");
|
||||
ADMIN_MAP.put(130623, "河北省保定市涞水县");
|
||||
ADMIN_MAP.put(130624, "河北省保定市阜平县");
|
||||
ADMIN_MAP.put(130626, "河北省保定市定兴县");
|
||||
ADMIN_MAP.put(130627, "河北省保定市唐县");
|
||||
ADMIN_MAP.put(130628, "河北省保定市高阳县");
|
||||
ADMIN_MAP.put(130629, "河北省保定市容城县");
|
||||
ADMIN_MAP.put(130630, "河北省保定市涞源县");
|
||||
ADMIN_MAP.put(130631, "河北省保定市望都县");
|
||||
ADMIN_MAP.put(130632, "河北省保定市安新县");
|
||||
ADMIN_MAP.put(130633, "河北省保定市易县");
|
||||
ADMIN_MAP.put(130634, "河北省保定市曲阳县");
|
||||
ADMIN_MAP.put(130635, "河北省保定市鑫县");
|
||||
ADMIN_MAP.put(130636, "河北省保定市顺平县");
|
||||
ADMIN_MAP.put(130637, " 河北省保定市博野县");
|
||||
ADMIN_MAP.put(130638, "河北省保定市雄县");
|
||||
ADMIN_MAP.put(130681, "河北省 保定市涿州市");
|
||||
ADMIN_MAP.put(130683, "河北省 保定市安国市");
|
||||
ADMIN_MAP.put(130684, "河北省保定市高碑店市");
|
||||
ADMIN_MAP.put(130700, "河北省张家口市");
|
||||
ADMIN_MAP.put(130702, "河北省张家口市桥东区");
|
||||
ADMIN_MAP.put(130703, "河北省张家口市桥西区");
|
||||
ADMIN_MAP.put(130705, "河北省张家口市宣化区");
|
||||
ADMIN_MAP.put(130706, "河北省张家口市下花园区");
|
||||
ADMIN_MAP.put(130708, "河北省张家口市万全区");
|
||||
ADMIN_MAP.put(130709, "河北省张家口市崇礼 区");
|
||||
ADMIN_MAP.put(130722, "河北省张家口市张北县");
|
||||
ADMIN_MAP.put(130723, "河北省张家口市康保县");
|
||||
ADMIN_MAP.put(130724, "河北省 张家口市沽源县");
|
||||
ADMIN_MAP.put(130725, " 河北省张家口市尚义县");
|
||||
ADMIN_MAP.put(130726, "河北省 张家口市蔚县");
|
||||
ADMIN_MAP.put(130727, "河北省张家口市阳原县");
|
||||
ADMIN_MAP.put(130728, "河北省张家口市怀安县");
|
||||
ADMIN_MAP.put(130730, "河北省张家口市怀来县");
|
||||
ADMIN_MAP.put(130731, "河北省 张家口市涿鹿县");
|
||||
ADMIN_MAP.put(130732, "河北省张家口市赤城县");
|
||||
ADMIN_MAP.put(130800, " 河北省 承德市");
|
||||
ADMIN_MAP.put(130802, "河北省承德市双桥区");
|
||||
ADMIN_MAP.put(130803, "河北省承德市双滦 区");
|
||||
ADMIN_MAP.put(130804, "河北省承德市鹰手营 子矿区");
|
||||
ADMIN_MAP.put(130821, "河北省承德市承德县 ");
|
||||
ADMIN_MAP.put(130822, "河北省承德市兴隆县");
|
||||
ADMIN_MAP.put(130823, "河北省 承德市平泉县");
|
||||
ADMIN_MAP.put(130824, "河北省承德市滦平县");
|
||||
ADMIN_MAP.put(130825, "河北省承德市隆化县");
|
||||
ADMIN_MAP.put(130826, "河北省承德市丰宁满族自治县");
|
||||
ADMIN_MAP.put(130827, "河北省承德市宽城满族自治县");
|
||||
ADMIN_MAP.put(130828, "河北省承德市国场满族蒙古族自治县");
|
||||
ADMIN_MAP.put(130900, "河北省沧州市");
|
||||
ADMIN_MAP.put(130902, "河北省沧州市新华 区");
|
||||
ADMIN_MAP.put(130903, "河北省沧州市运河区");
|
||||
ADMIN_MAP.put(130921, "河北省 沧州市沧县");
|
||||
ADMIN_MAP.put(130922, " 河北省沧州市青县");
|
||||
ADMIN_MAP.put(130923, "河北省沧州市东光县");
|
||||
ADMIN_MAP.put(130924, "河北省 沧州市海兴县");
|
||||
ADMIN_MAP.put(130925, " 河北省沧州市盐山县");
|
||||
ADMIN_MAP.put(130926, "河北省沧州市肃宁县");
|
||||
ADMIN_MAP.put(130927, "河北省沧州市南皮县");
|
||||
ADMIN_MAP.put(130928, "河北省沧州市吴桥县");
|
||||
ADMIN_MAP.put(130929, "河北省沧州市献县");
|
||||
ADMIN_MAP.put(130930, "河北省沧州市孟村回族自治县");
|
||||
ADMIN_MAP.put(130981, "河北省 沧州市泊头市");
|
||||
ADMIN_MAP.put(130982, "河北省沧州市任丘市");
|
||||
ADMIN_MAP.put(130983, "河北省沧州市黄骅市");
|
||||
ADMIN_MAP.put(130984, "河北省沧州市河间市");
|
||||
ADMIN_MAP.put(131000, "河北省廊坊市");
|
||||
ADMIN_MAP.put(131002, "河北省 廊坊市安次区");
|
||||
ADMIN_MAP.put(131003, "河北省廊坊市广阳区");
|
||||
ADMIN_MAP.put(131022, "河北省廊坊市固安县");
|
||||
ADMIN_MAP.put(131023, "河北省廊坊市永清县");
|
||||
ADMIN_MAP.put(131024, "河北省廊坊市香河县");
|
||||
ADMIN_MAP.put(131025, "河北省 廊坊市大城县");
|
||||
ADMIN_MAP.put(131026, "河北省廊坊市文安县");
|
||||
ADMIN_MAP.put(131028, "河北省廊坊市大厂回族自治县");
|
||||
ADMIN_MAP.put(131081, "河北省廊坊市霸州市");
|
||||
ADMIN_MAP.put(131082, "河北省廊坊市三河市");
|
||||
ADMIN_MAP.put(131100, "河北省衡水市");
|
||||
ADMIN_MAP.put(131102, "河北省衡水市桃城区");
|
||||
ADMIN_MAP.put(131103, "河北省衡水市冀州区");
|
||||
ADMIN_MAP.put(131121, "河北省衡水市枣强县");
|
||||
ADMIN_MAP.put(131122, "河北省衡水市武邑县");
|
||||
ADMIN_MAP.put(131123, "河北省衡水市武强县");
|
||||
ADMIN_MAP.put(131124, "河北省 衡水市饶阳县");
|
||||
ADMIN_MAP.put(131125, "河北省衡水市安平县");
|
||||
ADMIN_MAP.put(131126, "河北省衡水市故城县");
|
||||
ADMIN_MAP.put(131127, "河北省衡水市景县");
|
||||
ADMIN_MAP.put(131128, "河北省衡水市阜城县");
|
||||
ADMIN_MAP.put(131182, "河北省衡水市深州市");
|
||||
ADMIN_MAP.put(139000, "河北省省直辖县级行政区划");
|
||||
ADMIN_MAP.put(139001, "河北省省直辖县级行政区划定州市");
|
||||
ADMIN_MAP.put(139002, "河北省省直辖县级行政区划辛集市");
|
||||
ADMIN_MAP.put(140000, "山西省");
|
||||
ADMIN_MAP.put(140100, "山西省太原市");
|
||||
ADMIN_MAP.put(140105, "山西省太原市小店区");
|
||||
ADMIN_MAP.put(140106, "山西省太原市迎泽区");
|
||||
ADMIN_MAP.put(140107, "山西省太原市杏花岭区");
|
||||
ADMIN_MAP.put(140108, "山西省太原市尖草坪区");
|
||||
ADMIN_MAP.put(140109, "山西省太原市万柏林区");
|
||||
ADMIN_MAP.put(140110, "山西省太原市晋源区");
|
||||
ADMIN_MAP.put(140121, "山西省太原市清徐县");
|
||||
ADMIN_MAP.put(140122, "山西省太原市阳曲县");
|
||||
ADMIN_MAP.put(140123, "山西省太原市娄烦县");
|
||||
ADMIN_MAP.put(140181, "山西省太原市古交市");
|
||||
ADMIN_MAP.put(140200, "山西省大同市");
|
||||
ADMIN_MAP.put(140202, "山西省大同市城区");
|
||||
ADMIN_MAP.put(140203, "山西省大同市矿区");
|
||||
ADMIN_MAP.put(140211, "山西省大同市南郊区");
|
||||
ADMIN_MAP.put(140212, "山西省大同市新萊区");
|
||||
ADMIN_MAP.put(140221, "山西省大同市阳高县");
|
||||
ADMIN_MAP.put(140222, "山西省大同市天镇县");
|
||||
ADMIN_MAP.put(140223, "山西省大同市广灵县");
|
||||
ADMIN_MAP.put(140224, "山西省 大同市灵丘县");
|
||||
ADMIN_MAP.put(140225, "山西省大同市浑源县");
|
||||
ADMIN_MAP.put(140226, "山西省大同市左云县");
|
||||
ADMIN_MAP.put(140227, "山西省大同市大同县");
|
||||
ADMIN_MAP.put(140300, "山西省阳泉市");
|
||||
ADMIN_MAP.put(140302, "山西省阳泉市城区");
|
||||
ADMIN_MAP.put(140303, "山西省 阳泉市矿区");
|
||||
ADMIN_MAP.put(140311, "山西省阳泉市郊区");
|
||||
ADMIN_MAP.put(140321, "山西省阳泉市平定县");
|
||||
ADMIN_MAP.put(140322, "山西省阳泉市孟县");
|
||||
CITY_MAP = new HashMap<>();
|
||||
for (Map.Entry<Integer, String> entry : ADMIN_MAP.entrySet()) {
|
||||
CITY_MAP.put(entry.getValue(), entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.docus.api.prototype.utils;
|
||||
//地图坐标系
|
||||
public enum GpsType {
|
||||
|
||||
WGS,GCJ,BAIDU
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.docus.api.prototype.utils;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Objects;
|
||||
|
||||
public class IPUtils {
|
||||
|
||||
public static boolean isInternal(String ip) {
|
||||
//*本机地址: 127.0.0.1. loca Thost
|
||||
// I
|
||||
//* A奬地址: 10.0. 0.0--10.255.255.255
|
||||
// * B美地址: 172.16.0.0--172.31.255.255
|
||||
//C業地址: 192. 168.0.0--192.168.255.255
|
||||
if ("localhost".equalsIgnoreCase(ip) || "127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
String[] split = ip.split("\\.");
|
||||
int first = Integer.parseInt(split[0]);
|
||||
int second = Integer.parseInt(split[1]);
|
||||
if (Objects.equals(first, 10)) {
|
||||
return true;
|
||||
}
|
||||
if (Objects.equals(first, 172) && second >= 16 && second <= .31) {
|
||||
return true;
|
||||
}
|
||||
if (Objects.equals(first, 192) && Objects.equals(second, 168)) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// ignore ex
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//荻取客戸端靖求IP
|
||||
public static String getRequestIP(HttpServletRequest request) {
|
||||
String xForwardedFor = request.getHeader("x-forwarded-for");
|
||||
if (StringUtils.hasText(xForwardedFor)) {
|
||||
int index = xForwardedFor.indexOf(',');
|
||||
if (index > 0) {
|
||||
return xForwardedFor.substring(0, index);
|
||||
}
|
||||
return xForwardedFor;
|
||||
}
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,52 @@
|
||||
package com.docus.api.prototype.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class JsonUtils {
|
||||
|
||||
private static ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public static void setObjectMapper(ObjectMapper objectMapper) {
|
||||
JsonUtils.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
public static String toJson(Object obj) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.writeValueAsString(obj);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, Class<T> c1azz) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(json, c1azz);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//*反序列化为泛型
|
||||
public static <T> T fromJson(String json, Class<T> clazz, Class<?>... parameterClasses) {
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(clazz, parameterClasses);
|
||||
return objectMapper.readValue(json, javaType);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.docus.api.prototype.utils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class MapUtils {
|
||||
|
||||
// /公格
|
||||
//*对象集合转为Map的L ist
|
||||
// @param list
|
||||
// 源对象集合
|
||||
// @param action
|
||||
// 自定义字段的转化方法
|
||||
//@param autoConvert是否自动转换( true :对象每个属性自动加到map, false :通过action手动加到map )
|
||||
// t @return map: 7ist
|
||||
public static <T> List<Map<String, Object>> toMapList(Collection<T> list, BiConsumer<T, HashMap<String, Object>> action, boolean autoConvert) {
|
||||
if (list == null) {
|
||||
return null;
|
||||
}
|
||||
List<Map<String, Object>> mapList = new ArrayList<>(list.size());
|
||||
list.forEach(p -> mapList.add(toMap(p, action, autoConvert)));
|
||||
return mapList;
|
||||
}
|
||||
|
||||
//*对象转为Map
|
||||
//@param t .
|
||||
//源对象
|
||||
//@param action..自定义字段的转化方法
|
||||
//@param autoConvert 是否自动转换( true :对象每个属性自动加到map, false :通过action手动加到map )
|
||||
//文@return map
|
||||
public static <T> Map<String, Object> toMap(T t, BiConsumer<T, HashMap<String, Object>> action, boolean autoConvert) {
|
||||
|
||||
if (t == null) {
|
||||
return null;
|
||||
}
|
||||
HashMap<String, Object> map = autoConvert ? ReflectUtils.objectToMap(t) : new HashMap<>();
|
||||
if (action != null) {
|
||||
action.accept(t, map);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package com.docus.api.prototype.utils;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class ReflectUtils {
|
||||
// 获取包下面所有的类、接口
|
||||
public static List<Class<?>> getAllClassInPackage(String packageName, boolean isOnlyInterface) throws IOException, ClassNotFoundException {
|
||||
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
|
||||
String path = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(packageName) + "/**/*.class";
|
||||
Resource[] resources = resourcePatternResolver.getResources(path);
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
for (Resource resource : resources) {
|
||||
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
|
||||
if (!isOnlyInterface || metadataReader.getClassMetadata().isInterface()) {
|
||||
Class<?> loadClass = ReflectUtils.class.getClassLoader().loadClass(metadataReader.getClassMetadata().getClassName());
|
||||
classes.add(loadClass);
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
// 复制实体对象的属性
|
||||
|
||||
public static void copyProperties(Object source, Object target, String... ignoreProperties) {
|
||||
BeanUtils.copyProperties(source, target, ignoreProperties);
|
||||
}
|
||||
|
||||
public static <T> T copyProperties(Object source, Class<T> targetClass, String... ignoreProperties) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
T t = targetClass.newInstance();
|
||||
copyProperties(source, t, ignoreProperties);
|
||||
return t;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(targetClass.getName() + " 实例化失败 " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> List<T> copyProperties(List<?> sourceList, Class<T> targetClass, String... ignoreProperties) {
|
||||
if (sourceList == null) {
|
||||
return null;
|
||||
}
|
||||
List<T> list = new ArrayList<>(sourceList.size());
|
||||
try {
|
||||
for (Object s : sourceList) {
|
||||
T t = targetClass.newInstance();
|
||||
ReflectUtils.copyProperties(s, t, ignoreProperties);
|
||||
list.add(t);
|
||||
}
|
||||
return list;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(targetClass.getName() + " # f9l1t51k;" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
//获取利用反射获取类里面的值和名称(不递归子对象)
|
||||
|
||||
public static HashMap<String, Object> objectToMap(Object obj) {
|
||||
try {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
Class<?> clazz = obj.getClass();
|
||||
setValue(clazz, map, obj);
|
||||
Class<?> superclass = clazz.getSuperclass();
|
||||
//同项目下的继承类也包台进去
|
||||
if (superclass != null) {
|
||||
String[] clazzPackage = clazz.getTypeName().split("\\.");
|
||||
String[] superPackage = superclass.getTypeName().split("\\.");
|
||||
if (clazzPackage.length > 2 && superPackage.length > 2) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (!clazzPackage[i].equals(superPackage[i])) {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
setValue(superclass, map, obj);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setValue(Class<?> c1azz, HashMap<String, Object> map, Object obj) {
|
||||
try {
|
||||
for (Field field : c1azz.getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
String fieldName = field.getName();
|
||||
Object value = field.get(obj);
|
||||
map.put(fieldName, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.docus.api.prototype.utils.enums;
|
||||
|
||||
public enum DateTypeEnum {
|
||||
DAY(0, "day"),
|
||||
MONTH(1, "month"),
|
||||
YEAR(2, "year");
|
||||
|
||||
private Integer code;
|
||||
private String display;
|
||||
|
||||
DateTypeEnum(Integer code, String display) {
|
||||
this.code = code;
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.docus.api.prototype.web.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
//忽略权限验证
|
||||
@Target({ ElementType.METHOD,ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface IgnoreAuth {
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.docus.api.prototype.web.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
//忽略鉴权验证
|
||||
@Target({ ElementType.METHOD,ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface IgnoreValidate {
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.docus.api.prototype.web.aspect;
|
||||
|
||||
import com.docus.api.prototype.config.ApiProperties;
|
||||
import com.docus.api.prototype.web.annotations.OperateLog;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.After;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Aspect
|
||||
public class OperateLogAop {
|
||||
private static final Logger logger = LoggerFactory.getLogger(OperateLogAop.class);
|
||||
|
||||
@Autowired
|
||||
private ApiProperties apiProperties;
|
||||
private Consumer<OperateLogAopContext> logSaver;
|
||||
private Set<OperateType> ignoredOperateTypes;
|
||||
|
||||
public OperateLogAop(Consumer<OperateLogAopContext> logSaver) {
|
||||
this.logSaver = logSaver;
|
||||
}
|
||||
|
||||
@After(value = "@annotation(operateLog) ")
|
||||
public void after(JoinPoint joinPoint, OperateLog operateLog) {
|
||||
if (ignoredOperateTypes == null) {
|
||||
synchronized (this) {
|
||||
ignoredOperateTypes = new HashSet<>();
|
||||
if (!StringUtils.isEmpty(apiProperties.getOperateLogIgnoreType())) {
|
||||
String[] split = apiProperties.getOperateLogIgnoreType().split("\\| ");
|
||||
for (String str : split) {
|
||||
OperateType operateType = Enum.valueOf(OperateType.class, str);
|
||||
ignoredOperateTypes.add(operateType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (logSaver == null) {
|
||||
return;
|
||||
}
|
||||
if (ignoredOperateTypes.contains(operateLog.type())) {
|
||||
logger.debug("ignored operate log {}-{}", operateLog.type(), operateLog.module());
|
||||
return;
|
||||
}
|
||||
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
HttpServletRequest request = null;
|
||||
if (requestAttributes != null && requestAttributes.getClass().isAssignableFrom(ServletRequestAttributes.class)) {
|
||||
request = ((ServletRequestAttributes) requestAttributes).getRequest();
|
||||
|
||||
}
|
||||
if (request != null) {
|
||||
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
|
||||
OperateLogAopContext context = new OperateLogAopContext(operateLog, request, method, joinPoint.getArgs());
|
||||
logSaver.accept(context);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.docus.api.prototype.web.aspect;
|
||||
|
||||
import com.docus.api.prototype.web.annotations.OperateLog;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class OperateLogAopContext {
|
||||
private OperateLog operateLog;
|
||||
private HttpServletRequest request;
|
||||
private Method method;
|
||||
private Object[] args;
|
||||
|
||||
public OperateLogAopContext(OperateLog operateLog, HttpServletRequest request, Method method, Object[] args) {
|
||||
this.operateLog = operateLog;
|
||||
this.request = request;
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public OperateLog getOperateLog() {
|
||||
return operateLog;
|
||||
}
|
||||
|
||||
public HttpServletRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.docus.api.prototype.web.aspect;
|
||||
|
||||
public enum OperateType {
|
||||
LOGIN,
|
||||
LOGOUT,
|
||||
QUERY,
|
||||
SAVE,
|
||||
DELETE,
|
||||
UPLOAD,
|
||||
DOWNLOAD,
|
||||
OTHERS
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package com.docus.api.prototype.web.filter;
|
||||
|
||||
import com.docus.api.prototype.log.RequestLogManager;
|
||||
import com.docus.api.prototype.log.RequestLoggerManager;
|
||||
import com.docus.api.prototype.web.request.HttpServletRequestBodyWrapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
//跟踪请求,记录请求上下文日志
|
||||
@Order(10)
|
||||
public class RequestTrackingFilter implements Filter {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RequestTrackingFilter.class);
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
if (servletRequest instanceof HttpServletRequest && servletResponse instanceof HttpServletResponse) {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
|
||||
String ur1 = httpServletRequest.getRequestURI();
|
||||
if (ur1.contains("favicon.ico")) {
|
||||
return;
|
||||
}
|
||||
//actuator相关请求不处理
|
||||
if (ur1.startsWith("/actuator")) {
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
} else {
|
||||
filter(httpServletRequest, (HttpServletResponse) servletResponse, filterChain);
|
||||
}
|
||||
} else {
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
}
|
||||
|
||||
protected void filter(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws IOException {
|
||||
long startTime = System.currentTimeMillis();
|
||||
RequestLoggerManager loggerManager = RequestLoggerManager.get();
|
||||
boolean isTrace = "Y".equalsIgnoreCase(servletRequest.getParameter("trace"));
|
||||
try {
|
||||
// 初始化trace . logger
|
||||
loggerManager.initialize(servletRequest.getRequestURL().toString());
|
||||
logger.debug("=== - begin request processing ===");
|
||||
logger.debug("Request URL : []", servletRequest.getRequestURL());
|
||||
logHeaders(servletRequest);
|
||||
logParameters(servletRequest);
|
||||
HttpServletRequestBodyWrapper requestWrapper = null;
|
||||
if (isContainsBody(servletRequest)) {
|
||||
requestWrapper = new HttpServletRequestBodyWrapper(servletRequest);
|
||||
logger.debug(" request. body: {}", requestWrapper.getBody());
|
||||
}
|
||||
filterChain.doFilter(requestWrapper != null ? requestWrapper : servletRequest, servletResponse);
|
||||
if (isTrace) {
|
||||
logger.debug("手动跟踪请求");
|
||||
loggerManager.manualFlush();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("RequestTrackingFi1ter异常", ex);
|
||||
} finally {
|
||||
long elapsedTime = System.currentTimeMillis() - startTime;
|
||||
logger.debug("Total. elapsed: {}-ms", elapsedTime);
|
||||
logger.debug("=== finish request processing ===");
|
||||
boolean isElapsedover = loggerManager.flushOnElapsedCondition(elapsedTime);
|
||||
String requestUrl = loggerManager.getRequestUr1();
|
||||
String logFilePath = loggerManager.getLogFilePath();
|
||||
if (isElapsedover) {
|
||||
RequestLogManager.getInstance().addElapsedTrace(requestUrl, logFilePath, (int) elapsedTime);
|
||||
}
|
||||
if (loggerManager.isSqlCountExceed()) {
|
||||
RequestLogManager.getInstance().addSq1CountTrace(requestUrl, logFilePath, loggerManager.getSqlCount());
|
||||
}
|
||||
if (isTrace) {
|
||||
RequestLogManager.getInstance().addManualTrace(requestUrl, logFilePath);
|
||||
}
|
||||
loggerManager.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
// 是否包含body
|
||||
protected boolean isContainsBody(HttpServletRequest request) {
|
||||
String httpMethod = request.getMethod();
|
||||
String contentType = request.getContentType();
|
||||
return ("POST".equalsIgnoreCase(httpMethod) || "PUT".equalsIgnoreCase(httpMethod))
|
||||
&& (contentType == null || !contentType.toLowerCase().startsWith("multipart/"))
|
||||
&& (request.getContentLength() > 0);
|
||||
}
|
||||
|
||||
//记录请求头
|
||||
protected void logHeaders(HttpServletRequest request) {
|
||||
Enumeration headers = request.getHeaderNames();
|
||||
StringBuilder stringBuilder = new StringBuilder(200);
|
||||
stringBuilder.append("request headers:{").append("\r\n");
|
||||
while (headers.hasMoreElements()) {
|
||||
String headerName = (String) headers.nextElement();
|
||||
stringBuilder.append(" ").append(headerName).append(": ").append(request.getHeader(headerName)).append("\r\n");
|
||||
}
|
||||
stringBuilder.append("}").append("\r\n");
|
||||
logger.debug(stringBuilder.toString());
|
||||
}
|
||||
|
||||
//记录请求参数
|
||||
protected void logParameters(HttpServletRequest request) {
|
||||
Enumeration paramNames = request.getParameterNames();
|
||||
StringBuilder stringBuilder = new StringBuilder(200);
|
||||
stringBuilder.append(" request. parameters: {").append("\r\n");
|
||||
while (paramNames.hasMoreElements()) {
|
||||
String paramName = (String) paramNames.nextElement();
|
||||
stringBuilder.append(" ").append(paramName).append(":").append(request.getParameter(paramName)).append("\r\n");
|
||||
}
|
||||
stringBuilder.append("}").append("\r\n");
|
||||
logger.debug(stringBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
System.out.println("Reques tTrackingFi1ter destory");
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
package com.docus.api.prototype.web.monitor;
|
||||
|
||||
import com.docus.api.prototype.config.ApiProperties;
|
||||
import com.docus.api.prototype.log.RequestLog;
|
||||
import com.docus.api.prototype.log.RequestLogManager;
|
||||
import com.docus.api.prototype.security.EncryptUtils;
|
||||
import com.docus.api.prototype.utils.DateTimeUtils;
|
||||
import com.docus.api.prototype.utils.StringUtils;
|
||||
import com.docus.api.prototype.web.annotations.IgnoreAuth;
|
||||
import com.docus.api.prototype.web.annotations.IgnoreValidate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IgnoreAuth
|
||||
@IgnoreValidate
|
||||
@Controller
|
||||
@RequestMapping(value = "monitor/requestLog")
|
||||
public class RequestLogController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RequestLogController.class);
|
||||
@Autowired
|
||||
private ApiProperties apiProperties;
|
||||
|
||||
//简单bas ic验证,用户名密码固定logger:xmgpx
|
||||
private boolean doBasicAuth() {
|
||||
if (StringUtils.isEmpty(apiProperties.getRequestLogBasicAuth())) {
|
||||
return true;
|
||||
}
|
||||
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
|
||||
HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
|
||||
String authorization = request.getHeader("Authorization");
|
||||
if (StringUtils.isEmpty(authorization) || !authorization.startsWith("Basic ")) {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);//HTTP 401
|
||||
response.setHeader("WWW-Authenticate", "BASIC realm=/'auth/'");
|
||||
return false;
|
||||
}
|
||||
String userAndpassword = EncryptUtils.base64Decode(authorization.substring(6));
|
||||
if (!apiProperties.getRequestLogBasicAuth().equalsIgnoreCase(userAndpassword)) {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);//HTTP 401
|
||||
response.setHeader("WW-Authenticate", "BASIC realm=/'auth/'");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@GetMapping("")
|
||||
public void index(HttpServletResponse response) throws IOException {
|
||||
if (!doBasicAuth()) {
|
||||
return;
|
||||
}
|
||||
RequestLogManager traceLogStat = RequestLogManager.getInstance();
|
||||
StringBuilder content = new StringBuilder();
|
||||
content.append("<html><body><center>");
|
||||
content.append(" <h4>Begin 1og time: ").append(DateTimeUtils.dateTimeDisplay(traceLogStat.getBeginStatTime())).append(" </h4>");
|
||||
content.append(" <table border=1 width=400 cellpadding=5sty1e- border-co1lapse:co1lapse' >");
|
||||
content.append(" <thead><tr><th>跟踪类型</th><th>发生次数</th><th></th></tr></thead>");
|
||||
content.append(" <tbody>");
|
||||
if (traceLogStat.getExceptionTraces().size() > 0) {
|
||||
content.append("<tr><td>异常</td><td>").append(traceLogStat.getExceptionTraces().size()).append("</td><td><a href='./requestLog/exception'>详情</a></td></tr>");
|
||||
}
|
||||
if (traceLogStat.getElapsedTimeTraces().size() > 0) {
|
||||
content.append(" <tr><td>请求响应缓慢</ td><td>").append(traceLogStat.getElapsedTimeTraces().size()).append("</td><td><a href=' ./requestLog/elapsed'>详情</a></td></tr>");
|
||||
}
|
||||
if (traceLogStat.getSqlCountTraces().size() > 0) {
|
||||
content.append("<tr><td>数据库频繁操作</td><td>").append(traceLogStat.getSqlCountTraces().size()).append("</td><td><a href='./requestLog/sqlCount'>详情</a></td></tr>");
|
||||
}
|
||||
if (traceLogStat.getManualTracks().size() > 0) {
|
||||
content.append("<tr><td>手动跟踪请求</td><td>").append(traceLogStat.getManualTracks().size()).append("</td><td><a href='./requestLog/manual'>详情</a></td></tr>");
|
||||
}
|
||||
content.append("</tbody>");
|
||||
content.append("</table>");
|
||||
content.append("</center></body></htm1>");
|
||||
response.setContentType(" text/html;charset=utf-8");
|
||||
PrintWriter out = response.getWriter();
|
||||
out.println(content);
|
||||
out.close();
|
||||
}
|
||||
|
||||
@GetMapping("/exception")
|
||||
public void exception(HttpServletResponse response) throws IOException {
|
||||
RequestLogManager traceLogStat = RequestLogManager.getInstance();
|
||||
List<RequestLog> traceLogs = traceLogStat.getExceptionTraces().values().stream().sorted((o1, o2) -> o2.getLogIndex().compareTo(o1.getLogIndex())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/{index}")
|
||||
public void getExceptionLogFile(@PathVariable Integer index, HttpServletResponse response) {
|
||||
if (!doBasicAuth()) {
|
||||
return;
|
||||
}
|
||||
if (index != null && index > 0) {
|
||||
RequestLog traceLog = RequestLogManager.getInstance().getTraceLog(index);
|
||||
if (traceLog != null) {
|
||||
try {
|
||||
String filePath = traceLog.getLogFilePath();
|
||||
File file = new File(filePath);
|
||||
if (file.exists()) {
|
||||
long fileLength = file.length();
|
||||
//清空response
|
||||
response.reset();
|
||||
response.setContentType(" application/ octet-stream; charset=utf-8");
|
||||
response.setHeader("content-disposition", "attachment;filename=" + file.getName());
|
||||
response.setHeader("Content-Length", String.valueOf(fileLength));
|
||||
try (InputStream inputStream = new FileInputStream(file);
|
||||
OutputStream outputStream = response.getOutputStream()) {
|
||||
byte[] b = new byte[2048];
|
||||
while (inputStream.read(b) != -1) {
|
||||
outputStream.write(b);
|
||||
}
|
||||
outputStream.flush();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
response.setHeader("error", "file. does not exist");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
response.setHeader("error", e.getMessage());
|
||||
return;
|
||||
}
|
||||
//1 ignore
|
||||
} else {
|
||||
response.setHeader("error", "exception does not exist");
|
||||
return;
|
||||
}
|
||||
response.setHeader("error", "index argument. invalid");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.docus.api.prototype.web.request;
|
||||
|
||||
import com.docus.api.prototype.utils.ConvertUtils;
|
||||
import com.docus.api.prototype.utils.DateTimeUtils;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ParamsMap extends HashMap<String, Object> {
|
||||
public String getString(String key) {
|
||||
return get(key) == null ? null : get(key).toString();
|
||||
}
|
||||
|
||||
public Integer getInteger(String key) {
|
||||
return get(key) == null ? null : ConvertUtils.toInteger(get(key).toString(), null);
|
||||
}
|
||||
|
||||
public Integer getInteger(String key, Integer defaultvalue) {
|
||||
return get(key) == null ? defaultvalue : ConvertUtils.toInteger(get(key).toString(), defaultvalue);
|
||||
}
|
||||
|
||||
public Long getLong(String key) {
|
||||
return get(key) == null ? null : ConvertUtils.toLong(get(key).toString(), null);
|
||||
}
|
||||
|
||||
public Long getLong(String key, Long defaultvalue) {
|
||||
return get(key) == null ? defaultvalue : ConvertUtils.toLong(get(key).toString(), defaultvalue);
|
||||
}
|
||||
|
||||
public LocalDateTime getLocalDateTime(String key) {
|
||||
return get(key) == null ? null : DateTimeUtils.toLocalDateTime(get(key).toString());
|
||||
}
|
||||
|
||||
public LocalDate getLocalDate(String key) {
|
||||
return get(key) == null ? null : DateTimeUtils.toLocalDate(get(key).toString());
|
||||
}
|
||||
|
||||
public Boolean getBoolean(String key) {
|
||||
return get(key) == null ? null : ConvertUtils.toBoolean(get(key));
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.docus.api.prototype.web.response;
|
||||
|
||||
public class ApiException extends RuntimeException {
|
||||
|
||||
private Integer code;
|
||||
|
||||
public ApiException(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public ApiException(Integer code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public ApiException(ExceptionCode exceptionCode) {
|
||||
super(exceptionCode.getMessage());
|
||||
this.code = exceptionCode.getCode();
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.docus.api.prototype.web.response;
|
||||
|
||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||
import org.springframework.web.servlet.NoHandlerFoundException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
//api 统一返回类型
|
||||
public class ApiResult {
|
||||
|
||||
private Integer code;
|
||||
private String message;
|
||||
private Object result;
|
||||
|
||||
public static ApiResult success(Object result) {
|
||||
ApiResult apiResult = new ApiResult();
|
||||
apiResult.setCode(0);
|
||||
apiResult.setMessage("success");
|
||||
apiResult.setResult(result);
|
||||
return apiResult;
|
||||
}
|
||||
|
||||
public static ApiResult exception(Exception ex) {
|
||||
ApiResult apiResult = new ApiResult();
|
||||
if (ex instanceof ApiException) {
|
||||
apiResult.setCode(((ApiException) ex).getCode());
|
||||
apiResult.setMessage(ex.getMessage());
|
||||
} else if (ex instanceof NoHandlerFoundException) {
|
||||
apiResult.setCode(404);
|
||||
apiResult.setMessage(ex.getMessage());
|
||||
} else if (ex instanceof MaxUploadSizeExceededException) {
|
||||
apiResult.setCode(500);
|
||||
apiResult.setMessage(" 上传附件过大 !");
|
||||
} else {
|
||||
apiResult.setCode(500);
|
||||
if (ex instanceof NullPointerException) {
|
||||
apiResult.setMessage("NullPointerException");
|
||||
} else if (isSQLException(ex)) {
|
||||
apiResult.setMessage("SQLException");
|
||||
} else {
|
||||
String message = ex.getMessage();
|
||||
if (message != null && message.length() > 500) {
|
||||
message = message.substring(0, 500) + "...";
|
||||
}
|
||||
apiResult.setMessage(message);
|
||||
}
|
||||
}
|
||||
apiResult.setResult(null);
|
||||
return apiResult;
|
||||
}
|
||||
|
||||
//是否数据库异常
|
||||
private static boolean isSQLException(Throwable ex) {
|
||||
if (ex instanceof SQLException) {
|
||||
return true;
|
||||
}
|
||||
if (ex.getCause() != null) {
|
||||
return isSQLException(ex.getCause());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Object getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(Object result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.docus.api.prototype.web.response;
|
||||
|
||||
//异常代码每句
|
||||
public enum ExceptionCode {
|
||||
|
||||
ParamIllegal(100001, "参数不合法"),
|
||||
|
||||
IpRequestExceedLimit(100002, "当前ip请求超出限制"),
|
||||
|
||||
TokenError(100003, "token不合法或已过期"),
|
||||
|
||||
InternalError(100004, "内部错误");
|
||||
|
||||
ExceptionCode(Integer code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
private Integer code;
|
||||
private String message;
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.docus.api.prototype.web.response;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface RawResponse {
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
{
|
||||
"groups": [
|
||||
{
|
||||
"name": "api",
|
||||
"type": "com.docus.api.prototype.config.ApiProperties",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties"
|
||||
},
|
||||
{
|
||||
"name": "management.endpoint.request-1og",
|
||||
"type": "com. xmgps.api.prototype.actuator.endpoints.RequestLogEndpoint",
|
||||
"sourceType": "com.docus.api.prototype.actuator.endpoints.RequestLogEndpoint"
|
||||
}
|
||||
],
|
||||
"properties": [
|
||||
{
|
||||
"name": "api.auto-persist-create-update-time",
|
||||
"type": "java. lang. Boolean",
|
||||
"sourceType": "com. xmgps .api . prototype. config. ApiProperties",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "api.base-package",
|
||||
"type": "java.lang. String",
|
||||
" sourceType": "com.xmgps.api.prototype.config.ApiProperties"
|
||||
},
|
||||
{
|
||||
"name": " api.cache- impl",
|
||||
"type": "com.docus.api.prototype.cache.CacheImpl",
|
||||
"sourceType": " com.docus.api.prototype.config.ApiProperties"
|
||||
},
|
||||
{
|
||||
"name": " api.enable-cache",
|
||||
"type": "java.lang.Boolean",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "api.enable-request-1og",
|
||||
" type": "java.lang.Boolean",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
" defaultValue": false
|
||||
},
|
||||
{
|
||||
"name": "api.feign-connection-timeout-millis",
|
||||
"type": "java.lang.Integer",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": 60000
|
||||
},
|
||||
{
|
||||
"name": "api.feign-decode-global-response",
|
||||
"type": "java.lang.Boolean",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "api.fei gn-read-timeout-millis",
|
||||
"type": " java.lang.Integer",
|
||||
"sourceType": " com.docus.api.prototype.config.ApiProperties ",
|
||||
"defaultValue": 180000
|
||||
},
|
||||
{
|
||||
"name": "api.geo-address-request-ur1",
|
||||
"type": "java.lang.String",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties"
|
||||
},
|
||||
{
|
||||
"name": "api.ip-access-limit",
|
||||
"type": "java.lang.Integer",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": -1
|
||||
},
|
||||
{
|
||||
"name": "api.ip-access-limit-period-second",
|
||||
"type": "java.lang.Integer",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": 60
|
||||
},
|
||||
{
|
||||
"name": "api.mybatis-show-sql",
|
||||
"type": "java.lang.Boolean",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": " api. operate-log-ignore-type",
|
||||
"type": "java. lang. String",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties"
|
||||
},
|
||||
{
|
||||
"name": "api.request-log-basic-auth",
|
||||
"type": "java.lang.String",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": "logger:xmgps"
|
||||
},
|
||||
{
|
||||
"name": "api.request-log-contain-header",
|
||||
"type": "java.lang.Boolean",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"name": "api.security-account-lock-minutes",
|
||||
"type": "java.lang.Integer",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": 10
|
||||
},
|
||||
{
|
||||
"name": "api.security-login-attempt-expire-minutes",
|
||||
"type": "java.lang.Integer",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": 10
|
||||
},
|
||||
{
|
||||
"name": " api.security-login-attempt-limit",
|
||||
"type": "java.lang.Integer",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": 3
|
||||
},
|
||||
{
|
||||
"name": "api.security-master-verification-code",
|
||||
"type": "java.lang.String",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties"
|
||||
},
|
||||
{
|
||||
"name": "api.security-password-complexity",
|
||||
" type": " java.lang.Integer",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": 3
|
||||
},
|
||||
{
|
||||
"name": "api.security-password-min-length",
|
||||
"type": "java.lang.Integer",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": 8
|
||||
},
|
||||
{
|
||||
"name": " api.soft-delete-column-name",
|
||||
"type": "java.lang.String",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties"
|
||||
},
|
||||
{
|
||||
"name": "api.soft-delete-column-value",
|
||||
"type": "java.lang.Integer",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties"
|
||||
},
|
||||
{
|
||||
"name": "api.tenant-column-name",
|
||||
"type": "java.lang.String",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties"
|
||||
},
|
||||
{
|
||||
"name": "api.tenant-enable",
|
||||
"type": "java.lang.Boolean",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"name": "api.tenant-ignore-table",
|
||||
"type": "java.lang.String",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties"
|
||||
},
|
||||
{
|
||||
"name": "api.validation-sign-timestamp-expire-minutes",
|
||||
"type": "java.lang.Integer",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": 30
|
||||
},
|
||||
{
|
||||
"name": "api.validation-token-expire-minutes",
|
||||
"type": "java.lang.Integer",
|
||||
" sourceType": "com.xmgps.api.prototype.config.ApiProperties",
|
||||
"defaultValue": 60
|
||||
},
|
||||
{
|
||||
"name": "api.validation-token-white-list",
|
||||
"type": "java.lang.String",
|
||||
"sourceType": "com.docus.api.prototype.config.ApiProperties",
|
||||
"defaultValue": "swagger"
|
||||
},
|
||||
{
|
||||
"name": "management.endpoint.request-log.cache.time-to-live",
|
||||
"type": "java.time.Duration",
|
||||
"description": "Maximum time that aresponse can be cached.",
|
||||
"sourceType": "com.docus.api.prototype.actuator.endpoints.RequestLogEndpoint",
|
||||
"defaultValue": "Oms"
|
||||
},
|
||||
{
|
||||
"name": "management.endpoint.request-log.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether to enable the requestlog endpoint.",
|
||||
"sourceType": "com.docus.api.prototype.actuator.endpoints.RequestLogEndpoint",
|
||||
"defaultValue": true
|
||||
}
|
||||
],
|
||||
"hints": []
|
||||
}
|
@ -0,0 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.docus.api.prototype.config.ApiAutoConfig
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ehcache updateCheck="false">
|
||||
|
||||
<cache name="sysConfig" maxElementsInMemory="100" eternal="false" timeToIdleSeconds="1200" timeToLiveSeconds="3600" overflowToDisk="false"/>
|
||||
|
||||
<cache name="content" maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="false"/>
|
||||
</ehcache>
|
@ -0,0 +1,81 @@
|
||||
package ${package.Controller};
|
||||
|
||||
<#if cfg.clientInterfaceBasePackage??>
|
||||
import ${cfg.clientInterfaceBasePackage}.entity.<#if cfg.clientInterfaceSubFolder??>${cfg.clientInterfaceSubFolder}.</#if>${entity};
|
||||
import ${cfg.clientInterfaceBasePackage}.api.<#if cfg.clientInterfaceSubFolder??>${cfg.clientInterfaceSubFolder}.</#if>${entity}Api;
|
||||
import SearchRequest;
|
||||
import PageResult;
|
||||
<#else>
|
||||
import ${package.Entity}.${entity};
|
||||
import SearchRequest;
|
||||
import PageResult;
|
||||
import org.springframework.web.bind.annotation. *;
|
||||
</#if>
|
||||
import ${package.Service}.${table.serviceName};
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
<#if restControllerStyle>
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
<#else>
|
||||
import org.springframework.stereotype.Controller;
|
||||
</#if>
|
||||
<#if superControllerClassPackage??>
|
||||
import ${superControllerClassPackage};
|
||||
</#if>
|
||||
/**
|
||||
* ${table.comment!} Controller
|
||||
* Generated on ${date}
|
||||
*/
|
||||
<#if restControllerStyle>
|
||||
@RestController
|
||||
<#else>
|
||||
@Controller
|
||||
</#if>
|
||||
<#if kotlin>
|
||||
class ${table.controllerName} <#if superControllerClass??> : ${superControllerClass}()</#if>
|
||||
<#else>
|
||||
<#if superControllerClass??>
|
||||
<#if cfg.clientInterfaceBasePackage??>
|
||||
public class ${table.controllerName} extends ${superControllerClass} implements ${entity}Api {
|
||||
@RequestMapping("/${table.entityPath}")
|
||||
public class ${table.controllerName} extends ${superControllerClass} {
|
||||
</#if>
|
||||
<#else>
|
||||
<#if cfg.clientInterfaceBasePackage??>
|
||||
public class ${table.controllerName} implements ${entity}Api {
|
||||
<#else>
|
||||
@RequestMapping("/${table.entityPath}")
|
||||
public class ${table.controllerName} {
|
||||
</#if>
|
||||
</#if>
|
||||
@Autowired
|
||||
private ${table.serviceName} ${table.serviceName?uncap_first};
|
||||
/**
|
||||
*按主键查询
|
||||
* @param id 主键Id
|
||||
* @return实体
|
||||
*/
|
||||
<#if cfg.clientInterfaceBasePackage??>
|
||||
@Override
|
||||
public ${entity} find(String id) {
|
||||
<#else>
|
||||
@GetMapping("/find/{id}")
|
||||
public ${entity} find(@PathVariable(value = "id") String id) {
|
||||
</#if>
|
||||
return ${table.serviceName?uncap_first}.findById(id);
|
||||
}
|
||||
/*
|
||||
* 关键字搜素
|
||||
* @param searchRequest 搜索参数
|
||||
* @return 分页列表
|
||||
*/
|
||||
<#if cfg. clientInterfaceBasePackage??>
|
||||
@Override
|
||||
public PageResult<${entity}> search(SearchRequest searchRequest) {
|
||||
<#else>
|
||||
@PostMapping("/search")
|
||||
public PageResult<${entity}> search(@RequestBody SearchRequest searchRequest) {
|
||||
</#if>
|
||||
return ${table.serviceName?uncap_first}.search(searchRequest);
|
||||
}
|
||||
}
|
||||
</#if>
|
@ -0,0 +1,172 @@
|
||||
<#if cfg.clientInterfaceBasePackage??>
|
||||
package ${cfg.clientInterfaceBasePackage}.entity<#if cfg.clientInterfaceSubFolder??>.${cfg.clientInterfaceSubFolder}</#if>;
|
||||
<#else>
|
||||
package ${package.Entity};
|
||||
</#if>
|
||||
|
||||
<#list table.importPackages as pkg>
|
||||
import ${pkg};
|
||||
</#list>
|
||||
<#if swagger2>
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
</#if>
|
||||
<#if entityLombokModel>
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
</#if>
|
||||
|
||||
<#if cfg.enumPackages??>
|
||||
<#list cfg.enumPackages as package>
|
||||
import ${package}.*;
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* ${table.comment!}
|
||||
* </p>
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date}
|
||||
*/
|
||||
<#if entityLombokModel>
|
||||
@Data
|
||||
<#if superEntityClass??>
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
<#else>
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
</#if>
|
||||
<#if chainModel>
|
||||
@Accessors(chain = true)
|
||||
</#if>
|
||||
</#if>
|
||||
<#if table.convert>
|
||||
@TableName("${table.name}")
|
||||
</#if>
|
||||
<#if swagger2>
|
||||
@ApiModel(value="${entity}对象", description="${table.comment!}")
|
||||
</#if>
|
||||
<#if superEntityClass??>
|
||||
public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}></#if> {
|
||||
<#elseif activeRecord>
|
||||
public class ${entity} extends Model<${entity}> {
|
||||
<#else>
|
||||
public class ${entity} implements Serializable {
|
||||
</#if>
|
||||
<#-- ---------- BEGIN 字段循环遍历 ---------->
|
||||
<#list table.fields as field>
|
||||
<#if field.keyFlag>
|
||||
<#assign keyPropertyName="${field.propertyName}"/>
|
||||
</#if>
|
||||
|
||||
<#if swagger2>
|
||||
@ApiModelProperty(value = "${(field.comment)!}")
|
||||
<#else>
|
||||
/**
|
||||
* ${(field.comment)!} - ${field.type}
|
||||
*/
|
||||
</#if>
|
||||
<#if field.keyFlag>
|
||||
<#-- 主键 -->
|
||||
<#if field.keyIdentityFlag>
|
||||
@TableId(value = "${field.name}", type = IdType.AUTO)
|
||||
<#elseif idType??>
|
||||
@TableId(value = "${field.name}", type = IdType.${idType})
|
||||
<#elseif field.convert>
|
||||
@TableId("${field.name}")
|
||||
</#if>
|
||||
<#-- 普通字段 -->
|
||||
<#elseif field.fill??>
|
||||
<#-- ----- 存在字段填充设置 ----->
|
||||
<#if field.convert>
|
||||
@TableField(value = "${field.name}", fill = FieldFill.${field.fill})
|
||||
<#else>
|
||||
@TableField(fill = FieldFill.${field.fill})
|
||||
</#if>
|
||||
<#elseif field.convert>
|
||||
@TableField("${field.name}")
|
||||
</#if>
|
||||
<#-- 乐观锁注解 -->
|
||||
<#if (versionFieldName!"") == field.name>
|
||||
@Version
|
||||
</#if>
|
||||
<#-- 逻辑删除注解 -->
|
||||
<#if (logicDeleteFieldName!"") == field.name>
|
||||
@TableLogic
|
||||
</#if>
|
||||
<#-- property类型 -->
|
||||
<#if cfg.typeMap?? && cfg.typeMap[field.name]??>
|
||||
<#assign javaType=cfg.typeMap[field.name]>
|
||||
<#else>
|
||||
<#assign javaType=field.propertyType>
|
||||
</#if>
|
||||
private ${javaType} ${field.propertyName};
|
||||
</#list>
|
||||
<#------------ END 字段循环遍历 ---------->
|
||||
|
||||
<#if !entityLombokModel>
|
||||
<#list table.fields as field>
|
||||
<#if field.propertyType == "boolean">
|
||||
<#assign getprefix="is"/>
|
||||
<#else>
|
||||
<#assign getprefix="get"/>
|
||||
</#if>
|
||||
|
||||
<#-- property类型 -->
|
||||
<#if cfg.typeMap?? && cfg.typeMap[field.name]??>
|
||||
<#assign javaType=cfg.typeMap[field.name]>
|
||||
<#else>
|
||||
<#assign javaType=field.propertyType>
|
||||
</#if>
|
||||
|
||||
public ${javaType} ${getprefix}${field.capitalName}() {
|
||||
return ${field.propertyName};
|
||||
}
|
||||
|
||||
<#if entityBuilderModel>
|
||||
public ${entity} set${field.capitalName}(${javaType} ${field.propertyName}) {
|
||||
<#else>
|
||||
public void set${field.capitalName}(${javaType} ${field.propertyName}) {
|
||||
</#if>
|
||||
this.${field.propertyName} = ${field.propertyName};
|
||||
<#if entityBuilderModel>
|
||||
return this;
|
||||
</#if>
|
||||
}
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
<#if entityColumnConstant>
|
||||
<#list table.fields as field>
|
||||
public static final String ${field.name?upper_case} = "${field.name}";
|
||||
|
||||
</#list>
|
||||
</#if>
|
||||
<#if activeRecord>
|
||||
@Override
|
||||
protected Serializable pkVal() {
|
||||
<#if keyPropertyName??>
|
||||
return this.${keyPropertyName};
|
||||
<#else>
|
||||
return null;
|
||||
</#if>
|
||||
}
|
||||
|
||||
</#if>
|
||||
<#if !entityLombokModel>
|
||||
@Override
|
||||
public String toString() {
|
||||
return "${entity}{" +
|
||||
<#list table.fields as field>
|
||||
<#if field_index==0>
|
||||
"${field.propertyName}=" + ${field.propertyName} +
|
||||
<#else>
|
||||
", ${field.propertyName}=" + ${field.propertyName} +
|
||||
</#if>
|
||||
</#list>
|
||||
"}";
|
||||
}
|
||||
</#if>
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package ${cfg.clientInterfaceBasePackage}.api<#if cfg.clientInterfaceSubFolder??>.${cfg.clientInterfaceSubFolder}</#if>;
|
||||
|
||||
import ${cfg.clientInterfaceBasePackage}.entity.<#if cfg.clientInterfaceSubFolder??>${cfg.clientInterfaceSubFolder}.</#if>${entity};
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import SearchRequest;
|
||||
import PageResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
<#if superControllerClassPackage??>
|
||||
import ${superControllerClassPackage};
|
||||
</#if>
|
||||
|
||||
/**
|
||||
* ${table. comment!} API
|
||||
* Generated on ${date}
|
||||
*/
|
||||
@FeignClient(value = "${cfg.moduleName}", contextId = "${cfg.moduleName}.${entity}Api")
|
||||
@RequestMapping("<#if package.ModuleName??>/${package.ModuleName}</#if><#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
|
||||
public interface ${entity}Api {
|
||||
|
||||
/**
|
||||
* 按主键查询
|
||||
* @param id 主键id
|
||||
* @return 实体
|
||||
*/
|
||||
@GetMapping("/find/{id}")
|
||||
${entity} find(@PathVariable(value = "id") String id);
|
||||
|
||||
/*
|
||||
* 关键字搜素
|
||||
* @param searchRequest 搜索参数
|
||||
* @return 分页列表
|
||||
*/
|
||||
@PostMapping("/search")
|
||||
PageResult<${entity}> search(@RequestBody SearchRequest searchRequest);
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue