Commit cb7328cb by huangjy

初始化项目

parent 9ddc24ea
Showing with 4765 additions and 0 deletions
node {
// 配置项
def remote1 = [:]
remote1.name = "jifen"
remote1.host = "192.168.0.77"
remote1.user = "root"
remote1.password = "HopdelDad@!Ldko%dlogA"
remote1.allowAnyHosts = true
//配置项
def remoteList = [remote1]
//配置项
def project = "/home/group1_lzy/sz-tianma-server"
//配置项
def profileList = ["test"]
//配置项
def moduleList = ["top", "server-start"]
def remoteNameList = []
for (def a in remoteList) {
remoteNameList += a.name;
}
def module = "."
properties([
parameters([
gitParameter(branch: "",
branchFilter: "origin/(.*)",
defaultValue: "dev",
description: "",
name: "branch",
quickFilterEnabled: false,
selectedValue: "NONE",
sortMode: "NONE",
tagFilter: "*",
type: "PT_BRANCH"),
choice(name: "profile", choices: profileList),
choice(name: "module", choices: moduleList),
choice(name: "server", choices: remoteNameList)
])
])
def branch = "${params.branch}"
def profile = "${params.profile}"
def moduleTmp = "${params.module}"
def server = "${params.server}"
echo branch
echo profile
echo moduleTmp
echo server
stage("Preparation") {
checkout([$class : "GitSCM",
branches : [[name: "${params.branch}"]], // 传入分支
doGenerateSubmoduleConfigurations: false,
extensions : [],
gitTool : "Default",
submoduleCfg : [],
userRemoteConfigs : scm.userRemoteConfigs // !重要,复用我们在 Jenkins 上 SCM 配置,如凭据、仓库地址
])
}
stage("Build") {
if ("top" != moduleTmp) {
module = moduleTmp
}
dir(module) {
sh "/dependencies/apache-maven-3.8.6/bin/mvn -s /dependencies/apache-maven-3.8.6/conf/settings.xml clean install -Dmaven.test.skip=true"
}
}
stage("Deploy") {
def remote = null;
for (def a in remoteList) {
if (a.name == server) {
remote = a
}
}
if ("top" == moduleTmp) {
for (def a in moduleList) {
if ("top" != a) {
dir(a) {
sshPut remote: remote, from: "target/", filterRegex: /\.jar$/, into: project
sshCommand remote: remote, command: "mv " + project + "/target/*.jar " + project + "/tmp/" + "; rm -rf " + project + "/target"
}
sshPut remote: remote, from: "deploy.sh", into: project
sshCommand remote: remote, command: "chmod +x " + project + "/deploy.sh;" + project + "/deploy.sh " + project + " " + a + " " + profile
}
}
} else {
dir(module) {
sshPut remote: remote, from: "target/", filterRegex: /\.jar$/, into: project
sshCommand remote: remote, command: "mv " + project + "/target/*.jar " + project + "/tmp/" + "; rm -rf " + project + "/target"
}
sshPut remote: remote, from: "deploy.sh", into: project
sshCommand remote: remote, command: "chmod +x " + project + "/deploy.sh;" + project + "/deploy.sh " + project + " " + module + " " + profile
}
}
}
DATE=$(date +%Y%m%d)
DIR=$1
JARFILE=$2.jar
echo $JARFILE
if [ ! -d $DIR/backup ];then
mkdir -p $DIR/backup
fi
cd $DIR
ps -ef | grep $JARFILE | grep -v grep | awk '{print $2}' | xargs kill -9
if [ -f $JARFILE ];then
mv $JARFILE backup/$JARFILE$DATE
fi
mv $DIR/tmp/$JARFILE ./
nohup /usr/local/java/jdk1.8.0_202/bin/java -jar -Xms1024M -Xmx1024M -jar $JARFILE --spring.profiles.active=$3 > server.log 2>&1 &
#找出需要删除的备份
delfile=`ls -l -crt $DIR/backup/$JARFILE* | awk '{print $9 }' | head -1`
#判断现在的备份数量是否大于$number
count=`ls -l -crt $DIR/backup/$JARFILE* | awk '{print $9 }' | wc -l`
if [ $count -gt 3 ]
then
#删除最早生成的备份,只保留number数量的备份
rm $delfile
fi
This diff is collapsed. Click to expand it.
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>iot-platforn-server</artifactId>
<groupId>com.makeit</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>server-common</artifactId>
<version>1.0.0</version>
<name>${artifactId}</name>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.alibaba</groupId>-->
<!-- <artifactId>druid-spring-boot-starter</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
</dependency>
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java-bundle</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
</dependency>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
</dependencies>
<profiles>
<profile>
<id>workflow</id>
<!-- <dependencies>-->
<!-- <dependency>-->
<!-- <groupId>cn.dev33</groupId>-->
<!-- <artifactId>sa-token-spring-boot-starter</artifactId>-->
<!-- </dependency>-->
<!-- </dependencies>-->
</profile>
</profiles>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>
\ No newline at end of file
package com.makeit.common.config;
import com.makeit.common.utils.data.ELUtil;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class BizCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ELUtil.nonProdProfile(context.getEnvironment());
}
}
package com.makeit.common.config;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@EnableCaching
@Configuration
public class CacheConfig {
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.computePrefixWith(cacheName -> cacheName + ":")
.entryTtl(Duration.ofMinutes(5));
return config;
}
@Bean
public CacheManager cacheManager(@Autowired RedisConnectionFactory connectionFactory) {
return new CustomizerRedisCacheManager(redisCacheWriter(connectionFactory), redisCacheConfiguration());
}
@Bean
public RedisCacheWriter redisCacheWriter(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
}
private static class CustomizerRedisCacheManager extends RedisCacheManager {
public CustomizerRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
super(cacheWriter, defaultCacheConfiguration);
}
@Override
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
//名称中存在#标记进行到期时间配置
if (!name.isEmpty() && name.contains("#")) {
String[] spel = name.split("#");
if (StringUtils.isNotBlank(spel[1])) {
//配置缓存到期时间
int cycle = Integer.parseInt(spel[1]);
return super.createRedisCache(spel[0], cacheConfig.entryTtl(Duration.ofMinutes(cycle)));
}
}
return super.createRedisCache(name, cacheConfig);
}
}
}
package com.makeit.common.config;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
/**
* swagger 配置类,访问地址:http://localhost:8080/swagger-ui.html
* Knife4j 访问地址:http://localhost:8080/doc.html
*
* @author yaohy
*/
@EnableOpenApi
@Configuration
@ConfigurationProperties(prefix = "swagger")
@EnableKnife4j
@Conditional(BizCondition.class)
public class SwaggerCommonConfig {
@Bean
public Docket allApi() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("01-default");
ApiSelectorBuilder builder = docket.select();
//api过滤
builder = builder.apis(RequestHandlerSelectors.basePackage("com.makeit.controller")
//.or(RequestHandlerSelectors.basePackage("com.makeit.common.controller")
);
return builder.build();
}
@Bean
public Docket commonApi() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("02-common");
ApiSelectorBuilder builder = docket.select();
//api过滤
builder = builder.apis(
RequestHandlerSelectors.basePackage("com.makeit.common.controller")
.and(RequestHandlerSelectors.basePackage("com.makeit.common.controller.test").negate())
);
return builder.build();
}
@Bean
public Docket commonTestApi() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("03-commonTest");
ApiSelectorBuilder builder = docket.select();
//api过滤
builder = builder.apis(
RequestHandlerSelectors.basePackage("com.makeit.common.controller.test")
);
return builder.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("IOT平台端")
.description("服务端接口文档")
.version("1.0.0")
.build();
}
}
//TODO ywc 放到各自的模块里
//TODO ywc 从配置文件读上面配置
//TODO ywc 根据包前缀 设置模块名
\ No newline at end of file
package com.makeit.common.config;
import com.makeit.common.global.inteceptor.RequestIdInterceptor;
import com.makeit.common.global.inteceptor.SysAuthenticationInterceptor;
import com.makeit.common.global.inteceptor.SysAuthorizationInterceptor;
import com.makeit.common.utils.old.StringUtils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Arrays;
@Data
@ConfigurationProperties(prefix = "interceptor")
@Configuration
public class WebInterceptorConfig implements WebMvcConfigurer {
@Autowired
private RequestIdInterceptor requestIdInterceptor;
@Autowired
private SysAuthenticationInterceptor sysAuthenticationInterceptor;
@Autowired
private SysAuthorizationInterceptor sysAuthorizationInterceptor;
private String authenticationPlatPath;
private String authenticationPlatPathIgnore;
private String authorizationPlatPath;
private String authorizationPlatPathIgnore;
private String authenticationTntPath;
private String authenticationTntPathIgnore;
private String authorizationTntPath;
private String authorizationTntPathIgnore;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestIdInterceptor).addPathPatterns("/**");
InterceptorRegistration authenticationTnt = registry.addInterceptor(sysAuthenticationInterceptor);
if (StringUtils.isNotBlank(authenticationTntPath)) {
authenticationTnt.addPathPatterns(Arrays.asList(authenticationTntPath.split(",")));
}
if (StringUtils.isNotBlank(authenticationTntPathIgnore)) {
authenticationTnt.excludePathPatterns(Arrays.asList(authenticationTntPathIgnore.split(",")));
}
InterceptorRegistration authorizationTnt = registry.addInterceptor(sysAuthorizationInterceptor);
if (StringUtils.isNotBlank(authorizationTntPath)) {
authorizationTnt.addPathPatterns(Arrays.asList(authorizationTntPath.split(",")));
}
if (StringUtils.isNotBlank(authorizationTntPathIgnore)) {
authorizationTnt.excludePathPatterns(Arrays.asList(authorizationTntPathIgnore.split(",")));
}
}
}
package com.makeit.common.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Value("${file.log}")
private String fileLog;
@Value("${file.file}")
private String fileFile;
// /**
// * error page错误地址配置
// * @return
// */
// @Bean
// public WebServerFactoryCustomizer<ConfigurableWebServerFactory> containerCustomizer(){
// return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>(){
// @Override
// public void customize(ConfigurableWebServerFactory container) {
// container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"));
// container.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"));
// container.addErrorPages(new ErrorPage(Throwable.class,"/error/500"));
// }
// };
// }
//
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/doc.html").addResourceLocations(
"classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("/**").
addResourceLocations("file:" + fileLog).
addResourceLocations("file:" + fileFile).
addResourceLocations("classpath:/static/");
}
}
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.makeit.common.config.global.multipart;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.util.stream.Collectors;
public class CustomMultipartHttpServletRequest extends StandardMultipartHttpServletRequest {
private boolean flag = false;
private MultiValueMap<String, MultipartFile> newMap;
public CustomMultipartHttpServletRequest(HttpServletRequest request) throws MultipartException {
super(request);
}
public CustomMultipartHttpServletRequest(HttpServletRequest request, boolean lazyParsing) throws MultipartException {
super(request, lazyParsing);
}
@Override
protected MultiValueMap<String, MultipartFile> getMultipartFiles() {
if (!flag) {
MultiValueMap<String, MultipartFile> newMap = new LinkedMultiValueMap<>();
super.getMultipartFiles().forEach((k, v) -> {
newMap.put(k, v.stream().map(ExcelMultipartFile::new).collect(Collectors.toList()));
});
this.newMap = newMap;
this.flag = true;
}
return newMap;
}
}
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.makeit.common.config.global.multipart;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.MultipartProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import javax.servlet.http.HttpServletRequest;
@Component
public class CustomServletMultipartResolver extends StandardServletMultipartResolver {
@Autowired
private MultipartProperties multipartProperties;
@Override
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
return new CustomMultipartHttpServletRequest(request, this.multipartProperties.isResolveLazily());
}
}
package com.makeit.common.config.global.multipart;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
public class ExcelMultipartFile implements MultipartFile {
private MultipartFile origin;
private byte[] bytes;
public ExcelMultipartFile(MultipartFile origin) {
this.origin = origin;
try {
bytes = origin.getBytes();
}catch (IOException ex){
throw new RuntimeException(ex);
}
}
@Override
public String getName() {
return origin.getName();
}
@Override
public String getOriginalFilename() {
return origin.getOriginalFilename();
}
@Override
public String getContentType() {
return origin.getContentType();
}
@Override
public boolean isEmpty () {
return bytes.length == 0;
}
@Override
public long getSize () {
return bytes.length;
}
@Override
public byte[] getBytes(){
return bytes;
}
@Override
public InputStream getInputStream(){
return new ByteArrayInputStream(bytes);
}
@Override
public void transferTo (File destination) throws IOException {
try (OutputStream outputStream = new FileOutputStream(destination)) {
outputStream.write(bytes);
}
}
}
package com.makeit.common.config.global.swagger;
import com.makeit.common.utils.old.StringUtils;
import io.swagger.models.Swagger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponents;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.swagger2.web.SwaggerTransformationContext;
import springfox.documentation.swagger2.web.WebMvcSwaggerTransformationFilter;
import javax.servlet.http.HttpServletRequest;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
public class BasePathAndHostnameTransformationFilter implements WebMvcSwaggerTransformationFilter {
private static final Logger logger = LoggerFactory.getLogger(BasePathAndHostnameTransformationFilter.class);
@Value(("${swagger.prefix:}"))
private String swaggerPrefix;
private final Environment env;
public BasePathAndHostnameTransformationFilter(Environment env) {
this.env = env;
}
@Override
public Swagger transform(SwaggerTransformationContext<HttpServletRequest> context) {
logger.info("SwaggerBasePathAndHostnameTransformationFilter start");
Swagger swagger = context.getSpecification();
context.request().ifPresent(servletRequest -> {
if(StringUtils.isNotBlank(swaggerPrefix)){
swagger.basePath(swaggerPrefix + swagger.getBasePath());
}else{
swagger.basePath(swagger.getBasePath());
}
});
return swagger;
}
private String hostName(
UriComponents uriComponents,
String hostNameOverride) {
if ("DEFAULT".equals(hostNameOverride)) {
String host = uriComponents.getHost();
int port = uriComponents.getPort();
if (port > -1) {
return String.format("%s:%d", host, port);
}
return host;
}
return hostNameOverride;
}
@Override
public boolean supports(DocumentationType delimiter) {
return delimiter == DocumentationType.SWAGGER_2;
}
}
package com.makeit.common.config.global.swagger;
import io.swagger.annotations.ApiModel;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.schema.DefaultTypeNameProvider;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.swagger.common.SwaggerPluginSupport;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
import static springfox.documentation.builders.BuilderDefaults.nullToEmpty;
//为了让 apimodel注解不重复
@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER - 1)
public class CustomApiModelTypeNameProvider extends DefaultTypeNameProvider {
@Override
public String nameFor(Class<?> type) {
ApiModel annotation = findAnnotation(
type,
ApiModel.class);
String defaultTypeName = super.nameFor(type);
if (annotation != null) {
String value = nullToEmpty(annotation.value());
if (value.length() == 0) {
return defaultTypeName;
}
return defaultTypeName + value;
}
return defaultTypeName;
}
@Override
public boolean supports(DocumentationType delimiter) {
return SwaggerPluginSupport.pluginDoesApply(delimiter);
}
}
/*
*
* Copyright 2015-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package com.makeit.common.config.global.swagger;
import com.makeit.common.config.swagger.SwaggerModuleConfig;
import com.makeit.common.utils.old.StringUtils;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.builders.BuilderDefaults;
import springfox.documentation.service.Tag;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.ApiListingBuilderPlugin;
import springfox.documentation.spi.service.contexts.ApiListingContext;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toCollection;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
import static springfox.documentation.service.Tags.emptyTags;
import static springfox.documentation.swagger.common.SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER;
import static springfox.documentation.swagger.common.SwaggerPluginSupport.pluginDoesApply;
@Component
@Order(value = SWAGGER_PLUGIN_ORDER + 3000)
public class ModuleSwaggerApiListingReader implements ApiListingBuilderPlugin {
@Autowired(required = false)
private List<SwaggerModuleConfig> configList;
@Override
public void apply(ApiListingContext apiListingContext) {
Optional<? extends Class<?>> controller = apiListingContext.getResourceGroup().getControllerClass();
if (controller.isPresent()) {
Optional<Api> apiAnnotation = ofNullable(findAnnotation(controller.get(), Api.class));
Set<Tag> oasTags = tagsFromOasAnnotations(controller.get());
String description =
apiAnnotation.map(Api::description)
.map(BuilderDefaults::emptyToNull)
.orElse(null);
Set<String> tagSet = new TreeSet<>();
if (oasTags.isEmpty()) {
tagSet.addAll(apiAnnotation.map(tags(controller.get(), configList))
.orElse(new TreeSet<>()));
if (tagSet.isEmpty()) {
tagSet.add(apiListingContext.getResourceGroup().getGroupName());
}
}
apiListingContext.apiListingBuilder()
.description(description)
.tagNames(tagSet)
.tags(oasTags);
try {
Field field = apiListingContext.apiListingBuilder().getClass().getDeclaredField("tagNames");
field.setAccessible(true);
Set<String> set = (Set<String>) (field.get(apiListingContext.apiListingBuilder()));
Set<String> newSet = new HashSet<>(set);
set.removeIf(s -> newSet.stream().anyMatch(e -> e.contains("-" + s)));
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
private Set<Tag> tagsFromOasAnnotations(Class<?> controller) {
HashSet<Tag> controllerTags = new HashSet<>();
io.swagger.v3.oas.annotations.tags.Tags tags =
findAnnotation(controller, io.swagger.v3.oas.annotations.tags.Tags.class);
if (tags != null) {
Arrays.stream(tags.value())
.forEach(t -> controllerTags.add(new Tag(t.name(), t.description())));
}
io.swagger.v3.oas.annotations.tags.Tag tag
= findAnnotation(controller, io.swagger.v3.oas.annotations.tags.Tag.class);
if (tag != null) {
controllerTags.add(new Tag(tag.name(), tag.description()));
}
return controllerTags;
}
private Function<Api, Set<String>> tags(Class<?> clazz, List<SwaggerModuleConfig> configList) {
String moduleName = configList.stream().filter(e -> e.getPackageList().stream().anyMatch(ee -> clazz.getName().contains(ee))).map(SwaggerModuleConfig::getModuleName).findFirst().orElse("");
return input -> {
String[] tags = input.tags();
if (tags.length > 0 && StringUtils.isNotBlank(moduleName)) {
if (!tags[0].startsWith(moduleName + "-")) {
tags[0] = moduleName + "-" + tags[0];
}
}
return Stream.of(tags).filter(emptyTags()).collect(toCollection(TreeSet::new));
};
}
@Override
public boolean supports(DocumentationType delimiter) {
return pluginDoesApply(delimiter);
}
}
package com.makeit.common.config.global.swagger;
import com.makeit.common.config.swagger.SwaggerModuleConfig;
import com.makeit.common.utils.data.ReflectionUtil;
import com.makeit.common.utils.old.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.RequestHandler;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.OperationBuilderPlugin;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.spi.service.contexts.RequestMappingContext;
import springfox.documentation.swagger.common.SwaggerPluginSupport;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toSet;
import static springfox.documentation.service.Tags.emptyTags;
@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 3000)
public class ModuleSwaggerOperationTagsReader implements OperationBuilderPlugin {
@Autowired(required = false)
private List<SwaggerModuleConfig> configList;
@Override
public void apply(OperationContext context) {
context.operationBuilder().tags(
Stream.concat(operationTags(context).stream(),
controllerTags(context).stream()).collect(toSet()));
}
private Set<String> controllerTags(OperationContext context) {
try {
Field requestContextField = ReflectionUtil.getFieldList(context.getClass()).stream().filter(e -> "requestContext".equals(e.getName())).findFirst().get();
RequestMappingContext requestContext = (RequestMappingContext) requestContextField.get(context);
Field requestHandlerField = ReflectionUtil.getFieldList(requestContext.getClass()).stream().filter(e -> "handler".equals(e.getName())).findFirst().get();
RequestHandler handler = (RequestHandler) requestHandlerField.get(requestContext);
Class<?> controller = handler.declaringClass();
Optional<Api> controllerAnnotation = context.findControllerAnnotation(Api.class);
return controllerAnnotation
.map(tagsFromController(controller, configList))
.orElse(new HashSet<>());
} catch (Exception ex) {
Optional<Api> controllerAnnotation = context.findControllerAnnotation(Api.class);
return controllerAnnotation
.map(tagsFromController())
.orElse(new HashSet<>());
}
}
private Set<String> operationTags(OperationContext context) {
Optional<ApiOperation> annotation = context.findAnnotation(ApiOperation.class);
return new HashSet<>(annotation.map(tagsFromOperation())
.orElse(new HashSet<>()));
}
private Function<ApiOperation, Set<String>> tagsFromOperation() {
return input -> Stream.of(input.tags())
.filter(emptyTags())
.collect(toCollection(TreeSet::new));
}
private Function<Api, Set<String>> tagsFromController(Class<?> clazz, List<SwaggerModuleConfig> configList) {
String moduleName = configList.stream().filter(e -> e.getPackageList().stream().anyMatch(ee -> clazz.getName().contains(ee))).map(SwaggerModuleConfig::getModuleName).findFirst().orElse("");
return input -> {
String[] tags = input.tags();
if (tags.length > 0 && StringUtils.isNotBlank(moduleName)) {
if (!tags[0].startsWith(moduleName + "-")) {
tags[0] = moduleName + "-" + tags[0];
}
}
return Stream.of(tags).filter(emptyTags()).collect(toCollection(TreeSet::new));
};
}
private Function<Api, Set<String>> tagsFromController() {
return input -> {
String[] tags = input.tags();
return Stream.of(tags).filter(emptyTags()).collect(toCollection(TreeSet::new));
};
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
}
package com.makeit.common.config.global.swagger;
import io.swagger.models.Operation;
import io.swagger.models.Swagger;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.swagger2.web.SwaggerTransformationContext;
import springfox.documentation.swagger2.web.WebMvcSwaggerTransformationFilter;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Component
public class OperationTagTransformationFilter implements WebMvcSwaggerTransformationFilter {
@Override
public boolean supports(DocumentationType delimiter) {
return DocumentationType.SWAGGER_2.equals(delimiter);
}
@Override
public Swagger transform(SwaggerTransformationContext<HttpServletRequest> context) {
Swagger swagger = context.getSpecification();
// swagger.getPaths().values().forEach(e -> {
// fillOperation(e.getGet());
// fillOperation(e.getPost());
// fillOperation(e.getPut());
// fillOperation(e.getDelete());
// fillOperation(e.getPatch());
// fillOperation(e.getOptions());
// });
swagger.getPaths().forEach((k, e) -> {
fillOperation(k, e.getGet());
fillOperation(k, e.getPost());
fillOperation(k, e.getPut());
fillOperation(k, e.getDelete());
fillOperation(k, e.getPatch());
fillOperation(k, e.getOptions());
});
return swagger;
}
private void fillOperation(String key, Operation operation) {
if (operation == null) {
return;
}
List<String> tags = operation.getTags();
if (tags != null && !tags.isEmpty()) {
String tag = tags.get(0);
String tagNew = tag;
if (tag.contains("-")) {
tagNew = tagNew.substring(tag.lastIndexOf("-") + 1);
}
if (tag.startsWith("feign-")) {
tagNew = "feign-" + tagNew;
}
if (tag.startsWith("前台-")) {
tagNew = "前台-" + tagNew;
}
operation.setSummary(tagNew + "-" + operation.getSummary());
}
}
}
/*
*
* Copyright 2017-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package com.makeit.common.config.global.swagger;
import io.swagger.models.Swagger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;
import springfox.documentation.service.Documentation;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.spring.web.json.Json;
import springfox.documentation.spring.web.json.JsonSerializer;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
import springfox.documentation.swagger2.web.SwaggerTransformationContext;
import springfox.documentation.swagger2.web.WebMvcSwaggerTransformationFilter;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.stream.Collectors;
import static java.util.Optional.ofNullable;
import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;
@ApiIgnore
@RestController
//@RequestMapping(SWAGGER2_SPECIFICATION_PATH)
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SwaggerController {
public static final String SWAGGER2_SPECIFICATION_PATH
= "${springfox.documentation.swagger.v2.path:/v2/prefix/api-docs}";
public static final String SWAGGER2_SPECIFICATION_PATH_2
= "${springfox.documentation.swagger.v2.path:/v222/api-docs}";
private static final Logger LOGGER = LoggerFactory.getLogger(SwaggerController.class);
private static final String HAL_MEDIA_TYPE = "application/hal+json";
private final DocumentationCache documentationCache;
private final ServiceModelToSwagger2Mapper mapper;
private final JsonSerializer jsonSerializer;
private final PluginRegistry<WebMvcSwaggerTransformationFilter, DocumentationType> transformations;
@Autowired
public SwaggerController(
DocumentationCache documentationCache,
ServiceModelToSwagger2Mapper mapper,
JsonSerializer jsonSerializer,
@Qualifier("webMvcSwaggerTransformationFilterRegistry")
PluginRegistry<WebMvcSwaggerTransformationFilter, DocumentationType> transformations) {
this.documentationCache = documentationCache;
this.mapper = mapper;
this.jsonSerializer = jsonSerializer;
this.transformations = transformations;
}
@RequestMapping(
value = SWAGGER2_SPECIFICATION_PATH,
method = RequestMethod.GET,
produces = {APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE})
public ResponseEntity<Json> getDocumentation(
@RequestParam(value = "group", required = false) String swaggerGroup,
HttpServletRequest servletRequest) throws Exception {
String groupName = ofNullable(swaggerGroup).orElse(Docket.DEFAULT_GROUP_NAME);
Documentation documentation = documentationCache.documentationByGroup(groupName);
if (documentation == null) {
LOGGER.warn("Unable to find specification for group {}", groupName);
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Swagger swagger = mapper.mapDocumentation(documentation);
Constructor<?> constructor = SwaggerTransformationContext.class.getDeclaredConstructors()[0];
constructor.setAccessible(true);
SwaggerTransformationContext context = SwaggerTransformationContext.class.cast(constructor.newInstance(swagger, servletRequest));
List<WebMvcSwaggerTransformationFilter> filters = transformations.getPluginsFor(DocumentationType.SWAGGER_2);
filters = filters.stream().filter(e -> BasePathAndHostnameTransformationFilter.class != e.getClass()).collect(Collectors.toList());
for (WebMvcSwaggerTransformationFilter each : filters) {
LOGGER.info("WebMvcSwaggerTransformationFilter:{}", each.getClass());
context = context.next(each.transform(context));
}
return new ResponseEntity<>(jsonSerializer.toJson(swagger), HttpStatus.OK);
}
// @RequestMapping(
// value = SWAGGER2_SPECIFICATION_PATH_2,
// method = RequestMethod.GET,
// produces = {APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE})
// public ResponseEntity<Json> getDocumentation2(
// @RequestParam(value = "group", required = false) String swaggerGroup,
// HttpServletRequest servletRequest) throws Exception {
//
// String groupName = ofNullable(swaggerGroup).orElse(Docket.DEFAULT_GROUP_NAME);
// Documentation documentation = documentationCache.documentationByGroup(groupName);
// if (documentation == null) {
// LOGGER.warn("Unable to find specification for group {}", groupName);
// return new ResponseEntity<>(HttpStatus.NOT_FOUND);
// }
// Swagger swagger = mapper.mapDocumentation(documentation);
//
// Constructor<?> constructor = SwaggerTransformationContext.class.getDeclaredConstructors()[0];
// constructor.setAccessible(true);
// SwaggerTransformationContext context = SwaggerTransformationContext.class.cast(constructor.newInstance(swagger, servletRequest));
//
// List<WebMvcSwaggerTransformationFilter> filters = transformations.getPluginsFor(DocumentationType.SWAGGER_2);
//
// for (WebMvcSwaggerTransformationFilter each : filters) {
// LOGGER.info("WebMvcSwaggerTransformationFilter:{}", each.getClass());
// context = context.next(each.transform(context));
// }
// return new ResponseEntity<>(jsonSerializer.toJson(swagger), HttpStatus.OK);
// }
}
package com.makeit.common.config.global.swagger.model;
import com.makeit.common.global.validator.CanBlankPattern;
import com.makeit.common.utils.old.StringUtils;
import org.springframework.stereotype.Component;
import springfox.bean.validators.plugins.Validators;
import springfox.documentation.schema.ModelProperty;
import springfox.documentation.schema.PropertySpecification;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import java.util.Optional;
//@Order(Validators.BEAN_VALIDATOR_PLUGIN_ORDER + 10)
@Component
public class CanBlankPatternPlugin implements ModelPropertyBuilderPlugin {
@Override
public void apply(ModelPropertyContext context) {
Optional<CanBlankPattern> pattern = Validators.extractAnnotation(context, CanBlankPattern.class);
String patternValueFromAnnotation = this.createPatternValueFromAnnotation(pattern);
if (StringUtils.isNotBlank(patternValueFromAnnotation)) {
ModelProperty modelProperty = context.getBuilder().build();
PropertySpecification propertySpecification = context.getSpecificationBuilder().build();
context.getBuilder().description(modelProperty.getDescription() + " 正则:" + patternValueFromAnnotation);
context.getSpecificationBuilder().description(propertySpecification.getDescription() + " 正则:" + patternValueFromAnnotation);
}
}
private String createPatternValueFromAnnotation(Optional<CanBlankPattern> pattern) {
String patternValue = null;
if (pattern.isPresent()) {
patternValue = ((CanBlankPattern) pattern.get()).regexp();
}
return patternValue;
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
}
package com.makeit.common.config.global.swagger.model;
import com.makeit.common.global.aspect.tenant.FactoryIdUtil;
import com.makeit.common.global.validator.Config;
import com.makeit.common.utils.data.excel.easyexcel.ConfigFormat;
import com.makeit.enums.id.IdConst;
import org.springframework.stereotype.Component;
import springfox.bean.validators.plugins.Validators;
import springfox.documentation.schema.ModelProperty;
import springfox.documentation.schema.PropertySpecification;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import java.util.Optional;
//@Order(Validators.BEAN_VALIDATOR_PLUGIN_ORDER + 10)
@Component //现在用不了 因为运行时机 可能在feign初始后面 //后面试了可以
//可以用因为 用redis读数据
public class ConfigPlugin implements ModelPropertyBuilderPlugin {
private <T> void fill(String categoryCode, ModelPropertyContext context) {
FactoryIdUtil.execute(IdConst.DEFAULT_FACTORY_ID, () -> {
// String s = "配置 分类code:" + categoryCode + " " +
// TntConfigUtil.viewListByCategoryCode(categoryCode).stream().map(e -> e.getCode() + "-" + e.getValue() + "-" + e.getName()).collect(Collectors.joining(","));
String s = "配置 分类code:" + categoryCode;
ModelProperty modelProperty = context.getBuilder().build();
PropertySpecification propertySpecification = context.getSpecificationBuilder().build();
context.getBuilder().description(modelProperty.getDescription() + " " + s);
context.getSpecificationBuilder().description(propertySpecification.getDescription() + " " + s);
});
}
@Override
public void apply(ModelPropertyContext context) {
Optional<Config> config = this.extractDictEnumAnnotation(context);
if (config.isPresent()) {
fill(config.get().categoryCode(), context);
return;
}
Optional<ConfigFormat> dictEnumFormat = this.extractDictEnumFormatAnnotation(context);
if (dictEnumFormat.isPresent()) {
fill(dictEnumFormat.get().categoryCode(), context);
return;
}
}
private Optional<Config> extractDictEnumAnnotation(ModelPropertyContext context) {
return (Optional) Validators.annotationFromBean(context, Config.class).map(Optional::of).orElse(Validators.annotationFromField(context, Config.class));
}
private Optional<ConfigFormat> extractDictEnumFormatAnnotation(ModelPropertyContext context) {
return (Optional) Validators.annotationFromBean(context, ConfigFormat.class).map(Optional::of).orElse(Validators.annotationFromField(context, ConfigFormat.class));
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
}
package com.makeit.common.config.global.swagger.model;
import com.makeit.common.global.validator.DictEnum;
import com.makeit.common.utils.data.excel.easyexcel.DictEnumFormat;
import com.makeit.enums.BaseEnum;
import org.springframework.stereotype.Component;
import springfox.bean.validators.plugins.Validators;
import springfox.documentation.schema.ModelProperty;
import springfox.documentation.schema.PropertySpecification;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Collectors;
//@Order(Validators.BEAN_VALIDATOR_PLUGIN_ORDER + 10)
@Component //现在用不了 因为运行时机 可能在feign初始后面
//可以用因为 用redis读数据
public class DictEnumPlugin implements ModelPropertyBuilderPlugin {
private <T> void fill(Class<? extends BaseEnum> clazz, ModelPropertyContext context) {
String s = "字典大致分类code:" + clazz.getEnumConstants()[0].getCategoryCode() + " " +
Arrays.stream(clazz.getEnumConstants()).map(e -> e.getCode() + "-" + e.getValue() + "-" + e.getDefaultName()).collect(Collectors.joining(","));
ModelProperty modelProperty = context.getBuilder().build();
PropertySpecification propertySpecification = context.getSpecificationBuilder().build();
context.getBuilder().description(modelProperty.getDescription() + " " + s);
context.getSpecificationBuilder().description(propertySpecification.getDescription() + " " + s);
}
@Override
public void apply(ModelPropertyContext context) {
Optional<DictEnum> dictEnum = this.extractDictEnumAnnotation(context);
if (dictEnum.isPresent()) {
fill(dictEnum.get().em(), context);
return;
}
Optional<DictEnumFormat> dictEnumFormat = this.extractDictEnumFormatAnnotation(context);
if (dictEnumFormat.isPresent()) {
fill(dictEnumFormat.get().em(), context);
return;
}
}
private Optional<DictEnum> extractDictEnumAnnotation(ModelPropertyContext context) {
return (Optional) Validators.annotationFromBean(context, DictEnum.class).map(Optional::of).orElse(Validators.annotationFromField(context, DictEnum.class));
}
private Optional<DictEnumFormat> extractDictEnumFormatAnnotation(ModelPropertyContext context) {
return (Optional) Validators.annotationFromBean(context, DictEnumFormat.class).map(Optional::of).orElse(Validators.annotationFromField(context, DictEnumFormat.class));
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
}
package com.makeit.common.config.global.swagger.model;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import org.springframework.stereotype.Component;
import springfox.bean.validators.plugins.Validators;
import springfox.documentation.schema.ModelProperty;
import springfox.documentation.schema.PropertySpecification;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import java.util.Optional;
//@Order(Validators.BEAN_VALIDATOR_PLUGIN_ORDER + 100)
@Component
public class ExcelPropertyPlugin implements ModelPropertyBuilderPlugin {
@Override
public void apply(ModelPropertyContext context) {
Optional<ExcelProperty> optional = this.extractExcelAnnotation(context);
if (optional.isPresent()) {
ExcelProperty excelProperty = optional.get();
ModelProperty modelProperty = context.getBuilder().build();
PropertySpecification propertySpecification = context.getSpecificationBuilder().build();
context.getBuilder().description(modelProperty.getDescription() + " excel字段名:" + excelProperty.value()[excelProperty.value().length - 1]);
context.getSpecificationBuilder().description(propertySpecification.getDescription() + " excel字段名:" + excelProperty.value()[excelProperty.value().length - 1]);
}
}
private Optional<ExcelProperty> extractExcelAnnotation(ModelPropertyContext context) {
Optional<ExcelProperty> excelProperty = (Optional) Validators.annotationFromBean(context, ExcelProperty.class).map(Optional::of).orElse(Validators.annotationFromField(context, ExcelProperty.class));
Optional<ExcelIgnore> excelIgnore = (Optional) Validators.annotationFromBean(context, ExcelIgnore.class).map(Optional::of).orElse(Validators.annotationFromField(context, ExcelIgnore.class));
if (!excelIgnore.isPresent()) {
return excelProperty;
}
return Optional.empty();
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
}
package com.makeit.common.config.global.swagger.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.makeit.common.utils.old.StringUtils;
import org.springframework.stereotype.Component;
import springfox.bean.validators.plugins.Validators;
import springfox.documentation.schema.ModelProperty;
import springfox.documentation.schema.PropertySpecification;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import java.util.Optional;
//@Order(Validators.BEAN_VALIDATOR_PLUGIN_ORDER + 10)
@Component
public class JsonFormatPlugin implements ModelPropertyBuilderPlugin {
@Override
public void apply(ModelPropertyContext context) {
Optional<JsonFormat> jsonFormat = this.extractAnnotation(context);
if (jsonFormat.isPresent() && StringUtils.isNotBlank(jsonFormat.get().pattern())) {
ModelProperty modelProperty = context.getBuilder().build();
PropertySpecification propertySpecification = context.getSpecificationBuilder().build();
context.getBuilder().description(jsonFormat.get().pattern() + modelProperty.getDescription());
context.getSpecificationBuilder().description(propertySpecification.getDescription() + " " + jsonFormat.get().pattern());
context.getBuilder().example(modelProperty.getExample() + " " + jsonFormat.get().pattern());
context.getSpecificationBuilder().example(jsonFormat.get().pattern() + " " + propertySpecification.getExample());
}
}
private Optional<JsonFormat> extractAnnotation(ModelPropertyContext context) {
return (Optional) Validators.annotationFromBean(context, JsonFormat.class).map(Optional::of).orElse(Validators.annotationFromField(context, JsonFormat.class));
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
}
/*
*
* Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package com.makeit.common.config.global.swagger.model;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import javax.validation.constraints.NotBlank;
import java.util.Optional;
import static springfox.bean.validators.plugins.Validators.annotationFromBean;
import static springfox.bean.validators.plugins.Validators.annotationFromField;
@Component
public class NotBlankMsgPlugin implements ModelPropertyBuilderPlugin {
/**
* support all documentationTypes
*/
@Override
public boolean supports(DocumentationType delimiter) {
// we simply support all documentationTypes!
return true;
}
/**
* read NotBlank annotation
*/
@Override
@SuppressWarnings("deprecation")
public void apply(ModelPropertyContext context) {
Optional<NotBlank> notBlank = extractAnnotation(context);
if (notBlank.isPresent()) {
context.getBuilder().required(true);
context.getSpecificationBuilder().required(true);
}
}
private Optional<NotBlank> extractAnnotation(ModelPropertyContext context) {
return annotationFromBean(context, NotBlank.class)
.map(Optional::of)
.orElse(annotationFromField(context, NotBlank.class));
}
}
/*
*
* Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package com.makeit.common.config.global.swagger.model;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import javax.validation.constraints.NotEmpty;
import java.util.Optional;
import static springfox.bean.validators.plugins.Validators.annotationFromBean;
import static springfox.bean.validators.plugins.Validators.annotationFromField;
@Component
public class NotEmptyMsgPlugin implements ModelPropertyBuilderPlugin {
/**
* support all documentationTypes
*/
@Override
public boolean supports(DocumentationType delimiter) {
// we simply support all documentationTypes!
return true;
}
/**
* read NotBlank annotation
*/
@Override
@SuppressWarnings("deprecation")
public void apply(ModelPropertyContext context) {
Optional<NotEmpty> notBlank = extractAnnotation(context);
if (notBlank.isPresent()) {
context.getBuilder().required(true);
context.getSpecificationBuilder().required(true);
}
}
private Optional<NotEmpty> extractAnnotation(ModelPropertyContext context) {
return annotationFromBean(context, NotEmpty.class)
.map(Optional::of)
.orElse(annotationFromField(context, NotEmpty.class));
}
}
/*
*
* Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package com.makeit.common.config.global.swagger.model;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import javax.validation.constraints.NotNull;
import java.util.Optional;
import static springfox.bean.validators.plugins.Validators.annotationFromBean;
import static springfox.bean.validators.plugins.Validators.annotationFromField;
@Component
public class NotNullMsgPlugin implements ModelPropertyBuilderPlugin {
/**
* support all documentationTypes
*/
@Override
public boolean supports(DocumentationType delimiter) {
// we simply support all documentationTypes!
return true;
}
/**
* read NotNull annotation
*/
@Override
@SuppressWarnings("deprecation")
public void apply(ModelPropertyContext context) {
Optional<NotNull> notNull = extractAnnotation(context);
if (notNull.isPresent()) {
context.getBuilder().required(true);
context.getSpecificationBuilder().required(true);
}
}
private Optional<NotNull> extractAnnotation(ModelPropertyContext context) {
return annotationFromBean(context, NotNull.class)
.map(Optional::of)
.orElse(annotationFromField(context, NotNull.class));
}
}
package com.makeit.common.config.global.swagger.model;
import com.makeit.common.utils.old.StringUtils;
import org.springframework.stereotype.Component;
import springfox.bean.validators.plugins.Validators;
import springfox.documentation.schema.ModelProperty;
import springfox.documentation.schema.PropertySpecification;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import javax.validation.constraints.Pattern;
import java.util.Optional;
//@Order(Validators.BEAN_VALIDATOR_PLUGIN_ORDER + 10)
@Component
public class PatternMsgPlugin implements ModelPropertyBuilderPlugin {
@Override
public void apply(ModelPropertyContext context) {
Optional<Pattern> pattern = Validators.extractAnnotation(context, Pattern.class);
String patternValueFromAnnotation = this.createPatternValueFromAnnotation(pattern);
if (StringUtils.isNotBlank(patternValueFromAnnotation)) {
ModelProperty modelProperty = context.getBuilder().build();
PropertySpecification propertySpecification = context.getSpecificationBuilder().build();
context.getBuilder().description(modelProperty.getDescription() + " 正则:" + patternValueFromAnnotation);
context.getSpecificationBuilder().description(propertySpecification.getDescription() + " 正则:" + patternValueFromAnnotation);
}
}
private String createPatternValueFromAnnotation(Optional<Pattern> pattern) {
String patternValue = null;
if (pattern.isPresent()) {
patternValue = ((Pattern) pattern.get()).regexp();
}
return patternValue;
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
}
/*
*
* Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package com.makeit.common.config.global.swagger.model;
import org.springframework.stereotype.Component;
import springfox.documentation.schema.ModelProperty;
import springfox.documentation.schema.PropertySpecification;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import javax.validation.constraints.Size;
import java.util.Optional;
import static springfox.bean.validators.plugins.Validators.annotationFromBean;
import static springfox.bean.validators.plugins.Validators.annotationFromField;
@Component
public class SizeMsgPlugin implements ModelPropertyBuilderPlugin {
private static final String FORMAT = "(%s,%s)";
@Override
public boolean supports(DocumentationType delimiter) {
// we simply support all documentationTypes!
return true;
}
@Override
@SuppressWarnings("deprecation")
public void apply(ModelPropertyContext context) {
Optional<Size> optional = extractAnnotation(context);
ModelProperty modelProperty = context.getBuilder().build();
PropertySpecification propertySpecification = context.getSpecificationBuilder().build();
optional.ifPresent(size -> {
context.getBuilder().description(modelProperty.getDescription() + " 长度:" + String.format(FORMAT, size.min(), size.max()) + size.message());
context.getSpecificationBuilder().description(propertySpecification.getDescription() + " 长度:" + String.format(FORMAT, size.min(), size.max()) + size.message());
});
}
Optional<Size> extractAnnotation(ModelPropertyContext context) {
return annotationFromBean(context, Size.class).map(Optional::of).orElse(annotationFromField(context, Size.class));
}
}
/*
* Copyright (C) 2018 Zhejiang xiaominfo Technology CO.,LTD.
* All rights reserved.
* Official Web Site: http://www.xiaominfo.com.
* Developer Web Site: http://open.xiaominfo.com.
*/
package com.makeit.common.config.global.swagger.sort;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSort;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.spring.plugin.AbstractOperationBuilderPlugin;
import com.makeit.common.utils.data.ReflectionUtil;
import io.swagger.annotations.ApiOperation;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.RequestHandler;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.spi.service.contexts.RequestMappingContext;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Optional;
/***
*
* @since:swagger-bootstrap-ui 1.9.4
* @author <a href="mailto:xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
* 2019/06/06 19:59
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 50)
public class OperationPositionSortPlugin extends AbstractOperationBuilderPlugin {
/**
* 扩展接口的排序规则,添加排序扩展字段
* {@link ApiOperationSupport} field order
* {@link ApiOperationSort} field value
* {@link ApiOperation} field position
* ApiOperation - ApiOperationSort - ApioperationSupport
*
* @param context 操作上下文
*/
@Override
public void apply(OperationContext context) {
int position;
//首先查找ApiOperation注解
Optional<ApiOperation> api = context.findAnnotation(ApiOperation.class);
if (api.isPresent()) {
//判断postion是否有值
int posit = api.get().position();
if (posit != 0) {
position = posit;
} else {
position = findPosition(context);
}
} else {
position = findPosition(context);
}
context.operationBuilder().position(position);
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
private int findPosition(OperationContext context) {
int position = Integer.MAX_VALUE;
try {
Field requestContextField = ReflectionUtil.getFieldList(context.getClass()).stream().filter(e -> "requestContext".equals(e.getName())).findFirst().get();
RequestMappingContext requestContext = (RequestMappingContext) requestContextField.get(context);
Field requestHandlerField = ReflectionUtil.getFieldList(requestContext.getClass()).stream().filter(e -> "handler".equals(e.getName())).findFirst().get();
RequestHandler handler = (RequestHandler) requestHandlerField.get(requestContext);
Class<?> controller = handler.declaringClass();
List<Method> methodList = ReflectionUtil.getMethodList(controller);
for (int i = 0; i < methodList.size(); i++) {
if (handler.getHandlerMethod().getMethod().equals(methodList.get(i))) {
position = i;
return position;
}
}
} catch (Exception e) {
}
return position;
}
}
package com.makeit.common.config.global.swagger.sort.model;
import io.swagger.models.Model;
import springfox.documentation.service.ApiListing;
import java.util.List;
import java.util.Map;
//参考文章
//https://www.cnblogs.com/cnndevelop/p/13392479.html
//https://www.itxm.cn/post/45037.html
//https://blog.csdn.net/u014087707/article/details/121634380
//https://blog.csdn.net/m0_37607945/article/details/120230853
public class CustomModelMapper {
public static Map<String, Model> modelsFromApiListings(Map<String, List<ApiListing>> apiListings) {
return new CustomModelSpecificationMapper().modelsFromApiListings(apiListings);
}
}
package com.makeit.common.config.global.swagger.sort.model;
import io.swagger.models.properties.Property;
import springfox.documentation.schema.PropertySpecification;
import springfox.documentation.service.ModelNamesRegistry;
import springfox.documentation.swagger2.mappers.ModelSpecificationMapperImpl;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class CustomModelSpecificationMapper extends ModelSpecificationMapperImpl {
@Override
protected Map<String, Property> mapProperties(Map<String, PropertySpecification> properties, ModelNamesRegistry modelNamesRegistry) {
Map<String, Property> treeMap = super.mapProperties(properties, modelNamesRegistry);
List<String> keyList = properties.entrySet().stream()
.sorted(Map.Entry.comparingByValue(
Comparator.comparing(PropertySpecification::getPosition)
.thenComparing(PropertySpecification::getName)))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
for (String key : keyList) {
Property property = treeMap.get(key);
PropertySpecification propertySpecification = properties.get(key);
property.setPosition(propertySpecification.getPosition());
}
return treeMap;
}
}
package com.makeit.common.config.global.swagger.sort.model;
import io.swagger.models.Operation;
import io.swagger.models.Path;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiListing;
import springfox.documentation.service.ModelNamesRegistry;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2MapperImpl;
import java.util.*;
import static java.util.Optional.ofNullable;
import static springfox.documentation.builders.BuilderDefaults.nullToEmptyList;
@Primary
@Component
public class CustomServiceModelToSwagger2MapperImpl extends ServiceModelToSwagger2MapperImpl {
//接口排序
@Override
protected Map<String, Path> mapApiListings(Map<String, List<ApiListing>> apiListings) {
Map<String, Path> paths = new LinkedHashMap<>();
apiListings.values().stream()
.flatMap(Collection::stream)
.forEachOrdered(each -> {
each.getApis().sort((left, right) -> {
int leftPos = left.getOperations().size() >= 1 ? left.getOperations().get(0).getPosition() : 0;
int rightPos = right.getOperations().size() >= 1 ? right.getOperations().get(0).getPosition() : 0;
int position = Integer.compare(leftPos, rightPos);
if (position == 0) {
position = left.getPath().compareTo(right.getPath());
}
return position;
});
each.getApis().forEach(e -> {
paths.put(e.getPath(), mapOperations(e, ofNullable(paths.get(e.getPath())), each.getModelNamesRegistry()));
});
});
return paths;
}
private Path mapOperations(
ApiDescription api,
Optional<Path> existingPath,
ModelNamesRegistry modelNamesRegistry) {
Path path = existingPath.orElse(new Path());
for (springfox.documentation.service.Operation each : nullToEmptyList(api.getOperations())) {
Operation operation = mapOperation(each, modelNamesRegistry);
path.set(each.getMethod().toString().toLowerCase(), operation);
}
return path;
}
}
package com.makeit.common.config.global.swagger.sort.model;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.makeit.common.utils.data.ReflectionUtil;
import io.swagger.annotations.ApiModelProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import springfox.documentation.swagger.common.SwaggerPluginSupport;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Optional;
import static springfox.documentation.schema.Annotations.findPropertyAnnotation;
import static springfox.documentation.swagger.schema.ApiModelProperties.findApiModePropertyAnnotation;
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1)
@Component
public class ModelPositionSortPlugin implements ModelPropertyBuilderPlugin {
private Logger log = LoggerFactory.getLogger(getClass());
@Override
public boolean supports(DocumentationType delimiter) {
return SwaggerPluginSupport.pluginDoesApply(delimiter);
}
@Override
public void apply(ModelPropertyContext context) {
Optional<BeanPropertyDefinition> beanPropertyDefinitionOpt = context.getBeanPropertyDefinition();
Optional<ApiModelProperty> annotation = Optional.empty();
if (context.getAnnotatedElement().isPresent()) {
annotation = annotation.map(Optional::of).orElse(findApiModePropertyAnnotation(context.getAnnotatedElement().get()));
}
if (context.getBeanPropertyDefinition().isPresent()) {
annotation = annotation.map(Optional::of).orElse(findPropertyAnnotation(context.getBeanPropertyDefinition().get(), ApiModelProperty.class));
}
if (beanPropertyDefinitionOpt.isPresent()) {
BeanPropertyDefinition beanPropertyDefinition = beanPropertyDefinitionOpt.get();
if (annotation.isPresent() && annotation.get().position() != 0) {
return;
}
AnnotatedField field = beanPropertyDefinition.getField();
if (field == null) {
log.error("{} 没有驼峰:\n" +
"或者 有dto vo里 有getXxx/isXxx方法,但是没有xxx字段", beanPropertyDefinition.getName());
}
/*
@ApiModelProperty(value = "客户id")
private String customerId;
@ApiModelProperty(value = "订单id")
private String orderId;
@ApiModelProperty(value = "订单编号")
private String orderNo;
*/
/*
@ApiModelProperty(value = "创建时间", required = false)
@TableField(value = "created_at", fill = FieldFill.INSERT)
@DynamicDateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
private Long createdAt;
@ApiModelProperty(value = "更新时间", required = false)
@TableField(value = "updated_at", fill = FieldFill.INSERT_UPDATE)
@DynamicDateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
private Long updatedAt;
@TableLogic(value = "NULL", delval = "UNIX_TIMESTAMP(NOW())")
@ApiModelProperty(value = "删除时间", required = false)
@DynamicDateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
private Long deletedAt;
@ApiModelProperty(value = "创建人名称")
@TableField(fill = FieldFill.INSERT)
private String createdByName;
@ApiModelProperty(value = "更新人名称")
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updatedByName;
*/
//这一坨抽出来用map配置?
//或者 用反射拿到父类
if ("id".equals(field.getName())) {
context.getSpecificationBuilder().position(-1000);
return;
}
if ("tenantId".equals(field.getName())) {
context.getSpecificationBuilder().position(-990);
return;
}
if ("companyId".equals(field.getName())) {
context.getSpecificationBuilder().position(-980);
return;
}
if ("orderId".equals(field.getName())) {
context.getSpecificationBuilder().position(-970);
return;
}
if ("orderNo".equals(field.getName())) {
context.getSpecificationBuilder().position(-960);
return;
}
if ("createdAt".equals(field.getName())) {
context.getSpecificationBuilder().position(-950);
return;
}
if ("updatedAt".equals(field.getName())) {
context.getSpecificationBuilder().position(-940);
return;
}
if ("createdByName".equals(field.getName())) {
context.getSpecificationBuilder().position(-930);
return;
}
if ("updatedByName".equals(field.getName())) {
context.getSpecificationBuilder().position(-920);
return;
}
if ("createdById".equals(field.getName())) {
context.getSpecificationBuilder().position(-910);
return;
}
if ("updatedById".equals(field.getName())) {
context.getSpecificationBuilder().position(-900);
return;
}
Class<?> clazz = field.getDeclaringClass();
// Field[] declaredFields = clazz.getDeclaredFields();
List<Field> declaredFields = ReflectionUtil.getFieldList(clazz);
Field declaredField;
try {
declaredField = clazz.getDeclaredField(field.getName());
} catch (NoSuchFieldException | SecurityException e) {
log.error("", e);
return;
}
//int indexOf = ArrayUtils.indexOf(declaredFields, declaredField);
int indexOf = declaredFields.indexOf(declaredField);
if (indexOf != -1) {
context.getSpecificationBuilder().position(indexOf);
}
}
}
}
package com.makeit.common.config.global.swagger.sort.model;
import io.swagger.models.Model;
import io.swagger.models.Swagger;
import io.swagger.models.properties.Property;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.swagger2.web.SwaggerTransformationContext;
import springfox.documentation.swagger2.web.WebMvcSwaggerTransformationFilter;
import javax.servlet.http.HttpServletRequest;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class ModelPositionSortTransformationFilter implements WebMvcSwaggerTransformationFilter {
@Override
public boolean supports(DocumentationType delimiter) {
return DocumentationType.SWAGGER_2.equals(delimiter);
}
@Override
public Swagger transform(SwaggerTransformationContext<HttpServletRequest> context) {
Swagger swagger = context.getSpecification();
Map<String, Model> definitions = swagger.getDefinitions();
for (String key : definitions.keySet()) {
Model model = definitions.get(key);
Map<String, Property> properties = model.getProperties();
if (properties == null) {
continue;
}
Map<String, Property> sortedProperties = new LinkedHashMap<>(properties.size());
List<String> fieldNameList = properties.entrySet().stream()
.sorted(Map.Entry.comparingByValue(
Comparator.comparing(Property::getPosition)
.thenComparing(Property::getName)))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
for (String fieldName : fieldNameList) {
sortedProperties.put(fieldName, properties.get(fieldName));
}
model.getProperties().clear();
model.setProperties(sortedProperties);
}
return swagger;
}
}
package com.makeit.common.config.global.swagger.sort.model;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import springfox.documentation.service.ApiListing;
import springfox.documentation.swagger2.mappers.CompatibilityModelMapper;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
@Component
public class ModelSpecificationMapperPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof CompatibilityModelMapper) {
return createCompatibilityModelMapperProxy(bean);
}
return bean;
}
//cglib 动态代理 写法
private Object createCompatibilityModelMapperProxy(Object bean) {
//这里也能换成aop
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setProxyTargetClass(true);
proxyFactory.setTargetClass(bean.getClass());
proxyFactory.setTarget(bean);
proxyFactory.addAdvice((MethodInterceptor) invocation -> {
Object[] arguments = invocation.getArguments();
Method method = invocation.getMethod();
if ("modelsFromApiListings".equals(method.getName())) {
return CustomModelMapper.modelsFromApiListings((Map<String, List<ApiListing>>) arguments[0]);
}
return invocation.proceed();
});
return proxyFactory.getProxy();
}
}
package com.makeit.common.config.global.thread;
//public class MkThreadLocal<T> extends ThreadLocal<T> {
//}
import com.alibaba.ttl.TransmittableThreadLocal;
import com.makeit.common.utils.function.CallableThrowable;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
public class BizThreadLocal<T> extends TransmittableThreadLocal<T> {
public void execute(T t, Runnable runnable) {
set(t);
try {
runnable.run();
} finally {
remove();
}
}
public <M> M execute(T t, Supplier<M> supplier) {
set(t);
try {
return supplier.get();
} finally {
remove();
}
}
public <M> M execute(T t, Callable<M> callable) throws Exception {
set(t);
try {
return callable.call();
} finally {
remove();
}
}
public <M> M execute(T t, CallableThrowable<M> callable) throws Throwable {
set(t);
try {
return callable.call();
} finally {
remove();
}
}
}
package com.makeit.common.config.global.thread;
import com.makeit.common.config.global.thread.wrapper.RunnableWrapperUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//设定一个长度16的定时任务线程池
//taskRegistrar.setScheduler(Executors.newScheduledThreadPool(16));
taskRegistrar.setScheduler(new MDCScheduledThreadPoolExecutor(16));
}
public static class MDCScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
public MDCScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize);
}
@Override
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
return super.schedule(RunnableWrapperUtil.notRequestWrapper(command), delay, unit);
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
return super.schedule(RunnableWrapperUtil.wrapper(callable), delay, unit);
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
return super.scheduleAtFixedRate(RunnableWrapperUtil.notRequestWrapper(command), initialDelay, period, unit);
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
return super.scheduleWithFixedDelay(RunnableWrapperUtil.notRequestWrapper(command), initialDelay, delay, unit);
}
}
}
package com.makeit.common.config.global.thread;
import com.makeit.common.config.global.thread.wrapper.RunnableWrapperUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class ThreadPoolConfig implements AsyncConfigurer {
private static final Logger logger = LoggerFactory.getLogger(ThreadPoolConfig.class);
//或者重写java自带线程池的afterExecute的方法
//里面判断是future 要额外处理
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable arg0, Method arg1, Object... arg2) {
logger.error("exception class:{}, method:{}" + arg1.getDeclaringClass().getName(), arg1.getName());
logger.error("==========================" + arg0.getMessage() + "=======================", arg0);
}
};
}
@Override
public Executor getAsyncExecutor() {
return taskExecutor();
}
//@Bean("async")
@Bean
@Primary
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//executor.setTaskDecorator(RequestIdRunnableWrapper::new);
executor.setTaskDecorator(RunnableWrapperUtil::wrapper);
// 设置核心线程数
executor.setCorePoolSize(32);
// 设置最大线程数
executor.setMaxPoolSize(64);
// 设置队列容量,一般需要设置值大于等于notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE
executor.setQueueCapacity(100);
// 设置线程池维护线程所允许的空闲时间,默认为60s
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("makeit-thread-");
// 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务 CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
@Bean("log")
public ThreadPoolTaskExecutor log() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(RunnableWrapperUtil::wrapper);
// 设置核心线程数
executor.setCorePoolSize(1);
// 设置最大线程数
executor.setMaxPoolSize(1);
// 设置队列容量,一般需要设置值大于等于notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE
executor.setQueueCapacity(100);
// 设置线程池维护线程所允许的空闲时间,默认为60s
executor.setKeepAliveSeconds(0);
// 设置默认线程名称
executor.setThreadNamePrefix("makeit-log-");
// 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务 CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
//项目启动时 异步执行的线程池
//单线程是为了日志稳定
@Bean("start")
public ThreadPoolTaskExecutor start() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(RunnableWrapperUtil::wrapper);
// 设置核心线程数
executor.setCorePoolSize(1);
// 设置最大线程数
executor.setMaxPoolSize(1);
// 设置队列容量,一般需要设置值大于等于notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE
executor.setQueueCapacity(100);
// 设置线程池维护线程所允许的空闲时间,默认为60s
executor.setKeepAliveSeconds(0);
// 设置默认线程名称
executor.setThreadNamePrefix("makeit-start-");
// 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务 CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
@Bean("join")
public ThreadPoolTaskExecutor join() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//executor.setTaskDecorator(RequestIdRunnableWrapper::new);
executor.setTaskDecorator(RunnableWrapperUtil::wrapper);
// 设置核心线程数
executor.setCorePoolSize(32);
// 设置最大线程数
executor.setMaxPoolSize(64);
// 设置队列容量,一般需要设置值大于等于notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE
executor.setQueueCapacity(100);
// 设置线程池维护线程所允许的空闲时间,默认为60s
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("makeit-request-join-");
// 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务 CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
}
package com.makeit.common.config.global.thread.wrapper;
import java.util.concurrent.Callable;
@FunctionalInterface
public interface BizCallable<V> extends Callable<V> {
}
package com.makeit.common.config.global.thread.wrapper;
@FunctionalInterface
public interface BizRunnable extends Runnable{
}
package com.makeit.common.config.global.thread.wrapper;
import com.alibaba.ttl.TtlCallable;
import com.alibaba.ttl.TtlRunnable;
import com.makeit.common.config.global.thread.wrapper.ignore.FactoryIgnoreCallableWrapper;
import com.makeit.common.config.global.thread.wrapper.ignore.FactoryIgnoreRunnableWrapper;
import com.makeit.common.config.global.thread.wrapper.log.LogCallableWrapper;
import com.makeit.common.config.global.thread.wrapper.log.LogRunnableWrapper;
import com.makeit.common.config.global.thread.wrapper.log.RequestIdCallableWrapper;
import com.makeit.common.config.global.thread.wrapper.log.RequestIdRunnableWrapper;
import com.makeit.common.config.global.thread.wrapper.request.RequestAsyncRunnableWrapper2;
import com.makeit.common.config.global.thread.wrapper.tenant.FactoryIdRunnableWrapper;
import java.util.concurrent.Callable;
public class RunnableWrapperUtil {
//要不要改成List 装 class 反射做
public static Runnable wrapper(Runnable runnable) {
//执行顺序 外层的包装器先
return TtlRunnable.get(new UserRunnerWrapper(
/*new RequestAsyncRunnableWrapper(*/
new RequestAsyncRunnableWrapper2(
new FactoryIdRunnableWrapper(
new RequestIdRunnableWrapper(
new LogRunnableWrapper(runnable)
)
)
/*)*/
)
)
);
}
public static Runnable notRequestWrapper(Runnable runnable) {
return TtlRunnable.get(
new FactoryIgnoreRunnableWrapper(
new RequestIdRunnableWrapper(
new LogRunnableWrapper(runnable)
)
)
);
}
public static <V> Callable<V> wrapper(Callable<V> callable) {
//执行顺序 外层的包装器先
return TtlCallable.get(
new FactoryIgnoreCallableWrapper<>(
new RequestIdCallableWrapper<>(
new LogCallableWrapper<>(callable)
)
)
);
}
//TODO ywc
//spring 定时任务 或者xxl job 定时任务
//处理异常 要不要用aop 上面是 用包装器 装饰器实现的
}
package com.makeit.common.config.global.thread.wrapper;
import com.makeit.common.utils.user.tenant.SysUserUtil;
import com.makeit.common.utils.user.tenant.SysUserVO;
//TODO ywc 要不要用阿里的 TransmittableThreadLocal(TTL)
public class UserRunnerWrapper implements BizRunnable {
private Runnable task;
private SysUserVO userVO;
public UserRunnerWrapper(Runnable task) {
super();
this.task = task;
userVO = SysUserUtil.getUserVOCanNull();
}
@Override
public void run() {
SysUserUtil.execute(userVO, task);
}
}
package com.makeit.common.config.global.thread.wrapper.ignore;
import com.makeit.common.config.global.thread.wrapper.BizCallable;
import com.makeit.common.global.aspect.tenant.FactoryIdIgnoreUtil;
import java.util.concurrent.Callable;
public class FactoryIgnoreCallableWrapper<V> implements BizCallable<V> {
private Callable<V> task;
public FactoryIgnoreCallableWrapper(Callable<V> task) {
super();
this.task = task;
}
@Override
public V call() throws Exception {
return FactoryIdIgnoreUtil.executeCallable(task);
}
}
\ No newline at end of file
package com.makeit.common.config.global.thread.wrapper.ignore;
import com.makeit.common.config.global.thread.wrapper.BizRunnable;
import com.makeit.common.global.aspect.tenant.FactoryIdIgnoreUtil;
public class FactoryIgnoreRunnableWrapper implements BizRunnable {
private Runnable task;
public FactoryIgnoreRunnableWrapper(Runnable task) {
super();
this.task = task;
}
@Override
public void run() {
FactoryIdIgnoreUtil.execute(task);
}
}
\ No newline at end of file
package com.makeit.common.config.global.thread.wrapper.log;
import com.makeit.common.config.global.thread.wrapper.BizCallable;
import com.makeit.common.utils.CostTimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Callable;
public class LogCallableWrapper<V> implements BizCallable<V> {
private Callable<V> task;
private static final Logger logger = LoggerFactory.getLogger(LogRunnableWrapper.class);
public LogCallableWrapper(Callable<V> task) {
super();
this.task = task;
}
@Override
public V call() throws Exception {
// long start = System.currentTimeMillis();
// logger.info("async start");
// try {
// return task.call();
// } catch (Exception e) {
// logger.error(e.getMessage(), e);//这里可以不打印 重新丢出
// throw e;
// } finally {
// logger.info("async end");
// logger.info("耗时:{} ms", (System.currentTimeMillis() - start));
// }
// try {
// return CostTimeUtil.execute(()-> task.call(), (e, c)->{
// logger.error(e.getMessage(), e);//这里可以不打印 重新丢出
// },c->{
// logger.info("async end");
// logger.info("耗时:{} ms", c);
// });
// }catch (Throwable ex){
// throw new Exception(ex);
// }
return CostTimeUtil.executeBaseException(() -> task.call(), null, (e, c) -> {
logger.error(e.getMessage(), e);//这里可以不打印 重新丢出
}, c -> {
logger.info("async end");
logger.info("耗时:{} ms", c);
});
}
}
\ No newline at end of file
package com.makeit.common.config.global.thread.wrapper.log;
import com.makeit.common.utils.CostTimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogRunnableWrapper implements Runnable {
private Runnable task;
private static final Logger logger = LoggerFactory.getLogger(LogRunnableWrapper.class);
public LogRunnableWrapper(Runnable task) {
super();
this.task = task;
}
@Override
public void run() {
// long start = System.currentTimeMillis();
// logger.info("async start");
// try {
// task.run();
// } catch (RuntimeException e) {
// logger.error(e.getMessage(), e);//这里可以不打印 重新丢出
// throw e;
// } finally {
// logger.info("async end");
// logger.info("耗时:{} ms", (System.currentTimeMillis() - start));
// }
// }
CostTimeUtil.execute(task, (e, c) -> {
logger.error(e.getMessage(), e);//这里可以不打印 重新丢出
}, c -> {
logger.info("async end");
logger.info("耗时:{} ms", c);
});
}
}
\ No newline at end of file
package com.makeit.common.config.global.thread.wrapper.log;
import com.makeit.common.config.global.thread.wrapper.BizCallable;
import com.makeit.common.utils.request.RequestIdUtil;
import java.util.concurrent.Callable;
public class RequestIdCallableWrapper<V> implements BizCallable<V> {
private Callable<V> task;
private String requestId;
public RequestIdCallableWrapper(Callable<V> task) {
super();
this.task = task;
requestId = RequestIdUtil.set();
}
@Override
public V call() throws Exception {
return RequestIdUtil.execute(requestId, task);
}
}
\ No newline at end of file
package com.makeit.common.config.global.thread.wrapper.log;
import com.makeit.common.config.global.thread.wrapper.BizRunnable;
import com.makeit.common.utils.request.RequestIdUtil;
public class RequestIdRunnableWrapper implements BizRunnable {
private Runnable task;
private String requestId;
public RequestIdRunnableWrapper(Runnable task) {
super();
this.task = task;
requestId = RequestIdUtil.set();
}
@Override
public void run() {
RequestIdUtil.execute(requestId, task);
}
}
\ No newline at end of file
package com.makeit.common.config.global.thread.wrapper.request;
import com.makeit.common.config.global.thread.wrapper.BizRunnable;
import com.makeit.common.utils.request.RequestAsyncUtil;
import com.makeit.common.utils.request.RequestUtil;
import org.springframework.context.i18n.LocaleContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.util.Locale;
public class RequestAsyncRunnableWrapper implements BizRunnable {
private Runnable task;
private HttpServletRequest request;
private Locale locale;
public RequestAsyncRunnableWrapper(Runnable task) {
super();
this.task = task;
this.request = RequestUtil.getRequest();
this.locale = LocaleContextHolder.getLocale();
}
@Override
public void run() {
LocaleContextHolder.setLocale(locale);
try {
RequestAsyncUtil.execute(request, task);
}finally {
LocaleContextHolder.resetLocaleContext();
}
}
}
package com.makeit.common.config.global.thread.wrapper.request;
import com.makeit.common.config.global.thread.wrapper.BizRunnable;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import java.util.Locale;
public class RequestAsyncRunnableWrapper2 implements BizRunnable {
private Runnable task;
private RequestAttributes requestAttributes;
private Locale locale;
public RequestAsyncRunnableWrapper2(Runnable task) {
super();
this.task = task;
this.requestAttributes = RequestContextHolder.getRequestAttributes();
this.locale = LocaleContextHolder.getLocale();
}
@Override
public void run() {
RequestContextHolder.setRequestAttributes(requestAttributes);
LocaleContextHolder.setLocale(this.locale);
try {
task.run();
}finally {
RequestContextHolder.setRequestAttributes(null);
RequestContextHolder.resetRequestAttributes();
LocaleContextHolder.setLocale(null);
LocaleContextHolder.resetLocaleContext();
}
}
}
package com.makeit.common.config.global.thread.wrapper.tenant;
import com.makeit.common.config.global.thread.wrapper.BizCallable;
import com.makeit.common.global.aspect.tenant.FactoryIdUtil;
import com.makeit.common.utils.old.StringUtils;
import java.util.concurrent.Callable;
public class FactoryIdCallableWrapper<V> implements BizCallable<V> {
private Callable<V> task;
private String factoryId;
public FactoryIdCallableWrapper(Callable<V> task) {
super();
this.task = task;
factoryId = FactoryIdUtil.getFromThreadLocal();
}
@Override
public V call() throws Exception {
if (StringUtils.isNotBlank(factoryId)) {
FactoryIdUtil.setThreadLocal(factoryId);
try {
return task.call();
} finally {
FactoryIdUtil.removeThreadLocal();
}
} else {
return task.call();
}
}
}
\ No newline at end of file
package com.makeit.common.config.global.thread.wrapper.tenant;
import com.makeit.common.config.global.thread.wrapper.BizRunnable;
import com.makeit.common.global.aspect.tenant.FactoryIdUtil;
import com.makeit.common.utils.old.StringUtils;
public class FactoryIdRunnableWrapper implements BizRunnable {
private Runnable task;
private String factoryId;
public FactoryIdRunnableWrapper(Runnable task) {
super();
this.task = task;
this.factoryId = FactoryIdUtil.getFromThreadLocal();
}
@Override
public void run() {
if (StringUtils.isNotBlank(factoryId)) {
FactoryIdUtil.setThreadLocal(factoryId);
try {
task.run();
} finally {
FactoryIdUtil.removeThreadLocal();
}
}else{
task.run();
}
}
}
\ No newline at end of file
package com.makeit.common.config.mybatis;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.makeit.common.config.mybatis.objecthandler.MetaObjectHandlerInternal;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class BizMetaObjectHandler implements MetaObjectHandler {
@Autowired
private List<MetaObjectHandlerInternal> handlerInternalList;
@Override
public void insertFill(MetaObject metaObject) {
// this.setFieldValByName("createdAt", LocalDateTime.now(), metaObject);
// this.setFieldValByName("updatedAt", LocalDateTime.now(), metaObject);
for (MetaObjectHandlerInternal metaObjectHandlerInternal : handlerInternalList) {
if (metaObjectHandlerInternal.support(metaObject, this)) {
metaObjectHandlerInternal.insertFill(metaObject, this);
}
}
}
@Override
public void updateFill(MetaObject metaObject) {
for (MetaObjectHandlerInternal metaObjectHandlerInternal : handlerInternalList) {
if (metaObjectHandlerInternal.support(metaObject, this)) {
metaObjectHandlerInternal.updateFill(metaObject, this);
}
}
}
}
package com.makeit.common.config.mybatis;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.makeit.common.config.mybatis.interceptor.EmptyListInterceptor;
import com.makeit.common.config.mybatis.tenant.FactoryIdHandler;
import com.makeit.common.config.mybatis.tenant.FactoryIdInterceptor;
import com.makeit.common.config.mybatis.tenant.FactoryTableProperties;
import com.makeit.common.exception.BusinessException;
import com.makeit.common.global.aspect.tenant.FactoryIdIgnoreUtil;
import com.makeit.common.global.aspect.tenant.FactoryIdUtil;
import com.makeit.common.utils.data.convert.StreamUtil;
import com.makeit.enums.CodeMessageEnum;
import com.makeit.enums.Const;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashSet;
import java.util.Set;
/**
* MybatisPlus分页拦截器
*/
@Configuration
public class MybatisPlusConfig {
@Autowired
private FactoryTableProperties factoryTableProperties;
private static final Logger logger = LoggerFactory.getLogger(MybatisPlusConfig.class);
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new EmptyListInterceptor());
interceptor.addInnerInterceptor(tenantLineInnerInterceptor());
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
@Bean
public FactoryIdHandler tenantLineHandler() {
return new FactoryIdHandler() {
@Override
public String getTenantIdNoWrapper() {
String s = FactoryIdUtil.getFactoryId();
if (StringUtils.isBlank(s)) {
throw new BusinessException(CodeMessageEnum.SYSTEM_ERROR_FACTORY_ID_NOT_BLANK);
}
return s;
}
@Override
public Expression getTenantId() {
return new StringValue(getTenantIdNoWrapper());
}
@Override
public String getTenantIdColumn() {
return Const.FACTORY_ID_DB;
}
@Override
public boolean ignoreTable(String tableName) {
//TODO ywc 要不要做成 有工厂字段就开始多租户
//这样就不用配置文件配置
// List<TableFieldInfo> fieldInfoList = TableInfoHelper.getTableInfo(tableName).getFieldList();
// logger.info("{} has factoryId:{}", tableName, StreamUtil.anyMatch(fieldInfoList, e -> Const.FACTORY_ID_DB.equals(e.getColumn())));
if (Boolean.TRUE.equals(FactoryIdIgnoreUtil.get())) {
return true;
}
Set<String> set = new HashSet<>(factoryTableProperties.getIgnore());
boolean b = StreamUtil.anyMatch(factoryTableProperties.getPrefix(), tableName::startsWith);
if (b && !set.contains(tableName)) {
return false;
}
return true;
}
};
}
@Bean
public TenantLineInnerInterceptor tenantLineInnerInterceptor() {
return new FactoryIdInterceptor(tenantLineHandler());
}
}
package com.makeit.common.config.mybatis.interceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.makeit.common.utils.data.validate.CollectionUtils;
import com.makeit.common.utils.old.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class EmptyListInterceptor implements InnerInterceptor {
private static final Pattern PATTERN = Pattern.compile("[\"|'](.*?)[\"|']");
private static final Pattern PATTERN_IN_ONE = Pattern.compile("(?<=\\s" + "in" + "\\s{0,10}\\().*?(?=\\))");
private static final Pattern PATTERN_IN_TWO = Pattern.compile("(?<=\\s" + "IN" + "\\s{0,10}\\().*?(?=\\))");
private static final Logger logger = LoggerFactory.getLogger(EmptyListInterceptor.class);
@Override
public boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
return !hasEmptyList(boundSql.getSql());
}
/**
* 判断是否存在空list
*/
private static boolean hasEmptyList(String sql) {
sql = removeInterference(sql);
if (hasEmptyListInternal(sql, PATTERN_IN_ONE)) {
logger.info("sql:{}", sql);
return true;
}
if (hasEmptyListInternal(sql, PATTERN_IN_TWO)) {
logger.info("sql:{}", sql);
return true;
}
return false;
//return sql.contains("IN ()") || sql.contains("in ()");
}
// /**
// * 判断是否存在空list
// */
// private static boolean hasEmptyList(String sql) {
// sql = removeInterference(sql);
// List<String> keywordList = Lists.newArrayList("in", "IN");
// boolean hasEmptyList = Boolean.FALSE;
// for (String keyword : keywordList) {
// List<String> matcherList = Lists.newArrayList();
// // 获取关键词,关键词前必须为空白字符,但以关键词开头的单词也会被匹配
// // 匹配以" in (" 开头的,")"结尾的最短字符串
// Pattern pattern = Pattern.compile("(?<=\\s" + "IN" + "\\s{0,10}\\().*?(?=\\))");
// Matcher matcher = pattern.matcher(sql);
// while (matcher.find()) {
// matcherList.add(matcher.group());
// }
// if (CollectionUtils.isNotEmpty(matcherList)) {
// hasEmptyList = checkEmptyList(matcherList);
// if (hasEmptyList) {
// break;
// }
// }
// }
// return hasEmptyList;
// }
private static boolean hasEmptyListInternal(String sql, Pattern pattern) {
List<String> matcherList = new ArrayList<>(10);
// 获取关键词,关键词前必须为空白字符,但以关键词开头的单词也会被匹配
// 匹配以" in (" 开头的,")"结尾的最短字符串
Matcher matcher = pattern.matcher(sql);
while (matcher.find()) {
matcherList.add(matcher.group());
}
if (CollectionUtils.isNotEmpty(matcherList)) {
return checkEmptyList(matcherList);
}
return false;
}
/**
* 去除字符中的干扰项,避免字符串中的内容干扰判断。
*/
private static String removeInterference(String sql) {
Matcher matcher = PATTERN.matcher(sql);
while (matcher.find()) {
String replaceWord = matcher.group();
sql = sql.replace(replaceWord, "''");
}
return sql;
}
/**
* 校验是否有空的字符串
*/
private static boolean checkEmptyList(List<String> matcherList) {
boolean isHaveEmptyList = Boolean.FALSE;
// 获取()内的内容
for (String subSql : matcherList) {
// 如果关键词之后无任何sql语句,则sql语句结尾为关键词,此时判定为空列表
if (StringUtils.isBlank(subSql)) {
isHaveEmptyList = Boolean.TRUE;
break;
}
}
return isHaveEmptyList;
}
}
\ No newline at end of file
package com.makeit.common.config.mybatis.interceptor;
import com.makeit.common.utils.CostTimeUtil;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.Properties;
/**
* @author Robert Hafner
*/
@Component
@Intercepts({
@Signature(type = Executor.class, method = "query",
args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }),
@Signature(type = Executor.class, method = "query",
args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class }),
@Signature(type= Executor.class, method = "update", args = { MappedStatement.class, Object.class})
})
public class LogSqlExecutionTimePlugin implements Interceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(LogSqlExecutionTimePlugin.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
// long startTime = System.currentTimeMillis();
// Object retVal = invocation.proceed();
// long endTime = System.currentTimeMillis();
// MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
// //LOGGER.info("SQL Statement {} took {}ms", mappedStatement.getId(), endTime-startTime);
// LOGGER.info("SQL 执行{},耗时:{} ms", mappedStatement.getId(), endTime-startTime);
// return retVal;
return CostTimeUtil.executeSuccessException(invocation::proceed, c->{
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
LOGGER.info("SQL 执行{},耗时:{} ms", mappedStatement.getId(), c);
});
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
package com.makeit.common.config.mybatis.objecthandler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.makeit.common.entity.BaseEntity;
import com.makeit.enums.CommonEnum;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Order(10)
@Component
public class DelFlagObjectHandler implements MetaObjectHandlerInternal {
@Override
public boolean support(MetaObject metaObject, MetaObjectHandler handler) {
return true;
}
@Override
public void insertFill(MetaObject metaObject, MetaObjectHandler handler) {
handler.setFieldValByName(BaseEntity.Fields.delFlag, CommonEnum.NO.getValue(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject, MetaObjectHandler handler) {
}
}
package com.makeit.common.config.mybatis.objecthandler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.makeit.common.config.mybatis.tenant.FactoryIdHandler;
import com.makeit.common.entity.BaseBusEntity;
import com.makeit.common.utils.old.StringUtils;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Order(40)
@Component
public class FactoryIdObjectHandler implements MetaObjectHandlerInternal {
@Autowired
private FactoryIdHandler factoryIdHandler;
@Override
public boolean support(MetaObject metaObject, MetaObjectHandler handler) {
return !factoryIdHandler.ignoreTable(SqlHelper.table(metaObject.getOriginalObject().getClass()).getTableName());
}
@Override
public void insertFill(MetaObject metaObject, MetaObjectHandler handler) {
String oldValue = (String)handler.getFieldValByName(BaseBusEntity.Fields.factoryId, metaObject);
if(StringUtils.isBlank(oldValue)) {
handler.setFieldValByName(BaseBusEntity.Fields.factoryId, factoryIdHandler.getTenantIdNoWrapper(), metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject, MetaObjectHandler handler) {
//handler.setFieldValByName(BaseBusEntity.Fields.tenantId, tenantIdHandler.getTenantIdNoWrapper(), metaObject);
}
}
package com.makeit.common.config.mybatis.objecthandler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.makeit.common.entity.BaseEntity;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Order(20)
@Component
public class LocalDateTimeObjectHandler implements MetaObjectHandlerInternal{
@Override
public boolean support(MetaObject metaObject, MetaObjectHandler handler) {
return true;
//return !BaseEntity.class.isAssignableFrom(metaObject.getOriginalObject().getClass());
}
@Override
public void insertFill(MetaObject metaObject, MetaObjectHandler handler) {
handler.setFieldValByName(BaseEntity.Fields.createdAt, LocalDateTime.now(), metaObject);
handler.setFieldValByName(BaseEntity.Fields.updatedAt, LocalDateTime.now(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject, MetaObjectHandler handler) {
handler.setFieldValByName(BaseEntity.Fields.updatedAt, LocalDateTime.now(), metaObject);
}
}
package com.makeit.common.config.mybatis.objecthandler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
public interface MetaObjectHandlerInternal {
boolean support(MetaObject metaObject, MetaObjectHandler handler);
void insertFill(MetaObject metaObject, MetaObjectHandler handler);
default void updateFill(MetaObject metaObject, MetaObjectHandler handler) {
}
}
package com.makeit.common.config.mybatis.objecthandler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.makeit.common.entity.BaseEntity;
import com.makeit.common.global.aspect.misc.nofill.NoFillUtil;
import com.makeit.common.utils.user.common.CommonUserUtil;
import com.makeit.common.utils.user.common.CommonUserVO;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Order(30)
@Component
public class UserObjectHandler implements MetaObjectHandlerInternal {
@Override
public boolean support(MetaObject metaObject, MetaObjectHandler handler) {
return CommonUserUtil.getUser() != null;
}
@Override
public void insertFill(MetaObject metaObject, MetaObjectHandler handler) {
CommonUserVO commonUserVO = CommonUserUtil.getUser();
// if (metaObject.hasSetter(BaseEntity.Fields.createdByName)
// && handler.getFieldValByName(BaseEntity.Fields.createdByName, metaObject) == null) {
// handler.setFieldValByName(BaseEntity.Fields.createdByName, commonUserVO.getName(), metaObject);
// }
if (metaObject.hasSetter(BaseEntity.Fields.createdByName)) {
if (!Boolean.TRUE.equals(NoFillUtil.getCreate())) {
handler.setFieldValByName(BaseEntity.Fields.createdByName, commonUserVO.getName(), metaObject);
}
}
if (metaObject.hasSetter(BaseEntity.Fields.updatedByName)) {
handler.setFieldValByName(BaseEntity.Fields.updatedByName, commonUserVO.getName(), metaObject);
}
if (metaObject.hasSetter("createdById")) {
handler.setFieldValByName("createdById", commonUserVO.getId(), metaObject);
}
if (metaObject.hasSetter("updatedById")) {
handler.setFieldValByName("updatedById", commonUserVO.getId(), metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject, MetaObjectHandler handler) {
CommonUserVO commonUserVO = CommonUserUtil.getUser();
if (metaObject.hasSetter(BaseEntity.Fields.updatedByName)) {
if (!Boolean.TRUE.equals(NoFillUtil.getUpdate())) {
handler.setFieldValByName(BaseEntity.Fields.updatedByName, commonUserVO.getName(), metaObject);;
}
}
if (metaObject.hasSetter("updatedById")) {
handler.setFieldValByName("updatedById", commonUserVO.getId(), metaObject);
}
}
}
package com.makeit.common.config.mybatis.tenant;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
public interface FactoryIdHandler extends TenantLineHandler {
String getTenantIdNoWrapper();
}
package com.makeit.common.config.mybatis.tenant;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.sql.SQLException;
public class FactoryIdInterceptor extends TenantLineInnerInterceptor {
public FactoryIdInterceptor(TenantLineHandler tenantLineHandler) {
super(tenantLineHandler);
}
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
if (InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())) return;
PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
mpBs.sql(parserMulti(mpBs.sql(), null));//单个改多个
}
// @Override
// protected void processInsert(Insert insert, int index, String sql, Object obj) {
// if (tenantLineHandler.ignoreTable(insert.getTable().getName())) {
// // 过滤退出执行
// return;
// }
// List<Column> columns = insert.getColumns();
// if (CollectionUtils.isEmpty(columns)) {
// // 针对不给列名的insert 不处理
// return;
// }
// String tenantIdColumn = tenantLineHandler.getTenantIdColumn();
// if (tenantLineHandler.ignoreInsert(columns, tenantIdColumn)) {
// // 针对已给出租户列的insert 不处理
// return;
// }
// columns.add(new Column(tenantIdColumn));
//
// // fixed gitee pulls/141 duplicate update
// List<Expression> duplicateUpdateColumns = insert.getDuplicateUpdateExpressionList();
// if (CollectionUtils.isNotEmpty(duplicateUpdateColumns)) {
// EqualsTo equalsTo = new EqualsTo();
// equalsTo.setLeftExpression(new StringValue(tenantIdColumn));
// equalsTo.setRightExpression(tenantLineHandler.getTenantId());
// duplicateUpdateColumns.add(equalsTo);
// }
//
// Select select = insert.getSelect();
// if (select != null) {
// this.processInsertSelect(select.getSelectBody());
// } else if (insert.getItemsList() != null) {
// // fixed github pull/295
// ItemsList itemsList = insert.getItemsList();
// if (itemsList instanceof MultiExpressionList) {
// ((MultiExpressionList) itemsList).getExpressionLists().forEach(el -> el.getExpressions().add(tenantLineHandler.getTenantId()));
// } else {
// ((ExpressionList) itemsList).getExpressions().add(tenantLineHandler.getTenantId());
// }
// } else {
// throw ExceptionUtils.mpe("Failed to process multiple-table update, please exclude the tableName or statementId");
// }
// }
// @Override
// protected void processUpdate(Update update, int index, String sql, Object obj) {
// final Table table = update.getTable();
// if (tenantLineHandler.ignoreTable(table.getName())) {
// // 过滤退出执行
// return;
// }
// update.setWhere(this.andExpression(table, update.getWhere()));
// }
@Override
protected void processInsert(Insert insert, int index, String sql, Object obj) {
}
// /**
// * update 语句处理
// */
// @Override
// protected void processUpdate(Update update, int index, String sql, Object obj) {
// final Table table = update.getTable();
// if (tenantLineHandler.ignoreTable(table.getName())) {
// // 过滤退出执行
// return;
// }
// update.setWhere(this.andExpression(table, update.getWhere()));
// }
@Override
protected void processUpdate(Update update, int index, String sql, Object obj) {
}
}
package com.makeit.common.config.mybatis.tenant;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Data
@Component
@ConfigurationProperties(prefix = "tenant.table")
public class FactoryTableProperties {
private List<String> prefix;
private List<String> ignore;
}
package com.makeit.common.config.mybatis.typehandler;
import com.makeit.common.utils.old.encode.EncryptUtil;
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;
public class EncryptTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, EncryptUtil.encode(parameter));
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return EncryptUtil.decode(rs.getString(columnName));
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return EncryptUtil.decode(rs.getString(columnIndex));
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return EncryptUtil.decode(cs.getString(columnIndex));
}
}
package com.makeit.common.config.redis;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.makeit.common.global.aspect.log.RedisConnectionFactoryWrapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisTemplateConfig {
@Bean
public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory rcf, ObjectMapper objectMapper) {
RedisTemplate<String, T> redisTemplate = new RedisTemplate<String, T>();
redisTemplate.setConnectionFactory(new RedisConnectionFactoryWrapper(rcf));
redisTemplateConfig(redisTemplate, objectMapper);
return redisTemplate;
}
private <T> void redisTemplateConfig(RedisTemplate<String, T> redisTemplate, ObjectMapper objectMapper) {
redisTemplate.setKeySerializer(new StringRedisSerializer());
//redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//这里要是用string HashOperations<String,Integer,Integer> hashOperations中的hash key 就不能用string以外的
Jackson2JsonRedisSerializer<T> serializer = new Jackson2JsonRedisSerializer(Object.class);
redisTemplate.setHashKeySerializer(serializer);
serializer.setObjectMapper(objectMapper);
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
}
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory rcf, ObjectMapper objectMapper) {
StringRedisTemplate redisTemplate = new StringRedisTemplate();
redisTemplate.setConnectionFactory(new RedisConnectionFactoryWrapper(rcf));
redisTemplateConfig(redisTemplate, objectMapper);
return redisTemplate;
}
}
package com.makeit.common.config.swagger;
import lombok.Data;
import java.util.List;
@Data
public class SwaggerModuleConfig {
private List<String> packageList;
private String moduleName;
}
package com.makeit.common.config.xxljob;
import com.makeit.common.config.global.thread.wrapper.RunnableWrapperUtil;
import com.xxl.job.core.context.XxlJobHelper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class XxlJobAspect {
private static Logger logger = LoggerFactory.getLogger(XxlJobAspect.class);
@Pointcut("@annotation(com.xxl.job.core.handler.annotation.XxlJob)")
public void log() {
}
@Around("log()")
public Object doLogging(ProceedingJoinPoint pjp) throws Throwable {
return RunnableWrapperUtil.wrapper(() -> {
logger.info("xxl-job start");
XxlJobHelper.log("xxl-job start");
try {
return pjp.proceed();
} catch (Throwable e) {
logger.error("xxl-job error"+e.getMessage(),e);
XxlJobHelper.log("xxl-job error");
throw new RuntimeException(e);
}finally {
logger.info("xxl-job end");
XxlJobHelper.log("xxl-job end");
}
}).call();
}
}
package com.makeit.common.config.xxljob;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
/**
* xxl-job config
*
* @author xuxueli 2017-04-28
*/
//@Configuration
public class XxlJobConfig {
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@Value("${xxl.job.admin.addresses:}")
private String adminAddresses;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.address}")
private String address;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
@Value("${xxl.job.admin.username}")
private String username;
@Value("${xxl.job.admin.password}")
private String password;
public String adminAddress() {
return adminAddresses;
}
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
String addresses = adminAddress();
logger.info("xxl-job admin address:{}", addresses);
xxlJobSpringExecutor.setAdminAddresses(addresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
//logger.info("xxl-job executor ip:{}", IpUtil.getIp());
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
/**
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
*
* 1、引入依赖:
* <dependency>
* <groupId>org.springframework.cloud</groupId>
* <artifactId>spring-cloud-commons</artifactId>
* <version>${version}</version>
* </dependency>
*
* 2、配置文件,或者容器启动变量
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
*
* 3、获取IP
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
*/
}
\ No newline at end of file
///*
// * Copyright 2012-2019 the original author or authors.
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// * https://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//
//package com.makeit.common.controller;
//
//import com.makeit.common.utils.data.SpringContextHolder;
//import io.swagger.annotations.Api;
//import org.apache.commons.io.IOUtils;
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointProperties;
//import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
//import org.springframework.boot.logging.LogFile;
//import org.springframework.core.io.FileSystemResource;
//import org.springframework.core.io.Resource;
//import org.springframework.http.*;
//import org.springframework.web.bind.annotation.GetMapping;
//import org.springframework.web.bind.annotation.RequestMapping;
//import org.springframework.web.bind.annotation.RequestMethod;
//import org.springframework.web.bind.annotation.RestController;
//
//import javax.servlet.http.HttpServletResponse;
//import java.io.ByteArrayOutputStream;
//import java.io.IOException;
//import java.net.URLEncoder;
//import java.nio.charset.StandardCharsets;
//
///**
// * Web {@link Endpoint @Endpoint} that provides access to an application's log file.
// *
// * @author Johannes Edmeier
// * @author Phillip Webb
// * @author Andy Wilkinson
// * @since 2.0.0
// */
//@Api(tags = "系统-日志下载")
//@RestController
//@RequestMapping("/dev/sys/logfile")
//public class LogFileController {
//
// private static final Log logger = LogFactory.getLog(LogFileController.class);
//
// @Autowired
// private LogFileWebEndpointProperties properties;
//
// @Autowired(required = false)
// private LogFile logFile;
//
// @Value("${file.log}")
// private String fileLog;
//
// @GetMapping("/download")
// public void download(HttpServletResponse response) throws IOException {
// Resource resource = logFile();
//
// response.setCharacterEncoding("UTF-8");
// response.setContentType("application/octet-stream");
// // 设置文件头:最后一个参数是设置下载文件名
// response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(resource.getFilename(), "UTF-8"));
// IOUtils.copy(resource.getInputStream(), response.getOutputStream());
// }
//
// @GetMapping("/download2")
// public void download2(HttpServletResponse response) throws IOException {
// Resource resource = SpringContextHolder.getApplicationContext().getResource("file:" + fileLog).createRelative("/logs/app/info/log_info.log");
//
// response.setCharacterEncoding("UTF-8");
// response.setContentType("application/octet-stream");
// // 设置文件头:最后一个参数是设置下载文件名
// response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(resource.getFilename(), "UTF-8"));
// IOUtils.copy(resource.getInputStream(), response.getOutputStream());
// }
//
// @RequestMapping(value = "download3", method = {RequestMethod.GET, RequestMethod.POST})
// public ResponseEntity<byte[]> download3() throws IOException {
//
// Resource resource = logFile();
//
// HttpHeaders httpHeaders = new HttpHeaders();
// httpHeaders.setContentType(new MediaType("application", "octet-stream", StandardCharsets.UTF_8));
// httpHeaders.setContentDisposition(ContentDisposition.attachment().filename(resource.getFilename(), StandardCharsets.UTF_8).build());
//
//
// ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// IOUtils.copy(resource.getInputStream(), byteArrayOutputStream);
//
// return new ResponseEntity<>(byteArrayOutputStream.toByteArray(),httpHeaders, HttpStatus.OK);
// }
//
//
// public Resource logFile() {
// Resource logFileResource = getLogFileResource();
// if (logFileResource == null || !logFileResource.isReadable()) {
// return null;
// }
// return logFileResource;
// }
//
// private Resource getLogFileResource() {
// if (this.properties.getExternalFile() != null) {
// return new FileSystemResource(this.properties.getExternalFile());
// }
// if (this.logFile == null) {
// logger.debug("Missing 'logging.file.name' or 'logging.file.path' properties");
// return null;
// }
// return new FileSystemResource(this.logFile.toString());
// }
//
//}
package com.makeit.common.controller.test;
import com.makeit.common.response.ApiResponseEntity;
import com.makeit.common.response.ApiResponseUtils;
import com.makeit.common.startup.Runner;
import com.makeit.common.utils.event.BizEvent;
import com.makeit.common.utils.event.EventUtil;
import com.makeit.common.utils.user.tenant.SysUserVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api(tags = "测试-事件")
@RestController
@RequestMapping("/test/event")
public class TestEventController {
private static final Logger logger = LoggerFactory.getLogger(TestEventController.class);
@ApiOperation("test")
@PostMapping("test")
public ApiResponseEntity<?> test() {
EventUtil.publish(new TestEvent("123"));
return ApiResponseUtils.success();
}
@ApiOperation("test2")
@PostMapping("test2")
public ApiResponseEntity<?> test2() {
EventUtil.publish(new BizEvent<>(new SysUserVO()));
//EventUtil.publish(new BizEvent<>(new SubmitOrderDTO()));
return ApiResponseUtils.success();
}
@EventListener
public void onApplicationEvent(TestEvent event) {
logger.info("test event{}", event.getSource());
}
@EventListener
public void onApplicationEvent(BizEvent<SysUserVO> event) {
logger.info("biz event 1 {}", event.getSource());
}
// @EventListener
// public void onApplicationEvent2(BizEvent<SubmitOrderDTO> event) {
// logger.info("biz event 2 {}", event.getSource());
// }
@Order(2)
@Runner
public void run() throws Exception {
logger.info("TestRunner run 1");
}
private static class TestEvent extends ApplicationEvent {
public TestEvent(Object source) {
super(source);
}
}
}
package com.makeit.common.controller.test;
import com.makeit.common.global.aspect.lock.RedissonLock;
import com.makeit.common.response.ApiResponseEntity;
import com.makeit.common.response.ApiResponseUtils;
import com.makeit.common.utils.data.SpringContextHolder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api(tags = "测试-锁")
@RestController
@RequestMapping("/test/lock")
public class TestLockController {
private static final Logger logger = LoggerFactory.getLogger(TestLockController.class);
@RedissonLock(prefix = "test:", expression = "#id", timeout = 3)
@ApiOperation("测试锁aop")
@PostMapping("test")
public ApiResponseEntity<?> log(String id) {
return ApiResponseUtils.success(id);
}
@ApiOperation("测试幂等aop")
@PostMapping("feign/testDuplicateRequest")
public ApiResponseEntity<?> testDuplicateRequest() {
SpringContextHolder.getBean(TestLockController.class).testInternal();
//SpringContextHolder.getBean(TestLockController.class).testInternal();
return ApiResponseUtils.success();
}
public void testInternal() {
}
}
package com.makeit.common.controller.test;
import com.makeit.common.utils.requestjoin.Promise;
import com.makeit.common.utils.requestjoin.RequestJoin;
import com.makeit.dto.BaseIdDTO;
import io.swagger.annotations.Api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
@Api(tags = "测试-请求合并")
@RestController
@RequestMapping("/test/request-join")
public class TestRequestJoinController {
private RequestJoin<String, Integer> requestJoin = new RequestJoin<>(10);//这个是放到service里 作为实例变量使用
// @Autowired
// private CusCustomerFeignCommonService cusCustomerFeignCommonService;
private static final Logger logger = LoggerFactory.getLogger(TestRequestJoinController.class);
@RequestMapping(value = "consumer", method = {RequestMethod.GET, RequestMethod.POST})
public Integer consumer(@RequestBody BaseIdDTO baseIdDTO) {
Promise<String, Integer> promise = requestJoin.push(baseIdDTO.getId());//service里也要这种写法
if (promise.getFirstFlag()) {
//service要这种写法走事务
//或者springcotextholder
requestJoin.consumer(c -> ((TestRequestJoinController) AopContext.currentProxy()).consumer(c));
}
try {
return promise.join();
} catch (RuntimeException ex) {
ex.getCause().printStackTrace();
return 1;
}
}
//service那边要public才走事务
public void consumer(List<Promise<String, Integer>> c) {
List<String> list = c.stream().map(Promise::getParam).collect(Collectors.toList());
try {
logger.info(list + "");
for (int i = 0; i < list.size(); i++) {
c.get(i).setResult(i);
}
} catch (RuntimeException ex) {
for (int i = 0; i < list.size(); i++) {
c.get(i).exception(ex);
}
}
}
// @ApiOperation("测试异步批量切面")
// @PostMapping("testAsyncBatch")
// public ApiResponseEntity<List<Object>> testAsyncBatch() {
// List<Object> list = QueryAsyncBatchUtil.batchReturn(Arrays.asList(
// () -> FeignUtil.decode(cusCustomerFeignCommonService.listByIdList(Arrays.asList("1"))),
// () -> FeignUtil.decode(cusCustomerFeignCommonService.listByIdList(Arrays.asList("2"))),
// () -> FeignUtil.decode(cusCustomerFeignCommonService.listByIdList(Arrays.asList("3")))
// ));
//
// logger.info(list + "");
//
// List<Object> newList = new ArrayList<>(10);
// list.forEach(e -> {
// newList.add((List<CusCustomerSimpleFeignVO>) e);
// });
// return ApiResponseUtils.success(newList);
// }
}
package com.makeit.common.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
@FieldNameConstants
@Data
public class BaseBusEntity extends BaseEntity {
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty("厂别id")
private String factoryId;
}
package com.makeit.common.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
import org.apache.ibatis.type.LocalDateTimeTypeHandler;
import java.io.Serializable;
import java.time.LocalDateTime;
@FieldNameConstants
@Data
public class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
public BaseEntity() {
}
public BaseEntity(String id) {
this.id = id;
}
/**
* 主键ID
*/
@ApiModelProperty(value = "主键ID", required = false)
@TableId(type = IdType.ASSIGN_ID)
private String id;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间", required = false)
@TableField(value = "created_at", fill = FieldFill.INSERT, typeHandler = LocalDateTimeTypeHandler.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createdAt;
/**
* 更新时间
*/
@ApiModelProperty(value = "更新时间", required = false)
@TableField(value = "updated_at", fill = FieldFill.INSERT_UPDATE, typeHandler = LocalDateTimeTypeHandler.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updatedAt;
//
// /**
// * 删除时间(逻辑删除)
// */
// @TableLogic(value="NULL",delval = "NOW()")
// @ApiModelProperty(value = "删除时间",required = false)
// @JsonFormat(pattern="yyyy-mm-dd HH:mm:ss")
// private LocalDateTime deletedAt;
@TableLogic
@TableField(select = false, fill = FieldFill.INSERT)
private String delFlag;
@ApiModelProperty(value = "创建人名称")
@TableField(fill = FieldFill.INSERT)
private String createdByName;
@ApiModelProperty(value = "更新人名称")
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updatedByName;
}
package com.makeit.common.exception;
import com.makeit.enums.CodeMessageEnum;
public class BusinessException extends GlobalException {
public BusinessException(CodeMessageEnum codeMessageEnum) {
super(codeMessageEnum.getMessage(), codeMessageEnum.getCode());
}
public BusinessException(String message, int code) {
super(message, code);
}
public BusinessException(String message, int code, Object data) {
super(message, code, data);
}
public BusinessException(String message) {
super(message);
}
@Override
public String toString() {
return "BusinessException{" +
"message='" + getMessage() + '\'' +
", code=" + getCode() +
'}';
}
}
package com.makeit.common.exception;
import com.makeit.common.response.ApiResponseEntity;
public class BusinessWrapperException extends RuntimeException {
private ApiResponseEntity<?> apiResponseEntity;
public BusinessWrapperException(ApiResponseEntity<?> apiResponseEntity) {
this.apiResponseEntity = apiResponseEntity;
}
public ApiResponseEntity<?> getApiResponseEntity() {
return apiResponseEntity;
}
}
package com.makeit.common.exception;
import com.makeit.common.response.ApiResponseEntity;
import com.makeit.common.response.ApiResponseUtils;
import com.makeit.enums.GlobalCodeMessageEnum;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* 重写ErrorController 主要负责系统的异常页面的处理以及错误信息的显示 GlobalException除外无法捕捉的异常处理
*
*/
@RestController
public class ExceptionController implements ErrorController {
/**
* 定义错误JSON信息
*
* @param request
* @return
*/
@RequestMapping(value = "${server.error.path:${error.path:/error}}")
public ApiResponseEntity<String> error(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
// 404
if (GlobalCodeMessageEnum.SYSTEM_ERROR_NOT_FOUND.getCode() == statusCode) {
return ApiResponseUtils.fail(GlobalCodeMessageEnum.SYSTEM_ERROR_NOT_FOUND.getCode(),
GlobalCodeMessageEnum.SYSTEM_ERROR_NOT_FOUND.getMessage());
}
// 405
if (GlobalCodeMessageEnum.SYSTEM_ERROR_NOT_ALLOWED.getCode() == statusCode) {
return ApiResponseUtils.fail(GlobalCodeMessageEnum.SYSTEM_ERROR_NOT_ALLOWED.getCode(),
GlobalCodeMessageEnum.SYSTEM_ERROR_NOT_ALLOWED.getMessage());
}
return ApiResponseUtils.fail(GlobalCodeMessageEnum.SYSTEM_ERROR_EXCEPTION.getCode(),
GlobalCodeMessageEnum.SYSTEM_ERROR_EXCEPTION.getMessage());
}
}
\ No newline at end of file
package com.makeit.common.exception;
import com.makeit.enums.GlobalCodeMessageEnum;
/**
* 自定义异常rest
*
*/
public class GlobalException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String message;
private int code = 500;
private Object data;
public GlobalException(String message) {
super(message);
this.message = message;
}
public GlobalException(String message, Throwable e) {
super(message, e);
this.message = message;
}
public GlobalException(String message, int code) {
super(message);
this.message = message;
this.code = code;
}
public GlobalException(String message, int code, Object data) {
super(message);
this.message = message;
this.code = code;
this.data = data;
}
public GlobalException(String message, int code, Throwable e) {
super(message, e);
this.message = message;
this.code = code;
}
/**
* 方便抛出枚举类异常 gaoyizhong
* @param globalCodeMessageEnum
*/
public GlobalException(GlobalCodeMessageEnum globalCodeMessageEnum) {
super(globalCodeMessageEnum.getMessage());
this.message = globalCodeMessageEnum.getMessage();
this.code = globalCodeMessageEnum.getCode();
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
@Override
public String toString() {
return "GlobalException{" +
"message='" + message + '\'' +
", code=" + code +
'}';
}
}
package com.makeit.common.global.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
String module() default "";
String name();
String[] code() default {};
}
package com.makeit.common.global.annotation;
import java.lang.annotation.*;
/**
* 忽略登录认证校验
* @author chenyingyi
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthIgnore {
}
package com.makeit.common.global.aspect.cache;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
public interface BizCacheManager {
<T> T get(String key);
<T> void set(String key, T value, long expire, TimeUnit timeUnit);
<T> void set(String key, T value);
void del(String key);
void delLike(String key);
default <T> List<T> get(List<String> key){
throw new UnsupportedOperationException();
}
default <T,V> void set(List<T> list, Function<T, String> keyFunction, Function<T, V> valueFunction){
throw new UnsupportedOperationException();
}
default <T, V> void set(List<T> list, Function<T, String> keyFunction, Function<T, V> valueFunction, long expire, TimeUnit timeUnit) {
throw new UnsupportedOperationException();
}
}
package com.makeit.common.global.aspect.cache;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Cache.CacheMulti.class)
public @interface Cache {
String condition() default "";
String cacheName();
String key() default "";
int timeout() default 5;//分钟
Class<? extends BizCacheManager> cacheManager() default CacheRedisManager.class;
boolean spelCache() default false;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface CacheMulti {
Cache[] value();
}
}
package com.makeit.common.global.aspect.cache;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheByIdList {
String cacheName();
String keyField() default "";
int timeout();//分钟
Class<? extends BizCacheManager> cacheManager() default CacheRedisManager.class;
}
package com.makeit.common.global.aspect.cache;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(CacheDel.CacheDelMulti.class)
public @interface CacheDel {
String cacheName();
String key() default "";
boolean like() default false;
Class<? extends BizCacheManager> cacheManager() default CacheRedisManager.class;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface CacheDelMulti {
CacheDel[] value();
}
}
package com.makeit.common.global.aspect.cache;
import com.makeit.common.utils.redis.LocalCacheUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
public class CacheLocalManager implements BizCacheManager {
@Override
public <T> T get(String key) {
return (T) LocalCacheUtil.get(key);
}
@Override
public <T> void set(String key, T value, long expire, TimeUnit timeUnit) {
LocalCacheUtil.set(key, value, expire, timeUnit);
}
@Override
public <T> void set(String key, T value) {
LocalCacheUtil.set(key, value, -1);
}
@Override
public void del(String key) {
LocalCacheUtil.remove(key);
}
@Override
public void delLike(String key) {
LocalCacheUtil.removeLike(key);
}
@Override
public <T> List<T> get(List<String> key) {
List<T> list = new ArrayList<>(10);
key.forEach(e -> {
list.add(get(e));
});
return list;
}
@Override
public <T, V> void set(List<T> list, Function<T, String> keyFunction, Function<T, V> valueFunction) {
list.forEach(e -> {
set(keyFunction.apply(e), keyFunction.apply(e));
});
}
@Override
public <T, V> void set(List<T> list, Function<T, String> keyFunction, Function<T, V> valueFunction, long expire, TimeUnit timeUnit) {
list.forEach(e -> {
set(keyFunction.apply(e), keyFunction.apply(e), expire, timeUnit);
});
}
}
package com.makeit.common.global.aspect.cache;
import com.makeit.common.utils.redis.RedisCacheUtil;
import com.makeit.common.utils.redis.RedisUtil;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
public class CacheRedisManager implements BizCacheManager {
@Override
public <T> T get(String key) {
return RedisCacheUtil.get(key);
}
@Override
public <T> void set(String key, T value, long expire, TimeUnit timeUnit) {
RedisCacheUtil.set(key, value, expire, timeUnit);
}
@Override
public <T> void set(String key, T value) {
RedisCacheUtil.set(key, value);
}
@Override
public void del(String key) {
RedisCacheUtil.del(key);
}
@Override
public void delLike(String key) {
RedisUtil.deleteLike(key);
}
@Override
public <T> List<T> get(List<String> key) {
return RedisCacheUtil.get(key);
}
@Override
public <T, V> void set(List<T> list, Function<T, String> keyFunction, Function<T, V> valueFunction) {
RedisCacheUtil.set(list, keyFunction, valueFunction);
}
@Override
public <T, V> void set(List<T> list, Function<T, String> keyFunction, Function<T, V> valueFunction, long expire, TimeUnit timeUnit) {
RedisCacheUtil.set(list, keyFunction, valueFunction, expire, timeUnit);
}
}
This diff could not be displayed because it is too large.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment