diff options
| author | fangshunjian <[email protected]> | 2021-05-25 17:09:36 +0800 |
|---|---|---|
| committer | fangshunjian <[email protected]> | 2021-05-25 17:09:36 +0800 |
| commit | 4b5c7dda4918dd5c4eea1ebf5e95e85252a87363 (patch) | |
| tree | 1b1a3c23677f05aa627ba04f4958950025408e42 | |
perf: 项目初始化
203 files changed, 18196 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce4c46f --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/target/ +/.project +*.iml +*.log +/.setting/ +/.classpath diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/<project>=UTF-8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2cec88 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Cyber Narrator api
\ No newline at end of file diff --git a/cn-admin/.gitignore b/cn-admin/.gitignore new file mode 100644 index 0000000..ce4c46f --- /dev/null +++ b/cn-admin/.gitignore @@ -0,0 +1,6 @@ +/target/ +/.project +*.iml +*.log +/.setting/ +/.classpath diff --git a/cn-admin/.settings/org.eclipse.core.resources.prefs b/cn-admin/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..839d647 --- /dev/null +++ b/cn-admin/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding/<project>=UTF-8 diff --git a/cn-admin/.settings/org.eclipse.jdt.core.prefs b/cn-admin/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..71df522 --- /dev/null +++ b/cn-admin/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.methodParameters=generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/cn-admin/.settings/org.eclipse.m2e.core.prefs b/cn-admin/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/cn-admin/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/cn-admin/Dockerfile b/cn-admin/Dockerfile new file mode 100644 index 0000000..71acbfb --- /dev/null +++ b/cn-admin/Dockerfile @@ -0,0 +1,7 @@ +FROM java:8 +EXPOSE 8080 + +VOLUME /tmp +ADD cn-admin.jar /app.jar +RUN bash -c 'touch /app.jar' +ENTRYPOINT ["java","-jar","/app.jar"] diff --git a/cn-admin/pom.xml b/cn-admin/pom.xml new file mode 100644 index 0000000..6eb7576 --- /dev/null +++ b/cn-admin/pom.xml @@ -0,0 +1,345 @@ +<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> + <groupId>net.geedge</groupId> + <artifactId>cn-web</artifactId> + <version>2.0</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>cn-admin</artifactId> + <packaging>jar</packaging> + <description>cn-admin</description> + + <properties> + <quartz.version>2.3.0</quartz.version> + <shiro.version>1.4.0</shiro.version> + <kaptcha.version>0.0.9</kaptcha.version> + <qiniu.version>[7.2.0, 7.2.99]</qiniu.version> + <aliyun.oss.version>2.5.0</aliyun.oss.version> + <qcloud.cos.version>4.4</qcloud.cos.version> + <swagger.version>2.7.0</swagger.version> + <commons-lang3.version>3.3.2</commons-lang3.version> + <apache.poi.version>3.14</apache.poi.version> + <jackson.version>2.10.1</jackson.version> + </properties> + + <dependencies> + <!-- 集群环境,需要打开注释 --> + <!--<dependency> --> + <!--<groupId>org.springframework.session</groupId> --> + <!--<artifactId>spring-session-data-redis</artifactId> --> + <!--</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-freemarker</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-mail</artifactId> + </dependency> + <dependency> + <groupId>org.quartz-scheduler</groupId> + <artifactId>quartz</artifactId> + <exclusions> + <exclusion> + <groupId>com.mchange</groupId> + <artifactId>c3p0</artifactId> + </exclusion> + <exclusion> + <groupId>com.zaxxer</groupId> + <artifactId>HikariCP-java6</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.shiro</groupId> + <artifactId>shiro-core</artifactId> + <version>${shiro.version}</version> + </dependency> + <dependency> + <groupId>org.apache.shiro</groupId> + <artifactId>shiro-spring</artifactId> + <version>${shiro.version}</version> + </dependency> + <!--shiro-redis --> + <!-- https://mvnrepository.com/artifact/org.crazycake/shiro-redis --> + <dependency> + <groupId>org.crazycake</groupId> + <artifactId>shiro-redis</artifactId> + <version>3.3.1</version> + </dependency> + <dependency> + <groupId>com.github.axet</groupId> + <artifactId>kaptcha</artifactId> + <version>${kaptcha.version}</version> + </dependency> + + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-test</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> + <dependency> + <groupId>com.jcraft</groupId> + <artifactId>jsch</artifactId> + <version>0.1.54</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-websocket</artifactId> + </dependency> + <dependency> + <groupId>commons-net</groupId> + <artifactId>commons-net</artifactId> + <version>3.6</version> + </dependency> + <dependency> + <groupId>org.yaml</groupId> + <artifactId>snakeyaml</artifactId> + </dependency> + + <!-- prometheus java sdk --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + <dependency> + <groupId>io.micrometer</groupId> + <artifactId>micrometer-core</artifactId> + </dependency> + <dependency> + <groupId>io.micrometer</groupId> + <artifactId>micrometer-registry-prometheus</artifactId> + </dependency> + + <!-- telnet --> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + </dependency> + + <!-- excel poi --> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi</artifactId> + <version>${apache.poi.version}</version> + </dependency> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi-ooxml</artifactId> + <version>${apache.poi.version}</version> + </dependency> + + <!-- ldap --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-ldap</artifactId> + </dependency> + <!-- ldap测试 --> + <dependency> + <groupId>com.unboundid</groupId> + <artifactId>unboundid-ldapsdk</artifactId> + <scope>test</scope> + </dependency> + + <!--jackjson yaml支持 --> + <dependency> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-yaml</artifactId> + </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + </dependency> + + + <dependency> + <groupId>org.snmp4j</groupId> + <artifactId>snmp4j</artifactId> + <version>2.5.11</version> + </dependency> + + <!-- 添加 XJar 依赖 --> +<!-- <dependency>--> +<!-- <groupId>com.github.core-lib</groupId>--> +<!-- <artifactId>xjar</artifactId>--> +<!-- <version>4.0.1</version>--> +<!-- <!– <scope>test</scope> –>--> +<!-- </dependency>--> + + <dependency> + <groupId>org.flywaydb</groupId> + <artifactId>flyway-core</artifactId> + <version>5.2.4</version> + </dependency> + <dependency> + <groupId>com.github.oshi</groupId> + <artifactId>oshi-core</artifactId> + <version>5.7.0</version> + </dependency> + </dependencies> + + <build> + <finalName>${project.artifactId}</finalName> + <resources> + <resource> + <directory>src/main/resources</directory> + <excludes> + <exclude>**/license.key</exclude> + <exclude>**/*agent*.rpm</exclude> + <exclude>**/application-*.yml</exclude> + <!-- <exclude>**/logback-spring.xml</exclude> --> + <exclude>**/swagger/**</exclude> + <!-- <exclude>**/cn.properties</exclude> --> + </excludes> + <includes> + <!--包含文件夹以及子文件夹下所有资源 --> + <include>**/*.*</include> + </includes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>8</source> + <target>8</target> + <encoding>UTF-8</encoding> + </configuration> + </plugin> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <version>2.2.6.RELEASE</version> + </plugin> + <!-- 跳过单元测试 --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <skipTests>true</skipTests> + </configuration> + </plugin> + <!-- <plugin> <groupId>com.spotify</groupId> <artifactId>docker-maven-plugin</artifactId> + <version>0.4.14</version> <configuration> <imageName>nz/admin</imageName> + <dockerDirectory>${project.basedir}</dockerDirectory> <resources> <resource> + <targetPath>/</targetPath> <directory>${project.build.directory}</directory> + <include>${project.build.finalName}.jar</include> </resource> </resources> + </configuration> 运行命令 mvn clean package docker:build 打包并生成docker镜像 </plugin> --> + +<!-- <plugin>--> +<!-- <groupId>com.github.core-lib</groupId>--> +<!-- <artifactId>xjar-maven-plugin</artifactId>--> +<!-- <version>4.0.1</version>--> +<!-- <executions>--> +<!-- <execution>--> +<!-- <goals>--> +<!-- <goal>build</goal>--> +<!-- </goals>--> +<!-- <phase>install</phase>--> +<!-- </execution>--> +<!-- </executions>--> +<!-- </plugin>--> + <!-- 添加 XJar Maven 插件 --> + <plugin> + <groupId>com.mesalab.xjar-maven-plugin</groupId> + <artifactId>mesalab-xjar-maven-plugin</artifactId> + <version>1.0.0</version> + <executions> + <execution> + <goals> + <goal>build</goal> + </goals> + <phase>package</phase> + <configuration> + <password>111111</password> + </configuration> + </execution> + </executions> + </plugin> + + <!-- <plugin> + <groupId>pl.project13.maven</groupId> + <artifactId>git-commit-id-plugin</artifactId> + <executions> + <execution> + <id>get-the-git-infos</id> + <goals> + 目标:revision + <goal>revision</goal> + </goals> + 默认绑定阶段initialize + <phase>initialize</phase> + </execution> + </executions> + <configuration> + 检查的仓库根目录,${project.basedir}:项目根目录,即包含pom.xml文件的目录 + <dotGitDirectory>${project.basedir}/.git</dotGitDirectory> + false:扫描路径时不打印更多信息,默认值false,可以不配置 + <verbose>true</verbose> + 定义插件中所有时间格式,默认值:yyyy-MM-dd’T’HH:mm:ssZ + <dateFormat>yyyy-MM-dd HH:mm:ss</dateFormat> + git属性文件中各属性前缀,默认值git,可以不配置 + <prefix>git</prefix> + 生成git属性文件,默认false:不生成 + <generateGitPropertiesFile>true</generateGitPropertiesFile> + 生成git属性文件路径及文件名,默认${project.build.outputDirectory}/git.properties + <generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename> + 生成git属性文件格式,默认值properties + <format>json</format> + <commitIdGenerationMode>full</commitIdGenerationMode> + + 配置git-describe命令 + <gitDescribe> + <skip>false</skip> + <always>false</always> + <dirty>-dirty</dirty> + </gitDescribe> + + 获取指定属性 + <includeOnlyProperties> + <includeOnlyProperty>^git.branch$</includeOnlyProperty> + <includeOnlyProperty>^git.build.version$</includeOnlyProperty> + <includeOnlyProperty>^git.commit.id.full$</includeOnlyProperty> + <includeOnlyProperty>^git.commit.time$</includeOnlyProperty> + <includeOnlyProperty>^git.commit.tags$</includeOnlyProperty> + <includeOnlyProperty>^git.closest.tag.name$</includeOnlyProperty> + </includeOnlyProperties> + + <evaluateOnCommit>HEAD</evaluateOnCommit> + <useBranchNameFromBuildEnvironment>true</useBranchNameFromBuildEnvironment> + <injectIntoSysProperties>false</injectIntoSysProperties> + </configuration> + </plugin> --> + </plugins> + </build> +</project>
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/AdminApplication.java b/cn-admin/src/main/java/net/geedge/AdminApplication.java new file mode 100644 index 0000000..024cdd1 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/AdminApplication.java @@ -0,0 +1,89 @@ + +package net.geedge; + +import java.util.TimeZone; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import cn.hutool.core.util.StrUtil; +import io.micrometer.core.instrument.MeterRegistry; +import net.geedge.AdminApplication.SetupAutoConfiguration; + +@SpringBootApplication(scanBasePackages = { "net.geedge.setup" }) +@Import(SetupAutoConfiguration.class) +@PropertySource(value = { "file:./config/cn.properties","classpath:./config/cn.properties" }, encoding = "utf-8", ignoreResourceNotFound = true) +public class AdminApplication { + + public static void main(String[] args) { + // 默认为 UTC 时区 + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + SpringApplication.run(AdminApplication.class, args); + } + + @Bean + MeterRegistryCustomizer<MeterRegistry> configurer(@Value("cn") String applicationName) { + return (registry) -> registry.config().commonTags("application", applicationName); + } + + static class SetupAutoConfiguration implements ImportBeanDefinitionRegistrar, EnvironmentAware { + private Environment environment; + + @Override + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, + BeanDefinitionRegistry registry) { + String inited = environment.getProperty("cn.inited"); + if (!StrUtil.isEmpty(inited) && Integer.parseInt(inited) > 0) { + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, true); + scanner.scan("net.geedge.modules", "net.geedge.common"); + } + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + } + + @Bean + public FilterRegistrationBean<CorsFilter> corsFilter() { + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + final CorsConfiguration config = new CorsConfiguration(); + // 允许cookies跨域 + config.setAllowCredentials(true); + // #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin + config.addAllowedOrigin("*"); + // #允许访问的头信息,*表示全部 + config.addAllowedHeader("*"); + // 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了 + config.setMaxAge(18000L); + // 允许提交请求的方法,*表示全部允许 + config.addAllowedMethod("OPTIONS"); + config.addAllowedMethod("HEAD"); + config.addAllowedMethod("GET"); + config.addAllowedMethod("PUT"); + config.addAllowedMethod("POST"); + config.addAllowedMethod("DELETE"); + config.addAllowedMethod("PATCH"); + source.registerCorsConfiguration("/**", config); + FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(source)); + // 设置监听器的优先级 + bean.setOrder(0); + return bean; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/annotation/DataFilter.java b/cn-admin/src/main/java/net/geedge/common/annotation/DataFilter.java new file mode 100644 index 0000000..3e464bf --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/annotation/DataFilter.java @@ -0,0 +1,31 @@ +/** + + * + + * + + */ + +package net.geedge.common.annotation; + +import java.lang.annotation.*; + +/** + * 数据过滤 + * + + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataFilter { + /** 表的别名 */ + String tableAlias() default ""; + + /** true:没有本部门数据权限,也能查询本人数据 */ + boolean user() default true; + + /** 用户ID */ + String userId() default "id"; +} + diff --git a/cn-admin/src/main/java/net/geedge/common/annotation/SysLog.java b/cn-admin/src/main/java/net/geedge/common/annotation/SysLog.java new file mode 100644 index 0000000..a1c065d --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/annotation/SysLog.java @@ -0,0 +1,19 @@ +package net.geedge.common.annotation; + +import net.geedge.common.utils.OperationEnum; +import net.geedge.common.utils.TypeEnum; + +import java.lang.annotation.*; + +/** + * 系统日志注解 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface SysLog { + + OperationEnum operation() default OperationEnum.UNKNOWN; + + TypeEnum type() default TypeEnum.UNKNOWN; +} diff --git a/cn-admin/src/main/java/net/geedge/common/aspect/ControllerExecTimeAspect.java b/cn-admin/src/main/java/net/geedge/common/aspect/ControllerExecTimeAspect.java new file mode 100644 index 0000000..b694915 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/aspect/ControllerExecTimeAspect.java @@ -0,0 +1,62 @@ +package net.geedge.common.aspect; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; + +@Aspect +@Component +@Slf4j +public class ControllerExecTimeAspect { + + @Pointcut("execution(* net.geedge.modules.*.controller.*.*(..))") + public void logPointCut() { + } + + /** + * 只记录执行成功的方法执行时长 + * + * @param point + * @return + * @throws Throwable + */ + @Around("logPointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + long beginTime = System.currentTimeMillis(); + Object result = point.proceed(); + long time = System.currentTimeMillis() - beginTime; + + MethodSignature signature = (MethodSignature) point.getSignature(); + String className = point.getTarget().getClass().getName(); + String methodName = className + "." + signature.getName() + "()"; + + // 保留两位 + double execTime = new BigDecimal(time / 1000.0).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue(); + + log.info(String.format("方法:%s,执行 %s 秒,执行 %s 毫秒", methodName, execTime, time)); + return result; + } + + + @AfterThrowing(pointcut = "logPointCut()", throwing = "e") + public void saveExceptionLog(JoinPoint point, Throwable e) { + /* MethodSignature signature = (MethodSignature) point.getSignature(); + String className = point.getTarget().getClass().getName(); + String methodName = className + "." + signature.getName() + "()"; + String errorMsg; + if (e instanceof NZException) { + errorMsg = ((NZException) e).getMsg(); + } else { + errorMsg = e.getMessage(); + } + log.error(String.format("方法: %s 执行失败,异常信息是: %s", methodName,errorMsg));*/ + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/aspect/SysLogAspect.java b/cn-admin/src/main/java/net/geedge/common/aspect/SysLogAspect.java new file mode 100644 index 0000000..e7c4be9 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/aspect/SysLogAspect.java @@ -0,0 +1,434 @@ +package net.geedge.common.aspect; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.apache.shiro.SecurityUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.TableId; +import com.google.gson.Gson; + +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.log.Log; +import net.geedge.common.annotation.SysLog; +import net.geedge.common.exception.CNException; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.HttpContextUtils; +import net.geedge.common.utils.IPUtils; +import net.geedge.common.utils.R; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.entity.SysLogEntity; +import net.geedge.modules.sys.entity.SysUserEntity; +import net.geedge.modules.sys.service.SysLogService; +import net.geedge.modules.sys.shiro.ShiroUtils; + +/** + * 系统日志,切面处理类 + */ +@Aspect +@Component +public class SysLogAspect { + private static final Log logger = Log.get(); + @Autowired + private SysLogService sysLogService; + + private static Gson gson = new Gson(); + + @Pointcut("@annotation(net.geedge.common.annotation.SysLog)") + public void logPointCut() { + + } + + @Around("logPointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + // 开始时间 + long beginTime = System.currentTimeMillis(); + + // 当前登录用户 + SysUserEntity currentLoginUser = ShiroUtils.getUserEntity(); + + // 获取参数 处理参数 方便后续保存操作 + Object[] args = point.getArgs(); + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + SysLog syslog = method.getAnnotation(SysLog.class); + + // 处理记录参数 + String paramResult = this.handleArgs(syslog, args, currentLoginUser); + + // 执行方法 + Object result = point.proceed(); + + // 执行时长(毫秒) + long time = System.currentTimeMillis() - beginTime; + + // 保存日志 + saveSysLog(point, time, result, currentLoginUser, paramResult); + + return result; + } + + /** + * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行 + * + * @param joinPoint 切入点 + * @param e 异常信息 + */ + @AfterThrowing(pointcut = "logPointCut()", throwing = "e") + public void saveExceptionLog(JoinPoint joinPoint, Throwable e) { + R r = new R(); + if (e instanceof CNException) { + r = R.error(((CNException) e).getCode(), ((CNException) e).getMsg()); + } else { + r = R.error(999, e.getMessage()); + } + + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + + SysLogEntity sysLog = new SysLogEntity(); + SysLog syslog = method.getAnnotation(SysLog.class); + + String operationType = syslog.operation().getValue(); + + sysLog.setOperation(operationType); + sysLog.setType(syslog.type().getValue()); + sysLog.setResponse(JSON.toJSONString(r)); + sysLog.setException(Tool.StrUtil.utf8Str(r.get("msg"))); + sysLog.setTime(0L); + + // 获取request + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + // 设置IP地址 + sysLog.setIp(IPUtils.getIpAddr(request)); + // 请求的方法名 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = signature.getName(); + sysLog.setMethod(className + "." + methodName + "()"); + + // 请求的参数 + Object[] args = joinPoint.getArgs(); + List<Object> params = this.getRecordParams(args); + + // 获取请求参数名 + String oepraId = ""; + if ("update".equals(operationType)) { + oepraId = getOpId(params); + } + sysLog.setOperaId(oepraId); + + // 处理参数记录 + String paramResult = this.handleArgs(syslog, args, ShiroUtils.getUserEntity()); + paramResult = this.handleLogParam(request.getRequestURI(), paramResult); + if (paramResult.getBytes().length > Constant.MYSQL_TEXT_MAXLENGTH) { + paramResult = Tool.StrUtil.subWithLength(paramResult, 0, Constant.MYSQL_TEXT_MAXLENGTH); + } + sysLog.setParams(paramResult); + + // 登录出现异常时 + if ("login".equals(operationType)) { + sysLog.setUserId(null); + Map map = gson.fromJson(gson.toJson(params.get(0)), Map.class); + map.remove("pin"); + String logParams = gson.toJson(map); + logParams = Tool.ObjectUtil.isEmpty(logParams) ? "" : logParams; + if (logParams.getBytes().length > Constant.MYSQL_TEXT_MAXLENGTH) { + logParams = Tool.StrUtil.subWithLength(logParams, 0, Constant.MYSQL_TEXT_MAXLENGTH); + } + sysLog.setParams(logParams); + } else { + Object principal = SecurityUtils.getSubject().getPrincipal(); + if (principal != null) { + Long userId = ((SysUserEntity) principal).getId(); + sysLog.setUserId(userId == null ? null : userId.intValue()); + sysLog.setApiKeyId(((SysUserEntity) principal).getApiKeyId()); + } + } + + sysLog.setCreateDate(new Date()); + sysLog.setState("fail"); + + + sysLogService.save(sysLog); + } + + private void saveSysLog(ProceedingJoinPoint joinPoint, long time, Object result, SysUserEntity currentLoginUser, + String paramResult) { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + + SysLogEntity sysLog = new SysLogEntity(); + SysLog syslog = method.getAnnotation(SysLog.class); + String operationType = syslog.operation().getValue(); + + // 获取执行结果 + R r = (R) result; + + // 注解上的描述 + sysLog.setOperation(operationType); + // 类型 + sysLog.setType(syslog.type().getValue()); + // 当 operation = query 时,只记录 code != 200 的内容 + if (!"query".equals(operationType)) { + if ("login".equals(operationType)) { + Map<?,?> map = Tool.ObjectUtil.clone(r);//JSONObject.parseObject(JSONObject.toJSONString(r), Map.class); + map.remove("data"); + sysLog.setResponse(JSON.toJSONString(map)); + } else { + sysLog.setResponse(JSON.toJSONString(r)); + } + } + + // 由于 导出功能没有返回值 记录为 success , 原因为导出中若有异常会经过 saveExceptionLog() 方法 + if ("export".equals(operationType)) { + sysLog.setState("success"); + } else { + String state = "200".equals(r.get("code").toString()) ? "success" : "fail"; + sysLog.setState(state); + } + + // 请求的方法名 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = signature.getName(); + sysLog.setMethod(className + "." + methodName + "()"); + + // 请求的参数 + Object[] args = joinPoint.getArgs(); + List<Object> params = this.getRecordParams(args); + // 获取请求参数名 + String oepraId = ""; + if ("add".equals(operationType) || "update".equals(operationType)) { + oepraId = getOpId(params); + } + if ("delete".equals(operationType)) { + oepraId = JSON.toJSONString(params.get(0)).replace("\"", ""); + } + sysLog.setOperaId(oepraId); + // 获取request + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + + // 处理 参数信息 + paramResult = this.handleLogParam(request.getRequestURI(), paramResult); + if (paramResult.getBytes().length > Constant.MYSQL_TEXT_MAXLENGTH) { + paramResult = Tool.StrUtil.subWithLength(paramResult, 0, Constant.MYSQL_TEXT_MAXLENGTH); + } + sysLog.setParams(paramResult); + + Long userId = null; + Integer apiKeyId = null; + if (Tool.ObjectUtil.isEmpty(currentLoginUser)) { + Object principal = SecurityUtils.getSubject().getPrincipal(); + if (principal != null) { + userId = ((SysUserEntity) principal).getId(); + apiKeyId = ((SysUserEntity) principal).getApiKeyId(); + } + } else { + userId = currentLoginUser.getId(); + apiKeyId = currentLoginUser.getApiKeyId(); + } + sysLog.setUserId(userId == null ? null : userId.intValue()); + + // 设置IP地址 + sysLog.setIp(IPUtils.getIpAddr(request)); + + sysLog.setTime(time); + sysLog.setCreateDate(new Date()); + + sysLog.setApiKeyId(apiKeyId); + // 保存系统日志 注: 查询操作若无异常不记录操作日志 + if (!"query".equals(operationType)) { + sysLogService.save(sysLog); + } + } + + /** + * 处理保存参数信息 1. system ldap 不保存 ldap_password 2. system email 不保存 + * email_smtp_password 3. project topo 不保存 更新配置信息 topo + * + * @param requestURI + * @param paramResult + */ + private String handleLogParam(String requestURI, String paramResult) { + if (!requestURI.endsWith("project/topo") && !requestURI.endsWith("sysConfig")) { + return paramResult; + } + if (Tool.StrUtil.isNotEmpty(paramResult)) { + Map<String, Object> map = JSONObject.parseObject(paramResult, Map.class); + for (Map.Entry<String, Object> obj : map.entrySet()) { + Object value = obj.getValue(); + if (value instanceof Map) { + for (Object pojo : ((Map) value).values()) { + if (pojo instanceof Map && pojo != null) { + ((Map) pojo).remove("ldap_password"); + ((Map) pojo).remove("email_smtp_password"); + } + } + ((Map) value).remove("topo"); + obj.setValue(value); + } + } + return JSONObject.toJSONString(map); + } + return paramResult; + } + + /** + * 获取POST/PUT请求回添的实体 ID + * + * @param args + * @return + */ + private static String getOpId(List<Object> args) { + String oepraId = ""; + List<Object> list; + Map<String, Object> map; + for (Object arg : args) { + if (arg == null) { + continue; + } + // endpoint 保存方法参数为 集合形式 List<Endpoint> + if (arg instanceof List) { + list = (List<Object>) arg; + for (Object o : list) { + oepraId += getEntityId(o) + ","; + } + if (Tool.ObjectUtil.isNotEmpty(oepraId)) { + oepraId = oepraId.substring(0, oepraId.length() - 1); + } + } else if (arg instanceof Map) { + // 如果参数为 Map 则记录包含id的参数作为回添Id + map = (Map) arg; + if (Tool.ObjectUtil.isNotEmpty(map)) { + for (Map.Entry<String, Object> entry : map.entrySet()) { + if (entry.getKey().toLowerCase().indexOf("id") != -1) { + oepraId += entry.getValue() + ","; + } + } + if (Tool.ObjectUtil.isNotEmpty(oepraId)) { + oepraId = oepraId.substring(0, oepraId.length() - 1); + } + } + } else { + // 单个实体对象方式 + oepraId += getEntityId(arg) + ","; + ; + if (Tool.ObjectUtil.isNotEmpty(oepraId)) { + oepraId = oepraId.substring(0, oepraId.length() - 1); + } + } + } + return oepraId; + } + + /** + * 获取回添实体Id + * + * @param arg + * @return + */ + private static String getEntityId(Object arg) { + String oepraId = ""; + Class aClass = arg.getClass(); + String name = aClass.getPackage().getName(); + // 只有是本项目实体对象 才获取回添 ID + if (Tool.ObjectUtil.isNotEmpty(name) && name.indexOf("net.geedge") != -1) { + Field[] a = aClass.getFields(); + Field[] b = aClass.getDeclaredFields(); + Field[] fields = new Field[a.length + b.length]; + + for (int x = 0; x < a.length; x++) { + fields[x] = a[x]; + } + for (int y = 0; y < b.length; y++) { + fields[a.length + y] = b[y]; + } + for (Field field : fields) { + Boolean isId = field.isAnnotationPresent(TableId.class); + if (isId) { + Object fieldValue = ReflectUtil.getFieldValue(arg, field); + oepraId = Tool.ObjectUtil.isNotEmpty(fieldValue) ? fieldValue.toString() : ""; + break; + } + } + } + return oepraId; + } + + /** + * 去除形参列表中无用参数 例如 : ServletRequest Response... + * + * @param args + * @return + */ + private List<Object> getRecordParams(Object[] args) { + List<Object> list = new ArrayList<>(Arrays.asList(args)); + Iterator<Object> iterator = list.iterator(); + while (iterator.hasNext()) { + Object next = iterator.next(); + if (next instanceof ServletResponse || next instanceof ServletRequest) { + iterator.remove(); + } + } + return list; + } + + /** + * 处理记录方法的形参列表 + * + * @param syslog + * @param args + * @param currentLoginUser + * @return + */ + public String handleArgs(SysLog syslog, Object[] args, SysUserEntity currentLoginUser) { + // 需要记录的 + List<Object> list = this.getRecordParams(args); + + String result = ""; + String operationType = syslog.operation().getValue(); + // 退出操作 + if ("logout".equals(operationType)) { + // 补全 params 为 当前退出者 + Map map = new HashMap(); + map.put("username", currentLoginUser.getName()); + result = gson.toJson(map); + } else if ("login".equals(operationType)) { + String params = gson.toJson(list.get(0)); + Map map = gson.fromJson(params, Map.class); + map.remove("pin"); + result = gson.toJson(map); + } else { + if (Tool.ObjectUtil.isNotEmpty(list)) { + Map map = new LinkedHashMap(); + for (int i = 0; i < list.size(); i++) { + map.put("arg" + (i + 1), list.get(i)); + } + result = gson.toJson(map); + } + } + return result; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/config/DataSourceConfig.java b/cn-admin/src/main/java/net/geedge/common/config/DataSourceConfig.java new file mode 100644 index 0000000..232a95d --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/DataSourceConfig.java @@ -0,0 +1,127 @@ +package net.geedge.common.config; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.support.DefaultTransactionDefinition; + +import com.alibaba.druid.pool.DruidDataSource; +import net.geedge.common.utils.Tool; + +import cn.hutool.log.Log; + +@Configuration +public class DataSourceConfig { + + private static final Log log = Log.get(); + + @Value("${database.host}") + private String databaseHost; + @Value("${database.port:3306}") + private int databasePort; + @Value("${database.name}") + private String databaseName; + @Value("${database.user}") + private String databaseUser; + @Value("${database.pin}") + private String databasePin; + @Value("${mybatis-plus.mapper-locations}") + private String mapperLocation; + + + /** + * 数据源配置项 + */ + @Value("${spring.datasource.druid.driver-class-name:com.mysql.jdbc.Driver}") + private String driver; + @Value("${spring.datasource.druid.url-pattern:jdbc:mysql://{{host}}:{{port}}/{{dbName}}?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false}") + private String urlPattern; + @Value("${spring.datasource.druid.initial-size:10}") + private int initialSize; + @Value("${spring.datasource.druid.max-active:100}") + private int dbMaxActive; + @Value("${spring.datasource.druid.min-idle:5}") + private int dbMinIdle; + @Value("${spring.datasource.druid.max-wait:60000}") + private int dbMaxWait; + @Value("${spring.datasource.druid.pool-prepared-statements:true}") + private boolean poolPreparedStatements; + @Value("${spring.datasource.druid.validation-query:SELECT 1}") + private String validationQuery; + + + /** + * 创建自定义数据源 + * @return + */ + @Bean + public DataSource dataSource() { + if(!Tool.StrUtil.isAllNotBlank(this.databaseHost,this.databaseUser,this.databaseName)) { + return null; + } + log.info("datasource config,user:{}, url: {}",this.databaseUser,this.getDbUrl()); + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setUrl(this.getDbUrl()); + dataSource.setUsername(this.databaseUser); + dataSource.setPassword(this.databasePin); + dataSource.setDriverClassName(this.driver); + dataSource.setInitialSize(this.initialSize); + dataSource.setMaxActive(this.dbMaxActive); + dataSource.setMinIdle(this.dbMinIdle); + dataSource.setMaxWait(this.dbMaxWait); + dataSource.setPoolPreparedStatements(this.poolPreparedStatements); + dataSource.setValidationQuery(this.validationQuery); + return dataSource; + } + + /** 返回data数据库的事务 + * @param ds + * @return + **/ + @Configuration + static class DataSourceTransactionManagerConfiguration { + + private final DataSource dataSource; + + private final TransactionManagerCustomizers transactionManagerCustomizers; + + DataSourceTransactionManagerConfiguration(DataSource dataSource, + ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) { + this.dataSource = dataSource; + this.transactionManagerCustomizers = transactionManagerCustomizers + .getIfAvailable(); + } + + @Bean + public TransactionDefinition transactionDefinition() { + return new DefaultTransactionDefinition(); + } + + @Bean + public DataSourceTransactionManager transactionManager() { + DataSourceTransactionManager transactionManager = new DataSourceTransactionManager( + this.dataSource); + if (this.transactionManagerCustomizers != null) { + this.transactionManagerCustomizers.customize(transactionManager); + } + return transactionManager; + } + + } + + /** + * 获取数据库连接url + * @return + */ + private String getDbUrl() { + return this.urlPattern.replace("{{host}}", this.databaseHost) + .replace("{{port}}", String.valueOf(this.databasePort)) + .replace("{{dbName}}", this.databaseName); + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/config/FilterConfig.java b/cn-admin/src/main/java/net/geedge/common/config/FilterConfig.java new file mode 100644 index 0000000..86e5396 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/FilterConfig.java @@ -0,0 +1,50 @@ +/** + + * + + * + + */ + +package net.geedge.common.config; + +import net.geedge.common.xss.XssFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.DelegatingFilterProxy; + +import javax.servlet.DispatcherType; + +/** + * Filter配置 + * + + */ +@SuppressWarnings("all") +@Configuration +public class FilterConfig { + + @Bean + public FilterRegistrationBean shiroFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new DelegatingFilterProxy("shiroFilter")); + //该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 + registration.addInitParameter("targetFilterLifecycle", "true"); + registration.setEnabled(true); + registration.setOrder(Integer.MAX_VALUE - 1); + registration.addUrlPatterns("/*"); + return registration; + } + + @Bean + public FilterRegistrationBean xssFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setFilter(new XssFilter()); + registration.addUrlPatterns("/*"); + registration.setName("xssFilter"); + registration.setOrder(Integer.MAX_VALUE); + return registration; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/config/FlywayConfig.java b/cn-admin/src/main/java/net/geedge/common/config/FlywayConfig.java new file mode 100644 index 0000000..3c2a9f3 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/FlywayConfig.java @@ -0,0 +1,68 @@ +package net.geedge.common.config; + +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.log.Log; +import org.flywaydb.core.Flyway; +import org.flywaydb.core.api.FlywayException; +import org.flywaydb.core.api.configuration.FluentConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; + +import javax.annotation.PostConstruct; +import javax.sql.DataSource; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.util.HashMap; +import java.util.Map; + +@Configuration +@DependsOn(value = {"dataSourceConfig"}) +public class FlywayConfig { + + private static Log log = Log.get(); + + @Autowired + private DataSource dataSource; + + @Autowired + private FlywayProperties flywayProperties; + + @PostConstruct + public void migrate() { + + if (!flywayProperties.getEnabled()) { + return; + } + + Map<String, String> map = new HashMap<String, String>(); + try { + BeanInfo beanInfo = Introspector.getBeanInfo(flywayProperties.getClass()); + PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + for (PropertyDescriptor property : propertyDescriptors) { + String key = property.getName(); + if (!"class".equals(key) && !"enabled".equals(key)) { + //Method getter = property.getReadMethod(); + //Object value = getter.invoke(flywayProperties); + Object value = ReflectUtil.invoke(flywayProperties, property.getReadMethod(), key); + map.put("flyway." + key, value.toString()); + } + } + } catch (IntrospectionException e) { + log.error("flyway执行脚本失败", e); + } + + FluentConfiguration configure = Flyway.configure(); + configure.dataSource(dataSource); + configure.configuration(map); + Flyway flyway = configure.load(); + try { + flyway.migrate(); + } catch (FlywayException e) { + flyway.repair(); + log.error("flyway执行脚本失败", e); + } + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/config/FlywayProperties.java b/cn-admin/src/main/java/net/geedge/common/config/FlywayProperties.java new file mode 100644 index 0000000..89d1aa0 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/FlywayProperties.java @@ -0,0 +1,37 @@ +package net.geedge.common.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "spring.flyway") +public class FlywayProperties { + + private boolean enabled; + + private String encoding; + + private String sqlMigrationPrefix; + + private String sqlMigrationSeparator; + + private boolean baselineOnMigrate; + + private String locations; + + private boolean cleanDisabled; + + private boolean validateOnMigrate; + + private boolean placeholderReplacement; + + public boolean getEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/config/FreemarkerConfig.java b/cn-admin/src/main/java/net/geedge/common/config/FreemarkerConfig.java new file mode 100644 index 0000000..abc9954 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/FreemarkerConfig.java @@ -0,0 +1,55 @@ +/** + + * + + * + + */ + +package net.geedge.common.config; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.shiro.ShiroTag; + +import cn.hutool.log.Log; + +/** + * Freemarker配置 + * + * + */ +@Configuration +public class FreemarkerConfig { + private static Log log = Log.get(); + + @Value("${cn.ui.path:static}") + private String uiPath; + + @Bean + public FreeMarkerConfigurer freeMarkerConfigurer(ShiroTag shiroTag) { + FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); + boolean exist = Tool.FileUtil.exist(uiPath); + uiPath = exist ? uiPath : "classpath:" + uiPath; + log.info("static file path : {} ", uiPath); + configurer.setTemplateLoaderPath(uiPath); + Map<String, Object> variables = new HashMap<>(1); + variables.put("shiro", shiroTag); + configurer.setFreemarkerVariables(variables); + + Properties settings = new Properties(); + settings.setProperty("default_encoding", "utf-8"); + settings.setProperty("number_format", "0.##"); + configurer.setFreemarkerSettings(settings); + return configurer; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/config/I18nConfig.java b/cn-admin/src/main/java/net/geedge/common/config/I18nConfig.java new file mode 100644 index 0000000..8aaab78 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/I18nConfig.java @@ -0,0 +1,125 @@ +package net.geedge.common.config; + +import cn.hutool.log.Log; +import net.geedge.common.smartvalidate.utils.CommonUtil; +import net.geedge.common.utils.Constant; +import net.geedge.modules.sys.entity.SysI18nEntity; +import net.geedge.modules.sys.service.SysDictService; +import net.geedge.modules.sys.service.SysI18nService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.context.support.AbstractMessageSource; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +@Service("messageSource") +public class I18nConfig extends AbstractMessageSource implements ResourceLoaderAware { + + private ResourceLoader resourceLoader; + + @Autowired + SysI18nService sysI18nService; + @Autowired + SysDictService sysDictService; + + private final Log logger = Log.get(); + + /** + * 国际化缓存 + */ + public static final Map<String, Map<String, String>> I18N_CACHE = new HashMap<>(); + /** + * 初始化 + */ + @PostConstruct + public void init() { + this.reload(); + } + + /** + * 重新将数据库中的国际化配置加载 + */ + public void reload() { + I18N_CACHE.clear(); + } + + /** + * 从数据库中获取所有国际化配置 + */ + public void loadAllMessageResourcesFromDB() { + List<SysI18nEntity> list = sysI18nService.queryAll(); + if (!CommonUtil.isNull(list)) { + if (CommonUtil.isNull(Constant.langList)) { //语言种类列表 + sysDictService.updateLangCache(); + } +// try { + for (Map<String, String> l : Constant.langList) { + Map<String, String> langMap = I18N_CACHE.get(l.get("value")); + if (CommonUtil.isNull(langMap)) { + langMap = new HashMap<String, String>(); + I18N_CACHE.put(l.get("value"), langMap); + } + for (SysI18nEntity s : list) { + if (l.get("value").equals(s.getLang())) { + langMap.put(s.getCode(), s.getValue()); + } + } + } +/* } catch (Exception e) { + logger.error(e); + }*/ + } + } + + /** + * 从缓存中取出国际化配置对应的数据 或者从父级获取 + * + * @param code + * @param locale + * @return + */ + public String getSourceFromCache(String code, Locale locale) { + String language = locale.getLanguage(); + if (CommonUtil.isNull(I18N_CACHE)) { + loadAllMessageResourcesFromDB(); + } + Map<String, String> props = I18N_CACHE.get(language); + if (null != props && props.containsKey(code)) { + return props.get(code); + } else { +// try { + if (null != this.getParentMessageSource()) { + return this.getParentMessageSource().getMessage(code, null, locale); + } + /* } catch (Exception ex) { + logger.error(ex); + }*/ + return code; + } + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = (resourceLoader == null ? new DefaultResourceLoader() : resourceLoader); + } + + @Override + protected MessageFormat resolveCode(String code, Locale locale) { + String msg = getSourceFromCache(code, locale); + MessageFormat messageFormat = new MessageFormat(msg, locale); + return messageFormat; + } + + @Override + protected String resolveCodeWithoutArguments(String code, Locale locale) { + return getSourceFromCache(code, locale); + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/config/KaptchaConfig.java b/cn-admin/src/main/java/net/geedge/common/config/KaptchaConfig.java new file mode 100644 index 0000000..a7ad65b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/KaptchaConfig.java @@ -0,0 +1,39 @@ +/** + + * + + * + + */ + +package net.geedge.common.config; + +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; + + +/** + * 生成验证码配置 + * + + */ +@Configuration +public class KaptchaConfig { + + @Bean + public DefaultKaptcha producer() { + Properties properties = new Properties(); + properties.put("kaptcha.border", "no"); + properties.put("kaptcha.textproducer.font.color", "black"); + properties.put("kaptcha.textproducer.char.space", "5"); + properties.put("kaptcha.textproducer.font.names", "Arial,Courier,cmr10,宋体,楷体,微软雅黑"); + Config config = new Config(properties); + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/config/LocaleConfig.java b/cn-admin/src/main/java/net/geedge/common/config/LocaleConfig.java new file mode 100644 index 0000000..dab2780 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/LocaleConfig.java @@ -0,0 +1,93 @@ +package net.geedge.common.config; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.log.Log; +import net.geedge.common.smartvalidate.utils.CommonUtil; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.ObjectUtils; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; +import org.springframework.web.servlet.support.RequestContextUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Locale; + +@Configuration +@EnableAutoConfiguration +@ComponentScan +public class LocaleConfig implements WebMvcConfigurer { + + @Bean + public LocaleResolver localeResolver() { + SessionLocaleResolver slr = new SessionLocaleResolver(); + // 默认语言 + slr.setDefaultLocale(new Locale("en")); + return slr; + } + + @Bean + public LocaleChangeInterceptor localeChangeInterceptor() { + MyI18nInterceptor lci = new MyI18nInterceptor(); + // 参数名 + lci.setParamName("_lang"); + return lci; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(localeChangeInterceptor()); + } +} + +class MyI18nInterceptor extends LocaleChangeInterceptor { + private Log log = Log.get(); + private boolean validateHttpMethod(String currentMethod) { + String[] configuredMethods = getHttpMethods(); + if (ObjectUtils.isEmpty(configuredMethods)) { + return true; + } + for (String configuredMethod : configuredMethods) { + if (configuredMethod.equalsIgnoreCase(currentMethod)) { + return true; + } + } + return false; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + String newLocale = request.getParameter(getParamName()); + if (newLocale != null) { + if (validateHttpMethod(request.getMethod())) { + LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request); + if (localeResolver == null) { + throw new IllegalStateException("找不到LocaleResolver"); + } + try { + localeResolver.setLocale(request, response, parseLocaleValue(newLocale)); + // 若语言和session中记录的值不同了,刷新session中的值 + String currLang = (String) request.getSession().getAttribute(getParamName()); + if (CommonUtil.isNull(currLang) || !StrUtil.equals(currLang,newLocale)) { + request.getSession().setAttribute(getParamName(), newLocale); + } + } + catch (IllegalArgumentException ex) { + if (isIgnoreInvalidLocale()) { + log.debug("忽略无效的locale值 [" + newLocale + "]: " + ex); + } + else { + throw ex; + } + } + } + } + return true; + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/config/MybatisPlusConfig.java b/cn-admin/src/main/java/net/geedge/common/config/MybatisPlusConfig.java new file mode 100644 index 0000000..607312a --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/MybatisPlusConfig.java @@ -0,0 +1,237 @@ +package net.geedge.common.config; + +import cn.hutool.log.Log; +import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties; +import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS; +import com.baomidou.mybatisplus.core.MybatisConfiguration; +import com.baomidou.mybatisplus.core.config.GlobalConfig; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; +import com.baomidou.mybatisplus.core.injector.ISqlInjector; +import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.mapping.DatabaseIdProvider; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.mapper.ClassPathMapperScanner; +import org.mybatis.spring.mapper.MapperFactoryBean; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.context.annotation.*; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import javax.sql.DataSource; +import java.util.List; + +/** + * mybatis-plus 初始化配置 + */ +@Configuration +@DependsOn(value = { "flywayConfig" }) +@EnableConfigurationProperties(MybatisPlusProperties.class) +public class MybatisPlusConfig { + + public MybatisPlusConfig(MybatisPlusProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, + ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, + ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider, + ApplicationContext applicationContext) { + this.properties = properties; + this.interceptors = interceptorsProvider.getIfAvailable(); + this.resourceLoader = resourceLoader; + this.databaseIdProvider = databaseIdProvider.getIfAvailable(); + this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable(); + this.applicationContext = applicationContext; + } + + private static final Log logger = Log.get(); + + private final MybatisPlusProperties properties; + + private final Interceptor[] interceptors; + + private final ResourceLoader resourceLoader; + + private final DatabaseIdProvider databaseIdProvider; + + private final List<ConfigurationCustomizer> configurationCustomizers; + + private final ApplicationContext applicationContext; + + @PostConstruct + public void checkConfigFileExists() { + if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) { + Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation()); + Assert.state(resource.exists(), "Cannot find config location: " + resource + + " (please add config file or check your Mybatis configuration)"); + } + } + + @Bean + @ConditionalOnMissingBean + public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { + MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); + factory.setDataSource(dataSource); + factory.setVfs(SpringBootVFS.class); + if (StringUtils.hasText(this.properties.getConfigLocation())) { + factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); + } + applyConfiguration(factory); + if (this.properties.getConfigurationProperties() != null) { + factory.setConfigurationProperties(this.properties.getConfigurationProperties()); + } + if (!ObjectUtils.isEmpty(this.interceptors)) { + factory.setPlugins(this.interceptors); + } + if (this.databaseIdProvider != null) { + factory.setDatabaseIdProvider(this.databaseIdProvider); + } + if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { + factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); + } + // TODO 自定义枚举包 + if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) { + factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage()); + } + if (this.properties.getTypeAliasesSuperType() != null) { + factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType()); + } + if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { + factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); + } + if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { + factory.setMapperLocations(this.properties.resolveMapperLocations()); + } + // TODO 此处必为非 NULL + GlobalConfig globalConfig = this.properties.getGlobalConfig(); + // 注入填充器 + if (this.applicationContext.getBeanNamesForType(MetaObjectHandler.class, false, false).length > 0) { + MetaObjectHandler metaObjectHandler = this.applicationContext.getBean(MetaObjectHandler.class); + globalConfig.setMetaObjectHandler(metaObjectHandler); + } + // 注入主键生成器 + if (this.applicationContext.getBeanNamesForType(IKeyGenerator.class, false, false).length > 0) { + IKeyGenerator keyGenerator = this.applicationContext.getBean(IKeyGenerator.class); + globalConfig.getDbConfig().setKeyGenerator(keyGenerator); + } + // 注入sql注入器 + if (this.applicationContext.getBeanNamesForType(ISqlInjector.class, false, false).length > 0) { + ISqlInjector iSqlInjector = this.applicationContext.getBean(ISqlInjector.class); + globalConfig.setSqlInjector(iSqlInjector); + } + factory.setGlobalConfig(globalConfig); + return factory.getObject(); + } + + private void applyConfiguration(MybatisSqlSessionFactoryBean factory) { + MybatisConfiguration configuration = this.properties.getConfiguration(); + if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { + configuration = new MybatisConfiguration(); + } + if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { + for (ConfigurationCustomizer customizer : this.configurationCustomizers) { + customizer.customize(configuration); + } + } + factory.setConfiguration(configuration); + } + + @Bean + @ConditionalOnMissingBean + public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { + ExecutorType executorType = this.properties.getExecutorType(); + if (executorType != null) { + return new SqlSessionTemplate(sqlSessionFactory, executorType); + } else { + return new SqlSessionTemplate(sqlSessionFactory); + } + } + + /** + * This will just scan the same base package as Spring Boot does. If you want + * more power, you can explicitly use + * {@link org.mybatis.spring.annotation.MapperScan} but this will get typed + * mappers working correctly, out-of-the-box, similar to using Spring Data JPA + * repositories. + */ + public static class AutoConfiguredMapperScannerRegistrar + implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware { + + private BeanFactory beanFactory; + + private ResourceLoader resourceLoader; + + @Override + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, + BeanDefinitionRegistry registry) { + + logger.debug("Searching for mappers annotated with @Mapper"); + + ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); + + try { + if (this.resourceLoader != null) { + scanner.setResourceLoader(this.resourceLoader); + } + + List<String> packages = AutoConfigurationPackages.get(this.beanFactory); + if (logger.isDebugEnabled()) { + packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg)); + } + + scanner.setAnnotationClass(Mapper.class); + scanner.registerFilters(); + scanner.doScan(StringUtils.toStringArray(packages)); + } catch (IllegalStateException ex) { + logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex); + } + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + } + + /** + * {@link org.mybatis.spring.annotation.MapperScan} ultimately ends up creating + * instances of {@link MapperFactoryBean}. If + * {@link org.mybatis.spring.annotation.MapperScan} is used then this + * auto-configuration is not needed. If it is _not_ used, however, then this + * will bring in a bean registrar and automatically register components based on + * the same component-scanning path as Spring Boot itself. + */ + @Configuration + @Import({ AutoConfiguredMapperScannerRegistrar.class }) + @ConditionalOnMissingBean(MapperFactoryBean.class) + public static class MapperScannerRegistrarNotFoundConfiguration { + + @PostConstruct + public void afterPropertiesSet() { + logger.debug("No {} found.", MapperFactoryBean.class.getName()); + } + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/config/MybatisPlusPluginsConfig.java b/cn-admin/src/main/java/net/geedge/common/config/MybatisPlusPluginsConfig.java new file mode 100644 index 0000000..484788f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/MybatisPlusPluginsConfig.java @@ -0,0 +1,31 @@ +package net.geedge.common.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; + +import com.baomidou.mybatisplus.core.injector.ISqlInjector; +import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector; +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; + +/** + * mybatis-plus 插件配置 + */ +@Configuration +@DependsOn(value = {"flywayConfig"}) +public class MybatisPlusPluginsConfig { + + /** + * 分页插件 + */ + @Bean + public PaginationInterceptor paginationInterceptor() { + return new PaginationInterceptor(); + } + + @Bean + public ISqlInjector sqlInjector() { + return new LogicSqlInjector(); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/config/RedisConfig.java b/cn-admin/src/main/java/net/geedge/common/config/RedisConfig.java new file mode 100644 index 0000000..2807613 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/RedisConfig.java @@ -0,0 +1,130 @@ +package net.geedge.common.config; + +import java.net.UnknownHostException; +import java.time.Duration; + +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; + +import net.geedge.common.utils.Tool; + +import cn.hutool.log.Log; +import lombok.Data; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * redis 初始化配置 + * @author fang + * + */ +@Configuration +@Data +public class RedisConfig { + + private static final Log log = Log.get(); + + @Value("${redis.host}") + private String redisHost; + @Value("${redis.port:6379}") + private int redisPort; + @Value("${redis.database:0}") + private int redisDatabase; + @Value("${redis.pin}") + private String redisPin; + @Value("${cn.inited:0}") + private int inited; + /** + * redis配置项 + */ + @Value("${spring.redis.jedis.pool.max-idle:10}") + private int maxIdle; + @Value("${spring.redis.jedis.pool.min-idle:3}") + private int minIdle; + @Value("${spring.redis.jedis.pool.max-wait:100000}") + private int maxWait; + @Value("${spring.redis.jedis.pool.max-active:100}") + private int maxActive; + @Value("${spring.redis.timeout:100000}") + private long redisTimeout; + + + @Bean(name = "redisConnectionFactory") + public RedisConnectionFactory redisConnectionFactory() { + if(!Tool.ObjectUtil.isAllNotEmpty(this.getRedisHost(),this.getRedisPort(),this.getRedisDatabase())) { + return null; + } + log.info("redis config: {}:{}/{}",this.getRedisHost(),this.getRedisPort(),this.getRedisDatabase()); + RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(); + configuration.setDatabase(this.getRedisDatabase()); + configuration.setHostName(this.getRedisHost()); + configuration.setPort(this.getRedisPort()); + if(Tool.StrUtil.isNotBlank(this.getRedisPin())) { + configuration.setPassword(this.getRedisPin()); + } + GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); + poolConfig.setMinIdle(this.getMinIdle()); + poolConfig.setMaxIdle(this.getMaxIdle()); + poolConfig.setMaxTotal(this.getMaxActive()); + poolConfig.setMaxWaitMillis(this.getMaxWait()); + + LettucePoolingClientConfiguration lettucePoolingClientConfiguration = LettucePoolingClientConfiguration.builder() + .commandTimeout(Duration.ofMillis(this.getRedisTimeout())) + .shutdownTimeout(Duration.ZERO) + .poolConfig(poolConfig) + .build(); + + RedisConnectionFactory factory = new LettuceConnectionFactory(configuration, lettucePoolingClientConfiguration); + return factory; + } + + + @Bean(name = "redisTemplate") + public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { + RedisTemplate<?, ?> template = new RedisTemplate<>(); + + template.setKeySerializer(new StringRedisSerializer()); + template.setHashKeySerializer(new StringRedisSerializer()); + template.setHashValueSerializer(new StringRedisSerializer()); + template.setValueSerializer(new StringRedisSerializer()); + template.setConnectionFactory(redisConnectionFactory); + template.afterPropertiesSet(); + template.execute(new RedisCallback<Object>() { + + @Override + public Object doInRedis(RedisConnection connection) throws DataAccessException { + String ping = connection.ping(); + if(Tool.StrUtil.isBlank(ping)) { + log.error("redis connetion error"); + } + return null; + } + }); + return template; + } + + @Bean(name = "stringRedisTemplate") + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { + StringRedisTemplate template = new StringRedisTemplate(); + template.setKeySerializer(new StringRedisSerializer()); + template.setHashKeySerializer(new StringRedisSerializer()); + template.setHashValueSerializer(new StringRedisSerializer()); + template.setValueSerializer(new StringRedisSerializer()); + template.setConnectionFactory(redisConnectionFactory); + template.afterPropertiesSet(); + return template; + } + +} + + diff --git a/cn-admin/src/main/java/net/geedge/common/config/SetupRunner.java b/cn-admin/src/main/java/net/geedge/common/config/SetupRunner.java new file mode 100644 index 0000000..6234da1 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/SetupRunner.java @@ -0,0 +1,80 @@ +package net.geedge.common.config; + +import java.io.File; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.entity.SysUserEntity; +import net.geedge.modules.sys.service.SysConfigService; +import net.geedge.modules.sys.service.SysUserService; +import net.geedge.modules.sys.shiro.ShiroUtils; +import net.geedge.setup.entity.SetupEntity; + +import cn.hutool.log.Log; +import cn.hutool.setting.dialect.Props; + +/** + * setup初始化操作 + * @author fang + * + */ +@Component +public class SetupRunner implements CommandLineRunner{ + private static final Log log = Log.get(); + @Value("${cn.inited}") + private int inited; + + @Value("${cn.adminId:1}") + private String adminId; + + @Value("${server.tomcat.basedir}") + private String tmpDir; + @Value("${cn.config.path:./config/cn.properties}") + private String nezhaConfigPath; + + @Autowired + SysConfigService sysConfigService; + + @Autowired + SysUserService sysUserService; + + @Override + public void run(String... args) throws Exception { + if( inited != 1) { + log.debug(" inited = {} ,skip init setup", inited); + return ; + } + File file = Tool.FileUtil.file(tmpDir, Constant.SETUP_FILE_NAME); + log.debug("file path: {}",file.getAbsoluteFile()); + if(file.exists()) { + log.info("start inited setup"); + String jsonStr = Tool.FileUtil.readUtf8String(file); + SetupEntity setupEntity = Tool.JSONUtil.toBean(jsonStr, SetupEntity.class); + sysConfigService.updateValueByKey("alert_api",setupEntity.getSystem().getAlertPath()); +// sysConfigService.updateValueByKey("alert_path_prefix",setupEntity.getSystem().getAlertPrefix()); + sysConfigService.updateValueByKey("prometheus_federation_enabled",setupEntity.getSystem().getFederationEnabled()); + log.info("update db config"); + SysUserEntity sysUser = sysUserService.getById(adminId); + sysUser.setId(Long.parseLong(adminId)); + sysUser.setUsername(setupEntity.getSystem().getUsername()); + sysUser.setPin(ShiroUtils.sha256(setupEntity.getSystem().getPin(), sysUser.getSalt())); + log.info("update admin user"); + sysUserService.updateById(sysUser); + Tool.FileUtil.del(file);//删除临时配置文件 + } + //配置文件 + boolean absolutePath = Tool.FileUtil.isAbsolutePath(nezhaConfigPath); + File configFile = absolutePath ? Tool.FileUtil.file(nezhaConfigPath) : Tool.FileUtil.file(Tool.WebPathUtil.getRootPath(),nezhaConfigPath); + //更改 cn.inited 为 2,下次启动时不再执行 + //cn.properties 配置文件路径:./config/cn.properties + Props prop = new Props(configFile, Constant.DEFAULT_CHARTSET_NAME); + prop.put("cn.inited", "2"); + prop.store(configFile.getAbsolutePath()); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/config/ShiroConfig.java b/cn-admin/src/main/java/net/geedge/common/config/ShiroConfig.java new file mode 100644 index 0000000..6f5b856 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/ShiroConfig.java @@ -0,0 +1,230 @@ +package net.geedge.common.config; + +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.servlet.Filter; + +import org.apache.catalina.connector.Connector; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.session.mgt.SessionManager; +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; +import org.crazycake.shiro.RedisCacheManager; +import org.crazycake.shiro.RedisManager; +import org.crazycake.shiro.RedisSessionDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.data.redis.core.RedisTemplate; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; + +import cn.hutool.core.util.StrUtil; +import net.geedge.common.interceptor.TokenCheckFilter; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.dao.SysApiKeyDao; +import net.geedge.modules.sys.dao.SysUserDao; +import net.geedge.modules.sys.entity.SysConfigEntity; +import net.geedge.modules.sys.service.SysConfigService; +import net.geedge.modules.sys.shiro.MySessionManager; +import net.geedge.modules.sys.shiro.ShiroUtils; +import net.geedge.modules.sys.shiro.UserRealm; + +/** + * Shiro的配置文件 + * + */ +@Configuration +@DependsOn(value = { "mybatisPlusConfig", "redisConfig" }) +public class ShiroConfig { + + @Autowired + private RedisConfig config; + + @Autowired + private RedisTemplate<String, String> redisTemplate; + + @Autowired + private SysUserDao sysUserDao; + + @Autowired + private SysConfigService sysconfigService; + + @Autowired + private SysApiKeyDao sysApiKeyDao; + + @Bean("shiroFilter") + public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { + ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); + shiroFilter.setSecurityManager(securityManager); + shiroFilter.setLoginUrl("/sys/login"); + shiroFilter.setUnauthorizedUrl("/"); + + Map<String, String> filterMap = new LinkedHashMap<>(); + filterMap.put("/metrics", "anon"); + filterMap.put("/prometheus", "anon"); + filterMap.put("/prom/**", "anon"); + filterMap.put("/swagger/**", "anon"); + filterMap.put("/v2/api-docs", "anon"); + filterMap.put("/swagger-ui.html", "anon"); + filterMap.put("/webjars/**", "anon"); + filterMap.put("/swagger-resources/**", "anon"); +// filterMap.put("/statics/**", "anon"); + filterMap.put("/static/**", "anon"); + filterMap.put("/cn/**", "anon"); + filterMap.put("/", "anon"); + filterMap.put("/config.json", "anon"); + filterMap.put("/index.html", "anon"); + filterMap.put("/login.html", "anon"); + filterMap.put("/sys/login", "anon"); + filterMap.put("/healthy", "anon"); + filterMap.put("/buildInfo", "anon"); +// filterMap.put("/logout","anon"); + filterMap.put("/favicon.ico", "anon"); + filterMap.put("/captcha.jpg", "anon"); + filterMap.put("/api/**", "anon"); + filterMap.put("/terminal.ws", "anon"); + filterMap.put("/terminal/monitor.ws", "anon"); + filterMap.put("/sys/license/**", "anon");// license 相关接口 + filterMap.put("/setup/**", "anon");// license 相关接口 +// filterMap.put("/**", "authc"); + filterMap.put("/**", "tokenCheckFilter"); + + Integer loginExpiration = getTimeOutData(); + Map<String, Filter> cumstomFilterMap = new LinkedHashMap<String, Filter>(); + TokenCheckFilter tokenCheckFilter = new TokenCheckFilter(redisTemplate, loginExpiration, sysUserDao, + sysApiKeyDao); + cumstomFilterMap.put("tokenCheckFilter", tokenCheckFilter); + shiroFilter.setFilters(cumstomFilterMap); + shiroFilter.setFilterChainDefinitionMap(filterMap); + + return shiroFilter; + } + + @Bean + @ConditionalOnExpression("${cn.shiroPermisSupport:true}") + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { + AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); + advisor.setSecurityManager(securityManager); + return advisor; + } + + @Bean(name = { "tomcatServletWebServerFactory" }) + public ConfigurableServletWebServerFactory webServerFactory() { + TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); + factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { + @Override + public void customize(Connector connector) { + connector.setProperty("relaxedPathChars", "\"<>[\\]^`{|}"); + + connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}"); + } + }); + + return factory; + } + + /** + * 配置shiro redisManager 使用的是shiro-redis开源插件 + * + * @return + */ + public RedisManager redisManager() { + RedisManager redisManager = new RedisManager(); + redisManager.setHost(config.getRedisHost() + ":" + config.getRedisPort()); + redisManager.setTimeout(Tool.NumberUtil.parseInt(Tool.StrUtil.toString(config.getRedisTimeout()))); + redisManager.setDatabase(config.getRedisDatabase()); + if (Tool.StrUtil.isNotBlank(config.getRedisPin())) { + redisManager.setPassword(config.getRedisPin()); + } + return redisManager; + } + + /** + * cacheManager 缓存 redis实现 使用的是shiro-redis开源插件 + * + * @return + */ + @Bean + public RedisCacheManager cacheManager() { + Integer loginExpiration = getTimeOutData(); + RedisCacheManager redisCacheManager = new RedisCacheManager(); + redisCacheManager.setRedisManager(redisManager()); + // 配置缓存过期时间 + redisCacheManager.setExpire(loginExpiration * 60); + redisCacheManager.setKeyPrefix(ShiroUtils.REDIS_KEYPREFIX); + // user entity ID + redisCacheManager.setPrincipalIdFieldName("userId"); + return redisCacheManager; + } + + /** + * RedisSessionDAO shiro sessionDao层的实现 通过redis 使用的是shiro-redis开源插件 + */ + @Bean + public RedisSessionDAO redisSessionDAO() { + Integer loginExpiration = getTimeOutData(); + RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); + redisSessionDAO.setRedisManager(redisManager()); + redisSessionDAO.setExpire(loginExpiration * 60); + redisSessionDAO.setKeyPrefix(ShiroUtils.REDIS_KEYPREFIX); + return redisSessionDAO; + } + + /** + * 身份认证realm; (这个需要自己写,账号密码校验;权限等) + * + * @return + */ + @Bean + public UserRealm myShiroRealm() { + UserRealm myShiroRealm = new UserRealm(); + // 关闭 cache + myShiroRealm.setCachingEnabled(false); + return myShiroRealm; + } + + /** + * 自定义 sessionManager + * + * @return + */ + @Bean + public SessionManager sessionManager() { + MySessionManager mySessionManager = new MySessionManager(); + mySessionManager.setSessionDAO(redisSessionDAO()); + return mySessionManager; + } + + @Bean + public SecurityManager securityManager() { + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); + // 设置realm. + securityManager.setRealm(myShiroRealm()); + // 自定义缓存实现 使用redis + securityManager.setCacheManager(cacheManager()); + // 自定义session管理 使用redis + securityManager.setSessionManager(sessionManager()); + return securityManager; + } + + private Integer getTimeOutData() { + SysConfigEntity configEntity = sysconfigService.getOne(new QueryWrapper<SysConfigEntity>().lambda() + .eq(SysConfigEntity::getParamKey, Constant.SYSCONFIG_SESSION_TIMEOUT_KEY)); + Integer loginExpiration = 30; + if (Tool.ObjectUtil.isNotEmpty(configEntity)) { + loginExpiration = StrUtil.isNotBlank(configEntity.getParamValue()) + ? Integer.valueOf(configEntity.getParamValue()) + : loginExpiration; + } + return loginExpiration; + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/config/ShiroLifecycleBeanPostProcessorConfig.java b/cn-admin/src/main/java/net/geedge/common/config/ShiroLifecycleBeanPostProcessorConfig.java new file mode 100644 index 0000000..48be044 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/ShiroLifecycleBeanPostProcessorConfig.java @@ -0,0 +1,14 @@ +package net.geedge.common.config; + +import org.apache.shiro.spring.LifecycleBeanPostProcessor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ShiroLifecycleBeanPostProcessorConfig { + + @Bean("lifecycleBeanPostProcessor") + public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { + return new LifecycleBeanPostProcessor(); + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/config/WebConfig.java b/cn-admin/src/main/java/net/geedge/common/config/WebConfig.java new file mode 100644 index 0000000..3b6a5a2 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/config/WebConfig.java @@ -0,0 +1,89 @@ +/** + + * + + * + + */ + +package net.geedge.common.config; + +import java.sql.SQLException; +import java.util.Properties; + +import org.apache.ibatis.mapping.DatabaseIdProvider; +import org.apache.ibatis.mapping.VendorDatabaseIdProvider; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import net.geedge.common.interceptor.LicenseInterceptor; +import net.geedge.common.interceptor.SysMenuInterceptor; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.SQLUtils; +import net.geedge.common.utils.SpringContextUtils; +import net.geedge.common.utils.SqlHelper.MysqlHelper; +import net.geedge.common.utils.SqlHelper.OracleHelper; +import net.geedge.common.utils.SqlHelper.PostgresqlHelper; +import net.geedge.modules.sys.service.SysConfigService; + +/** + * WebMvc配置 + * + + */ +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Bean + public DatabaseIdProvider getDatabaseIdProvider(){ + DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider(); + Properties properties = new Properties(); + properties.setProperty("Oracle","oracle"); + properties.setProperty("MySQL","mysql"); + properties.setProperty("DB2","db2"); + properties.setProperty("Derby","derby"); + properties.setProperty("H2","h2"); + properties.setProperty("HSQL","hsql"); + properties.setProperty("Informix","informix"); + properties.setProperty("MS-SQL","ms-sql"); + properties.setProperty("PostgreSQL","postgresql"); + properties.setProperty("Sybase","sybase"); + properties.setProperty("Hana","hana"); + databaseIdProvider.setProperties(properties); + + return databaseIdProvider; + } + @Bean + public SQLUtils getSqlUtils() throws SQLException { + switch (Constant.DB_TYPE){ + case Constant.MYSQL: + return new MysqlHelper(); + case Constant.POSTGRESQL: + return new PostgresqlHelper(); + case Constant.ORACLE: + return new OracleHelper(); + default: + return new MysqlHelper(); + } + } + + /** + * license校验拦截器 + * @return + */ + @Bean + LicenseInterceptor licenseInterceptor() { + return new LicenseInterceptor(); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + //添加license 拦截器,排除 license 接口 + registry.addInterceptor(licenseInterceptor()).excludePathPatterns("/sys/license/**","/api/v1/alerts","/api/v2/alerts","/setup/**"); + + SysConfigService sysConfigService = (SysConfigService) SpringContextUtils.getBean("sysConfigService"); + registry.addInterceptor(new SysMenuInterceptor(sysConfigService)).addPathPatterns("/sys/menu/**"); + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/exception/CNException.java b/cn-admin/src/main/java/net/geedge/common/exception/CNException.java new file mode 100644 index 0000000..99bf4b6 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/exception/CNException.java @@ -0,0 +1,68 @@ +/** + + * + + * + * + */ + +package net.geedge.common.exception; + +import net.geedge.common.utils.RCode; + +/** + * 自定义异常 + * + * @author Mark [email protected] + */ +public class CNException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private String msg; + private int code = RCode.ERROR.getCode(); + + public CNException(RCode rCode) { + this.code = rCode.getCode(); + this.msg = rCode.getMsg(); + + } + + public CNException(String msg) { + super(msg); + this.msg = msg; + } + + public CNException(String msg, Throwable e) { + super(msg, e); + this.msg = msg; + } + + public CNException(String msg, int code) { + super(msg); + this.msg = msg; + this.code = code; + } + + public CNException(String msg, int code, Throwable e) { + super(msg, e); + this.msg = msg; + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/exception/CNExceptionHandler.java b/cn-admin/src/main/java/net/geedge/common/exception/CNExceptionHandler.java new file mode 100644 index 0000000..cfda723 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/exception/CNExceptionHandler.java @@ -0,0 +1,62 @@ +/** + + * + + * + + */ + +package net.geedge.common.exception; + +import cn.hutool.log.Log; +import net.geedge.common.utils.R; +import net.geedge.common.utils.RCode; +import org.apache.shiro.authz.AuthorizationException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * 异常处理器 + * + + */ +@RestControllerAdvice +public class CNExceptionHandler { + private Log logger = Log.get(); + + /** + * 处理自定义异常 + */ + @ExceptionHandler(CNException.class) + @ResponseStatus(value=HttpStatus.BAD_REQUEST) + public R handleCNException(CNException e){ + R r = new R(); + r.put("code", e.getCode()); + r.put("msg", e.getMsg()); + return r; + } + + @ExceptionHandler(DuplicateKeyException.class) + @ResponseStatus(value=HttpStatus.BAD_REQUEST) + public R handleDuplicateKeyException(DuplicateKeyException e){ + logger.error(e); + return R.error(RCode.SYS_DB_DUPLICATERECORD); + } + + @ExceptionHandler(AuthorizationException.class) + @ResponseStatus(value=HttpStatus.UNAUTHORIZED) + public R handleAuthorizationException(AuthorizationException e){ + logger.error(e); + return R.error(RCode.SYS_DB_AUTH); + } + + @ExceptionHandler(Exception.class) + @ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR) + public R handleException(Exception e){ + logger.error(e); + return R.error().put("msg", e.getMessage()); + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/interceptor/ComplexPropertyPreFilter.java b/cn-admin/src/main/java/net/geedge/common/interceptor/ComplexPropertyPreFilter.java new file mode 100644 index 0000000..e0aab54 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/interceptor/ComplexPropertyPreFilter.java @@ -0,0 +1,108 @@ +package net.geedge.common.interceptor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.JSONSerializer; +import com.alibaba.fastjson.serializer.PropertyPreFilter; +import com.alibaba.fastjson.serializer.SerializerFeature; + +public class ComplexPropertyPreFilter implements PropertyPreFilter { + + private Map<Class<?>, List<String>> includes = new HashMap<>(); + private Map<Class<?>, List<String>> excludes = new HashMap<>(); + + static { + JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask(); + } + + public ComplexPropertyPreFilter() { + + } + + public ComplexPropertyPreFilter(Map<Class<?>, List<String>> includes) { + super(); + this.includes = includes; + } + + public boolean apply(JSONSerializer serializer, Object source, String name) { + + // 对象为空。直接放行 + if (source == null) { + return true; + } + + // 获取当前需要序列化的对象的类对象 + Class<?> clazz = source.getClass(); + + // 无需序列的对象、寻找需要过滤的对象,可以提高查找层级 + // 找到不需要的序列化的类型 + for (Map.Entry<Class<?>, List<String>> item : this.excludes.entrySet()) { + // isAssignableFrom(),用来判断类型间是否有继承关系 + if (item.getKey().isAssignableFrom(clazz)) { + List<String> strs = item.getValue(); + + // 该类型下 此 name 值无需序列化 + if (isHave(strs, name)) { + return false; + } + } + } + + // 需要序列的对象集合为空 表示 全部需要序列化 + if (this.includes.isEmpty()) { + return true; + } + + // 需要序列的对象 + // 找到不需要的序列化的类型 + for (Map.Entry<Class<?>, List<String>> item : this.includes.entrySet()) { + // isAssignableFrom(),用来判断类型间是否有继承关系 + if (item.getKey().isAssignableFrom(clazz)) { + List<String> strs = item.getValue(); + // 该类型下 此 name 值无需序列化 + if (isHave(strs, name)) { + return true; + } + } + } + + return false; + } + + /* + * 此方法有两个参数,第一个是要查找的字符串数组,第二个是要查找的字符或字符串 + */ + public static boolean isHave(List<String> strs, String s) { + + for (int i = 0; i < strs.size(); i++) { + // 循环查找字符串数组中的每个字符串中是否包含所有查找的内容 + if (strs.get(i).equals(s)) { + // 查找到了就返回真,不在继续查询 + return true; + } + } + + // 没找到返回false + return false; + } + + public Map<Class<?>, List<String>> getIncludes() { + return includes; + } + + public void setIncludes(Map<Class<?>, List<String>> includes) { + this.includes = includes; + } + + public Map<Class<?>, List<String>> getExcludes() { + return excludes; + } + + public void setExcludes(Map<Class<?>, List<String>> excludes) { + this.excludes = excludes; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/interceptor/LicenseInterceptor.java b/cn-admin/src/main/java/net/geedge/common/interceptor/LicenseInterceptor.java new file mode 100644 index 0000000..2007e1e --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/interceptor/LicenseInterceptor.java @@ -0,0 +1,27 @@ +package net.geedge.common.interceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import net.geedge.modules.sys.entity.LicenseEntity; +import net.geedge.modules.sys.service.LicenseService; +@Configuration +public class LicenseInterceptor extends HandlerInterceptorAdapter { + + @Autowired + private LicenseService licenseService; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + //获取license + LicenseEntity licenseEntity = licenseService.getAndSetLicenseCache(); + //验证并返回结果 + return licenseService.verify(licenseEntity); + } + +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/interceptor/ResultHandleInterceptor.java b/cn-admin/src/main/java/net/geedge/common/interceptor/ResultHandleInterceptor.java new file mode 100644 index 0000000..0b34914 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/interceptor/ResultHandleInterceptor.java @@ -0,0 +1,177 @@ +package net.geedge.common.interceptor; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.core.MethodParameter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.log.Log; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.R; +import net.geedge.common.utils.Tool; + +@ControllerAdvice +public class ResultHandleInterceptor implements ResponseBodyAdvice { + + private Log log =Log.get(); + + private static final String INCLUDE = "include"; + + private static final String EXCLUDE = "exclude"; + + @Override + public Object beforeBodyWrite(Object body, MethodParameter arg1, + MediaType arg2, Class arg3, ServerHttpRequest req, + ServerHttpResponse resp) { + if(!(body instanceof R)) { + return body; + } + log.debug("后端响应的数据信息为"+JSON.toJSONString(body)); + //如果响应值为空则无需过滤 + R result = (R)body; + Object object = result.get("data"); + if(Tool.ObjectUtil.isEmpty(object)) { + return body; + } + HttpHeaders headers = req.getHeaders(); + List<String> list = headers.get("Content-Fields"); + // 判断前端是否传入过滤字段信息 + if(Tool.ObjectUtil.isEmpty(list)) { + return body; + } + String contentFiled = list.get(0); + //处理获取map值对应include和exclude + Map<String, List<String>> map = this.contentFieldHandle(contentFiled); + try { + Object handleResponseData = handleResponseData(body,map); + return handleResponseData; + } catch (NoSuchFieldException e) { + log.error(e); + return body; + } catch (SecurityException e) { + log.error(e); + return body; + } + } + + @Override + public boolean supports(MethodParameter arg0, Class arg1) { + return true; + } + + public Map<String,List<String>> contentFieldHandle(String param){ + Map<String,List<String>> result = new HashMap<String,List<String>>(); + String[] split = StrUtil.split(param, ";"); + for(String s : split) { + String[] split2 = StrUtil.split(s, "="); + String fields = split2[1]; + List<String> filedList = StrUtil.split(fields, StrUtil.C_COMMA); + result.put(split2[0],filedList); + } + // include优先级高于exclude 去除exclude中间无用数值 + if(Tool.ObjectUtil.equals(result.size(), 2)) { + /*List<String> includeFields = (List<String>) result.get(INCLUDE); + List<String> excludeFields = (List<String>) result.get(EXCLUDE); + // 交集 + List<String> intersection = includeFields.stream().filter(item -> excludeFields.contains(item)).collect(toList()); + excludeFields.removeAll(intersection); + result.put(EXCLUDE, excludeFields);*/ + + // include 和 exclude互斥 所以有include 就可以忽视 exclude + result.remove(EXCLUDE); + } + return result; + } + + public Object handleResponseData(Object obj,Map<String,List<String>> map) throws NoSuchFieldException, SecurityException { + log.debug("handleResponseData 处理中"); + R r = (R)obj; + Object object = r.get("data"); + if(object instanceof PageUtils) { + PageUtils data = (PageUtils)object; + List<?> list = data.getList(); + Class c = list.get(0).getClass(); + List<Object> result = new ArrayList<Object>(); + for(Object param : list) { + Object res = filterFieldsJson(param,c,map); + result.add(res); + } + data.setList(result); + }else if(object instanceof Map){ + List<?> list = (List<?>) ((Map) object).get("list"); + Class c = list.get(0).getClass(); + List<Object> result = new ArrayList<Object>(); + for(Object param : list) { + Object res = filterFieldsJson(param,c,map); + result.add(res); + } + ((Map) object).put("list", result); + }else { + Class c = object.getClass(); + Object res = filterFieldsJson(object,c,map); + r.put("data", res); + } + return obj; + } + + + /** + * Description:过滤实体中的字段 + * @throws SecurityException + * @throws NoSuchFieldException + */ + public static Object filterFieldsJson(Object src, Class<?> clazz, Map<String,List<String>> map) throws NoSuchFieldException, SecurityException + { + boolean isExclude =true; + ComplexPropertyPreFilter filter = new ComplexPropertyPreFilter(); + Map<Class<?>, List<String>> filterMap = new HashMap<Class<?>,List<String>>(); + filterMap.put(clazz, new ArrayList<String>()); + List<String> fields = map.get(EXCLUDE); + if(Tool.ObjectUtil.isEmpty(fields)) { + fields = map.get(INCLUDE); + isExclude = false; + } + for(String field : fields) { + if(field.contains(StrUtil.DOT)) { + String[] split = StrUtil.split(field, StrUtil.DOT); + String attributeName = split[0]; + Field declaredField = clazz.getDeclaredField(attributeName); + Class<?> attributeType = declaredField.getType(); + List<String> list = filterMap.get(attributeType); + if(!isExclude) { + filterMap.get(clazz).add(split[0]); + } + if(Tool.ObjectUtil.isEmpty(list)) { + List<String> s = new ArrayList<String>(); + s.add(split[1]); + filterMap.put(attributeType, s); + }else { + list.add(split[1]); + } + }else { + filterMap.get(clazz).add(field); + } + } + + if(isExclude) { + filter.setExcludes(filterMap); + }else { + filter.setIncludes(filterMap); + } + String jsonString = JSON.toJSONString(src, filter,SerializerFeature.WriteMapNullValue); + return JSON.parseObject(jsonString); + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/interceptor/SysMenuInterceptor.java b/cn-admin/src/main/java/net/geedge/common/interceptor/SysMenuInterceptor.java new file mode 100644 index 0000000..8d0f4d1 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/interceptor/SysMenuInterceptor.java @@ -0,0 +1,40 @@ +package net.geedge.common.interceptor; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import net.geedge.modules.sys.entity.SysConfigEntity; +import net.geedge.modules.sys.entity.SysUserEntity; +import net.geedge.modules.sys.service.SysConfigService; +import net.geedge.modules.sys.shiro.ShiroUtils; +import org.apache.http.HttpStatus; +import org.springframework.http.HttpMethod; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class SysMenuInterceptor extends HandlerInterceptorAdapter { + + private SysConfigService sysConfigService; + + + public SysMenuInterceptor(SysConfigService sysConfigService) { + this.sysConfigService = sysConfigService; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + // GET 请求不拦截,不进行校验 + if(StrUtil.equals(request.getMethod(),HttpMethod.GET.toString())) { + return true; + } else { + SysUserEntity user = ShiroUtils.getUserEntity(); + SysConfigEntity developDdmin = sysConfigService.getOne(new LambdaQueryWrapper<SysConfigEntity>().eq(SysConfigEntity::getParamKey, "develop_admin")); + if(!StrUtil.equals(user.getUsername(),developDdmin.getParamValue())) { + response.sendError(HttpStatus.SC_NOT_FOUND, "Not Found"); + return false; + } + return true; + } + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/interceptor/TokenCheckFilter.java b/cn-admin/src/main/java/net/geedge/common/interceptor/TokenCheckFilter.java new file mode 100644 index 0000000..98e3905 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/interceptor/TokenCheckFilter.java @@ -0,0 +1,170 @@ +package net.geedge.common.interceptor; + +import java.util.Date; +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.session.mgt.SimpleSession; +import org.apache.shiro.subject.SimplePrincipalCollection; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.subject.support.DefaultSubjectContext; +import org.apache.shiro.util.ThreadContext; +import org.apache.shiro.web.filter.AccessControlFilter; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.R; +import net.geedge.common.utils.RCode; +import net.geedge.common.utils.SpringContextUtils; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.dao.SysApiKeyDao; +import net.geedge.modules.sys.dao.SysUserDao; +import net.geedge.modules.sys.entity.SysApiKey; +import net.geedge.modules.sys.entity.SysUserEntity; +import net.geedge.modules.sys.shiro.ShiroUtils; + +public class TokenCheckFilter extends AccessControlFilter { + + private Integer loginExpiration; + private SysUserDao sysUserDao; + private RedisTemplate<String, String> redisTemplate; + private SysApiKeyDao sysApiKeyDao; + + public TokenCheckFilter(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + public TokenCheckFilter(RedisTemplate redisTemplate, Integer loginExpiration) { + this.redisTemplate = redisTemplate; + this.loginExpiration = loginExpiration; + } + + public TokenCheckFilter(RedisTemplate redisTemplate, Integer loginExpiration, SysUserDao sysUserDao, SysApiKeyDao sysApiKeyDao) { + this.redisTemplate = redisTemplate; + this.loginExpiration = loginExpiration; + this.sysUserDao = sysUserDao; + this.sysApiKeyDao = sysApiKeyDao; + } + + +// @Override +// protected boolean preHandle(ServletRequest req, ServletResponse resp) throws Exception { +// HttpServletRequest request=(HttpServletRequest) req; +// HttpServletResponse response=(HttpServletResponse)resp; +// //跨域请求标志 +// String origin = request.getHeader("Origin"); +// if(StringUtils.isNotBlank(origin)){ +// response.setHeader("Access-Control-Allow-Origin",origin); +// response.setHeader("Access-Control-Allow-Credentials","true"); +// } +// +// return super.preHandle(request, response); +// } + + @Override + protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object o) throws Exception { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) resp; + String requestToken = request.getHeader(Constant.AUTH_TOKEN_CODE); + if (StringUtils.isBlank(requestToken)) { + requestToken = request.getParameter(Constant.AUTH_TOKEN_CODE); + } + if (StringUtils.isBlank(requestToken)) { + response.getWriter().write(JSON.toJSON(R.error(RCode.SYS_LOGIN_REQUIRED)).toString()); + return false; + } + + Boolean exist = redisTemplate.hasKey(ShiroUtils.REDIS_KEYPREFIX + requestToken); + if (exist) { + SysUserEntity userEntity = ShiroUtils.getUserEntity(); + if(Tool.ObjectUtil.equals(ShiroUtils.getUserEntity().getId(), 0L)) { + // 第三方api key登录 + return true; + } + // 重新查询数据库 + SysUserEntity entity = this.sysUserDao.selectById(ShiroUtils.getUserEntity().getId()); + if (entity.getStatus() == 0) { + response.getWriter().write(JSON.toJSON(R.error(RCode.SYS_LOGIN_LOCK)).toString()); + return false; + } + // key 存在 证明验证成功,刷新过期时间 + redisTemplate.expire(requestToken, this.loginExpiration, TimeUnit.MINUTES); + return true; + } else { + Date now = new Date(); + String time = DateUtil.format(now , "yyyy-MM-dd hh:mm:ss"); + // 查询sys_api_key是否有该token记录 + SysApiKey apiKey = sysApiKeyDao.selectOne(new QueryWrapper<SysApiKey>().lambda().eq(SysApiKey::getToken, requestToken) + .and(wrapper -> wrapper.ge(SysApiKey::getExpireAt,time).or().isNull(SysApiKey::getExpireAt))); + // 如果有的话则认证通过 同时将该值存放到redis里 + if(Tool.ObjectUtil.isEmpty(apiKey)) { + // 如果没有则 返回响应值 + response.getWriter().write(JSON.toJSON(R.error(RCode.SYS_LOGIN_REQUIRED)).toString()); + return false; + }else { + RedisConnectionFactory factory = SpringContextUtils.getBean("redisConnectionFactory", RedisConnectionFactory.class); + RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); + redisTemplate.setConnectionFactory(factory); + redisTemplate.afterPropertiesSet(); + + + //获取存在缓存中的过期时间 + Date expireAt = apiKey.getExpireAt(); + + SimpleSession session = new SimpleSession(); + SysUserEntity user = new SysUserEntity(); + user.setApiKeyId(apiKey.getId()); + user.setId(0L); + user.setName(apiKey.getName()); + SimplePrincipalCollection primaryPrincipal =new SimplePrincipalCollection(user,""); + session.setAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY, primaryPrincipal); + session.setId(apiKey.getToken()); + + if(!Tool.ObjectUtil.isEmpty(expireAt)){ + long seconds = DateUtil.between(now, expireAt, DateUnit.SECOND); + redisTemplate.opsForValue().set(ShiroUtils.REDIS_KEYPREFIX + requestToken, session,seconds,TimeUnit.SECONDS); + }else{ + redisTemplate.opsForValue().set(ShiroUtils.REDIS_KEYPREFIX + requestToken, session); + } + + DefaultSubjectContext context =new DefaultSubjectContext(); + context.setSession(session); + SecurityManager securityManager = SecurityUtils.getSecurityManager(); + Subject subject = securityManager.createSubject(context); + ThreadContext.bind(subject); + return true; + } + } + } + + public Integer getLoginExpiration() { + return loginExpiration; + } + + public void setLoginExpiration(Integer loginExpiration) { + this.loginExpiration = loginExpiration; + } + + @Override + protected boolean onAccessDenied(ServletRequest req, ServletResponse resp) throws Exception { + + return false; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/job/HaJob.java b/cn-admin/src/main/java/net/geedge/common/job/HaJob.java new file mode 100644 index 0000000..81ebcf3 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/job/HaJob.java @@ -0,0 +1,40 @@ +package net.geedge.common.job; + +import java.util.concurrent.TimeUnit; + +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.log.Log; +import net.geedge.common.utils.Constant; + +@DisallowConcurrentExecution +public class HaJob extends QuartzJobBean { + + private Log log = Log.get(); + + @Autowired + private RedisTemplate<String, String> redisTemplate; + + @Override + protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException { + String serverId = redisTemplate.opsForValue().get(Constant.SYS_HA_LOCK); + if(StrUtil.isBlank(serverId)) { + Boolean lock = redisTemplate.opsForValue().setIfAbsent(Constant.SYS_HA_LOCK, Constant.SERVER_ID,10, TimeUnit.SECONDS); + if(lock) { + log.debug("HA job set lock"); + } + }else if(StrUtil.equals(serverId, Constant.SERVER_ID)){ + redisTemplate.expire(Constant.SYS_HA_LOCK, 10, TimeUnit.SECONDS); + log.debug("HA job get lock , Timeout update"); + }else { + log.debug("HA job can not get lock , job in another program"); + } + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/job/JobConfig.java b/cn-admin/src/main/java/net/geedge/common/job/JobConfig.java new file mode 100644 index 0000000..cad5b44 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/job/JobConfig.java @@ -0,0 +1,61 @@ +package net.geedge.common.job; + +import javax.annotation.PostConstruct; + +import org.quartz.CronScheduleBuilder; +import org.quartz.CronTrigger; +import org.quartz.JobDetail; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.TriggerBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; + +import cn.hutool.log.Log; + +/** + * JobConfig 统一管理 job config + * + */ +@Configuration +public class JobConfig { + + private static final Log log = Log.get(); + + @Autowired + private SchedulerFactoryBean schedulerFactoryBean; + private static final String JOB_NAME = "CNJOB"; + + @PostConstruct + public void init() throws SchedulerException { + } + + /** + * 根据 jobName jobDetail jobCronExpression 创建任务,如果存在则删除再创建 + * @param jobName + * @param jobDetail + * @param jobCronExpression + * @param scheduler + * @throws Exception + */ + public static void createCronScheduleJob(String jobName, JobDetail jobDetail, String jobCronExpression, Scheduler scheduler) throws SchedulerException { + CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobCronExpression); + + CronTrigger cronTrigger = TriggerBuilder.newTrigger() + .forJob(jobDetail) + .withSchedule(cronScheduleBuilder) + .build(); + + // job如果存在则删除 + JobKey jobKey = new JobKey(JOB_NAME + jobName); + boolean b = scheduler.checkExists(jobKey); + if (b) { + scheduler.deleteJob(jobKey); + } + // 创建任务 + scheduler.scheduleJob(jobDetail, cronTrigger); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/Test.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/Test.java new file mode 100644 index 0000000..7c0b4f2 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/Test.java @@ -0,0 +1,15 @@ +package net.geedge.common.smartvalidate; + +public class Test { + + private String tt; + + public String getTt() { + return tt; + } + + public void setTt(String tt) { + this.tt = tt; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateCache.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateCache.java new file mode 100644 index 0000000..0728514 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateCache.java @@ -0,0 +1,48 @@ +package net.geedge.common.smartvalidate; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * ValidateCache + * Created by ZhangGang on 2017/2/24. + */ +public class ValidateCache { + + private static ValidateCache ourInstance = new ValidateCache(); + + public static ValidateCache getInstance() { + return ourInstance; + } + + private Map<Class, Set<Field>> classFieldSetMap; + private Map<Field, Annotation[]> fieldAnnotationMap; + + private ValidateCache() { + classFieldSetMap = new HashMap<>(); + fieldAnnotationMap = new HashMap<>(); + } + + public void setClassFields(Class classType, Set<Field> fieldSet) { + if (null == fieldSet) fieldSet = new HashSet<>(); + classFieldSetMap.put(classType, fieldSet); + } + + public void setFieldAnnotations(Field field, Annotation[] annotations) { + if (null == annotations) annotations = new Annotation[0]; + fieldAnnotationMap.put(field, annotations); + } + + public Set<Field> getFieldsByClass(Class classType) { + return classFieldSetMap.get(classType); + } + + public Annotation[] getAnnotationsByField(Field field) { + return fieldAnnotationMap.get(field); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateHandler.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateHandler.java new file mode 100644 index 0000000..a8361d8 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateHandler.java @@ -0,0 +1,223 @@ +package net.geedge.common.smartvalidate; + +import net.geedge.common.exception.CNException; +import net.geedge.common.utils.RCode; + +import java.util.Collection; +import java.util.Map; + +/** + * ValidateHandler + * Created by ZhangGang on 2016/9/27. + */ +public class ValidateHandler { + + public static void notNull(Object value, RCode code) { + try { + ValidateProcess.notNull(value); + if (value instanceof String) { + ValidateProcess.notNull((String) value); + } else if (value instanceof Number) { + ValidateProcess.notNull((Number) value); + } else if (value instanceof Collection) { + ValidateProcess.notNull((Collection) value); + } else if (value instanceof Map) { + ValidateProcess.notNull((Map) value); + } else if (value instanceof Object[]) { + ValidateProcess.notNull((Object[]) value); + } + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void regex(String regex, Object value, RCode code) { + try { + if (null == value) { + return; + } + ValidateProcess.regex(regex, value.toString()); + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void max(Number max, Object value, RCode code) { + try { + if (null == value || !(value instanceof Number)) { + return; + } + if (value instanceof Integer) { + ValidateProcess.max(max.intValue(), (Integer) value); + } else if (value instanceof Long) { + ValidateProcess.max(max.longValue(), (Long) value); + } else if (value instanceof Double) { + ValidateProcess.max(max.doubleValue(), (Double) value); + } else if (value instanceof Float) { + ValidateProcess.max(max.floatValue(), (Float) value); + } else if (value instanceof Short) { + ValidateProcess.max(max.shortValue(), (Short) value); + } else if (value instanceof Byte) { + ValidateProcess.max(max.byteValue(), (Byte) value); + } + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void maxLength(int max, Object value, RCode code) { + try { + if (null == value) { + return; + } + if (value instanceof String) { + ValidateProcess.maxLength(max, (String) value); + } else if (value instanceof Collection) { + ValidateProcess.maxLength(max, (Collection) value); + } else if (value instanceof Map) { + ValidateProcess.maxLength(max, (Map) value); + } else if (value instanceof Object[]) { + ValidateProcess.maxLength(max, (Object[]) value); + } + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void minLength(int min, Object value, RCode code) { + try { + if (null == value) { + return; + } + if (value instanceof String) { + ValidateProcess.minLength(min, (String) value); + } else if (value instanceof Collection) { + ValidateProcess.minLength(min, (Collection) value); + } else if (value instanceof Map) { + ValidateProcess.minLength(min, (Map) value); + } else if (value instanceof Object[]) { + ValidateProcess.minLength(min, (Object[]) value); + } + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + + public static void min(Number min, Object value, RCode code) { + try { + if (null == value || !(value instanceof Number)) { + return; + } + if (value instanceof Integer) { + ValidateProcess.min(min.intValue(), (Integer) value); + } else if (value instanceof Long) { + ValidateProcess.min(min.longValue(), (Long) value); + } else if (value instanceof Double) { + ValidateProcess.min(min.doubleValue(), (Double) value); + } else if (value instanceof Float) { + ValidateProcess.min(min.floatValue(), (Float) value); + } else if (value instanceof Short) { + ValidateProcess.min(min.shortValue(), (Short) value); + } else if (value instanceof Byte) { + ValidateProcess.min(min.byteValue(), (Byte) value); + } + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void chinese(Object value, RCode code) { + try { + if (null == value) { + return; + } + ValidateProcess.chinese(value.toString()); + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void english(Object value, RCode code) { + try { + if (null == value) { + return; + } + ValidateProcess.english(value.toString()); + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void phone(Object value, RCode code) { + try { + if (null == value) { + return; + } + ValidateProcess.phone(value.toString()); + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void email(Object value, RCode code) { + try { + if (null == value) { + return; + } + ValidateProcess.email(value.toString()); + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void date(String format, Object value, RCode code) { + try { + if (null != value) { + ValidateProcess.date(format, value.toString()); + } + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void idCard(Object value, RCode code) { + try { + if (null == value) { + return; + } + ValidateProcess.idCard(value.toString()); + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + public static void ip(Object value, RCode code) { + try { + if (null == value) { + return; + } + ValidateProcess.isIp(value.toString()); + } catch (CNException e) { + errorMsgHandler(e, code); + } + } + + private static void errorMsgHandler(CNException e, RCode code) { + if (code == null) { + throw e; + } + throw new CNException(code); + } + + public static void port(Object value, RCode code) { + try { + if (null == value) { + return; + } + ValidateProcess.isPort(value.toString()); + } catch (CNException e) { + errorMsgHandler(e, code); + } + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateProcess.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateProcess.java new file mode 100644 index 0000000..85b40a6 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateProcess.java @@ -0,0 +1,342 @@ +package net.geedge.common.smartvalidate; + + +import net.geedge.common.exception.CNException; +import net.geedge.common.smartvalidate.utils.CharUtil; +import net.geedge.common.smartvalidate.utils.CommonUtil; +import net.geedge.common.smartvalidate.utils.RegexUtil; +import net.geedge.common.utils.RCode; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * ValidateProcess + * Created by ZhangGang on 2016/9/21. + */ +class ValidateProcess { + + private final static int[] factorArr = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1}; + private final static char[] parityBit = {'1', '0', 'x', '9', '8', '7', '6', '5', '4', '3', '2'}; + + private final static String REGEX_AREA = "^[0-9]{2}$"; + private final static String REGEX_DATE8 = "^[0-9]{8}$"; + private final static String REGEX_IP = "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d|\\*)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d|\\*)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d|\\*)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d|\\*)"; + private final static String REGEX_PORT = "^[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]{1}|6553[0-5]$"; + //private final static String REGEX_DATE = "^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1-2][0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$"; + //private final static String REGEX_CHINESE = "^[\\u4e00-\\u9fa5]{1,}$"; + private final static String REGEX_ENGLISH = "^[a-zA-z]{1,}$"; + private final static String REGEX_PHONE = "^1(3[0-9]|4[57]|5[0-35-9]|7[01678]|8[0-9])\\d{8}$"; + private final static String REGEX_EMAIL = "\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}"; + + private final static int MIN_YEAR = 1700; + private final static int MAX_YEAR = 2500; + + private final static Map<Integer, String> zoneNum = new HashMap<>(); + + //private final static String RCode.NOT_NULL_ERROR = "非空校验失败"; + private final static String RegexErrorMsg = "正则校验失败"; + private final static String MaxErrorMsg = "最大值校验失败"; + private final static String MinErrorMsg = "最小值校验失败"; + private final static String MaxLengthErrorMsg = "maxleng_error"; + private final static String MinLengthErrorMsg = "minleng_error"; + private final static String DateFormatErrorMsg = "dataformat_error"; + private final static String IdCardErrorMsg = "身份证校验失败"; + private final static String IpErrorMsg = "身份证校验失败"; + private final static String ChineseErrorMsg = "中文校验失败"; + private final static String EnglishErrorMsg = "英文校验失败"; + private final static String EmailErrorMsg = "邮箱校验失败"; + private final static String PhoneNumErrorMsg = "手机号校验失败"; + + static { + zoneNum.put(11, "北京"); + zoneNum.put(12, "天津"); + zoneNum.put(13, "河北"); + zoneNum.put(14, "山西"); + zoneNum.put(15, "内蒙古"); + zoneNum.put(21, "辽宁"); + zoneNum.put(22, "吉林"); + zoneNum.put(23, "黑龙江"); + zoneNum.put(31, "上海"); + zoneNum.put(32, "江苏"); + zoneNum.put(33, "浙江"); + zoneNum.put(34, "安徽"); + zoneNum.put(35, "福建"); + zoneNum.put(36, "江西"); + zoneNum.put(37, "山东"); + zoneNum.put(41, "河南"); + zoneNum.put(42, "湖北"); + zoneNum.put(43, "湖南"); + zoneNum.put(44, "广东"); + zoneNum.put(45, "广西"); + zoneNum.put(46, "海南"); + zoneNum.put(50, "重庆"); + zoneNum.put(51, "四川"); + zoneNum.put(52, "贵州"); + zoneNum.put(53, "云南"); + zoneNum.put(54, "西藏"); + zoneNum.put(61, "陕西"); + zoneNum.put(62, "甘肃"); + zoneNum.put(63, "青海"); + zoneNum.put(64, "新疆"); + zoneNum.put(71, "台湾"); + zoneNum.put(81, "香港"); + zoneNum.put(82, "澳门"); + zoneNum.put(91, "外国"); + } + + static void notNull(Object value) { + if (null == value) throw new CNException(RCode.NOT_NULL_ERROR); + } + + static void notNull(String value) { + if (CommonUtil.isNull(value)) throw new CNException(RCode.NOT_NULL_ERROR); + } + + static void notNull(Number number) { + if (null == number) throw new CNException(RCode.NOT_NULL_ERROR); + } + + static void notNull(Collection value) { + if (CommonUtil.isNull(value)) throw new CNException(RCode.NOT_NULL_ERROR); + } + + static void notNull(Map value) { + if (CommonUtil.isNull(value)) throw new CNException(RCode.NOT_NULL_ERROR); + } + + static void notNull(Object[] value) { + if (CommonUtil.isNull(value)) throw new CNException(RCode.NOT_NULL_ERROR); + } + + static void regex(String regex, String value) { + regex(regex, value, RegexErrorMsg + ", regex:" + regex + ", value:" + value); + } + + private static void regex(String regex, String value, String msg) { + if (!CommonUtil.isNull(value)) { + if (!RegexUtil.test(regex, value)) { + throw new CNException(msg); + } + } + } + + static void max(int max, int value) { + if (value > max) throw new CNException(MaxErrorMsg + ", max:" + max + ", value:" + value); + } + + static void max(long max, long value) { + if (value > max) throw new CNException(MaxErrorMsg + ", max:" + max + ", value:" + value); + } + + static void max(float max, float value) { + if (value > max) throw new CNException(MaxErrorMsg + ", max:" + max + ", value:" + value); + } + + static void max(double max, double value) { + if (value > max) throw new CNException(MaxErrorMsg + ", max:" + max + ", value:" + value); + } + + static void max(byte max, byte value) { + if (value > max) throw new CNException(MaxErrorMsg + ", max:" + max + ", value:" + value); + } + + static void max(short max, short value) { + if (value > max) throw new CNException(MaxErrorMsg + ", max:" + max + ", value:" + value); + } + + static void maxLength(int max, String value) { + if (!CommonUtil.isNull(value)) { + if (value.length() > max) + throw new CNException(MaxLengthErrorMsg + ", max:" + max + ", value:" + value); + } + } + + static void maxLength(int max, Collection value) { + if (null != value) { + if (value.size() > max) + throw new CNException(MaxLengthErrorMsg + ", max:" + max + ", value:" + value.size()); + } + } + + static void maxLength(int max, Map value) { + if (null != value) { + if (value.size() > max) + throw new CNException(MaxLengthErrorMsg + ", max:" + max + ", value:" + value.size()); + } + } + + static void maxLength(int max, Object[] value) { + if (null != value) { + if (value.length > max) + throw new CNException(MaxLengthErrorMsg + ", max:" + max + ", value:" + value.length); + } + } + + static void min(int min, int value) { + if (value < min) throw new CNException(MinErrorMsg + ", min:" + min + ", value:" + value); + } + + static void min(long min, long value) { + if (value < min) throw new CNException(MinErrorMsg + ", min:" + min + ", value:" + value); + } + + static void min(float min, float value) { + if (value < min) throw new CNException(MinErrorMsg + ", min:" + min + ", value:" + value); + } + + static void min(double min, double value) { + if (value < min) throw new CNException(MinErrorMsg + ", min:" + min + ", value:" + value); + } + + static void min(byte min, byte value) { + if (value < min) throw new CNException(MinErrorMsg + ", min:" + min + ", value:" + value); + } + + static void min(short min, short value) { + if (value < min) throw new CNException(MinErrorMsg + ", min:" + min + ", value:" + value); + } + + static void minLength(int min, String value) { + if (!CommonUtil.isNull(value)) { + if (value.length() < min) throw new CNException(MinErrorMsg + ", min:" + min + ", value:" + value); + } + } + + static void minLength(int min, Collection value) { + if (null != value) { + if (value.size() < min) + throw new CNException(MinLengthErrorMsg + ", min:" + min + ", value:" + value.size()); + } + } + + static void minLength(int min, Map value) { + if (null != value) { + if (value.size() < min) + throw new CNException(MinLengthErrorMsg + ", min:" + min + ", value:" + value.size()); + } + } + + static void minLength(int min, Object[] value) { + if (null != value) { + if (value.length < min) + throw new CNException(MinLengthErrorMsg + ", min:" + min + ", value:" + value.length); + } + } + + static void date(String format, String value) { + if (!CommonUtil.isNull(value)) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); + try { + simpleDateFormat.parse(value); + } catch (ParseException e) { + throw new CNException(DateFormatErrorMsg + ", format:" + format + ", value:" + value); + } + } + } + + /** + * 身份证15位编码规则:dddddd yymmdd xx p + * dddddd:地区码 + * yymmdd: 出生年月日 + * xx: 顺序类编码 + * p: 性别,奇数为男,偶数为女 + * <p/> + * 身份证18位编码规则:dddddd yyyymmdd xxx y + * dddddd:地区码 + * yyyymmdd: 出生年月日 + * xxx:顺序类编码,奇数为男,偶数为女 + * y: 校验码,该位数值可通过前17位计算获得 + * <p/> + * 18位号码加权因子为(从右到左) wi = [ 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2,1 ] + * 验证位 Y = [ 1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2 ] + * 校验位计算公式:Y_P = mod( ∑(Ai×wi),11 ) + * i为身份证号码从右往左数的 2...18 位; Y_P为校验码所在校验码数组位置 + */ + static void idCard(String value) { + if (!CommonUtil.isNull(value)) { + String idCard = value.toLowerCase(); + int length = idCard.length(); + //校验位数 + if (length != 15 && length != 18) { + throw new CNException(IdCardErrorMsg + ", value:" + value); + } + //校验区域 + if (!isArea(idCard.substring(0, 2))) { + throw new CNException(IdCardErrorMsg + ", value:" + value); + } + //校验日期 + if (15 == length && !isDate6(idCard.substring(6, 12))) { + throw new CNException(IdCardErrorMsg + ", value:" + value); + } + if (18 == length && !isDate8(idCard.substring(6, 14))) { + throw new CNException(IdCardErrorMsg + ", value:" + value); + } + //校验18位校验码 + if (18 == length) { + char[] idCardArray = idCard.toCharArray(); + int sum = 0; + for (int i = 0; i < idCardArray.length - 1; i++) { + if (idCardArray[i] < '0' || idCardArray[i] > '9') { + throw new CNException(IdCardErrorMsg + ", value:" + value); + } + sum += (idCardArray[i] - '0') * factorArr[i]; + } + if (idCardArray[idCardArray.length - 1] != parityBit[sum % 11]) { + throw new CNException(IdCardErrorMsg + ", value:" + value); + } + } + } + } + + private static boolean isArea(String area) { + return RegexUtil.test(REGEX_AREA, area) && zoneNum.containsKey(Integer.valueOf(area)); + } + + private static boolean isDate6(String date) { + return isDate8("19" + date); + } + + private static boolean isDate8(String date) { + if (!RegexUtil.test(REGEX_DATE8, date)) { + return false; + } + int[] iaMonthDays = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + int year = Integer.parseInt(date.substring(0, 4)); + int month = Integer.parseInt(date.substring(4, 6)); + int day = Integer.parseInt(date.substring(6, 8)); + if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) iaMonthDays[1] = 29; + return !(year < MIN_YEAR || year > MAX_YEAR) && !(month < 1 || month > 12) && !(day < 1 || day > iaMonthDays[month - 1]); + } + + + static void isIp(String value) { + regex(REGEX_IP, value, IpErrorMsg + ", value:" + value); + } + + static void chinese(String value) { + boolean ret = CharUtil.isChinese(value); + if (!ret) { + throw new CNException(ChineseErrorMsg + ", value:" + value); + } + } + + static void english(String value) { + regex(REGEX_ENGLISH, value, EnglishErrorMsg + ", value:" + value); + } + + static void phone(String value) { + regex(REGEX_PHONE, value, PhoneNumErrorMsg + ", value:" + value); + } + + static void email(String value) { + regex(REGEX_EMAIL, value, EmailErrorMsg + ", value:" + value); + } + + public static void isPort(String value) { + regex(REGEX_PORT, value, IpErrorMsg + ", value:" + value); + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateUtils.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateUtils.java new file mode 100644 index 0000000..ad1a92b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ValidateUtils.java @@ -0,0 +1,401 @@ +package net.geedge.common.smartvalidate; + +import net.geedge.common.smartvalidate.utils.CommonUtil; +import net.geedge.common.smartvalidate.utils.ReflectUtils; +import net.geedge.common.utils.RCode; +import org.apache.commons.beanutils.PropertyUtils; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.Set; + +/** + * ValidateUtils + * Created by ZhangGang on 2016/9/6. + */ +public class ValidateUtils { + + private Object value; + + private ValidateUtils(Object value) { + this.value = value; + } + + /** + * 新建校验实例,传入目标对象 + * + * @param value 校验对象 + * @return ValidateUtils + */ + public static ValidateUtils is(Object value) { + return new ValidateUtils(value); + } + + /** + * 切换目标对象,不重新创建实例 + * + * @param value 校验对象 + * @return ValidateUtils + */ + public ValidateUtils and(Object value) { + this.value = value; + return this; + } + + /** + * 非空校验 + * + * @return ValidateUtils + */ + public ValidateUtils notNull() { + return notNull(null); + } + + /** + * 非空校验 + * + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils notNull(RCode code) { + ValidateHandler.notNull(value, code); + return this; + } + + /** + * 正则校验 + * + * @param regex 正则表达式 + * @return ValidateUtils + */ + public ValidateUtils regex(String regex) { + return regex(regex, null); + } + + /** + * 正则校验 + * + * @param regex 正则表达式 + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils regex(String regex, RCode code) { + ValidateHandler.regex(regex, value, code); + return this; + } + + /** + * 最大值校验 + * + * @param max 最大值 + * @return ValidateUtils + */ + public ValidateUtils max(Number max) { + return max(max, null); + } + + /** + * 最大值校验 + * + * @param max 最大值 + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils max(Number max, RCode code) { + ValidateHandler.max(max, value, code); + return this; + } + + /** + * 最小值校验 + * + * @param min 最小值 + * @return ValidateUtils + */ + public ValidateUtils min(Number min) { + return min(min, null); + } + + /** + * 最小值校验 + * + * @param min 最小值 + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils min(Number min, RCode code) { + ValidateHandler.min(min, value, code); + return this; + } + + /** + * 最大长度校验 + * + * @param max 最大长度 + * @return ValidateUtils + */ + public ValidateUtils maxLength(int max) { + return maxLength(max, null); + } + + /** + * 最大长度校验 + * + * @param max 最大长度 + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils maxLength(int max, RCode code) { + ValidateHandler.maxLength(max, value, code); + return this; + } + + /** + * 最小长度校验 + * + * @param min 最小长度 + * @return ValidateUtils + */ + public ValidateUtils minLength(int min) { + return minLength(min, null); + } + + /** + * 最小长度校验 + * + * @param min 最小长度 + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils minLength(int min, RCode code) { + ValidateHandler.minLength(min, value, code); + return this; + } + + /** + * 中文校验 + * + * @return ValidateUtils + */ + public ValidateUtils chinese() { + return chinese(null); + } + + /** + * 中文校验 + * + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils chinese(RCode code) { + ValidateHandler.chinese(value, code); + return this; + } + + /** + * 英文校验 + * + * @return ValidateUtils + */ + public ValidateUtils english() { + return english(null); + } + + /** + * 英文校验 + * + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils english(RCode code) { + ValidateHandler.english(value, code); + return this; + } + + /** + * 手机号校验 + * + * @return ValidateUtils + */ + public ValidateUtils phone() { + return phone(null); + } + + /** + * 手机号校验 + * + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils phone(RCode code) { + ValidateHandler.phone(value, code); + return this; + } + + /** + * 邮箱校验 + * + * @return ValidateUtils + */ + public ValidateUtils email() { + return email(null); + } + + /** + * 邮箱校验 + * + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils email(RCode code) { + ValidateHandler.email(value, code); + return this; + } + + /** + * 自定义日期格式校验 + * + * @param format 格式 + * @return ValidateUtils + */ + public ValidateUtils date(String format) { + return date(format, null); + } + + /** + * 自定义日期格式校验 + * + * @param format 格式 + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils date(String format, RCode code) { + ValidateHandler.date(format, value, code); + return this; + } + + /** + * 身份证校验 + * + * @return ValidateUtils + */ + public ValidateUtils idCard() { + return idCard(null); + } + + /** + * 身份证校验 + * + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils idCard(RCode code) { + ValidateHandler.idCard(value, code); + return this; + } + + /** + * IP地址校验 + * + * @return ValidateUtils + */ + public ValidateUtils ip() { + return ip(null); + } + + /** + * IP地址校验 + * + * @param msg 错误信息 + * @return ValidateUtils + */ + public ValidateUtils ip(RCode code) { + ValidateHandler.ip(value, code); + return this; + } + + public ValidateUtils port(RCode code) { + ValidateHandler.port(value, code); + return this; + } + + /** + * 对象校验(通过注解) + * + * @param value 校验对象 + * @return ValidateUtils + */ + public static ValidateUtils check(Object value) { + ValidateUtils validateUtils = new ValidateUtils(value); + validateUtils.notNull(); + Class classType = value.getClass(); + Set<Field> fieldSet = ValidateCache.getInstance().getFieldsByClass(classType); + if (null == fieldSet) { + fieldSet = ReflectUtils.getFieldsByClass(value.getClass()); + ValidateCache.getInstance().setClassFields(classType, fieldSet); + } + if (CommonUtil.isNull(fieldSet)) { + return validateUtils; + } + for (Field field : fieldSet) { + Annotation[] annotations = ValidateCache.getInstance().getAnnotationsByField(field); + if (null == annotations) { + annotations = field.getAnnotations(); + ValidateCache.getInstance().setFieldAnnotations(field, annotations); + } + if (CommonUtil.isNull(annotations)) { + return validateUtils; + } +// Object fieldValue; + try { +// fieldValue = PropertyUtils.getProperty(value, field.getName()); + PropertyUtils.getProperty(value, field.getName()); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + /*for (Annotation annotation : annotations) { + if (annotation instanceof NotNull) { + validateUtils.and(fieldValue).notNull(((NotNull) annotation).code()); + } else if (annotation instanceof Max) { + Max max = (Max) annotation; + validateUtils.and(fieldValue).max(max.value(), max.msg()); + } else if (annotation instanceof Min) { + Min min = (Min) annotation; + validateUtils.and(fieldValue).min(min.value(), min.msg()); + } else if (annotation instanceof MaxLength) { + MaxLength maxLength = (MaxLength) annotation; + validateUtils.and(fieldValue).maxLength(maxLength.value(), maxLength.msg()); + } else if (annotation instanceof MinLength) { + MinLength minLength = (MinLength) annotation; + validateUtils.and(fieldValue).minLength(minLength.value(), minLength.msg()); + } else if (annotation instanceof Email) { + validateUtils.and(fieldValue).email(((Email) annotation).msg()); + } else if (annotation instanceof Phone) { + validateUtils.and(fieldValue).phone(((Phone) annotation).msg()); + } else if (annotation instanceof IdCard) { + validateUtils.and(fieldValue).idCard(((IdCard) annotation).msg()); + } else if (annotation instanceof Regex) { + Regex regex = (Regex) annotation; + validateUtils.and(fieldValue).regex(regex.value(), regex.msg()); + } else if (annotation instanceof Date) { + Date date = (Date) annotation; + String format = date.format(); + validateUtils.and(fieldValue).date(format, date.msg()); + } else if (annotation instanceof Chinese) { + validateUtils.and(fieldValue).chinese(((Chinese) annotation).msg()); + } else if (annotation instanceof English) { + validateUtils.and(fieldValue).english(((English) annotation).msg()); + } else if (annotation instanceof IP) { + validateUtils.and(fieldValue).ip(((IP) annotation).msg()); + } + }*/ + } + return validateUtils; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Chinese.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Chinese.java new file mode 100644 index 0000000..6dbb2f0 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Chinese.java @@ -0,0 +1,11 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface Chinese { + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Date.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Date.java new file mode 100644 index 0000000..cbfbf51 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Date.java @@ -0,0 +1,12 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface Date { + String format(); + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Email.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Email.java new file mode 100644 index 0000000..ee97bca --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Email.java @@ -0,0 +1,11 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface Email { + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/English.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/English.java new file mode 100644 index 0000000..bbe827f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/English.java @@ -0,0 +1,11 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface English { + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/IP.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/IP.java new file mode 100644 index 0000000..f10e987 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/IP.java @@ -0,0 +1,11 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface IP { + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/IdCard.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/IdCard.java new file mode 100644 index 0000000..7010082 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/IdCard.java @@ -0,0 +1,11 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface IdCard { + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Max.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Max.java new file mode 100644 index 0000000..64cb86b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Max.java @@ -0,0 +1,12 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface Max { + int value(); + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/MaxLength.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/MaxLength.java new file mode 100644 index 0000000..689c29c --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/MaxLength.java @@ -0,0 +1,12 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface MaxLength { + int value(); + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Min.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Min.java new file mode 100644 index 0000000..cc397e5 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Min.java @@ -0,0 +1,12 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface Min { + int value(); + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/MinLength.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/MinLength.java new file mode 100644 index 0000000..bb4bea0 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/MinLength.java @@ -0,0 +1,12 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface MinLength { + int value(); + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/NotNull.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/NotNull.java new file mode 100644 index 0000000..7aa2285 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/NotNull.java @@ -0,0 +1,12 @@ +package net.geedge.common.smartvalidate.ann; + +import net.geedge.common.utils.RCode; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface NotNull { + RCode code() default RCode.ERROR; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Phone.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Phone.java new file mode 100644 index 0000000..1742467 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Phone.java @@ -0,0 +1,11 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface Phone { + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Regex.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Regex.java new file mode 100644 index 0000000..29d6032 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/ann/Regex.java @@ -0,0 +1,12 @@ +package net.geedge.common.smartvalidate.ann; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface Regex { + String value(); + String code() default "999"; + String msg() default "error"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/CharUtil.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/CharUtil.java new file mode 100644 index 0000000..fe3e464 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/CharUtil.java @@ -0,0 +1,29 @@ +package net.geedge.common.smartvalidate.utils; + + +/** + * Created by ZhangGang on 2017/9/22. + */ +public class CharUtil { + + // 根据Unicode编码完美的判断中文汉字和符号 + private static boolean isChinese(char c) { + Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); + return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS + || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B + || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS + || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION; + } + + // 完整的判断中文汉字和符号 + public static boolean isChinese(String strName) { + char[] ch = strName.toCharArray(); + for (char c : ch) { + if (!isChinese(c)) { + return false; + } + } + return true; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/CommonUtil.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/CommonUtil.java new file mode 100644 index 0000000..57c5f36 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/CommonUtil.java @@ -0,0 +1,28 @@ +package net.geedge.common.smartvalidate.utils; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; + +import java.util.Collection; +import java.util.Map; + +/** + * Created by ZhangGang on 2017/8/31. + */ +public class CommonUtil { + public static boolean isNull(String str) { + return StringUtils.isBlank(str); + } + + public static boolean isNull(Collection<?> collection) { + return CollectionUtils.isEmpty(collection); + } + + public static boolean isNull(Map<?, ?> paramMap) { + return null == paramMap || paramMap.isEmpty(); + } + + public static boolean isNull(Object[] array) { + return null == array || array.length == 0; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/ReflectUtils.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/ReflectUtils.java new file mode 100644 index 0000000..4e927df --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/ReflectUtils.java @@ -0,0 +1,27 @@ +package net.geedge.common.smartvalidate.utils; + +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Set; + +/** + * Created by ZhangGang on 2017/9/26. + */ +public class ReflectUtils { + + public static Set<Field> getFieldsByClass(Class cls) { + Set<Field> fieldSet = new HashSet<>(); + for (Class<?> clazz = cls; clazz != Object.class; clazz = clazz.getSuperclass()) { + Field[] fields = clazz.getDeclaredFields(); + if (CommonUtil.isNull(fields)) { + continue; + } + for (Field field : fields) { + if (!field.getName().equals("class") && !field.getName().equals("serialVersionUID")) { + fieldSet.add(field); + } + } + } + return fieldSet; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/RegexUtil.java b/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/RegexUtil.java new file mode 100644 index 0000000..849f1da --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/smartvalidate/utils/RegexUtil.java @@ -0,0 +1,15 @@ +package net.geedge.common.smartvalidate.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by ZhangGang on 2017/8/31. + */ +public class RegexUtil { + public static boolean test(String regex, String value) { + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(value); + return m.matches(); + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/AESUtil.java b/cn-admin/src/main/java/net/geedge/common/utils/AESUtil.java new file mode 100644 index 0000000..ea808e4 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/AESUtil.java @@ -0,0 +1,4 @@ +package net.geedge.common.utils; +public class AESUtil { + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/BufferReaderWrapper.java b/cn-admin/src/main/java/net/geedge/common/utils/BufferReaderWrapper.java new file mode 100644 index 0000000..d3f92ad --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/BufferReaderWrapper.java @@ -0,0 +1,31 @@ +package net.geedge.common.utils; + +import cn.hutool.core.util.StrUtil; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; + +public class BufferReaderWrapper extends BufferedReader { + public Reader in; + // public static final int MAX_STR_LEN=1024; + public BufferReaderWrapper(Reader in) { + super(in); + this.in=in; + } + public String load() throws IOException { + StringBuffer sb = new StringBuffer(); + int intC; + while ((intC = in.read()) != -1) { + char c = (char) intC; + if (c == '\n') { + break; + } + /* if (sb.length() >= MAX_STR_LEN) { + throw new IOException("input too long"); + }*/ + sb.append(c); + } + return StrUtil.isEmpty(sb.toString()) ? null : sb.toString(); + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/ConfigConstant.java b/cn-admin/src/main/java/net/geedge/common/utils/ConfigConstant.java new file mode 100644 index 0000000..3325a25 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/ConfigConstant.java @@ -0,0 +1,21 @@ +/** + + * + + * + + */ + +package net.geedge.common.utils; + +/** + * 系统参数相关Key + * + + */ +public class ConfigConstant { + /** + * 云存储配置KEY + */ + public final static String CLOUD_STORAGE_CONFIG_KEY = "CLOUD_STORAGE_CONFIG_KEY"; +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/Constant.java b/cn-admin/src/main/java/net/geedge/common/utils/Constant.java new file mode 100644 index 0000000..85a1f3f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/Constant.java @@ -0,0 +1,933 @@ +/** + + * + + * + + */ + +package net.geedge.common.utils; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.log.Log; +import org.apache.ibatis.mapping.DatabaseIdProvider; +import org.apache.poi.util.TempFile; + +import javax.sql.DataSource; +import java.io.File; +import java.sql.SQLException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.regex.Pattern; + +/** + * 常量 + * + * + */ +public class Constant { + private final static Log logger = Log.get(); + /** 超级管理员ID */ + public static final int SUPER_ADMIN = 1; + + // 系统 普通用户角色 + public static final int SYSTEM_COMMON_ROLE = 2; + /** 数据权限过滤 */ + public static final String SQL_FILTER = "sql_filter"; + /** + * 当前页码 + */ + public static final String PAGE = "pageNo"; + /** + * 每页显示记录数 + */ + public static final String LIMIT = "pageSize"; + /** + * 每页显示条数 + */ + public static final long PAGESIZE = 10; + + /** + * 排序方式 + */ + public static final String ORDER = "orderBy"; + /** + * 升序 + */ + public static final String ASC = "asc"; + + /** + * mysql text 最大长度 65535 + */ + public static final Integer MYSQL_TEXT_MAXLENGTH = 65535; + + /** + * 统一utf-8字符编码 + */ + public static final String DEFAULT_CHARTSET_NAME = "UTF-8"; + + /** + * 菜单类型 + */ + public enum MenuType { + /** + * 目录 + */ + CATALOG(0), + /** + * 菜单 + */ + MENU(1), + /** + * 按钮 + */ + BUTTON(2), + + /** + * tab标签 + */ + TAB(3); + + private int value; + + MenuType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** + * 当前数据库类型 + */ + public static final String DB_TYPE; + + public static final String ORACLE = "oracle"; + public static final String MYSQL = "mysql"; + public static final String POSTGRESQL = "postgresql"; + + // 系统重置类型 + public static final String[] SYSCONFIG_RESET_TYPE = { "metric", "alert", "sysconfig" }; + + /** + * 告警信息状态 + */ + public static final List<Integer> ALERTMESSAGE_STATE; + /** + * redis告警信息的key + */ + public static final String REDIS_KEY_ALERTMESSAGE = "ALERT_MESSAGE"; + + /** + * 记录endpoint和proserver 对应关系 + */ + public static final String REDIS_KEY_ENDPOINT_PROM = "endpoint_prom"; + + /** + * 支持告警的 promserver id + */ + public static final String REDIS_KEY_SUPPORT_ALERT_PROMSERVER_ID = "support_alert_promserver_id"; + + /** + * 记录 + */ + public static final String REDIS_KEY_CONF_EVENT = "conf_event"; + + /** + * 告警消息邮件通知 + */ + public static final String REDIS_KEY_EMAIL_ALERT_MESSAGE = "alert_message_list"; + + /** + * prometheus query range 代理接口 限制查询最大条数 + */ + public static final String QUERY_MAX_SERIES = "query_max_series"; + + /** + * prometheus server up 也就是endpoint状态 'endpoint'键值对应endpointId + */ + public static final String PROMSERVERUP_ENDPOINT_LABEL = "endpoint"; + + /** + * 临时目录 + */ + public static final String TEMP_PATH = System.getProperty("user.dir") + File.separator + "tmp"; + + /** + * 工具目录 + */ + public static final String TOOL_PATH = System.getProperty("user.dir") + File.separator + "tools"; + + // 当前sys_config 配置中配置项和所属类别map + public static final Map<String, List<String>> SYSCONFIG_TYPEWITHKEYS_MAP; + + // module 类型 可选值 http、snmp + public static final String MODULE_TYPE_HTTP = "http"; + public static final String MODULE_TYPE_SNMP = "snmp"; + + // module http 类型默认 path + public static final String MODULE_HTTP_DEFAULT_PATH = "/metrics"; + + public static final Integer SNMP_DEFAULT_PORT = 161; + + // snmp set value 可选类型集合 + public static final List<String> SNMP_SETVLAUE_TYPE; + + // 图表 singleStat statistics可选值列表 + public static final List<String> CHART_SINGLESTAT_STATISTICS; + + // alert rule 比较符号 + public static final List<String> RULE_OPERATORS; + + // snmp 采集指标相关 oid 信息 + public static final Map<String, String> SNMP_OID_MAP; + + public static final Map<String, String> SNMP_IFENTRY_MAP; + + // ssh 采集相关服务器信息指令 + public static final Map<String, String> SSH_SHELL_MAP; + + // alert rule unit + public static final Map<String, Integer> ALERT_RULE_UNIT_MAP; + + // asset field meta 配置值 + public static final List<String> ASSET_FIELD_META_VALUE; + /* + * alert message 不同状态对应表 + */ + public static final String ALERT_MESSAGE_ACTIVE_TABLE = "ALERT_MESSAGE_ACTIVE"; + public static final String ALERT_MESSAGE_SILENCE_TABLE = "ALERT_MESSAGE_SILENCE"; + public static final String ALERT_MESSAGE_HISTORY_TABLE = "ALERT_MESSAGE_HISTORY"; + /* + * alert message 不同状态 + */ + public static final Integer ALERT_MESSAGE_ACTIVE_STATE = 1; + public static final Integer ALERT_MESSAGE_SILENCE_STATE = 2; + public static final Integer ALERT_MESSAGE_HISTORY_STATE = 3; + + /** + * 可选值:1:active 2:pending 3:expired + */ + public static final Integer ALERT_SILENCE_STATE_ACTIVE = 1; + public static final Integer ALERT_SILENCE_STATE_PENDING = 2; + public static final Integer ALERT_SILENCE_STATE_EXPIRED = 3; + + /** + * alert message 表 与 状态 对应关系 KEY :tablename + */ + public static final Map<String, Integer> ALERT_MESSAGE_TABLE_STATE_MAPPING = Tool.MapUtil.newHashMap(); + /** + * alert message 状态 与 表 对应关系 KEY :state + */ + public static final Map<Integer, String> ALERT_MESSAGE_STATE_TABLE_MAPPING = Tool.MapUtil.newHashMap(); + + /** + * alert message 状态 与 名称 对应关系 KEY :state + */ + public static final Map<Integer, String> ALERT_MESSAGE_STATE_NAME_MAPPING = Tool.MapUtil.newHashMap(); + + /** + * 表名 和 排序字段对应关系 KEY: tablename + */ + public static final Map<String, Map<String, String>> TABLE_NAME_ORDER_FIELD_MAPPING = Tool.MapUtil.newHashMap(); + + static { + DatabaseIdProvider databaseIdProvider = SpringContextUtils.getBean("getDatabaseIdProvider", + DatabaseIdProvider.class); + DataSource dataSource = SpringContextUtils.getBean("dataSource", DataSource.class); + String databaseId = null; + try { + databaseId = databaseIdProvider.getDatabaseId(dataSource); + } catch (SQLException e) { + logger.error(e); + } + DB_TYPE = databaseId; + + File tempPath = FileUtil.file(TEMP_PATH); + if (!tempPath.isDirectory()) { + boolean mkdir = tempPath.mkdir(); + if (mkdir) { + logger.debug("临时目录tmp创建成功"); + } else { + logger.debug("临时目录tmp创建失败"); + } + } + + // 设置 POI 临时目录为项目 临时目录 + TempFile.setTempFileCreationStrategy(new TempFile.DefaultTempFileCreationStrategy(tempPath)); + + ALERTMESSAGE_STATE = new ArrayList<Integer>(); + ALERTMESSAGE_STATE.add(1); + ALERTMESSAGE_STATE.add(2); + + SYSCONFIG_TYPEWITHKEYS_MAP = new HashMap<>(); + + SYSCONFIG_TYPEWITHKEYS_MAP.put("basic", + Arrays.asList(new String[] { "alert_api", "asset_ping_switch", "asset_ping_interval", + "node_exporter_target_path", "scrape_interval", "storage_local_retention", "system_name", + "timezone", "default_cabinet_usize", "query_max_series", "map_center_config", + "unsaved_change" })); + SYSCONFIG_TYPEWITHKEYS_MAP.put("email", + Arrays.asList(new String[] { "email_enable", "email_smtp_host", "email_smtp_port", "email_smtp_account", + "email_smtp_password", "email_send_account", "email_test_reciver", "email_ssl_flag", + "email_tls_flag", "test" })); + SYSCONFIG_TYPEWITHKEYS_MAP.put("terminal", Arrays.asList(new String[] { "max_terminal_num" })); + SYSCONFIG_TYPEWITHKEYS_MAP.put("ldap", Arrays.asList(new String[] { "ldap_address", "ldap_dn", "ldap_password", + "ldap_ou", "ldap_user_filter", "ldap_mapping", "ldap_enable", "test" })); + + SNMP_SETVLAUE_TYPE = new ArrayList<>(); + SNMP_SETVLAUE_TYPE.add("OctetString"); + SNMP_SETVLAUE_TYPE.add("Integer"); + SNMP_SETVLAUE_TYPE.add("OID"); + SNMP_SETVLAUE_TYPE.add("Counter32"); + SNMP_SETVLAUE_TYPE.add("IpAddress"); + SNMP_SETVLAUE_TYPE.add("TimeTicks"); + SNMP_SETVLAUE_TYPE.add("UnsignedInteger"); + SNMP_SETVLAUE_TYPE.add("BITS"); + SNMP_SETVLAUE_TYPE.add("Float"); + SNMP_SETVLAUE_TYPE.add("DateAndTime"); + + CHART_SINGLESTAT_STATISTICS = new ArrayList<>(); + CHART_SINGLESTAT_STATISTICS.add("min"); + CHART_SINGLESTAT_STATISTICS.add("max"); + CHART_SINGLESTAT_STATISTICS.add("average"); + CHART_SINGLESTAT_STATISTICS.add("total"); + CHART_SINGLESTAT_STATISTICS.add("first"); + CHART_SINGLESTAT_STATISTICS.add("last"); + CHART_SINGLESTAT_STATISTICS.add("range"); + CHART_SINGLESTAT_STATISTICS.add("different"); + + RULE_OPERATORS = Arrays.asList(new String[] { "==", "!=", ">", "<", ">=", "<=" }); + + SNMP_OID_MAP = new HashMap<>(); + SNMP_OID_MAP.put("sysName", "1.3.6.1.2.1.1.5"); + SNMP_OID_MAP.put("sysLocation", "1.3.6.1.2.1.1.6"); + SNMP_OID_MAP.put("sysContact", "1.3.6.1.2.1.1.4"); + SNMP_OID_MAP.put("sysServices", "1.3.6.1.2.1.1.7"); + SNMP_OID_MAP.put("sysUpTime", "1.3.6.1.2.1.1.3"); + SNMP_OID_MAP.put("ifNumber", "1.3.6.1.2.1.2.1"); + SNMP_OID_MAP.put("ifEntry", "1.3.6.1.2.1.2.2.1"); + + SNMP_IFENTRY_MAP = new HashMap<>(); + SNMP_IFENTRY_MAP.put("1.3.6.1.2.1.2.2.1.1", "ifIndex"); + SNMP_IFENTRY_MAP.put("1.3.6.1.2.1.2.2.1.2", "ifDescr"); + SNMP_IFENTRY_MAP.put("1.3.6.1.2.1.2.2.1.3", "ifType"); + SNMP_IFENTRY_MAP.put("1.3.6.1.2.1.2.2.1.4", "ifMtu"); + SNMP_IFENTRY_MAP.put("1.3.6.1.2.1.2.2.1.5", "ifSpeed"); + SNMP_IFENTRY_MAP.put("1.3.6.1.2.1.2.2.1.6", "ifPhysAddress"); + SNMP_IFENTRY_MAP.put("1.3.6.1.2.1.2.2.1.7", "ifAdminStatus"); + SNMP_IFENTRY_MAP.put("1.3.6.1.2.1.2.2.1.8", "ifOperStatus"); + SNMP_IFENTRY_MAP.put("1.3.6.1.2.1.2.2.1.9", "ifLastChange"); + + SSH_SHELL_MAP = new HashMap<>(); + SSH_SHELL_MAP.put("hostname", "hostname"); + SSH_SHELL_MAP.put("cpu", + "cat /proc/cpuinfo| grep \"physical id\"| sort| uniq| wc -l;echo `cat /proc/cpuinfo|grep \"model name\" | uniq -d|awk -F: '{print $2}'` \\* `cat /proc/cpuinfo| grep \"processor\"| wc -l`"); + SSH_SHELL_MAP.put("memory", "free -m | grep Mem | awk -F ' ' '{printf (\"%.3f\\n\",$2/1024)}'"); + SSH_SHELL_MAP.put("disk", + "lsblk|grep disk|awk '{print $1,$4}';cat /proc/scsi/scsi|grep Vendor|awk '{print $2,$4}'|grep -v DVD"); + SSH_SHELL_MAP.put("core", "cat /proc/version"); + // put("os","cat /etc/redhat-release"); + SSH_SHELL_MAP.put("uptime", "uptime -s"); + + ALERT_RULE_UNIT_MAP = new HashMap<>(); + ALERT_RULE_UNIT_MAP.put("none", 1); + ALERT_RULE_UNIT_MAP.put("short", 2); + ALERT_RULE_UNIT_MAP.put("percent(0-100)", 3); + ALERT_RULE_UNIT_MAP.put("percent(0.0-1.0)", 4); + ALERT_RULE_UNIT_MAP.put("local format", 5); + ALERT_RULE_UNIT_MAP.put("bits", 6); + ALERT_RULE_UNIT_MAP.put("bytes", 7); + ALERT_RULE_UNIT_MAP.put("kilobytes", 8); + ALERT_RULE_UNIT_MAP.put("megabytes", 9); + ALERT_RULE_UNIT_MAP.put("gigabytes", 10); + ALERT_RULE_UNIT_MAP.put("terabytes", 11); + ALERT_RULE_UNIT_MAP.put("petabytes", 12); + ALERT_RULE_UNIT_MAP.put("packets/sec", 13); + ALERT_RULE_UNIT_MAP.put("bits/sec", 14); + ALERT_RULE_UNIT_MAP.put("bytes/sec", 15); + ALERT_RULE_UNIT_MAP.put("kilobytes/sec", 16); + ALERT_RULE_UNIT_MAP.put("kilobits/sec", 17); + ALERT_RULE_UNIT_MAP.put("megabytes/sec", 18); + ALERT_RULE_UNIT_MAP.put("megabits/sec", 19); + ALERT_RULE_UNIT_MAP.put("gigabytes/sec", 20); + ALERT_RULE_UNIT_MAP.put("gigabits/sec", 21); + ALERT_RULE_UNIT_MAP.put("terabytes/sec", 22); + ALERT_RULE_UNIT_MAP.put("terabits/sec", 23); + ALERT_RULE_UNIT_MAP.put("petabytes/sec", 24); + ALERT_RULE_UNIT_MAP.put("petabits/sec", 25); + ALERT_RULE_UNIT_MAP.put("Hertz(1/s)", 26); + ALERT_RULE_UNIT_MAP.put("nanoseconds(ns)", 27); + ALERT_RULE_UNIT_MAP.put("nanoseconds", 27); + ALERT_RULE_UNIT_MAP.put("ns", 27); + ALERT_RULE_UNIT_MAP.put("microseconds(us)", 28); + ALERT_RULE_UNIT_MAP.put("microseconds", 28); + ALERT_RULE_UNIT_MAP.put("us", 28); + ALERT_RULE_UNIT_MAP.put("milliseconds(ms)", 29); + ALERT_RULE_UNIT_MAP.put("milliseconds", 29); + ALERT_RULE_UNIT_MAP.put("ms", 29); + ALERT_RULE_UNIT_MAP.put("seconds(s)", 30); + ALERT_RULE_UNIT_MAP.put("seconds", 30); + ALERT_RULE_UNIT_MAP.put("s", 30); + ALERT_RULE_UNIT_MAP.put("minutes(m)", 31); + ALERT_RULE_UNIT_MAP.put("minutes", 31); + ALERT_RULE_UNIT_MAP.put("m", 31); + ALERT_RULE_UNIT_MAP.put("hours(h)", 32); + ALERT_RULE_UNIT_MAP.put("hours", 32); + ALERT_RULE_UNIT_MAP.put("h", 32); + ALERT_RULE_UNIT_MAP.put("days(d)", 33); + ALERT_RULE_UNIT_MAP.put("days", 33); + ALERT_RULE_UNIT_MAP.put("d", 33); + ALERT_RULE_UNIT_MAP.put("YYYY-MM-DD HH:mm:ss", 34); + ALERT_RULE_UNIT_MAP.put("MM/DD/YYYY h:mm:ss a", 35); + + ASSET_FIELD_META_VALUE = Arrays.asList(new String[] { "text", "multitext", "textarea", "radio", "checkbox", + "select", "integer", "double", "datetime", "email" }); + + ALERT_MESSAGE_TABLE_STATE_MAPPING.put(ALERT_MESSAGE_ACTIVE_TABLE, ALERT_MESSAGE_ACTIVE_STATE); + ALERT_MESSAGE_TABLE_STATE_MAPPING.put(ALERT_MESSAGE_SILENCE_TABLE, ALERT_MESSAGE_SILENCE_STATE); + ALERT_MESSAGE_TABLE_STATE_MAPPING.put(ALERT_MESSAGE_HISTORY_TABLE, ALERT_MESSAGE_HISTORY_STATE); + + ALERT_MESSAGE_STATE_TABLE_MAPPING.put(ALERT_MESSAGE_ACTIVE_STATE, ALERT_MESSAGE_ACTIVE_TABLE); + ALERT_MESSAGE_STATE_TABLE_MAPPING.put(ALERT_MESSAGE_SILENCE_STATE, ALERT_MESSAGE_SILENCE_TABLE); + ALERT_MESSAGE_STATE_TABLE_MAPPING.put(ALERT_MESSAGE_HISTORY_STATE, ALERT_MESSAGE_HISTORY_TABLE); + + ALERT_MESSAGE_STATE_NAME_MAPPING.put(ALERT_MESSAGE_ACTIVE_STATE, "active"); + ALERT_MESSAGE_STATE_NAME_MAPPING.put(ALERT_MESSAGE_SILENCE_STATE, "silence"); + ALERT_MESSAGE_STATE_NAME_MAPPING.put(ALERT_MESSAGE_HISTORY_STATE, "expired"); + + Map<String, String> assetOrderFieldMap = new HashMap<>(); + assetOrderFieldMap.put("name", "asset.name"); + assetOrderFieldMap.put("id", "asset.id"); + assetOrderFieldMap.put("manageIp", "asset.manage_ip"); + assetOrderFieldMap.put("type", "type.name"); + assetOrderFieldMap.put("state", "state.name"); + assetOrderFieldMap.put("dc", "dc.name"); + assetOrderFieldMap.put("cabinet", "cab.name"); + assetOrderFieldMap.put("brand", "brand.name"); + assetOrderFieldMap.put("model", "model.name"); + assetOrderFieldMap.put("endpointNum", "endpointNum"); + assetOrderFieldMap.put("alertNum", "alertNum"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("asset_asset", assetOrderFieldMap); + + Map<String, String> modelOrderFieldMap = new HashMap<>(); + modelOrderFieldMap.put("name", "model.name"); + modelOrderFieldMap.put("id", "model.id"); + modelOrderFieldMap.put("brand", "brand.name"); + modelOrderFieldMap.put("assetNum", "assetNum"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("asset_model", modelOrderFieldMap); + + Map<String, String> labelsOrderFieldMap = new HashMap<>(); + labelsOrderFieldMap.put("name", "afm.name"); + labelsOrderFieldMap.put("id", "afm.id"); + labelsOrderFieldMap.put("metaKey", "afm.meta_key"); + labelsOrderFieldMap.put("group", "afg.name"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("asset_field_meta", labelsOrderFieldMap); + + Map<String, String> assetTypeOrderFieldMap = new HashMap<>(); + assetTypeOrderFieldMap.put("name", "name"); + assetTypeOrderFieldMap.put("id", "id"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("asset_type_conf", assetTypeOrderFieldMap); + + Map<String, String> projectOrderFieldMap = new HashMap<>(); + projectOrderFieldMap.put("name", "mp.name"); + projectOrderFieldMap.put("id", "mp.id"); + projectOrderFieldMap.put("moduleNum", "moduleNum"); + projectOrderFieldMap.put("endpointNum", "endpointNum"); + projectOrderFieldMap.put("alertNum", "alertNum"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("monitor_project", projectOrderFieldMap); + + Map<String, String> moduleOrderFieldMap = new HashMap<>(); + moduleOrderFieldMap.put("name", "m.name"); + moduleOrderFieldMap.put("id", "m.id"); + moduleOrderFieldMap.put("project", "p.name"); + moduleOrderFieldMap.put("endpointNum", "endpointNum"); + moduleOrderFieldMap.put("alertNum", "alertNum"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("monitor_module", moduleOrderFieldMap); + + Map<String, String> endpointOrderFieldMap = new HashMap<>(); + endpointOrderFieldMap.put("name", "e.name"); + endpointOrderFieldMap.put("id", "e.id"); + endpointOrderFieldMap.put("project", "p.name"); + endpointOrderFieldMap.put("module", "m.name"); + endpointOrderFieldMap.put("asset", "a.name"); + endpointOrderFieldMap.put("alerts", "alertNum"); + endpointOrderFieldMap.put("state", "es.state"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("monitor_endpoint", endpointOrderFieldMap); + + Map<String, String> alertMsgOrderFieldMap = new HashMap<>(); + alertMsgOrderFieldMap.put("priority", "alsc.name"); + alertMsgOrderFieldMap.put("id", "am.id"); + alertMsgOrderFieldMap.put("alertRule", "ar.name"); + alertMsgOrderFieldMap.put("labels", "am.labels"); + alertMsgOrderFieldMap.put("startAt", "am.start_at"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("alert_message_active", alertMsgOrderFieldMap); + + Map<String, String> alertRuleOrderFieldMap = new HashMap<>(); + alertRuleOrderFieldMap.put("name", "ar.name"); + alertRuleOrderFieldMap.put("id", "ar.name"); + alertRuleOrderFieldMap.put("severity", "alsc.name"); + alertRuleOrderFieldMap.put("alertNum", "alertNum"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("alert_rule", alertRuleOrderFieldMap); + + Map<String, String> alertSilenceOrderFieldMap = new HashMap<>(); + alertSilenceOrderFieldMap.put("state", "state"); + alertSilenceOrderFieldMap.put("id", "id"); + alertSilenceOrderFieldMap.put("matchers", "matchers"); + alertSilenceOrderFieldMap.put("startAt", "start_at"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("alert_silence_conf", alertSilenceOrderFieldMap); + + Map<String, String> dcOrderFieldMap = new HashMap<>(); + dcOrderFieldMap.put("name", "dc.name"); + dcOrderFieldMap.put("id", "dc.id"); + dcOrderFieldMap.put("cabinetNum", "cabinetNum"); + dcOrderFieldMap.put("assetNum", "assetNum"); + dcOrderFieldMap.put("alertNum", "alertNum"); + dcOrderFieldMap.put("state", "dc.state"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("dc", dcOrderFieldMap); + + Map<String, String> agentOrderFieldMap = new HashMap<>(); + agentOrderFieldMap.put("datacenter", "dc.name"); + agentOrderFieldMap.put("id", "ps.id"); + agentOrderFieldMap.put("type", "ps.type"); + agentOrderFieldMap.put("status", "ps.status"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("prom_server", agentOrderFieldMap); + + Map<String, String> expreOrderFieldMap = new HashMap<>(); + expreOrderFieldMap.put("name", "name"); + expreOrderFieldMap.put("id", "id"); + expreOrderFieldMap.put("gname", "gname"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("visual_expression_tmpl", expreOrderFieldMap); + + Map<String, String> chartTempOrderFieldMap = new HashMap<>(); + chartTempOrderFieldMap.put("name", "vch.name"); + chartTempOrderFieldMap.put("id", "vch.id"); + chartTempOrderFieldMap.put("type", "vch.type"); + chartTempOrderFieldMap.put("varType", "vch.var_type"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("visual_chart", chartTempOrderFieldMap); + + Map<String, String> mibOrderFieldMap = new HashMap<>(); + mibOrderFieldMap.put("name", "sm.name"); + mibOrderFieldMap.put("id", "sm.id"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("snmp_mib", mibOrderFieldMap); + + Map<String, String> snmpCerdenOrderFieldMap = new HashMap<>(); + snmpCerdenOrderFieldMap.put("name", "name"); + snmpCerdenOrderFieldMap.put("id", "id"); + snmpCerdenOrderFieldMap.put("type", "type"); + TABLE_NAME_ORDER_FIELD_MAPPING.put("snmp_credential", snmpCerdenOrderFieldMap); + } + + /** + * 支持的语言 [{"name":"简体中文","value":"zh"},...] + */ + public static final List<Map<String, String>> langList = new ArrayList<>(); + + /** + * 字典中语言的名称和类型 + */ + public static final String DICT_NAME_LANG = "lang"; + + /** + * 定时任务状态 + */ + public enum ScheduleStatus { + /** + * 正常 + */ + NORMAL(0), + /** + * 暂停 + */ + PAUSE(1); + + private int value; + + ScheduleStatus(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + // delFlag + public static final String DELFLAG_FALSE = "0"; // 未删除 + + public static final Integer AUTH_PASSWORD = 1;// 密码认证 + public static final Integer AUTH_CERTIFICATE = 2;// 私钥证书认证 + + public static final String AUTH_TOKEN_CODE = "Authorization"; + + public static final Integer SNMPV1 = 1; + public static final Integer SNMPV2 = 2; + public static final Integer SNMPV3 = 3; + // snmp默认团体名 + public static final String SNMP_DEFAULT_COMMUNITY = "public"; + + public enum SnmpOperationType { + GET("get"), WALK("walk"), GETNEXT("getnext"), SET("set"); + + private String value; + + SnmpOperationType(String value) { + this.value = value; + } + + public static String getOperationType(String value) { + for (SnmpOperationType type : SnmpOperationType.values()) { + if (StrUtil.equals(type.getValue(), value)) { + return type.getValue(); + } + } + return null; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + } + + public enum PanelType { + DASHBOARD("dashboard"), ASSET("asset"), PROJECT("project"), MODULE("module"), ENDPOINT("endpoint"), + MODEL("model"); + + private String value; + + PanelType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + } + + public enum PromserverType { + GLOBAL("global", 1), PER_DATACENTER("per_datacenter", 2), THANOS_QUERY("thanos_query", 3), + THANOS_RULE("thanos_rule", 4), THANOS_SIDECAR("thanos_sidecar", 5), THANOS_STORE("thanos_store", 6), + THANOS_COMPACTOR("thanos_compactor", 7); + + private String name; + private Integer value; + + PromserverType(String name, Integer value) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public void setValue(Integer value) { + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static PromserverType getPromserverType(Integer value) { + for (PromserverType server : PromserverType.values()) { + if (server.getValue().equals(value)) { + return server; + } + } + return null; + } + } + + // cn-web 新增常量 + + // 字典表中 chart 类型的 type 值 + public static final String DICT_CHART_TYPE = "chartType"; + + // 字典表中 chart element 表达式类型的 type 值 + public static final String DICT_EXPRESSION_TYPE = "exprType"; + + // 目前机柜最大值限制 + public static final Integer CURRENT_CABINET_MAXU = 47; + + // 默认告警间隔为15s + public static final Integer ALERT_INTERVAL = 15; + + // ip 校验正则 + public static final String REGEX_IP = "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d|\\*)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d|\\*)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d|\\*)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d|\\*)"; + + // 二级域名 + public static final String REGEX_DOMAIN = "(\\w*\\.?){2}\\.(com.cn|net.cn|gov.cn|org\\.nz|org.cn|com|net|org|gov|cc|biz|info|cn|co)$"; + + // 配置表中 告警间隔 key + public static final String SYSCONFIG_KEY_ALERTINTERVAL = "alert_interval"; + + // 配置表中 刮取周期 key + public static final String SYSCONFIG_KEY_SCRAPEINTERVAL = "default_scrape_interval"; + + // 配置表中 刮取超时时间 + public static final String SYSCONFIG_KEY_SCRAPETIMEOUT = "default_scrape_timeout"; + + // 配置表中 blackbox job scrape_interval 刮取周期 key + public static final String SYSCONFIG_KEY_ASSET_PING_INTERVAL = "asset_ping_interval"; + + // 配置表中 prometheus yml 模板 key + public static final String SYSCONFIG_KEY_PROM_YML_TMPL = "prom_yml_tmpl"; + + // 配置表中 prometheus cmd 模板 Key + public static final String SYSCONFIG_KEY_PROM_CMD_TMPL = "prom_cmd_tmpl"; + + // 配置表中 prometheus rule.yml 模板 Key + public static final String SYSCONFIG_KEY_PROM_RULE_TMPL = "prom_rule_tmpl"; + + // 配置表中 prometheus 本地保存天数配置 + public static final String SYSCONFIG_KEY_STORAGE_LOCAL_RETENTION = "storage_local_retention"; + + // 配置表中 alert_api + public static final String SYSCONFIG_KEY_ALERT_API = "alert_api"; + + // 配置表中 alert_path_prefix + public static final String SYSCONFIG_KEY_ALERT_PATH_PREFIX = "alert_path_prefix"; + + // endpoint state 定时任务执行间隔时间 + public static final String SYSCONFIG_KEY_ENDPOINT_QUERYINTERVAL = "endpoint_query_interval"; + + // 邮件告警开关 + public static final String SYSCONFIG_KEY_EMAIL_ENABLE = "email_enable"; + + // cn 系统版本 + public static final String SYSCONFIG_KEY_SYSTEM_VERSION = "system_version"; + + // 内置 generator 路径 + public static final String SYSCONFIG_KEY_GENERATOR_PATH = "generator_path"; + // 配置表中 blackbox 源, on 时,通过 global 做 ping 检测,off 时,通过 per-datacenter 检测 + public static final String SYSCONFIG_KEY_ASSET_PING_FROM = "asset_ping_from"; + + // 配置表中 配置prometheus是否开启联邦模式,1:开启,0:关闭(界面禁用 添加选择 per-datacenter agent,所有endpoint + // 配置信息 hash 分布到 global prometheus) + public static final String SYSCONFIG_KEY_PROM_FEDER_ENABLED = "prometheus_federation_enabled"; + + // 机柜默认大小 + public static final String SYSCONFIG_KEY_DEFAULT_CABINETU = "default_cabinet_usize"; + + // 测试邮件发送模板 + public static final String SYSCONFIG_KEY_TESTEMAIL_SEND_TEMPLATE = "test_email_send_template"; + + // 新增 asset 添加chart配置 + public static final String SYSCONFIG_KEY_ASSET_CHART_TPL = "asset_chart_tpl"; + + // 新增 endpoint 添加chart配置 + public static final String SYSCONFIG_KEY_ENDPOINT_CHART_TPL = "endpoint_chart_tpl"; + + // 新增model 添加chart配置 + public static final String SYSCONFIG_KEY_MODEL_CHART_TPL = "model_chart_tpl"; + + // 新增project 添加chart配置 + public static final String SYSCONFIG_KEY_PROJECT_CHART_TPL = "project_chart_tpl"; + + // asset 导入表头 + public static final String SYSCONFIG_KEY_ASSET_ASSET_EXPORT_HEADER = "asset_asset_export_header"; + + // alert rule 导入表头 + public static final String SYSCONFIG_KEY_ALERTRULE_EXPORT_HEADER = "rule_export_header"; + + // chart dashboard 类型导入表头 + public static final String SYSCONFIG_KEY_CHART_EXPORT_HEADER = "chart_export_header"; + + // model 类型导入表头 + public static final String SYSCONFIG_KEY_MODEL_CHART_EXPORT_HEADER = "model_chart_export_header"; + + // asset 类型导入表头 + public static final String SYSCONFIG_KEY_ASSET_CHART_EXPORT_HEADER = "asset_chart_export_header"; + + // endpoint 导入表头 + public static final String SYSCONFIG_KEY_MONITORENDPOINT_EXPORT_HEADER = "monitor_endpoint_export_header"; + + // expression template 导入表头 + public static final String SYSCONFIG_KEY_EXPRETMPL_EXPORT_HEADER = "expretmpl_export_header"; + + // 登录时 ldap template 超时时间 + public static final String SYSCONFIG_KEY_LDAP_QUERY_TIMEOUT = "ldap_query_timeout"; + + // 告警级别 高 + public static final String ALERT_SEVERITY_HIGH = "P1"; + + // 告警级别 中 + public static final String ALERT_SEVERITY_MEDIUM = "P2"; + + // 告警级别 低 + public static final String ALERT_SEVERITY_LOW = "P3"; + + // account protocol ssh协议 + public static final String ACCOUNT_SSH_PROTOCOL = "SSH"; + + // account protocol telnet协议 + public static final String ACCOUNT_TELNET_PROTOCOL = "TELNET"; + + // account protocol snmp协议 + public static final String ACCOUNT_SNMP_PROTOCOL = "SNMP"; + + // confagent程序 端口 + public static final String CONFAGENT_PORT = "confagent_port"; + // confagent项目名称 + public static final String CONFAGENT_PATH = "confagent_path"; + + // 开关开启状态 + public static final String SWITCH_OPEN = "on"; + + // 开关关闭状态 + public static final String SWITCH_CLOSE = "off"; + + // 资产服务器类型 + public static final String ASSET_SERVER_TYPE = "server"; + + // panel chart link 链表结构 首位 prev 值 + public static final Integer START_PREV_VALUE = 0; + + // panel chart link 链表结构 末尾 next 值 + public static final Integer END_NEXT_VALUE = -1; + + // 连接smtp邮箱服务器超时时间 10秒 + public static final String CONNECTION_SMTP_TIMEOUT = "10000"; + + /** + * MIB四种数据类型 IDENTIFIER 、OBJECT、TABLE、ENTRY + */ + public static final String MIB_IDENTIFIER_TYPE = "IDENTIFIER"; + public static final String MIB_OBJECT_TYPE = "OBJECT"; + public static final String MIB_TABLE_TYPE = "TABLE"; + public static final String MIB_ENTRY_TYPE = "ENTRY"; + // mib定义中 entry采用的格式为sequence 用以区分type 为 entry + public static final String MIB_ENTRY_SYNTAX = "SEQUENCE"; + + // snmp browser 中返回oid 与 mib文件中name对应,当前截取位置为 倒数1位 + public static final int OIDNAME_TRUNCATION_INDEX = 1; + + // 图表 url类型 + public static final String CHART_URL_TYPE = "url"; + + // 图表 singleStat 类型 + public static final String CHART_SINGLESTAT_TYPE = "singleStat"; + + // 图表singleStat 类型 paramkey名称 + public static final String CHART_SINGLESTAT_PARAMkEY = "statistics"; + + // IDC traffic中tags key正则校验表达式 注:同 prometheus 标签正则 + public static final Pattern PROMETHEUS_LABELSKEY_PATTERN = Pattern.compile("^[a-zA-Z_][a-zA-Z0-9_]*$"); + // node_exporter shell 脚本中 替换路径的名称 + public static final String NODEEXPORTER_SHELLREPLACE_PATH = "target_path"; + + // 测试邮件发送标题 + public static final String TESTEMAIL_SEND_TITLE = "Test"; + + // reset操作处理的表信息数据 + public static final String RESET_TABLE_INFOS = "reset_table_infos"; + + // 图表类型为line bar stackArea + public static final String CHART_DEFAULT_PARAMkEY = "threshold"; + + // 图表类型为alertList + public static final String CHART_ALERTLIST_TYPE = "alertList"; + + // 图表类型为 text + public static final String CHART_TEXT_TYPE = "text"; + + // 图表类型为 assetInfo + public static final String CHART_ASSETINFO_TYPE = "assetInfo"; + + // 图表类型为 endpointInfo + public static final String CHART_ENDPOINTINFO_TYPE = "endpointInfo"; + + public static final String CHART_GROUP_TYPE = "group"; + + public static final String CHART_ELEMENT_EXPERT_TYPE = "expert"; + + // 国际化对应 + public static final String I18N_MAPPING = "i18n_mapping"; + + // endpoint state功能是否开启 0 不开启 1 开启 + public static final String ENDPOINT_ALERT_PUSH = "endpoint_alert_push"; + + // endpoint state告警规则 + public static final String ENDPOINT_ALERT_RULE = "endpoint_alert_rule"; + + // 存放prometheus推送过来的告警消息 + public static final String ALERT_MESSAGE_RECV = "alert_message_recv"; + + /** + * 存放 active 状态 告警消息 + */ + public static final String ALERT_MESSAGE_ACTIVE_PRIX = "alert_message_active_"; + /** + * 通过redis 自增实现 alert message 表中id 全局唯一 + */ + public static final String ALERT_MESSAGE_ID_PRIX = "alert_message_id_"; + /** + * alert message 自增主键时间前缀 + */ + public static final SimpleDateFormat ALERT_MESSAGE_ID_FORMAT = new SimpleDateFormat("yyMMddHHmm"); + /** + * 存放 silence 状态 告警消息 + */ + public static final String ALERT_MESSAGE_SILENCE_PRIX = "alert_message_silence_"; + + // 存放prometheus已经处理过的告警信息 + public static final String ALERT_MESSAGE_SILENCE = "alert_message_silence"; + + // 存放需要通知的告警信息 + public static final String ALERT_MESSAGE_NOTIFY = "alert_message_notify"; + + public static final SimpleDateFormat ALERT_MESSAGE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + + public static final Integer ADMIN_USER_ID = 1; + + public static final String PIN = "password"; + + // 高可用 + public static final String SERVER_ID = Tool.IdUtil.fastUUID(); + public static final String SYS_HA_LOCK = "sys_ha_lock"; + + public static final String CN_ROOT_PATH = StrUtil.subBefore(System.getProperty("user.dir"), StrUtil.C_SLASH, + true); + public static final String CNWEB_ROOT_PATH = CN_ROOT_PATH + "/cn-web"; + public static final String TMP_ROOT_PATH = CN_ROOT_PATH + "/cn-web/tmp"; + public static final String GUI_ROOT_PATH = CN_ROOT_PATH + "/cn-web/webRoot"; + public static final String RESOURCE_ROOT_PATH = CN_ROOT_PATH + "/cn-web/resource";// + public static final String BIN_ROOT_PATH = CN_ROOT_PATH + "/cn-web/bin";// promtool,generator + + /* + * alert message label 中自定义key + */ + public static final String LABEL_ENDPOINT_ID_KEY = "endpoint_id"; + public static final String LABEL_MODULE_ID_KEY = "module_id"; + public static final String LABEL_PROJECT_ID_KEY = "project_id"; + public static final String LABEL_ASSET_ID_KEY = "asset_id"; + public static final String LABEL_DC_ID_KEY = "datacenter_id"; + public static final String LABEL_RULE_ID_KEY = "alertname"; + public static final String LABEL_SEVERITY_ID_KEY = "severity_id"; + + public static final String ALERT_API = "alert_api"; + public static final String ALERT_PATH_PREFIX = "alert_path_prefix"; + + public static final String SYSCONFIG_SNMP_PORT_KEY = "snmp_trap_listen_port"; + public static final String SYSCONFIG_SESSION_TIMEOUT_KEY = "session_timeout"; + + public static final String SETUP_FILE_NAME = "setup.json"; + + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/HttpContextUtils.java b/cn-admin/src/main/java/net/geedge/common/utils/HttpContextUtils.java new file mode 100644 index 0000000..e73fa27 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/HttpContextUtils.java @@ -0,0 +1,12 @@ +package net.geedge.common.utils; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +public class HttpContextUtils { + public static HttpServletRequest getHttpServletRequest() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/IPUtils.java b/cn-admin/src/main/java/net/geedge/common/utils/IPUtils.java new file mode 100644 index 0000000..08a437d --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/IPUtils.java @@ -0,0 +1,63 @@ +/** + + * + + * + * + */ + +package net.geedge.common.utils; + +import cn.hutool.log.Log; +import org.apache.commons.lang.StringUtils; + +import javax.servlet.http.HttpServletRequest; + +/** + * IP地址 + * + * @author Mark [email protected] + */ +public class IPUtils { + private static Log logger = Log.get(); + + /** + * 获取IP地址 + * + * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 + * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 + */ + public static String getIpAddr(HttpServletRequest request) { + String ip = null; + try { + ip = request.getHeader("x-forwarded-for"); + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + } catch (Exception e) { + logger.error("IPUtils ERROR ",e); + } + +// //使用代理,则获取第一个IP地址 +// if(StringUtils.isEmpty(ip) && ip.length() > 15) { +// if(ip.indexOf(",") > 0) { +// ip = ip.substring(0, ip.indexOf(",")); +// } +// } + + return ip; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/JSONUtil.java b/cn-admin/src/main/java/net/geedge/common/utils/JSONUtil.java new file mode 100644 index 0000000..d1421ce --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/JSONUtil.java @@ -0,0 +1,907 @@ +package net.geedge.common.utils; + +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.file.FileReader; +import cn.hutool.core.lang.TypeReference; +import cn.hutool.core.util.*; +import cn.hutool.json.*; +import cn.hutool.json.serialize.*; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Type; +import java.nio.charset.Charset; +import java.time.temporal.TemporalAccessor; +import java.util.*; + +/** + * JSON工具类 + * + * @author Looly + */ +public class JSONUtil { + + // -------------------------------------------------------------------- Pause start + + /** + * 创建JSONObject + * + * @return JSONObject + */ + public static JSONObject createObj() { + return new JSONObject(); + } + + /** + * 创建JSONObject + * + * @param config JSON配置 + * @return JSONObject + * @since 5.2.5 + */ + public static JSONObject createObj(JSONConfig config) { + return new JSONObject(config); + } + + /** + * 创建 JSONArray + * + * @return JSONArray + */ + public static JSONArray createArray() { + return new JSONArray(); + } + + /** + * 创建 JSONArray + * + * @param config JSON配置 + * @return JSONArray + * @since 5.2.5 + */ + public static JSONArray createArray(JSONConfig config) { + return new JSONArray(config); + } + + /** + * JSON字符串转JSONObject对象 + * + * @param jsonStr JSON字符串 + * @return JSONObject + */ + public static JSONObject parseObj(String jsonStr) { + return new JSONObject(jsonStr); + } + + /** + * JSON字符串转JSONObject对象<br> + * 此方法会忽略空值,但是对JSON字符串不影响 + * + * @param obj Bean对象或者Map + * @return JSONObject + */ + public static JSONObject parseObj(Object obj) { + return new JSONObject(obj); + } + + /** + * JSON字符串转JSONObject对象<br> + * 此方法会忽略空值,但是对JSON字符串不影响 + * + * @param obj Bean对象或者Map + * @param config JSON配置 + * @return JSONObject + * @since 5.3.1 + */ + public static JSONObject parseObj(Object obj, JSONConfig config) { + return new JSONObject(obj, config); + } + + /** + * JSON字符串转JSONObject对象 + * + * @param obj Bean对象或者Map + * @param ignoreNullValue 是否忽略空值,如果source为JSON字符串,不忽略空值 + * @return JSONObject + * @since 3.0.9 + */ + public static JSONObject parseObj(Object obj, boolean ignoreNullValue) { + return new JSONObject(obj, ignoreNullValue); + } + + /** + * JSON字符串转JSONObject对象 + * + * @param obj Bean对象或者Map + * @param ignoreNullValue 是否忽略空值,如果source为JSON字符串,不忽略空值 + * @param isOrder 是否有序 + * @return JSONObject + * @since 4.2.2 + */ + public static JSONObject parseObj(Object obj, boolean ignoreNullValue, boolean isOrder) { + return new JSONObject(obj, ignoreNullValue, isOrder); + } + + /** + * JSON字符串转JSONArray + * + * @param jsonStr JSON字符串 + * @return JSONArray + */ + public static JSONArray parseArray(String jsonStr) { + return new JSONArray(jsonStr); + } + + /** + * JSON字符串转JSONArray + * + * @param arrayOrCollection 数组或集合对象 + * @return JSONArray + * @since 3.0.8 + */ + public static JSONArray parseArray(Object arrayOrCollection) { + return new JSONArray(arrayOrCollection); + } + + /** + * JSON字符串转JSONArray + * + * @param arrayOrCollection 数组或集合对象 + * @param config JSON配置 + * @return JSONArray + * @since 5.3.1 + */ + public static JSONArray parseArray(Object arrayOrCollection, JSONConfig config) { + return new JSONArray(arrayOrCollection, config); + } + + /** + * JSON字符串转JSONArray + * + * @param arrayOrCollection 数组或集合对象 + * @param ignoreNullValue 是否忽略空值 + * @return JSONArray + * @since 3.2.3 + */ + public static JSONArray parseArray(Object arrayOrCollection, boolean ignoreNullValue) { + return new JSONArray(arrayOrCollection, ignoreNullValue); + } + + /** + * 转换对象为JSON<br> + * 支持的对象:<br> + * String: 转换为相应的对象<br> + * Array Collection:转换为JSONArray<br> + * Bean对象:转为JSONObject + * + * @param obj 对象 + * @return JSON + */ + public static JSON parse(Object obj) { + return parse(obj, JSONConfig.create()); + } + + /** + * 转换对象为JSON<br> + * 支持的对象:<br> + * String: 转换为相应的对象<br> + * Array、Iterable、Iterator:转换为JSONArray<br> + * Bean对象:转为JSONObject + * + * @param obj 对象 + * @param config JSON配置 + * @return JSON + * @since 5.3.1 + */ + public static JSON parse(Object obj, JSONConfig config) { + if (null == obj) { + return null; + } + + JSON json; + if (obj instanceof JSON) { + json = (JSON) obj; + } else if (obj instanceof CharSequence) { + final String jsonStr = StrUtil.trim((CharSequence) obj); + json = StrUtil.startWith(jsonStr, '[') ? parseArray(jsonStr) : parseObj(jsonStr); + } else if (obj instanceof Iterable || obj instanceof Iterator || ArrayUtil.isArray(obj)) {// 列表 + json = new JSONArray(obj, config); + } else {// 对象 + json = new JSONObject(obj, config); + } + + return json; + } + + /** + * XML字符串转为JSONObject + * + * @param xmlStr XML字符串 + * @return JSONObject + */ + public static JSONObject parseFromXml(String xmlStr) { + return XML.toJSONObject(xmlStr); + } + + /** + * Map转化为JSONObject + * + * @param map {@link Map} + * @return JSONObjec + * @deprecated 请直接使用 {@link #parseObj(Object)} + */ + @Deprecated + public static JSONObject parseFromMap(Map<?, ?> map) { + return new JSONObject(map); + } + + /** + * ResourceBundle转化为JSONObject + * + * @param bundle ResourceBundle文件 + * @return JSONObject + * @deprecated 请直接使用 {@link #parseObj(Object)} + */ + @Deprecated + public static JSONObject parseFromResourceBundle(ResourceBundle bundle) { + return new JSONObject(bundle); + } + // -------------------------------------------------------------------- Pause end + + // -------------------------------------------------------------------- Read start + + /** + * 读取JSON + * + * @param file JSON文件 + * @param charset 编码 + * @return JSON(包括JSONObject和JSONArray) + * @throws IORuntimeException IO异常 + */ + public static JSON readJSON(File file, Charset charset) throws IORuntimeException { + return parse(FileReader.create(file, charset).readString()); + } + + /** + * 读取JSONObject + * + * @param file JSON文件 + * @param charset 编码 + * @return JSONObject + * @throws IORuntimeException IO异常 + */ + public static JSONObject readJSONObject(File file, Charset charset) throws IORuntimeException { + return parseObj(FileReader.create(file, charset).readString()); + } + + /** + * 读取JSONArray + * + * @param file JSON文件 + * @param charset 编码 + * @return JSONArray + * @throws IORuntimeException IO异常 + */ + public static JSONArray readJSONArray(File file, Charset charset) throws IORuntimeException { + return parseArray(FileReader.create(file, charset).readString()); + } + // -------------------------------------------------------------------- Read end + + // -------------------------------------------------------------------- toString start + + /** + * 转为JSON字符串 + * + * @param json JSON + * @param indentFactor 每一级别的缩进 + * @return JSON字符串 + */ + public static String toJsonStr(JSON json, int indentFactor) { + if (null == json) { + return null; + } + return json.toJSONString(indentFactor); + } + + /** + * 转为JSON字符串 + * + * @param json JSON + * @return JSON字符串 + */ + public static String toJsonStr(JSON json) { + if (null == json) { + return null; + } + return json.toJSONString(0); + } + + /** + * 转为JSON字符串,并写出到write + * + * @param json JSON + * @param writer Writer + * @since 5.3.3 + */ + public static void toJsonStr(JSON json, Writer writer) { + if (null != json) { + json.write(writer); + } + } + + /** + * 转为JSON字符串 + * + * @param json JSON + * @return JSON字符串 + */ + public static String toJsonPrettyStr(JSON json) { + if (null == json) { + return null; + } + return json.toJSONString(4); + } + + /** + * 转换为JSON字符串 + * + * @param obj 被转为JSON的对象 + * @return JSON字符串 + */ + public static String toJsonStr(Object obj) { + if (null == obj) { + return null; + } + if (obj instanceof CharSequence) { + return StrUtil.str((CharSequence) obj); + } + return toJsonStr(parse(obj)); + } + + /** + * 转换为JSON字符串并写出到writer + * + * @param obj 被转为JSON的对象 + * @param writer Writer + * @since 5.3.3 + */ + public static void toJsonStr(Object obj, Writer writer) { + if (null != obj) { + toJsonStr(parse(obj), writer); + } + } + + /** + * 转换为格式化后的JSON字符串 + * + * @param obj Bean对象 + * @return JSON字符串 + */ + public static String toJsonPrettyStr(Object obj) { + return toJsonPrettyStr(parse(obj)); + } + + /** + * 转换为XML字符串 + * + * @param json JSON + * @return XML字符串 + */ + public static String toXmlStr(JSON json) { + return XML.toXml(json); + } + // -------------------------------------------------------------------- toString end + + // -------------------------------------------------------------------- toBean start + + /** + * JSON字符串转为实体类对象,转换异常将被抛出 + * + * @param <T> Bean类型 + * @param jsonString JSON字符串 + * @param beanClass 实体类对象 + * @return 实体类对象 + * @since 3.1.2 + */ + public static <T> T toBean(String jsonString, Class<T> beanClass) { + return toBean(parseObj(jsonString), beanClass); + } + + /** + * 转为实体类对象,转换异常将被抛出 + * + * @param <T> Bean类型 + * @param json JSONObject + * @param beanClass 实体类对象 + * @return 实体类对象 + */ + public static <T> T toBean(JSONObject json, Class<T> beanClass) { + return null == json ? null : json.toBean(beanClass); + } + + /** + * JSON字符串转为实体类对象,转换异常将被抛出 + * + * @param <T> Bean类型 + * @param jsonString JSON字符串 + * @param typeReference {@link TypeReference}类型参考子类,可以获取其泛型参数中的Type类型 + * @param ignoreError 是否忽略错误 + * @return 实体类对象 + * @since 4.3.2 + */ + public static <T> T toBean(String jsonString, TypeReference<T> typeReference, boolean ignoreError) { + return toBean(jsonString, typeReference.getType(), ignoreError); + } + + /** + * JSON字符串转为实体类对象,转换异常将被抛出 + * + * @param <T> Bean类型 + * @param jsonString JSON字符串 + * @param beanType 实体类对象类型 + * @param ignoreError 是否忽略错误 + * @return 实体类对象 + * @since 4.3.2 + */ + public static <T> T toBean(String jsonString, Type beanType, boolean ignoreError) { + return toBean(parse(jsonString), beanType, ignoreError); + } + + /** + * 转为实体类对象 + * + * @param <T> Bean类型 + * @param json JSONObject + * @param typeReference {@link TypeReference}类型参考子类,可以获取其泛型参数中的Type类型 + * @param ignoreError 是否忽略转换错误 + * @return 实体类对象 + * @since 4.6.2 + */ + public static <T> T toBean(JSON json, TypeReference<T> typeReference, boolean ignoreError) { + return toBean(json, typeReference.getType(), ignoreError); + } + + /** + * 转为实体类对象 + * + * @param <T> Bean类型 + * @param json JSONObject + * @param beanType 实体类对象类型 + * @param ignoreError 是否忽略转换错误 + * @return 实体类对象 + * @since 4.3.2 + */ + public static <T> T toBean(JSON json, Type beanType, boolean ignoreError) { + if (null == json) { + return null; + } + return json.toBean(beanType, ignoreError); + } + // -------------------------------------------------------------------- toBean end + + /** + * 将JSONArray字符串转换为Bean的List,默认为ArrayList + * + * @param <T> Bean类型 + * @param jsonArray JSONArray字符串 + * @param elementType List中元素类型 + * @return List + * @since 5.5.2 + */ + public static <T> List<T> toList(String jsonArray, Class<T> elementType) { + return toList(parseArray(jsonArray), elementType); + } + + /** + * 将JSONArray转换为Bean的List,默认为ArrayList + * + * @param <T> Bean类型 + * @param jsonArray {@link JSONArray} + * @param elementType List中元素类型 + * @return List + * @since 4.0.7 + */ + public static <T> List<T> toList(JSONArray jsonArray, Class<T> elementType) { + return null == jsonArray ? null : jsonArray.toList(elementType); + } + + /** + * 通过表达式获取JSON中嵌套的对象<br> + * <ol> + * <li>.表达式,可以获取Bean对象中的属性(字段)值或者Map中key对应的值</li> + * <li>[]表达式,可以获取集合等对象中对应index的值</li> + * </ol> + * <p> + * 表达式栗子: + * + * <pre> + * persion + * persion.name + * persons[3] + * person.friends[5].name + * </pre> + * + * @param json {@link JSON} + * @param expression 表达式 + * @return 对象 + * @see JSON#getByPath(String) + */ + public static Object getByPath(JSON json, String expression) { + return (null == json || StrUtil.isBlank(expression)) ? null : json.getByPath(expression); + } + + /** + * 设置表达式指定位置(或filed对应)的值<br> + * 若表达式指向一个JSONArray则设置其坐标对应位置的值,若指向JSONObject则put对应key的值<br> + * 注意:如果为JSONArray,则设置值得下标不能大于已有JSONArray的长度<br> + * <ol> + * <li>.表达式,可以获取Bean对象中的属性(字段)值或者Map中key对应的值</li> + * <li>[]表达式,可以获取集合等对象中对应index的值</li> + * </ol> + * <p> + * 表达式栗子: + * + * <pre> + * persion + * persion.name + * persons[3] + * person.friends[5].name + * </pre> + * + * @param json JSON,可以为JSONObject或JSONArray + * @param expression 表达式 + * @param value 值 + */ + public static void putByPath(JSON json, String expression, Object value) { + json.putByPath(expression, value); + } + + /** + * 对所有双引号做转义处理(使用双反斜杠做转义)<br> + * 为了能在HTML中较好的显示,会将</转义为<\/<br> + * JSON字符串中不能包含控制字符和未经转义的引号和反斜杠 + * + * @param string 字符串 + * @return 适合在JSON中显示的字符串 + */ + public static String quote(String string) { + return quote(string, true); + } + + /** + * 对所有双引号做转义处理(使用双反斜杠做转义)<br> + * 为了能在HTML中较好的显示,会将</转义为<\/<br> + * JSON字符串中不能包含控制字符和未经转义的引号和反斜杠 + * + * @param string 字符串 + * @param isWrap 是否使用双引号包装字符串 + * @return 适合在JSON中显示的字符串 + * @since 3.3.1 + */ + public static String quote(String string, boolean isWrap) { + StringWriter sw = new StringWriter(); + try { + return quote(string, sw, isWrap).toString(); + } catch (IOException ignored) { + // will never happen - we are writing to a string writer + return StrUtil.EMPTY; + } + } + + /** + * 对所有双引号做转义处理(使用双反斜杠做转义)<br> + * 为了能在HTML中较好的显示,会将</转义为<\/<br> + * JSON字符串中不能包含控制字符和未经转义的引号和反斜杠 + * + * @param str 字符串 + * @param writer Writer + * @return Writer + * @throws IOException IO异常 + */ + public static Writer quote(String str, Writer writer) throws IOException { + return quote(str, writer, true); + } + + /** + * 对所有双引号做转义处理(使用双反斜杠做转义)<br> + * 为了能在HTML中较好的显示,会将</转义为<\/<br> + * JSON字符串中不能包含控制字符和未经转义的引号和反斜杠 + * + * @param str 字符串 + * @param writer Writer + * @param isWrap 是否使用双引号包装字符串 + * @return Writer + * @throws IOException IO异常 + * @since 3.3.1 + */ + public static Writer quote(String str, Writer writer, boolean isWrap) throws IOException { + if (StrUtil.isEmpty(str)) { + if (isWrap) { + writer.write("\"\""); + } + return writer; + } + + char b; // 前一个字符 + char c; // 当前字符 + int len = str.length(); + if (isWrap) { + writer.write('"'); + } + for (int i = 0; i < len; i++) { +// b = c; + c = str.charAt(i); + switch (c) { + case '\\': + case '"': + writer.write("\\"); + writer.write(c); + break; + //此处转义导致输出不和预期一致 +// case '/': +// if (b == '<') { +// writer.write('\\'); +// } +// writer.write(c); +// break; + default: + writer.write(escape(c)); + } + } + if (isWrap) { + writer.write('"'); + } + return writer; + } + + /** + * 转义显示不可见字符 + * + * @param str 字符串 + * @return 转义后的字符串 + */ + public static String escape(String str) { + if (StrUtil.isEmpty(str)) { + return str; + } + + final int len = str.length(); + final StringBuilder builder = new StringBuilder(len); + char c; + for (int i = 0; i < len; i++) { + c = str.charAt(i); + builder.append(escape(c)); + } + return builder.toString(); + } + + /** + * 在需要的时候包装对象<br> + * 包装包括: + * <ul> + * <li><code>null</code> =》 <code>JSONNull.NULL</code></li> + * <li>array or collection =》 JSONArray</li> + * <li>map =》 JSONObject</li> + * <li>standard property (Double, String, et al) =》 原对象</li> + * <li>来自于java包 =》 字符串</li> + * <li>其它 =》 尝试包装为JSONObject,否则返回<code>null</code></li> + * </ul> + * + * @param object 被包装的对象 + * @param jsonConfig JSON选项 + * @return 包装后的值,null表示此值需被忽略 + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static Object wrap(Object object, JSONConfig jsonConfig) { + if (object == null) { + return jsonConfig.isIgnoreNullValue() ? null : JSONNull.NULL; + } + if (object instanceof JSON // + || JSONNull.NULL.equals(object) // + || object instanceof JSONString // + || object instanceof CharSequence // + || object instanceof Number // + || ObjectUtil.isBasicType(object) // + ) { + return object; + } + + // 自定义序列化 + final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(object.getClass()); + if (null != serializer) { + final Type jsonType = TypeUtil.getTypeArgument(serializer.getClass()); + if (null != jsonType) { + if (serializer instanceof JSONObjectSerializer) { + serializer.serialize(new JSONObject(jsonConfig), object); + } else if (serializer instanceof JSONArraySerializer) { + serializer.serialize(new JSONArray(jsonConfig), object); + } + } + } + + try { + // JSONArray + if (object instanceof Iterable || ArrayUtil.isArray(object)) { + return new JSONArray(object, jsonConfig); + } + // JSONObject + if (object instanceof Map) { + return new JSONObject(object, jsonConfig); + } + + // 日期类型原样保存,便于格式化 + if (object instanceof Date + || object instanceof Calendar + || object instanceof TemporalAccessor + ) { + return object; + } + // 枚举类保存其字符串形式(4.0.2新增) + if (object instanceof Enum) { + return object.toString(); + } + + // Java内部类不做转换 + if (ClassUtil.isJdkClass(object.getClass())) { + return object.toString(); + } + + // 默认按照JSONObject对待 + return new JSONObject(object, jsonConfig); + } catch (RuntimeException exception) { + return null; + } + } + + /** + * 格式化JSON字符串,此方法并不严格检查JSON的格式正确与否 + * + * @param jsonStr JSON字符串 + * @return 格式化后的字符串 + * @since 3.1.2 + */ + public static String formatJsonStr(String jsonStr) { + return JSONStrFormater.format(jsonStr); + } + + /** + * 是否为JSON字符串,首尾都为大括号或中括号判定为JSON字符串 + * + * @param str 字符串 + * @return 是否为JSON字符串 + * @since 3.3.0 + */ + public static boolean isJson(String str) { + return isJsonObj(str) || isJsonArray(str); + } + + /** + * 是否为JSONObject字符串,首尾都为大括号判定为JSONObject字符串 + * + * @param str 字符串 + * @return 是否为JSON字符串 + * @since 3.3.0 + */ + public static boolean isJsonObj(String str) { + if (StrUtil.isBlank(str)) { + return false; + } + return StrUtil.isWrap(str.trim(), '{', '}'); + } + + /** + * 是否为JSONArray字符串,首尾都为中括号判定为JSONArray字符串 + * + * @param str 字符串 + * @return 是否为JSON字符串 + * @since 3.3.0 + */ + public static boolean isJsonArray(String str) { + if (StrUtil.isBlank(str)) { + return false; + } + return StrUtil.isWrap(str.trim(), '[', ']'); + } + + /** + * 是否为null对象,null的情况包括: + * + * <pre> + * 1. {@code null} + * 2. {@link JSONNull} + * </pre> + * + * @param obj 对象 + * @return 是否为null + * @since 4.5.7 + */ + public static boolean isNull(Object obj) { + return null == obj || obj instanceof JSONNull; + } + + /** + * XML转JSONObject<br> + * 转换过程中一些信息可能会丢失,JSON中无法区分节点和属性,相同的节点将被处理为JSONArray。 + * + * @param xml XML字符串 + * @return JSONObject + * @since 4.0.8 + */ + public static JSONObject xmlToJson(String xml) { + return XML.toJSONObject(xml); + } + + /** + * 加入自定义的序列化器 + * + * @param type 对象类型 + * @param serializer 序列化器实现 + * @see GlobalSerializeMapping#put(Type, JSONArraySerializer) + * @since 4.6.5 + */ + public static void putSerializer(Type type, JSONArraySerializer<?> serializer) { + GlobalSerializeMapping.put(type, serializer); + } + + /** + * 加入自定义的序列化器 + * + * @param type 对象类型 + * @param serializer 序列化器实现 + * @see GlobalSerializeMapping#put(Type, JSONObjectSerializer) + * @since 4.6.5 + */ + public static void putSerializer(Type type, JSONObjectSerializer<?> serializer) { + GlobalSerializeMapping.put(type, serializer); + } + + /** + * 加入自定义的反序列化器 + * + * @param type 对象类型 + * @param deserializer 反序列化器实现 + * @see GlobalSerializeMapping#put(Type, JSONDeserializer) + * @since 4.6.5 + */ + public static void putDeserializer(Type type, JSONDeserializer<?> deserializer) { + GlobalSerializeMapping.put(type, deserializer); + } + + // --------------------------------------------------------------------------------------------- Private method start + + /** + * 转义不可见字符<br> + * 见:https://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF + * + * @param c 字符 + * @return 转义后的字符串 + */ + private static String escape(char c) { + switch (c) { + case '\b': + return "\\b"; + case '\t': + return "\\t"; + case '\n': + return "\\n"; + case '\f': + return "\\f"; + case '\r': + return "\\r"; + default: + if (c < StrUtil.C_SPACE || // + (c >= '\u0080' && c <= '\u00a0') || // + (c >= '\u2000' && c <= '\u2010') || // + (c >= '\u2028' && c <= '\u202F') || // + (c >= '\u2066' && c <= '\u206F')// + ) { + return HexUtil.toUnicodeHex(c); + } else { + return Character.toString(c); + } + } + } + // --------------------------------------------------------------------------------------------- Private method end +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/LicenseUtil.java b/cn-admin/src/main/java/net/geedge/common/utils/LicenseUtil.java new file mode 100644 index 0000000..1e38104 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/LicenseUtil.java @@ -0,0 +1,124 @@ +package net.geedge.common.utils; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.crypto.asymmetric.SignAlgorithm; +import cn.hutool.log.Log; +import cn.hutool.system.oshi.OshiUtil; +import com.alibaba.fastjson.JSON; +import net.geedge.modules.sys.entity.LicenseEntity; +import net.geedge.modules.sys.entity.LicenseEntity.Signature; +import org.w3c.dom.Document; +import oshi.hardware.ComputerSystem; + +import java.io.UnsupportedEncodingException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Map; + +public class LicenseUtil { + private static final Log log = Log.get(); + private static String machineIdCache; + + static { + try { + ComputerSystem system = OshiUtil.getSystem(); + String hardwareUUID = system.getHardwareUUID(); + String serialNumber = system.getSerialNumber(); + String boardSerialNumber = system.getBaseboard().getSerialNumber(); + if (StrUtil.isAllBlank(hardwareUUID, serialNumber, boardSerialNumber)) { + machineIdCache = null; + } + String token = StrUtil.concat(true, hardwareUUID, serialNumber, boardSerialNumber); + machineIdCache = SecureUtil.sha1(token); + } catch (Throwable e) { + log.warn("Get machine id error", e); + } + } + + /** + * 验证证书签名是否合法 + * + * @param pk + * @return + */ + public static boolean verifyLicenseSign(LicenseEntity license, PublicKey pk, String signAlgorithm) { + Signature signature = license.getSignature(); + if (signature != null + && Tool.StrUtil.isAllNotBlank(signature.getDigestValue(), signature.getSignatureValue())) { + String genLicenseDigest = license.genLicenseDigest();// 计算摘要 + String digestValue = signature.getDigestValue();// 上传证书摘要 + if (!Tool.StrUtil.equals(digestValue, genLicenseDigest)) {//摘要不一致说明license 不合法 + return false; + } + // 验证摘要签名是否正确 + String signatureValue = signature.getSignatureValue(); + Sign sign = SecureUtil.sign(SignAlgorithm.valueOf(signAlgorithm)); + sign.setPublicKey(pk); + try { + //hex解码 + byte[] signData = Tool.HexUtil.decodeHex(signatureValue); + return sign.verify(digestValue.getBytes(Constant.DEFAULT_CHARTSET_NAME),signData); + } catch (UnsupportedEncodingException e) { + } + } + return false; + + } + + /** + * 生成签名摘要信息 + * + * @param key + * @return + * @throws UnsupportedEncodingException + */ + public static String genSign(LicenseEntity license, PrivateKey privateKey, String signAlgorithm) + throws UnsupportedEncodingException { + Sign sign = SecureUtil.sign(SignAlgorithm.valueOf(signAlgorithm)); + sign.setPrivateKey(privateKey); + String content = license.genLicenseDigest(); + byte[] bs = sign.sign(content.getBytes(Constant.DEFAULT_CHARTSET_NAME)); + return Tool.HexUtil.encodeHexStr(bs); + } + + /** + * 生成机器token,限定设备使用 + * + * @return + */ + public static String getMachineID() { + return machineIdCache; + } + + /** + * xml 格式 license转为 javabean + * + * @param licenseXml + * @return + */ + public static LicenseEntity xmlToLicenseBean(String licenseXml) { + if (Tool.StrUtil.isNotBlank(licenseXml)) { + Map<String, Object> map = Tool.XmlUtil.xmlToMap(licenseXml); + return Tool.BeanUtil.toBeanIgnoreError(map, LicenseEntity.class); + } + return null; + } + + /** + * license javabean 转为xml字符串 + * + * @param license + * @return + */ + public static String licenseBeanToXml(LicenseEntity license, boolean isPretty) { + if (license == null) { + return null; + } + Map<String, Object> beanToMap = Tool.BeanUtil.beanToMap(JSON.toJSON(license)); + Document document = Tool.XmlUtil.mapToXml(beanToMap,"license"); + return Tool.XmlUtil.toStr(document, Constant.DEFAULT_CHARTSET_NAME, isPretty); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/LockUtils.java b/cn-admin/src/main/java/net/geedge/common/utils/LockUtils.java new file mode 100644 index 0000000..000a3f0 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/LockUtils.java @@ -0,0 +1,66 @@ +package net.geedge.common.utils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +/** + * redis 分布式锁 + */ +@Component +public class LockUtils { + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Autowired + private DefaultRedisScript<Long> redisScript; + + private final Long RELEASE_SUCCESS = 1L; + + + /** + * 加锁 + * + * @param key + * @return + */ + public boolean lock(String key, String value, Long timeout) { + // 加锁并设置过期时间 + return stringRedisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.MINUTES); + } + + /** + * 释放锁 + * + * @param key + * @return + */ + public boolean unlock(String key, String value) { + // 使用 lua 脚本:先判断是否是自己设置的锁,再执行删除 + Long result = (Long) stringRedisTemplate.execute(redisScript, Arrays.asList(key, value)); + return RELEASE_SUCCESS.equals(result); + } + + + /** + * 注入redis script 在上面释放锁的时候使用 + * + * @return + */ + @Bean + public DefaultRedisScript<Long> defaultRedisScript() { + DefaultRedisScript<Long> defaultRedisScript = new DefaultRedisScript<>(); + defaultRedisScript.setResultType(Long.class); + // 使用脚本的方式执行 两步合成一步 保证了操作原子性 + defaultRedisScript.setScriptText("if redis.call('get', KEYS[1]) == KEYS[2] then return redis.call('del', KEYS[1]) else return 0 end"); + return defaultRedisScript; + } + + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/ObjectUtils.java b/cn-admin/src/main/java/net/geedge/common/utils/ObjectUtils.java new file mode 100644 index 0000000..2f7a3fb --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/ObjectUtils.java @@ -0,0 +1,376 @@ +/** + * Copyright (c) 2015 The cn Project + * <p> + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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 net.geedge.common.utils; + +/** + * @Package: cn.damai.usercenter.common.util + * @Description: + * @author: <a href="mailto:[email protected]">Wanghuajie</a> + * @date: 13-3-6 - 上午11:17 + * @version: V1.0 + * @company: damai + */ + +import java.util.Arrays; + +public abstract class ObjectUtils { + + private static final int INITIAL_HASH = 7; + private static final int MULTIPLIER = 31; + + private static final String EMPTY_STRING = ""; + private static final String NULL_STRING = "null"; + private static final String ARRAY_START = "{"; + private static final String ARRAY_END = "}"; + private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END; + private static final String ARRAY_ELEMENT_SEPARATOR = ", "; + + + /** + * Return whether the given throwable is a checked exception: + * that is, neither a RuntimeException nor an Error. + * + * @param ex the throwable to check + * @return whether the throwable is a checked exception + * @see Exception + * @see RuntimeException + * @see Error + */ + public static boolean isCheckedException(Throwable ex) { + return !(ex instanceof RuntimeException || ex instanceof Error); + } + + + /** + * Determine whether the given object is an array: + * either an Object array or a primitive array. + * + * @param obj the object to check + */ + public static boolean isArray(Object obj) { + return (obj != null && obj.getClass().isArray()); + } + + /** + * Determine whether the given array is empty: + * i.e. <code>null</code> or of zero length. + * + * @param array the array to check + */ + public static boolean isEmpty(Object[] array) { + return (array == null || array.length == 0); + } + + + + + + //--------------------------------------------------------------------- + // Convenience methods for content-based equality/hash-code handling + //--------------------------------------------------------------------- + + /** + * Determine if the given objects are equal, returning <code>true</code> + * if both are <code>null</code> or <code>false</code> if only one is + * <code>null</code>. + * <p>Compares arrays with <code>Arrays.equals</code>, performing an equality + * check based on the array elements rather than the array reference. + * + * @param o1 first Object to compare + * @param o2 second Object to compare + * @return whether the given objects are equal + * @see Arrays#equals + */ + public static boolean safeEquals(Object o1, Object o2) { + if (o1 == null || o2 == null) { + return false; + } + + if (o1 == o2) { + return true; + } + + if (o1.equals(o2)) { + return true; + } + if (o1.getClass().isArray() && o2.getClass().isArray()) { + if (o1 instanceof Object[] && o2 instanceof Object[]) { + return Arrays.equals((Object[]) o1, (Object[]) o2); + } + if (o1 instanceof boolean[] && o2 instanceof boolean[]) { + return Arrays.equals((boolean[]) o1, (boolean[]) o2); + } + if (o1 instanceof byte[] && o2 instanceof byte[]) { + return Arrays.equals((byte[]) o1, (byte[]) o2); + } + if (o1 instanceof char[] && o2 instanceof char[]) { + return Arrays.equals((char[]) o1, (char[]) o2); + } + if (o1 instanceof double[] && o2 instanceof double[]) { + return Arrays.equals((double[]) o1, (double[]) o2); + } + if (o1 instanceof float[] && o2 instanceof float[]) { + return Arrays.equals((float[]) o1, (float[]) o2); + } + if (o1 instanceof int[] && o2 instanceof int[]) { + return Arrays.equals((int[]) o1, (int[]) o2); + } + if (o1 instanceof long[] && o2 instanceof long[]) { + return Arrays.equals((long[]) o1, (long[]) o2); + } + if (o1 instanceof short[] && o2 instanceof short[]) { + return Arrays.equals((short[]) o1, (short[]) o2); + } + } + return false; + } + + /** + * Return as hash code for the given object; typically the value of + * <code>{@link Object#hashCode()}</code>. If the object is an array, + * this method will delegate to any of the <code>safeHashCode</code> + * methods for arrays in this class. If the object is <code>null</code>, + * this method returns 0. + * + * @see #safeHashCode(Object[]) + * @see #safeHashCode(boolean[]) + * @see #safeHashCode(byte[]) + * @see #safeHashCode(char[]) + * @see #safeHashCode(double[]) + * @see #safeHashCode(float[]) + * @see #safeHashCode(int[]) + * @see #safeHashCode(long[]) + * @see #safeHashCode(short[]) + */ + public static int safeHashCode(Object obj) { + if (obj == null) { + return 0; + } + if (obj.getClass().isArray()) { + if (obj instanceof Object[]) { + return safeHashCode((Object[]) obj); + } + if (obj instanceof boolean[]) { + return safeHashCode((boolean[]) obj); + } + if (obj instanceof byte[]) { + return safeHashCode((byte[]) obj); + } + if (obj instanceof char[]) { + return safeHashCode((char[]) obj); + } + if (obj instanceof double[]) { + return safeHashCode((double[]) obj); + } + if (obj instanceof float[]) { + return safeHashCode((float[]) obj); + } + if (obj instanceof int[]) { + return safeHashCode((int[]) obj); + } + if (obj instanceof long[]) { + return safeHashCode((long[]) obj); + } + if (obj instanceof short[]) { + return safeHashCode((short[]) obj); + } + } + return obj.hashCode(); + } + + /** + * Return a hash code based on the contents of the specified array. + * If <code>array</code> is <code>null</code>, this method returns 0. + */ + public static int safeHashCode(Object[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + for (Object anArray : array) { + hash = MULTIPLIER * hash + safeHashCode(anArray); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If <code>array</code> is <code>null</code>, this method returns 0. + */ + public static int safeHashCode(boolean[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + for (boolean anArray : array) { + hash = MULTIPLIER * hash + hashCode(anArray); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If <code>array</code> is <code>null</code>, this method returns 0. + */ + public static int safeHashCode(byte[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + for (byte anArray : array) { + hash = MULTIPLIER * hash + anArray; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If <code>array</code> is <code>null</code>, this method returns 0. + */ + public static int safeHashCode(char[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + for (char anArray : array) { + hash = MULTIPLIER * hash + anArray; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If <code>array</code> is <code>null</code>, this method returns 0. + */ + public static int safeHashCode(double[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + for (double anArray : array) { + hash = MULTIPLIER * hash + hashCode(anArray); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If <code>array</code> is <code>null</code>, this method returns 0. + */ + public static int safeHashCode(float[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + for (float anArray : array) { + hash = MULTIPLIER * hash + hashCode(anArray); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If <code>array</code> is <code>null</code>, this method returns 0. + */ + public static int safeHashCode(int[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + for (int anArray : array) { + hash = MULTIPLIER * hash + anArray; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If <code>array</code> is <code>null</code>, this method returns 0. + */ + public static int safeHashCode(long[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + for (long anArray : array) { + hash = MULTIPLIER * hash + hashCode(anArray); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If <code>array</code> is <code>null</code>, this method returns 0. + */ + public static int safeHashCode(short[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + for (short anArray : array) { + hash = MULTIPLIER * hash + anArray; + } + return hash; + } + + /** + * Return the same value as <code>{@link Boolean#hashCode()}</code>. + * + * @see Boolean#hashCode() + */ + public static int hashCode(boolean bool) { + return bool ? 1231 : 1237; + } + + /** + * Return the same value as <code>{@link Double#hashCode()}</code>. + * + * @see Double#hashCode() + */ + public static int hashCode(double dbl) { + long bits = Double.doubleToLongBits(dbl); + return hashCode(bits); + } + + /** + * Return the same value as <code>{@link Float#hashCode()}</code>. + * + * @see Float#hashCode() + */ + public static int hashCode(float flt) { + return Float.floatToIntBits(flt); + } + + /** + * Return the same value as <code>{@link Long#hashCode()}</code>. + * + * @see Long#hashCode() + */ + public static int hashCode(long lng) { + return (int) (lng ^ (lng >>> 32)); + } + + + + +} + diff --git a/cn-admin/src/main/java/net/geedge/common/utils/OperationEnum.java b/cn-admin/src/main/java/net/geedge/common/utils/OperationEnum.java new file mode 100644 index 0000000..7459239 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/OperationEnum.java @@ -0,0 +1,31 @@ +package net.geedge.common.utils; + +/** + *操作日志相关枚举类型 + */ +public enum OperationEnum { + // 操作方式operation + QUERY("query"), + ADD("add"), + UPDATE("update"), + IMPORT("import"), + EXPORT("export"), + DELETE("delete"), + RESET("reset"), + UNKNOWN("unknown"), + LOGIN("login"), + LOGOUT("logout"); + + + private String value; + + public String getValue() { + return value; + } + + OperationEnum( String value) { + this.value = value; + } + + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/PageUtils.java b/cn-admin/src/main/java/net/geedge/common/utils/PageUtils.java new file mode 100644 index 0000000..8a1b846 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/PageUtils.java @@ -0,0 +1,110 @@ +/** + + * + + * + * + */ + +package net.geedge.common.utils; + +import com.baomidou.mybatisplus.core.metadata.IPage; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页工具类 + * + * @author Mark [email protected] + */ +public class PageUtils implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 总记录数 + */ + private int total; + /** + * 每页记录数 + */ + private int pageSize; + /** + * 总页数 + */ + private int pages; + /** + * 当前页数 + */ + private int pageNo; + /** + * 列表数据 + */ + private List<?> list; + + /** + * 分页 + * @param list 列表数据 + * @param total 总记录数 + * @param pageSize 每页记录数 + * @param pageNo 当前页数 + */ + public PageUtils(List<?> list, int total, int pageSize, int pageNo) { + this.list = list; + this.total = total; + this.pageSize = pageSize; + this.pageNo = pageNo; + this.pages = (int)Math.ceil((double)total/pageSize); + } + + /** + * 分页 + */ + public PageUtils(IPage<?> page) { + this.list = page.getRecords(); + this.total = (int)page.getTotal(); + this.pageSize = (int)page.getSize(); + this.pageNo = (int)page.getCurrent(); + this.pages = (int)page.getPages(); + } + + public int gettotal() { + return total; + } + + public void settotal(int total) { + this.total = total; + } + + public int getPageSize() { + return pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public int getpages() { + return pages; + } + + public void setpages(int pages) { + this.pages = pages; + } + + public int getpageNo() { + return pageNo; + } + + public void setpageNo(int pageNo) { + this.pageNo = pageNo; + } + + public List<?> getList() { + return list; + } + + public void setList(List<?> list) { + this.list = list; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/Query.java b/cn-admin/src/main/java/net/geedge/common/utils/Query.java new file mode 100644 index 0000000..09cdeeb --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/Query.java @@ -0,0 +1,97 @@ +package net.geedge.common.utils; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.geedge.common.exception.CNException; +import net.geedge.common.xss.SQLFilter; +import org.apache.commons.lang.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * 查询参数 + */ +public class Query { + + private Class clz; + + public Class<? extends Object> getClz() { + return clz; + } + + public void setClz(Class clz) { + this.clz = clz; + } + + public Query(Class clz) { + this.clz = clz; + } + + public IPage getPage(Map<String, Object> params) { + return this.getPage(params, null, false); + } + + public IPage getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) { + //分页参数 + long curPage = 1; + long limit = Constant.PAGESIZE; + + if(params.get(Constant.PAGE) != null){ + curPage = Long.parseLong((String)params.get(Constant.PAGE)); + } + if(params.get(Constant.LIMIT) != null){ + limit = Long.parseLong((String)params.get(Constant.LIMIT)); + if(limit == -1){ + limit = Long.MAX_VALUE; + curPage = 0; + } + } + + //分页对象 + Page page = new Page(curPage, limit); + + //分页参数 + params.put(Constant.PAGE, page); + + //排序字段 orderBy=id + //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险) + String orderField = SQLFilter.sqlInject((String)params.get(Constant.ORDER)); + + if (StringUtils.isNotEmpty(orderField)) { + boolean matcheFlag = orderField.trim().matches("-?[a-zA-Z_.-]+"); + if (!matcheFlag) { + throw new CNException(RCode.ERROR); + } + + // 获取表名 + Class<?> clz = this.getClz(); + String tableName = ""; + if (clz != null) { + TableName table = this.getClz().getAnnotation(TableName.class); + tableName = table.value(); + } + // 通过表名获取排序字段映射 + Map<String, String> columnAliasMap = Constant.TABLE_NAME_ORDER_FIELD_MAPPING.get(tableName); + columnAliasMap = Tool.ObjectUtil.isEmpty(columnAliasMap) ? new HashMap<>():columnAliasMap; + if (orderField.startsWith("-")) { + orderField = orderField.substring(1, orderField.length()); + orderField = columnAliasMap.get(orderField) != null ? columnAliasMap.get(orderField) : orderField; + return page.setDesc(orderField); + } else { + orderField = columnAliasMap.get(orderField) != null ? columnAliasMap.get(orderField) : orderField; + return page.setAsc(orderField); + } + } + + // 默认排序 + if(isAsc) { + page.setAsc(defaultOrderField); + }else { + page.setDesc(defaultOrderField); + } + + return page; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/R.java b/cn-admin/src/main/java/net/geedge/common/utils/R.java new file mode 100644 index 0000000..c9856dd --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/R.java @@ -0,0 +1,91 @@ +package net.geedge.common.utils; + +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import net.geedge.common.exception.CNException; + +/** + * 返回数据 + * + * 错误码、错误内容统一在枚举类RCode中定义, 错误码格式见RCode注释,错误码内容必须用英文,作为国际化的code + * 自定义的错误类型必须加注释 + */ +public class R extends HashMap<String, Object> { + private static final long serialVersionUID = 1L; + + public R() { + put("code", RCode.SUCCESS.getCode()); + put("msg", RCode.SUCCESS.getMsg()); + put("time", new Date()); + } + + public static R error() { + return error(RCode.ERROR.getCode(), RCode.ERROR.getMsg()); + } + + public static R error(RCode rCode) { + R r = new R(); + r.put("code", rCode.getCode()); + r.put("msg", rCode.getMsg()); + r.put("time", new Date()); + return r; + } + + public static R error(Integer code, String msg) { + R r = new R(); + r.put("code", code); + r.put("msg", msg); + r.put("time", new Date()); + return r; + } + + public static R ok(String msg) { + R r = new R(); + r.put("msg", msg); + r.put("time", new Date()); + return r; + } + + public static R ok() { + return new R(); + } + + public static R ok(Object data) { + R r = new R(); + r.put("data", data); + r.put("time", new Date()); + return r; + } + + @Override + public R put(String key, Object value) { + super.put(key, value); + return this; + } + + @SuppressWarnings("unchecked") + public R putData(String key,Object value) { + Object data = super.getOrDefault("data", new LinkedHashMap<String, Object>()); + if( !(data instanceof Map)) { + throw new CNException("data put error"); + } + ((Map<String, Object>)data).put(key, value); + super.put("data", data); + return this; + } + + @SuppressWarnings("unchecked") + public R putDataAll(Map<String,Object> dataAll) { + Object data = super.getOrDefault("data", new LinkedHashMap<String, Object>()); + if( !(data instanceof Map)) { + throw new CNException("data putAll error"); + } + ((Map<String, Object>)data).putAll(dataAll);; + super.put("data", data); + return this; + } +} + diff --git a/cn-admin/src/main/java/net/geedge/common/utils/RCode.java b/cn-admin/src/main/java/net/geedge/common/utils/RCode.java new file mode 100644 index 0000000..ba9e6c7 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/RCode.java @@ -0,0 +1,813 @@ +package net.geedge.common.utils; + +public enum RCode { + + /** + * 第一位对应页面菜单项 + * 1:dashboard + * 2:project + * 3:assets + * 4:alerts + * 5:settings + * 6: webshell + * 7: license + * + * <p> + * 第二位对应页面左侧菜单 + * 从上到下顺序 + * 1-~ + * <p> + * + * 第三位 + * 1:参数不能为空 + * 2:参数重复 + * 3:参数值与要求不符合 + * 4:参数值不在枚举类型内 + * 5:数值类型参数 不在合理范围内 + * 6:内容不存在 + * 7:权限相关错误 + * 8: 登陆相关错误 + * 9:文件相关错误 + * 0: 第三方服务相关错误 + */ + + + SUCCESS(200, "success"), //成功 + + /** + * dashboard菜单项相关 + */ + PANEL_NAME_ISNULL(121000, "Panel name can not be empty"), + PANEL_ID_ISNULL(121001, "Panel ID can not be empty"), + PANEL_NAME_DUPLICATE(122002, "Panel name is duplicate"), + PANEL_TYPE_ISNULL(121003, "Panel type can not be empty when link is not empty"), + PANEL_TYPE_INVALIDE(124004, "Panel type must be dashboard, asset, project, module, endpoint or model"), + PANEL_LINK_ISNULL(121005,"Panel link can not be empty when the type is not dashboard"), + PANEL_BUILDIN_CAN_NOT_REMOVE(127006, "This panel is built-in and cannot be deleted"), + CHART_TITLE_ISNULL(121007, "Chart title can not be empty"), + CHART_SPAN_ISNULL(121008, "Chart span can not be empty"), + CHART_HEIGHT_ISNULL(121009, "Chart height can not be empty"), + CHART_TYPE_ISNULL(121010, "Chart type can not be empty"), + CHART_CREATEAT_ISNULL(121011, "Chart create time can not be empty"), + CHART_ELEMENT_ISNULL(121012, "Chart element can not be empty"), + CHART_TYPE_INVALIDE(123013, "Chart type is invalide"), + CHART_PANEL_ISNULL(126014, "Panel is not exsits"), + CHART_NOTEXSITS(126015, "Chart is not exsits"), + CHART_ID_ISNULL(121016, "Chart ID can not be empty"), + CHART_UNIT_ISNULL(121017, "Chart unit can not be empty"), + CHART_PREV_ISNULL(121018,"Chart prev can not be empty"), + CHART_NEXT_ISNULL(121019,"Chart next can not be empty"), + CHART_CANNOT_MODIFY(126020,"Chart can not modify"), + CHART_PREVNEXT_INCORRECT(123021,"Prev and next is incorrect"), + CHART_TITLE_DUPLICATE(122022,"Chart title is duplicate"), // 同一个panel 下 chart title重复 + CHART_URLPARAM_ISNULL(121023,"Chart param cannot be empty when type is url"), // 当type为url时,param不能为空 + CHART_PARAM_FORMAT(123024,"Chart param must be JSON format"), // param类型必须为json格式 + CHART_PARAMURL_ISNULL(121025,"Chart param url not found when type is url"), // param 中未找到url key值 + CHART_PARAMURL_FORMAT(123026,"Chart param url value must be URL format"), // param 中url的值必须为网址类型 + CHART_PARAMSINGLESTAT_ISNULL(121027,"Chart param statistics not found when type is singleStat"), + CHART_PARAMSINGLESTAT_INVALIDE(124028,"Chart param statistics must be min, max, average, total, first, last, range or different"), + CHART_SINGLESTATPARAM_ISNULL(121029,"Chart param cannot be empty when type is singleStat"), + CHART_BUILDIN_CAN_NOT_REMOVE(127030, "This chart is built-in and cannot be deleted"), + CHARTELEMENT_EXPRESSION_ISNULL(121031, "Chart element expression can not be empty"), + CHARTELEMENT_TYPE_ISNULL(121032, "Chart element type can not be empty"), + CHARTELEMENT_TYPE_INVALIDE(123033, "Chart element type is invalide"), + CHARTELEMENT_NOTEXSITS(126034, "chart element is not exists"), + PANEL_PREV_ISNULL(121035,"Panel prev can not be empty"), + PANEL_NEXT_ISNULL(121036,"Panel next can not be empty"), + PANEL_NOT_EXIST(126037,"Panel does not exist"), + PANEL_NOTFOUND_BYTYPE(126038,"There is no panel under this type"), + PANEL_CHARTS_EXISTS(123039, "These panel contain charts and cannot be deleted"), + PANEL_EXPORT_HEADER_LANGUAGE_ISNULL(121040,"Export header language can not be empty"), + PANEL_EXPORT_HEADER_LANGUAGE_ERROR(124041,"Export header language must be en, cn and ru"), + PANEL_IMPORT_FILE_ISNULL(121042, "Panel chart import file can not be null"), + PANEL_IMPORTFILE_TYPE(129043,"Only support import XLS or XLSX file"), + PANEL_CANCELIMPORTSEQ_ISNULL(121044, "Panel chart cancel import seq can not be null"), + PANEL_IMPORTFILE_FAILED(119045,"Import file resolution failed"), // 导入文件解析失败 + PANEL_EXPORT_HEADER_TEMPLATE_ERROR(114046,"The header row of the excel import template is inconsistent with the system template"), + CHART_WIDTH_FORMAT(123047, "Chart width format should be a integer"), + CHART_WIDTH_INVALIDE(123048, "Chart width should be between 1 and 12"), + CHART_HEIGHT_FORMAT(123049, "Chart height format should be a integer"), + CHART_UNIT_NOTFOUND(126050, "Chart unit not found"), + CHART_ELEMENTS_FORMAT(123051,"Chart elements must be JSON format"), + PANEL_CHART_TEMPLATE_TYPE_INCORRECT(123052, "Panel charts template type must be dashboard, model and asset"), + PANEL_CHART_IMPORT_LINKID_ISNULL(121053, "When the type is model or asset, link Id cannot be empty"), + PANEL_CHART_TEMPLATE_TYPE_ISNULL(121054, "Panel charts template type is null"), + CHART_TEXTPARAM_ISNULL(121055,"Chart param cannot be empty when type is text"), + CHART_PARAMTEXT_ISNULL(121056,"Chart param text not found when type is text"), + CHART_WEIGHT_ISNULL(121057,"Chart weight can not be empty"), + PANEL_PID_ISNULL(121058,"Panel pid can not be empty"), + PANEL_WEIGHT_ISNULL(121059,"Panel weight not be empty"), + PANEL_NAME_FORMAT_ERROR(123060,"Panel name format error, can not include '/'"), + CHART_GROUPID_ISNULL(121061,"Chart group id can not be empty"), + CHART_VARTYPE_ISNULL(121062,"Chart var type can not be empty when panel id is empty"), + CHART_PID_ISNULL(121063,"pid can not be empty"), + CHART_VARID_ISNULL(121064,"varid can not be empty"), + CHART_SYNCTMPL_ERROR(121065,"Chart sync param can not be null"), + CHART_VARID_ERROR(121066,"varid param error"), + CHART_GROUP_NAME_DUPLICATE(121067,"chart type is group name is duplicate"), + CHART_HEIGHT_INVALIDE(123068, "Chart height should be between 1 and 12"), + + EXPRETMPL_NOT_FOUND(136000, "Expression template not found"), + EXPRETMPL_NAME_ISNULL(131001, "Expression template name is null"), + EXPRETMPL_EXPRESSION_ISNULL(131002, "Expression template expression is null"), + EXPRETMPL_NAME_DUPLICATE(132003, "Expression template name is duplicate"), + EXPRETMPL_ID_ISNULL(131004, "Expression template id is null"), + EXPRETMPL_BUILDIN_CAN_NOT_REMOVE(137005, "This expression template is built-in and cannot be deleted"), + EXPRETMPL_CONTAIN_BABY_CAN_NOT_REMOVE(137006, "This expression template contain sub-templates and cannot be deleted"), + EXPRETMPL_EXPORT_HEADER_LANGUAGE_ISNULL(131007, "Export header language can not be empty"), + EXPRETMPL_EXPORT_HEADER_LANGUAGE_ERROR(134008, "Export header language must be en, cn and ru"), + EXPRETMPL_RENDER_DATA_ISNULL(131009, "Expression template render data is null"), + EXPRETMPL_IMPORT_FILE_ISNULL(131010, "Expression template import file is null"), + EXPRETMPL_SEQ_ISNULL(131011, "Cancel import serial number is empty"), + EXPRETMPL_IMPORTFILE_TYPE(139012, "Only support import XLS or XLSX file"), + EXPRETMPL_IMPORTFILE_FAILED(139013, "Import file resolution failed"), + EXPRETMPL_GROUP_NOT_FOUND(136014, "Expression group not found"), + EXPRETMPL_IMPORT_ERROR(133015, "Expression template import error"), + EXPRETMPL_BUILDIN_INCORRECT(134016, "Expression template buildin must be 0 or 1"), + + /** + * project菜单项相关 + */ + PROJECT_ID_ISNULL(211000, "Project id can not be empty"), + PROJECT_NAME_ISNULL(211001, "Project name can not be empty"), + PROJECT_BUILDIN_CAN_NOT_REMOVE(217002, "This project is built-in and cannot be deleted"), + PROJECT_NAME_TOO_LONG(213003, "Project name too long"), + PROJECT_REMARK_TOO_LONG(213004, "Project remark too long"), + PROJECT_NAME_DUPLICATE(212005, "Project name is duplicate"), + PROJECT_REMOVE_ERROR(213006,"These projects contains module can't remove projects"), + PROJECT_TOPOICON_FILE_ISNULL(211007,"Topo icon file is null"), + PROJECT_TOPOICON_NAME_ISNULL(211008,"Topo icon name is null"), + PROJECT_TOPOICON_FILETYPE_ERROR(219009,"Topo icon file type must be jpg, jpeg, png and gif"), + PROJECT_ICONID_ISNULL(211010, "Topo icon id can not be empty"), + PROJECT_ICON_NOTFOUND(216011, "Topo icon not found"), + PROJECT_TOPOCONFIG_ISNULL(211012, "Project topo is null"), + PROJECT_NOTFOUND(216013, "Project not found"), + PROJECT_TOPOICON_UNIT_ISNULL(211014,"Topo icon unit is null"), + PROJECT_BUILDIN_CAN_NOT_EDIT(217015, "The built-in project does not allow editing"), + PROJECT_ICON_BASE64_VALUEERROR(214016, "The base64 value must be 0 and 1"), + + MODULE_ID_ISNULL(221000, "Module id can not be empty"), + MODULE_PROJECTID_ISNULL(221001, "Project id can not be empty"), + MODULE_NAME_ISNULL(221002, "Module name info can not be empty"), + MODULE_PORT_ISNULL(221003, "Module port info can not be empty"), + MODULE_PATH_ISNULL(221004, "Module path info can not be empty"), + MODULE_PORT_ERROR(221005, "Module port is incorrect"), + MODULE_BUILDIN_CAN_NOT_REMOVE(227006, "This module is built-in and cannot be deleted"), + MODULE_NAME_TOO_LONG(223007, "Module name too long"), + MODULE_REMARK_TOO_LONG(223008, "Module remark too long"), + SYS_CONFIG_MODULEKEY_ISNULL(221009, "System config init module node exporter can not be null"),// 内置module不能为空 + MODULE_NAME_DUPLICATE(222010, "Module name is duplicate"), + MODULE_TYPE_ISNULL(221011, "Module type can not be empty"), + MODULE_TYPE_INVALID(224012, "Module type must be http or snmp"), + MODULE_SNMPVERSION_INVALID(224013,"Snmp version must be 2 or 3"), + MODULE_AUTHSECURITYLEVEL_INVALID(224014,"Security level must be one of authPriv, authNoPriv or noAuthNoPriv"), + MODULE_PRIVPASSWORD_ISNULL(221015,"Priv password is missing, required for SNMPv3 with priv"), + MODULE_PRIVPROTOCOL_INVALID(224016,"Priv protocol must be DES or AES"), + MODULE_AUTHPROTOCOL_INVALID(224017,"Auth protocol must be SHA or MD5"), + MODULE_PASSWORD_INVALID(221018,"Auth password is missing, required for SNMPv3 with auth"), + MODULE_USERNAME_INVALID(221019,"Auth username is missing, required for SNMPv3"), + MODULE_REMOVE_ERROR(223020,"These modules contains endpoint can't remove modules"), + MODULE_NOTFOUND(226021, "Module not found"), + MODULE_NOTEXIS_PROJECT(226022, "Module does not exist in the current project"), + MODULE_TYPE_INCONSISTENT(223023, "Module type is inconsistent with the filling type"), + MODULE_SNMP_NOTEXIST(226024, "SNMP type module must exist"), + MODULE_LABELS_FORMAT(223025,"Module labels must be JSON format"), + MODULE_LABELS_KEY_FORMAT(223026,"Module labels key format is incorrect"), + MODULE_ENDPOINTNAMETMPL_ISNULL(221027, "Module endpoint name template can not be empty"), + MODULE_CONFIGS_ISNULL(221028, "Module configs can not be empty"), + MODULE_CONFIGS_FORMAT(223029,"Module configs must be JSON format"), + MODULE_SNMP_WALK_ISNULL(221030,"Snmp type module walk oids cannot be empty"), + MODULE_SNMP_WALK_FORMAT(223031,"Module walk oids format error"), + + ENDPOINT_ID_ISNULL(231000, "Endpoint id can not be empty"), + ENDPOINT_MODULEID_ISNULL(231001, "Module Id can not be empty"), + ENDPOINT_ASSETID_ISNULL(231002, "Asset Id can not be empty"), + ENDPOINT_PORT_ISNULL(231003, "Port can not be empty"), + ENDPOINT_PATH_ISNULL(231004, "Path can not be empty"), + ENDPOINT_QUERYACTIVE_ERROR(236005, "Endpoint query active state error"), // 请求prometheus查询endpoint状态失败 + ENDPOINT_IMPORT_FILE_ISNULL(231006, "Endpoint import file can not be null"),// 导入文件不能为空 + ENDPOINT_CANCELIMPORTSEQ_ISNULL(231007, "Endpoint cancel import seq can not be null"),// 导入撤销 seq不能为空 + ENDPOINT_HOST_ERROR(233008, "Endpoint host is incorrect"), + ENDPOINT_PROMETHEUS_UNAVAILABLE(230009,"Prometheus server unavailable"), + ENDPOINT_PROMETHEUS_ON_USE(230010,"Prometheus can be used"), + ENDPOINT_PROMETHEUS_UNUSE(230011,"Endpoint connection refused"), + ENDPOINT_PARAM_FORMAT_ERROR(233012,"Endpoint param incorrect format"), + ENDPOINT_IMPORTFILE_TYPE(239013,"Only support import XLS or XLSX file"), + ENDPOINT_IMPORTFILE_FAILED(239014,"Import file resolution failed"), + ENDPOINT_EXPORT_HEADER_LANGUAGE_ISNULL(231015, "Export header language can not be empty"), + ENDPOINT_EXPORT_HEADER_LANGUAGE_ERROR(234016, "Export header language must be en, cn and ru"), + ENDPOINT_EXPORT_HEADER_TEMPLATE_ERROR(234017, "The header row of the excel import template is inconsistent with the system template"), + ENDPOINT_SN_HOST_ISNULL(231018, "Sn and host cannot be empty at the same time"), + ENDPOINT_SN_HOST_MISMATCH(235019, "Asset sn and host address do not correspond"), + ENDPOINT_LABELS_FORMAT(233020,"Endpoint labels must be JSON format"), + ENDPOINT_LABELS_KEY_FORMAT(233021,"Endpoint labels key format is incorrect"), + ENDPOINT_TIMEOUT_UPDATE(233022,"Data has not been updated for more than multiple cycles"), + ENDPOINT_ENABLED_INVALIDE(234023, "Endpoint enabled must be 0 or 1"), + ENDPOINT_NOTFOUND(236024, "Endpoint not found"), + ENDPOINT_NAME_ISNULL(231025, "Endpoint name can not be empty"), + ENDPOINT_NAME_DUPLICATE(232026, "Endpoint name duplicate"), + ENDPOINT_PORT_ERROR(231027, "Endpoint port is incorrect"), + ENDPOINT_ASSET_NAME_HOST_ISNULL(231028, "Asset name and host cannot be empty at the same time"), + ENDPOINT_IMPORT_ERROR(233029, "Endpoint template import error"), + ENDPOINT_CONFIGS_FORMAT(233030,"Endpoint configs must be JSON format"), + + /** + * assets菜单项相关 + */ + ASSET_ID_ISNULL(311000, "Asset id can not be empty"), // 资产ID不能为空 + ASSET_SN_ISNULL(311001, "Asset serial number can not be empty"), // 资产序列号不能为空 + ASSET_HOST_ISNULL(311002, "Asset host can not be empty"), // 资产主机地址不能为空 + ASSET_HOST_FORMAT(313003, "Asset host format error, format such as xxx.xxx.xxx.xxx(192.168.40.247)"),// 资产主机地址格式 + ASSET_MAINTENANCEID_ISNULL(311004, "Asset maintenance id can not be empty"),// 资产维修记录ID不能为空 + ASSET_NOT_EXIST(316005, "Asset does not exist"), // 资产不存在 + ASSET_MAINTENANCE_CONTENT_ISNULL(311006, "Asset maintenance content can not be empty"),// 资产维修记录内容不能为空 + ASSET_DC_NOTFOUND(316007, "Asset dc not found"), // 数据中心未找到 + ASSET_CABINET_NOTFOUND(336008, "Asset cabinet not found"), // 机柜未找到 + ASSET_HOST_DUPLICATE(312009, "Asset host duplicate"), // 资产主机地址重复 + ASSET_SN_DUPLICATE(312010, "Asset serial number duplicate"), // 资产序列号重复 + ASSET_PURCHASEDATE_FORMAT(313011, "Asset purchase date format error"),// 资产购买日期格式错误 + ASSET_PURCHASEDATE_UNAVAILABLE(313012, "Asset purchase date unavailable"),// 资产购买日期不可用,不合法 + ASSET_STATE_NOTFOUND(316013, "Asset state not found"), // 资产状态未找到 + ASSET_ID_FORMAT(313014, "Id format error , type should be integer"), // ID类型错误 + ASSET_VENDOR_ISNULL(311015, "Model vendor can not be empty"), // 厂商不能为空 + ASSET_TYPE_ISNULL(311016, "Asset type can not be empty"), // 资产类型不能为空 + ASSET_VENDOR_NOTFOUND(316017, "Asset model vendor not found"), // 资产型号厂商未找到 + ASSET_ACCOUNT_ISNULL(311018, "Account can not be null, because exporter is specified"),// 账号信息不能为空,因为指明了需要安装exporter + ASSET_UPLOAD_FAIL(319019, "The asset and account are saved successfully, but export upload error. You can upload files manually, sorry."), + ASSET_SN_TOO_LONG(313020, "Asset serial number too long"), // 资产序列号长度过长 + ASSET_CANCELIMPORTSEQ_ISNULL(311021, "Asset cancel import seq can not be null"),// 导入撤销 seq不能为空 + ASSET_IMPORT_FILE_ISNULL(311022, "Asset import file can not be null"),// 导入文件不能为空 + ASSET_EXPORTER_UPLOAD_FAIL(319023, "Export upload error. You can upload files manually, sorry."), + ASSET_CABINET_ISNULL(311024,"Cabinet must be selected when start or end position is not empty"), // 机柜起始位置不为空 必须指定机柜才可以 + ASSET_POSITION_INVALID(315025,"Asset cabinet start or end value is invalid"), // 位置选值有误 不在合理返回内 + ASSET_POSITION_MISMATCH(315026,"Asset usize does not match the usize of the associated model"), // 位置选值有误 不在合理返回内 + ASSET_POSITION_OCCUPY(315027,"Asset selected position is already occupied"), // 位置已被占用 + ASSET_CABINETSTART_INVALIDE(313028,"Asset cabinet start must be an integer"), // 开始位置必须为数字类型 + ASSET_CABINETEND_INVALIDE(313029,"Asset cabinet end must be an integer"), // 结束位置必须为数字类型 + ASSET_SERVERPORT_ERROR(315030,"Asset ipmi port is incorrect"), + ASSET_SERVERHOST_ERROR(313031,"Asset ipmi host format error, format such as xxx.xxx.xxx.xxx(192.168.40.247)"), + ASSET_LOGINSERVER_FAILED(310032,"exporter error: User login to target server failed, It may be caused by 1.Authentication failed 2.Server is down or not reachable 3.Server is too slow to respond."), + ASSET_UPLOADFILE_FAILED(310033,"exporter error: Built in exporter upload failed"), + ASSET_EXECCOMMAND_FAILED(310034,"exporter error: Failed to run exporter program"), + ASSET_STATE_INVALIDE(313035,"Asset state must be an integer"), // 资产状态必须为数字类型 + ASSET_IMPORTFILE_TYPE(319036,"Only support import XLS or XLSX file"),// 导入文件格式只能为xls xlsx + ASSET_IMPORTFILE_FAILED(319037,"Import file resolution failed"), // 导入文件解析失败 + ASSET_TAGKEY_ISNULL(311038,"Asset tag name can no be empty"), + ASSET_EXPORTER_UPLOADBYSSH(313039,"Must use SSH protocol account to upload exporter"), + ASSET_EXPORT_HEADER_LANGUAGE_ISNULL(311040,"Export header language can not be empty"), + ASSET_EXPORT_HEADER_LANGUAGE_ERROR(314041,"Export header language must be en, cn and ru"), + ASSET_EXPORT_HEADER_TEMPLATE_ERROR(314042,"The header row of the excel import template is inconsistent with the system template"), + ASSET_TYPE_VALUE_DUPLICATE(312043,"Asset type vlaue is duplicate"), + ASSET_VENDOR_VALUE_DUPLICATE(312044,"Asset vendor vlaue is duplicate"), + ASSET_NAME_ISNULL(311045, "Asset name can not be empty"), + ASSET_MANAGEIP_ISNULL(311046, "Asset manage ip can not be empty"), + ASSET_MODEL_ID_ISNULL(311047, "Asset model id can not be empty"), + ASSET_DC_ID_ISNULL(311048, "Asset dc id can not be empty"), + ASSET_STATE_ID_ISNULL(311049, "Asset state id can not be empty"), + ASSET_TYPE_ID_ISNULL(311050, "Asset type id can not be empty"), + ASSET_NAME_DUPLICATE(312051, "Asset name duplicate"), + ASSET_NUMBER_DUPLICATE(312052, "Asset number duplicate"), + ASSET_MANAGEIP_DUPLICATE(312053, "Asset manage ip duplicate"), + ASSET_SSH_PORT_ERROR(315054, "Asset ssh port is incorrect"), + ASSET_TELNET_PORT_ERROR(315055, "Asset telnet port is incorrect"), + ASSET_NOT_SELECT_PARENT(311056, "Asset must select the asset host"), + ASSET_NOT_SUPPORT_MOUNTING(313057, "Asset does not support mounting"), + ASSET_NOT_UPDATE(313058, "It is currently a virtual machine host and cannot be modified as a virtual machine"), + ASSET_MANAGEIP_FORMAT(313059, "Asset manage IP address format is incorrect"), + ASSET_SSHPORT_MORE(312060, "Assets can only fill in one ssh port"), + ASSET_TELNET_MORE(312061, "Assets can only fill in one telnet port"), + ASSET_PARENT_NOT_EXIST(316062, "Asset parent does not exist"), + ASSET_AUTHUSERNAME_ISNULL(311063, "Asset auth username can not be empty"), + ASSET_AUTHPIN_ISNULL(311064, "Asset auth pin can not be empty"), + ASSET_AUTHPRIKEY_ISNULL(311065, "Asset auth pri key can not be empty"), + ASSET_EDITTYPE_ISNULL(311066,"Asset edit type can not be empty"), + + ASSET_MODELNAME_ISNULL(321000, "Asset model name can not be null"), // 资产型号名称不能为空 + ASSET_MODELID_ISNULL(321001, "Asset model id can not be null"), // 资产型号ID不能为空 + ASSET_MODELNAME_DUPLICATE(322002, "Asset model name duplicate"), // 资产型号名称重复 + ASSET_MODELTYPE_NOTFOUND(326003, "Asset model type not found"), // 资产型号类型未找到 + ASSET_MODELRELATED_ASSET(323004, "These mdoels contain assets and cannot be deleted"), // 资产型号关联资产 + ASSET_MODEL_NOTFOUND(326005, "Asset model not found"), // 资产型号未找到 + ASSET_MODEL_USIZEMINIMUM(325006, "The minimum value of model usize is 1"), // 资产型号u位最小值为1 + ASSET_MODEL_USIZEERROR(323007,"Model usize cannot be larger than associated asset size"),// 修改的时候model uSize 不能大于关联 asset 的大小 + ASSET_MODEL_EXISTS(322008,"Model already exists"), // 型号已经存在 + ASSET_MODEL_PARAM_ISNULL(321009,"The model Id and asset Id cannot both be empty, when the model chart is updated."), + ASSET_MODELID_INCONSISTENT(323010,"Asset model is inconsistent with model Id"), + ASSET_IPMITYPE_ERROR(323011,"Asset type must be a server can save ipmi information"), + ASSET_MODELRELATED_MIBS(323012, "These models contain mibs and cannot be deleted"), + ASSET_MODEL_BRANDID_ISNULL(321013, "Asset model brand id can not be null"), + ASSET_MODEL_CHART_ERROR(321014,"Asset model chart template not exist"), + + ACCOUNT_AUTHTYPE_ISNULL(331000, "Authentication type cannot be empty"), + ACCOUNT_AUTHTYPE_INVALIDE(333001, "Invalid authentication type"), + ACCOUNT_USER_ISNULL(331002, "Username cannot be empty"), + ACCOUNT_PWD_ISNULL(331003, "Login password cannot be empty"), + ACCOUNT_KEYFILE_ISNULL(331004, "Login certificate cannot be empty"), + ACCOUNT_PORT_ISNULL(331005, "Login port cannot be empty"), + ACCOUNT_ID_ISNULL(331006, "Account ID cannot be null"), + ACCOUNT_ID_INVALIDE(331007, "Account ID cannot be null"), + ACCOUNT_FILE_INSUFFICIENT(333008, "Account insufficient number of documents"), // 文件数量不足 + ACCOUNT_PORT_ERROR(335009, "Account port is incorrect"), // 账号端口不正确 + ACCOUNT_PROTOCOL_ISNULL(331010, "Account protocol cannot be empty"), // 协议信息不能为空 + ACCOUNT_PROTOCOL_INCORRECT(334011, "Account protocol must be SSH, TELNET or SNMP"), + ACCOUNT_PROTOCOL_PARAMS_ISNULL(331012, "Account protocol params can not be empty"), + ACCOUNT_PROTOCOL_PARAMS_FORMATERROR(333013, "Account protocol params must be JSON format"), + ACCOUNT_PROTOCOL_EXCEED_COUNT(337014, "An protocol can only have one account"), + ACCOUNT_SSH_METHOD_INCORRECT(334015,"SSH account login method must be key or password"), + ACCOUNT_SNMP_USERNAME_ISNULL(331016,"SNMP account username is required for SNMPv3"), + ACCOUNT_SNMP_SECURITYLEVEL_INVALID(334017,"SNMP account security level must be one of authPriv, authNoPriv or noAuthNoPriv"), + ACCOUNT_SNMP_VERSION_INVALIDE(333018,"Snmp version must be 2 or 3"), + ACCOUNT_SNMP_AUTHPROTOCOL_INVALIDE(334019,"Auth protocol must be MD5 or SHA"), + ACCOUNT_SNMP_PRIVPROTOCOL_INVALIDE(334020,"Priv protocol must be DES or AES"), + + ASSET_ACCOUNT_ID_ISNULL(331001,"asset account id can not be null"), + ASSET_ACCOUNT_NAME_ISNULL(331002,"asset account name can not be null"), + ASSET_ACCOUNT_PROTOCOL_ISNULL(331003,"asset account protocol can not be null"), + ASSET_ACCOUNT_AUTHTYPE_ISNULL(331004,"asset account auth type can not be null"), + ASSET_ACCOUNT_USERNAME_ISNULL(331005,"asset account username can not be null"), + ASSET_ACCOUNT_PASSWORD_ISNULL(331006,"asset account password can not be null"), + ASSET_ACCOUNT_PRIKEY_ISNULL(331007,"asset account prikey can not be null"), + ASSET_ACCOUNT_USERTIP_ISNULL(331008,"asset account user tip can not be null when auth type is telnet"), + ASSET_ACCOUNT_PASSWORDTIP_ISNULL(331009,"asset account password tip can not be null when auth type is telnet"), + ASSET_ACCOUNT_WEIGHT_ISNULL(331010,"asset account id can not be null"), + ASSET_ACCOUNT_STATE_ISNULL(331011,"asset account id can not be null"), + ASSET_ACCOUNT_NOT_FOUND(336012, "Asset account not found"), + + STATECONF_NAME_ISNULL(341000,"Asset state conf name is null"), + STATECONF_PING_ISNULL(341001,"Asset state conf ping is null"), + STATECONF_MONITOR_ISNULL(341002,"Asset state conf monitor is null"), + STATECONF_ALERT_ISNULL(341003,"Asset state conf alert is null"), + STATECONF_NAME_DUPLICATE(342004, "Asset state conf name is duplicate"), + STATECONF_ID_ISNULL(341005,"Asset state conf id is null"), + STATECONF_BUILDIN_CAN_NOT_REMOVE(347006, "This config is built-in and cannot be deleted"), + STATECONF_PING_INCORRECT(344007,"Asset state conf ping must be 0 or 1"), + STATECONF_MONITOR_INCORRECT(344008,"Asset state conf monitor must be 0 or 1"), + STATECONF_ALERT_INCORRECT(344009,"Asset state conf alert must be 0 or 1"), + STATECONF_BUILDIN_INCORRECT(344010,"Asset state conf buildin must be 0 or 1"), + STATECONF_CAN_NOT_REMOVE(347011, "This config is already used by the asset and cannot be deleted"), + STATECONF_NOT_FOUND(346012, "Asset state conf not found"), + + TYPECONF_NOT_FOUND(356000, "Asset type config not found"), + TYPECONF_NAME_ISNULL(351001, "Asset type config name is null"), + TYPECONF_VM_ISNULL(351002, "Asset type config vm is null"), + TYPECONF_VMH_ISNULL(351003, "Asset type config vmh is null"), + TYPECONF_SSH_ISNULL(351004, "Asset type config ssh is null"), + TYPECONF_TELNET_ISNULL(351005, "Asset type config telnet is null"), + TYPECONF_NAME_DUPLICATE(352006, "Asset type config name is duplicate"), + TYPECONF_VM_INCORRECT(354007, "Asset type config vm must be 0 or 1"), + TYPECONF_VMH_INCORRECT(354008, "Asset type config vmh must be 0 or 1"), + TYPECONF_SSH_INCORRECT(354009, "Asset type config ssh must be 0 or 1"), + TYPECONF_TELNET_INCORRECT(354010, "Asset type config telnet must be 0 or 1"), + TYPECONF_BUILDIN_INCORRECT(354011, "Asset type config buildin must be 0 or 1"), + TYPECONF_ID_ISNULL(351012, "Asset type config id is null"), + TYPECONF_BUILDIN_CAN_NOT_REMOVE(357013, "This configuration is built-in and cannot be deleted"), + TYPECONF_BEUSED_CAN_NOT_REMOVE(357014, "This configurations is already used by the asset and cannot be deleted"), + TYPECONF_PARENT_NOT_FOUND(356015, "Asset type parent config not found"), + TYPECONF_CONTAIN_BABY_CAN_NOT_REMOVE(357016, "This configurations contain sub-configuration and cannot be deleted"), + TYPECONF_AUTHPROTOCOL_ISNULL(351017, "Asset type config auth protocol is null"), + TYPECONF_SNMPENABLE_ISNULL(351018, "Asset type config snmp enable is null"), + TYPECONF_SNMPCOLLECT_ISNULL(351019, "Asset type config snmp collect is null"), + TYPECONF_SSHCOLLECT_ISNULL(351020, "Asset type config ssh collect is null"), + TYPECONF_SSHCOLLECTSCRIPT_ISNULL(351021, "Asset type config ssh collect script is null"), + + ASSET_BRAND_NOT_FOUND(366000, "Asset brand not found"), + ASSET_BRAND_NAME_ISNULL(361001, "Asset brand name is null"), + ASSET_BRAND_ID_ISNULL(361002, "Asset brand id is null"), + ASSET_BRAND_NAME_DUPLICATE(362003, "Asset brand name is duplicate"), + ASSET_BRAND_BEUSED_CAN_NOT_REMOVE(367004, "This brand is already used and cannot be deleted"), + ASSET_BRAND_NOT_CONTAIN_MODEL(366005, "This model is not included under this brand"), + + ASSET_FIELD_GROUP_ID_ISNULL(361001,"Asset field group id can not be empty"), + ASSET_FIELD_GROUP_NAME_ISNULL(361002,"Asset field group name can not be empty"), + ASSET_FIELD_GROUP_NAME_DUPLICATE(362003,"Asset field group name can not duplicate"), + + ASSET_FIELD_META_ID_ISNULL(371001,"Asset field meta id can not be empty"), + ASSET_FIELD_META_NAME_ISNULL(371002,"Asset field meta name can not be empty"), + ASSET_FIELD_META_KEY_ISNULL(371003,"Asset field meta key can not be empty"), + ASSET_FIELD_META_GROUPID_ISNULL(371004,"Asset field meta group id can not be empty"), + ASSET_FIELD_META_SEARCH_ISNULL(371005,"Asset field meta search can not be empty"), + ASSET_FIELD_META_DISPLAY_ISNULL(371006,"Asset field meta display can not be empty"), + ASSET_FIELD_META_TYPE_ISNULL(371007,"Asset field meta type can not be empty"), + ASSET_FIELD_META_TYPE_ERROR(375008,"Asset field type value out of range"), + ASSET_FIELD_META_KEY_ERROR(373009,"Asset field key value incorrect format"), + ASSET_FIELD_META_KEY_DUPLICATE(372010,"Asset field key value duplicate"), + ASSET_FIELD_META_NOT_FOUND(376011, "Asset field meta not found"), + + /** + * alerts菜单栏相关 + */ + ALERTMSG_IDS_ISNULL(411000, "Ids is required"), //告警信息ids不能为空 + ALERTMSG_STATE_ISNULL(411001, "State is required"), //告警信息state不能为空 + ALERTMSG_STATE_INCORRECT(412002, "State is incorrect"), //告警信息state不合法 + ALERTMSG_PARSE_ERROR(413003, "Data parse error"), //告警信息解析失败 + ALERTMSG_SAVE_ERROR(413004, "Data save faild"), //告警信息解析失败 + ALERTMSG_TOPN_ISNULL(411005, "TopN is required"), //告警信息topn不能为空 + ALERTMSG_REMARK_ISNULL(411006, "Remark is required"), //告警信息topn不能为空 + + + ALERTRULE_ID_ISNULL(421000, "ID is required"), //告警规则ID不能为空 + ALERTRULE_NAME_ISNULL(421001, "Alert name is required"), //告警规则名称不能为空 + ALERTRULE_NAME_DUPLICATE(421002, "Alert name is duplicate"), //告警规则名称不能为空 + ALERTRULE_EXPR_ISNULL(421003, "Expr is required"), //告警规则表达式不能为空 + ALERTRULE_EXPR_ERROR(423004, "Expr syntax error"), //告警规则表达式不合法 + ALERTRULE_LAST_ISNULL(421005, "Last is required"), //告警持续时间不能为空 + ALERTRULE_LAST_ISNOTPOSITIVE(425006, "Last must be a positive number"), //告警持续时间必须是正数 + ALERTRULE_SEVERITY_ISNULL(421007, "Severity is required"), //告警级别不能为空 + ALERTRULE_SEVERITY_INCORRECT(424008, "Severity is not exists"), + ALERTRULE_LINK_OBJECT_ISNULL(426009, "Association object does not exist"), + ALERTRULE_TYPE_ISNULL(421010, "Alarm type is empty"), + ALERTRULE_TYPE_INVALIDE(424011, "Alarm type is invalide"), + ALERTRULE_BUILDIN_CAN_NOT_REMOVE(427012, "This rule is built-in and cannot be deleted"), + ALERTRULE_TOPN_ISNULL(421013, "TopN is required"), //告警信息topn不能为空 + ALERTRULE_SUMMARY_ISNULL(421014, "Alert summary is required"), + ALERTRULE_RECEIVER_FORMAT(423015, "Alert receiver id format error , it's should be integer"), + ALERTRULE_BUILDIN_CAN_NOT_UPDATE(427016, "This rule is built-in and cannot be updated"), + ALERTRULE_OPERATOR_ISNULL(421017, "Alert operator can not be empty"), + ALERTRULE_THRESHOLD_ISNULL(421018, "Alert threshold can not be empty"), + ALERTRULE_UNIT_ISNULL(421019, "Alert unit can not be empty"), + ALERTRULE_OPERATOR_INVALIDE(423020, "Alert operator is invalide"), + ALERTRULE_UNIT_INVALIDE(423021, "Alert unit is invalide"), + ALERTRULE_EXPORT_HEADER_LANGUAGE_ISNULL(421022,"Export header language can not be empty"), + ALERTRULE_EXPORT_HEADER_LANGUAGE_ERROR(424023,"Export header language must be en, cn and ru"), + ALERTRULE_IMPORT_FILE_ISNULL(421024, "Alert import file can not be null"), + ALERTRULE_IMPORTFILE_TYPE(429025,"Only support import XLS or XLSX file"), + ALERTRULE_CANCELIMPORTSEQ_ISNULL(421026, "Alert rule cancel import seq can not be null"), + ALERTRULE_THRESHOLD_FORMAT(423027, "Alert threshold format should be a long integer"), + ALERTRULE_UNIT_FORMAT(423028, "Alert unit format should be a integer"), + ALERTRULE_DESCRIPTION_ISNULL(4210629, "Alert description can not be empty"), + ALERTRULE_RECEIVER_NOTFOUND(421030, "Alert receiver user not found"), + ALERTRULE_IMPORT_ERROR(423031, "Alert import error"), + ALERTRULE_METHOD_ISNULL(421027, "Alert rule method can not be null"), + ALERTRULE_METHOD_NOTFOUND(426028, "Alert rule method not found"), + + /** + * 告警通知脚本 + */ + ALERT_NOTIFISCRIPT_NAME_ISNULL(431001, "Alert notification script name can not be empty"), + ALERT_NOTIFISCRIPT_FILE_NOTFOUND(436002, "Notification script file not found by file path"), + ALERT_NOTIFISCRIPT_NOT_FILE(439003, "The file found through this file path is not a file"), + ALERT_NOTIFISCRIPT_NOT_EXECUTABLE(439004, "The file does not have executable permissions"), + ALERT_NOTIFISCRIPT_ID_ISNULL(431005, "Alert notification script id can not be empty"), + ALERT_NOTIFISCRIPT_ACCOUNT_ISNULL(431006, "Alert notification script account can not be empty"), + ALERT_NOTIFISCRIPT_SCRIPT_NOTFOUND(436007, "Alert notification script not found"), + + /** + * 告警静默 + */ + ALERTSILENCE_STARTTIME_ISNULL(441001,"AlertSilence start time can not be null"), + ALERTSILENCE_ENDTIME_ISNULL(441002,"AlertSilence end time can not be null"), + ALERTSILENCE_ENDTIME_MUSTGTNOW(441003,"AlertSilence end time must great now time"), + ALERTSILENCE_ID_IS_NOT_NULL(441004,"ids can not be null"), + ALERTSILENCE_TYPE_ERROR(445005,"AlertSilence type value error"), + ALERTSILENCE_MATCHER_ISNULL(441006,"AlertSilence matchers can not be null"), + + /** + * 告警级别 + */ + ALERTSEVERITY_NAME_ISNULL(451001,"Alert severity name can not be null"), + ALERTSEVERITY_COLOR_ISNULL(451002,"Alert severity color can not be null"), + ALERTSEVERITY_METHODS_ISNULL(451003,"Alert severity methods can not be null"), + ALERTSEVERITY_ID_ISNULL(451004,"Alert severity id can not be null"), + ALERTSEVERITY_REMARK_ISNULL(451005,"Alert severity remark can not be null"), + ALERTSEVERITY_WEIGHT_PARAM_ISNULL(451006,"Alert severity id or weight is null"), + + + /** + * 告警通知 + */ + ALERTNOTIFY_NOT_EXISTS(461001,"Alert notify method is not exists"), + ALERTNOTIFY_NAME_ISNULL(461002,"Alert notify method name can not be null"), + ALERTNOTIFY_FILE_NOTEXISTS(461003,"Alert notify method script file is not exsits"), + ALERTNOTIFY_ACCOUNT_ISNULL(461004,"Alert notify method account can not be null"), + ALERTNOTIFY_STATE_ISNULL(461005,"Alert notify method state can not be null"), + ALERTNOTIFY_ID_ISNULL(461006,"Alert notify method ID can not be null"), + ALERTNOTIFY_FILEPATH_ISNULL(461007,"Alert notify method file path can not be null"), + ALERTNOTIFY_NAME_DUPLICATE(462008, "Alert notify method name duplicate"), + /** + * setting菜单项相关 + */ + SYS_ERROR(517000, "system error"), //10xxxx,系统类(业务系统、用户组、权限等)通用错误以及其他系统内部错误 + + SYS_DB_DUPLICATERECORD(512001, "duplicate record"), //数据库中已存在该记录 + SYS_DB_AUTH(517002, "Permission denied"), //没有权限 + SYS_LOGIN_CAPTCHA(518003, "Captcha verification failed"), //登录验证码错误 + SYS_LOGIN_UNKNOWNACCOUNT(518004, "Unknown error"), //未知校验错误 + SYS_LOGIN_USERPWD(518005, "Incorrect username or password"), //账号或密码错误 + SYS_LOGIN_LOCK(518006, "Locked account"), //账号被锁定 + SYS_LOGIN_ACCOUNTAUTH(518007, "Incorrect username or password"), //账号验证失败 + SYS_LOGIN_REQUIRED(518008, "Please log in to the system first"), //账号验证失败 + SYS_MENU_SYSMENUDEL(517009, "Delete system menu is not allowed"), //系统菜单,不能删除 + SYS_MENU_DELSUB(517010, "Please delete the submenu first"), //请先删除子菜单或按钮 + SYS_USER_OLDPWD(518011, "user oldpwd error"), //原密码不正确 + SYS_USER_DELADMIN(517012, "del admin error"), //系统管理员不能删除 + SYS_USER_CANNOTDEL(517013, "The currently logged in user cannot be deleted"), //当前登录用户不能删除 + SYS_USER_DUPLICATENAME(517014, "user name duplicate error"), //业务系统选择错误 + SYS_USER_NOT_EXIST(516015, "System user does not exist"), //系统用户不存在 + SYS_USER_USERNAME_ISNULL(511016, "System user login name can not be empty"), + SYS_USER_STATUS_ISNULL(511017, "System user status can not be empty"), + SYS_USER_PASSWORD_ISNULL(511018, "System user password can not be empty"), + SYS_USER_ID_ISNULL(511019, "System user id can not be empty"), + SYS_USER_SCRIPT_ACCOUNT_REPEATED(512020, "System user script id and account cannot be repeated"), + SYS_USER_STATUS_INVALIDE(514021, "System user status must be 0 or 1"), + SYS_USER_EMAIL_FORMAT(513022, "System user email format is incorrect"), + SYS_MENU_ISNULL(516023, "Menu is not exsits"), + SYS_MENU_ID_ISNULL(511024, "Menu id is required"), + SYS_MENU_NAME_ISNULL(511025, "Menu name is required"), + SYS_MENU_CODE_ISNULL(511026, "Menu code is required"), + SYS_MENU_I18N_ISNULL(511027, "Menu i18n is required"), + SYS_MENU_TYPE_ISNULL(511028, "Menu type is required"), + SYS_MENU_ORDERNUM_ISNULL(511029, "Menu order num is required"), + SYS_MENU_CODE_DUPLICATE(512030, "Menu code duplicate"), + SYS_MENU_TYPE_INVALIDE(513031,"Menu type not found"), + SYS_MENU_BUTTON_PARENTID_ISNULL(511032,"Button must have a parent id"), + SYS_MENU_BUTTON_PARENTTYPE_INVALIDE(513033,"Button cannot be used as a parent menu"), + SYS_TOKEN_ISNULL(511034,"Cannot get token information from request header"), + SYS_USER_NAME_ISNULL(511035, "System user name can not be empty"), + SYS_USER_NAME_DUPLICATE(511036, "System user name duplicate"), + SYS_MENU_TAB_PARENTTYPE_INVALIDE(513037,"Tab cannot be used as a parent menu"), + + PROMSERVER_ID_ISNULL(521000, "PromServer id can not be empty"), + PROMSERVER_DCID_ISNULL(521001, "Dc id can not be empty"), + PROMSERVER_TYPE_ISNULL(521002, "PromServer type can not be empty"), + PROMSERVER_HOST_ISNULL(521003, "PromServer host can not be empty"), + PROMSERVER_PORT_ISNULL(521004, "PromServer port can not be empty"), + PROMSERVER_REQUEST_FAILD(521005, "Request faild"), + PROMSERVER_PARAM_TIME_INVALIDE(523006, "Invalid parameter for time type"), + PROMSERVER_PARAM_QUERY_ISNULL(521007, "Parameter 'query' is required"), + PROMSERVER_PARAM_START_ISNULL(521008, "Parameter 'start' is required"), + PROMSERVER_PARAM_END_ISNULL(521009, "Parameter 'end' is required"), + PROMSERVER_PARAM_STEP_ISNULL(521010, "Parameter 'step' is required"), + PROMSERVER_PARAM_MATCH_ISNULL(521011, "Parameter 'match[]' is required"), + PROMSERVER_PORT_ERROR(523012, "PromServer port is incorrect"), + PROMSERVER_HOST_ERROR(523013, "PromServer host is incorrect"), + PROMSERVER_NOTEXSITS(526014, "PromServer is not exsits"), // PromServer 不存在 + PROMSERVER_EXIST_ERROR(526015, "PromServer is exists : host,type,port repeat"), + PROMSERVER_TYPE_INVALIDE(523016,"PromServer type is incorrect"), + PROMSERVER_UNAVAILABLE(526017,"No PromServer available"), + PROMSERVER_TOKEN_ISNULL(521018, "PromServer token info can not be empty"), + + + DC_NAME_ISNULL(531000, "Dc name can not be empty"), // 数据中心name不能为空 + DC_ID_ISNULL(531001, "Dc id can not be empty"), // 数据中心id不能为空 + DC_PHONE_FORMAT(533002, "Dc phone format error"), + DC_PRINCIPAL_NOT_EXISTS(536003, "Dc principal does not exist"), // 数据中心负责人不存在 + DC_NAME_DUPLICATE(532004, "Dc name duplicate"), // 数据中心名称重复 + DC_CABINETS_EXISTS(533005, "These Dc contain cabinets and cannot be deleted"), // 数据中心内含有机柜 + DC_ASSETS_EXISTS(533006, "These Dc contain assets and cannot be deleted"), // 数据中心内含有资产 + DC_NOT_EXISTS(536007, "Dc does not exist"), // 数据中心不存在 + DC_NOTHAS_CABINET(536008, "There is no this cabinet in the dc"), // 数据中心中没有该机柜 + DC_ID_FORMAT(533009, "Id format error , type should be integer"), // ID类型错误 + DC_CABINETNAME_ISNULL(531010, "Cabinet name can not be empty"), // 机柜名称不能为空 + DC_CABINETID_ISNULL(531011, "Cabinet id can not be empty"), // 机柜id不能为空 + DC_CABINETNAME_DUPLICATE(532012, "Cabinet name duplicate"), // 机柜名称重复 + DC_CABINETUSIZE_MINIMUM(535013, "Cabinet u size is a minimum of 1"),// 机柜U位大小最小为1 + DC_CABINET_ASSETS_EXISTS(533014, "These cabinets contain assets and cannot be deleted"),// 机柜中有资产 + DC_CABINET_MAXU(535015, "The maximum U of current cabinet is 47"), // 当前机柜最大U为47 + DC_Y_MINIMUM(535016,"Dc y is a minimum of 1"), // 数据中心行数最少为1 + DC_X_MINIMUM(535017,"Dc x is a minimum of 1"), // 数据中心列数最少为1 + DC_Y_ALREADYINUSE(535018,"Dc y is already in use"), // 数据中心行已经被使用 + DC_X_ALREADYINUSE(535019,"Dc x is already in use"), // 数据中心列已经被使用 + CABINET_Y_MINIMUM(535020,"Cabinet y is a minimum of 1"), // 机柜所在行至少为1 + CABINET_X_MINIMUM(535021,"Cabinet x is a minimum of 1"), // 机柜所在列至少为1 + CABINET_Y_INCORRECT(535022,"Cabinet y is not in this dc"), // 机柜所选行不在dc范围内 + CABINET_X_INCORRECT(535023,"Cabinet x is not in this dc"), // 机柜所选列不在dc范围内 + CABINET_POSITION_OCCUPIED(535024,"Cabinet position is occupied"), // 机柜所选位置已被占用 + DC_PROMSERVER_EXISTS(533025, "There are promservers in the dc"), + DC_TRAFFIC_DIRECTIONS_INVALIDE(533026, "Dc traffic direction must be rx or tx"), + DC_TRAFFIC_SETTING_ISNULL(531027, "Dc traffic setting can not be empty"), + DC_TRAFFIC_DIRECTIONS_ISNULL(531028, "Dc traffic direction can not be empty"), + DC_TRAFFIC_IFINDEX_ISNULL(531029, "Dc traffic Ifindex can not be empty"), + DC_TRAFFIC_IFDESCR_ISNULL(531030, "Dc traffic ifdescr can not be empty"), + DC_NOT_INCLUDED_ASSET(533031,"Current asset is not included under the data center"), + DC_TRAFFIC_HOST_FORMAT(533032,"Dc traffic host must be in IP format"), + DC_TRAFFIC_HOST_ISNULL(531033,"Dc traffic host can not be empty"), + DC_TRAFFIC_PORT_ISNULL(531034,"Dc traffic port can not be empty"), + DC_TRAFFIC_VERSION_ISNULL(531035,"Dc traffic version can not be empty"), + DC_TRAFFIC_PORT_INVALIDE(535036,"Dc traffic port is invalide"), + DC_TRAFFIC_TAGSKEY_FORMAT(533037,"Dc traffic tags key format is incorrect"), + DC_PROMSERVERS_EXISTS(533038, "These dc contain prometheus servers and cannot be deleted"), + DC_STATE_ISNULL(531039, "Dc state can not be empty"), + DC_STATE_ERROR(534040, "Dc state must be ON or OFF"), + DC_LONGITUDE_ERROR(535041, "Dc longitude range is -180 to +180"), + DC_LATITUDE_ERROR(535042, "Dc latitude range is -90 to +90"), + CABINET_NOT_EXISTS(536043, "Cabinet does not exist"), + + SYS_I18N_DUPLICATE(542000, "duplicate error (code + lang)"), //国际化配置重复(code+lang) + SYS_I18N_NOSUCHLANG(543001, "no such lang"), //不合法的lang + + + SYS_DICT_NAME_ISNULL(551000, "Field 'name' is not null"), // 字典名称不能为空 + SYS_DICT_TYPE_ISNULL(551001, "Field 'type' is not null"), // 字典类型不能为空 + SYS_DICT_VALUE_ISNULL(551002, "Field 'type' is not null"), // 字典值不能为空 + SYS_DICT_CODE_ISNULL(551003, "Field 'code' is not null"), // 字典值不能为空 + SYS_DICT_VALUE_DUPLICATE(552004, "Field 'type' is duplicate"), // 字典值重复 + SYS_DICT_ID_INVALIDE(553005, "Invalid system dictionary ID"), + SYS_DICT_ID_ISNULL(551006, "System dictionary ID is null"), + SYS_DICT_REMOVE_ERROR(553007,"Those dict params contain model can not remove"), + + SNMP_MIB_FILE_ISNULL(561000,"Snmp mib file can not be empty"), // snmp mib文件不能为空 + SNMP_MIB_ID_ISNULL(561001,"Snmp mib id can not be empty"), // snmp mib id 不能为空 + SNMP_MIB_PARSING_FAILED(569002,"SNMP MIB file parsing failed"),// snmp mib 解析失败 + SNMP_MIB_OPERATION_ISNULL(561003,"Snmp mib operation can not be empty"),// operation不能为空 + SNMP_MIB_HOST_ISNULL(561004,"Snmp mib host can not be empty"),// host 不能为空 + SNMP_MIB_HOST_FORMAT(563005,"Snmp mib host must be in IP format"),// host 必须为IP格式 + SNMP_MIB_PORT_ISNULL(561006,"Snmp mib port can not be empty"),// port 不能为空 + SNMP_MIB_PORT_INVALIDE(565007,"Snmp mib port is invalide"), // port 错误 + SNMP_MIB_VERSION_ISNULL(561008,"Snmp mib version can not be empty"),// version 不能为空 + SNMP_MIB_OID_ISNULL(561009,"Snmp mib oid can not be empty"),// oid 不能为空 + SNMP_MIB_OPERATION_INVALIDE(563010,"Snmp operation type must be get, walk, getnext or set "),// operation值不在合理返回内 + SNMP_MIB_VERSION_INVALIDE(563011,"Snmp version must be 2 or 3"),// version值不在合理返回内 + SNMP_MIB_AUTH_ISNULL(561012,"Snmp auth can not be empty when version is 3"), // auth值不在合理返回内 + SNMP_MIB_BROWSER_FAILED(560013,"Failed to execute Broswer according by oid"), + SNMP_MIB_BROWSER_TIMEOUT(560014,"Browse timed out.It may be caused by 1.The SNMP version number is not supported by agent 2.Agent is down or not reachable 3.Agent is too slow to respond.You can increase the timeout value 4.Browser request has been blocked by firewall 5.Authentication failed.Community name or password is not right"), + SNMP_MIB_VALUE_ISNULL(561015,"Snmp value cannot be empty when operation is set"), + SNMP_MIB_TOOBIG(560016,"PDU encoding is too big for the transport used."), + SNMP_MIB_NOSUCHNAME(560017,"No such variable binding name."), + SNMP_MIB_BADVALUE(560018,"Bad value in variable binding"), + SNMP_MIB_READONLY(560019,"The variable binding is read-only"), + SNMP_MIB_NOACCESS(560020,"The variable binding is not accessible by the current MIB view,No assess"), + SNMP_MIB_TYPE_ISNULL(561021,"Snmp value type cannot be empty when operation is set"), + SNMP_MIB_TYPE_INVALIDE(563022,"Snmp value type is invalide"), + SNMP_MIB_NOTWRITABLE(560023,"The variable's value cannot be modified"), + SNMP_MIB_CONFIG_ISNULL(561024,"Snmp Credential Id and config cannot be empty at the same time"), + + + SYS_CONFIG_TYPE_ISNULL(571000,"System config type can not be null"), // sysConfig 查询type参数不能为空 + SYS_CONFIG_TYPE_INVALIDE(574001,"System config type is invalide"), // type 不在枚举值类 + SYS_CONFIG_SAVEENTITY_ISNULL(571002,"System config save entity can not be null"),// 保存实体数据不能为空 + SYS_CONFIG_MAXTERMINALNUM_ISNULL(571003, "System config max terminal num can not be null"),// 每个用户最大打开窗口数量不能为空 + SYS_CONFIG_MAXTERMINALNUM_INVALIDE(575004, "System config max terminal num is invalide, Its minimum value is integer 1"),// 参数值不正确 + SYS_CONFIG_ALERTAPI_ISNULL(571005,"System config alert api can not be null"), // alert api 不能为空 + SYS_CONFIG_SWITCHVAUE_INVALIDE(574006,"System config switch value is invalid, must be on or off"), // 开关值不在枚举范围内 + SYS_CONFIG_ASSETPINGSWITCH_ISNULL(571007,"System config asset pings witch can not be null"), // assetpingswitch不能为空 + SYS_CONFIG_NODETARGETPATH_ISNULL(571008,"System config node export target path can not be null"), // node exporter targer path不能为空 + SYS_CONFIG_ASSETPINGINTERVAL_ISNULL(571009,"System config asset ping interval can not be null"), // asset_ping_interval不能为空 + SYS_CONFIG_ASSETPINGINTERVAL_INVALIDE(573010,"System config asset ping interval should be an integer"), // asset_ping_interval参数与要求不符合 + SYS_CONFIG_PORT_INVALID(573011,"port must be between 1 and 65535"), + SYS_CONFIG_EMAILENABLE_ISNULL(571011,"System config email enable can not be empty"), // email_enable 不能为空 + SYS_CONFIG_EMAILSMTPHOST_ISNULL(571012,"System config email smtp host can not be empty"), // email_smtp_host 不能为空 + SYS_CONFIG_EMAILSMTPHOST_FORMAT(573013,"System config email smtp host format error"), // email_smtp_host 格式不正确 + SYS_CONFIG_EMAILSMTPPORT_ISNULL(571014,"System config email smtp port can not be empty"), // email_smtp_port 不能为空 + SYS_CONFIG_EMAILSMTPPORT_ERROR(575015,"System config email smtp port is invalide"), // email_smtp_port 端口错误 + SYS_CONFIG_EMAILSMTPACCOUNT_ISNULL(571016,"System config email smtp account can not be empty"), // email_smtp_account 不能为空 + SYS_CONFIG_EMAILSMTPPASSWORD_ISNULL(571017,"System config email smtp password can not be empty"), // email_smtp_password 不能为空 + SYS_CONFIG_EMAILSENDACCOUNT_ISNULL(571018,"System config email send account can not be empty"), // email_send_account 不能为空 + SYS_CONFIG_EMAILTESTRECIVER_ISNULL(571019,"System config email test reciver can not be empty"), // email_test_reciver 不能为空 + SYS_CONFIG_EMAILTESTRECIVER_FORMAT(573020,"System config email test reciver format error, format such as [email protected]"), // email_test_reciver 邮箱格式错误 + SYS_CONFIG_EMAILSSLFLAG_FORMAT(571021,"System config email ssl flag can not be empty"), // email_ssl_flag 不能为空 + SYS_CONFIG_EMAILTLSFLAG_FORMAT(571022,"System config email tls flag can not be empty"), // email_tls_flag 不能为空 + SYS_CONFIG_EMAILSSLFLAG_INVALIDE(573023,"System config email ssl flag is invalide"), // email_ssl_flag 参数与要求不符合 + SYS_CONFIG_EMAILTLSFLAG_INVALIDE(573024,"System config email tls flag is invalide"), // email_tls_flag 参数与要求不符合 + SYS_CONFIG_EMAILPROTOCOL_INVALIDE(573025,"System config email security type is invalide"), // email_tls_flag 参数与要求不符合 + SYS_CONFIG_LDAPENABLE_ISNULL(571025,"System config ldap enable can not be empty"), // ldap_enable 不能为空 + SYS_CONFIG_LDAPADDRESS_ISNULL(571026,"System config ldap address can not be empty"), // ldap_address 不能为空 + SYS_CONFIG_LDAPDN_ISNULL(571027,"System config ldap dn can not be empty"), // ldap_dn 不能为空 + SYS_CONFIG_LDAPPASSWORD_ISNULL(571028,"System config ldap password can not be empty"), // ldap_password 不能为空 + SYS_CONFIG_LDAPUSERFILTER_ISNULL(571029,"System config ldap user filter can not be empty"), // ldap_user_filter 不能为空 + SYS_CONFIG_LDAPMAPPING_ISNULL(571030,"System config ldap mapping can not be empty"), // ldap_mapping 不能为空 + SYS_CONFIG_PASSWORDORTYPE_INVALID(571031,"The password or type is invalid when reset"), + SYS_CONFIG_PASSWORD_ERROR(571032,"The password is different from the original one when reset"), + SYS_CONFIG_QUERYPARAMS_ISNULL(571033,"Type and paramKey cannot be empty at the same time when sysconfig queries"),// 查询sysConfig时, type 和 paramKey不能同时为空 + SYS_CONFIG_SCRAPEINTERVAL_ISNULL(571034,"System config scrape interval can not be empty"), // scrape_interval 不能为空 + SYS_CONFIG_LOCALRETENTION_ISNULL(571035,"System config storage local retention can not be empty"), // storage_local_retention 不能为空 + SYS_CONFIG_SYSTEMNAME_ISNULL(571036,"System config system name can not be empty"), // system_name 不能为空 + SYS_CONFIG_SCRAPEINTERVAL_INVALIDE(573037,"System config scrape interval should be an integer"), // scrape_interval参数与要求不符合 + SYS_CONFIG_LOCALRETENTION_INVALIDE(573038,"System config storage local retention should be an integer"), // storage_local_retention参数与要求不符合 + SYS_CONFIG_EMAILSMTPPORT_INVALIDE(573039,"System config email smtp port should be an integer"), // email_smtp_port参数与要求不符合 + SYS_CONFIG_EMAILSMTPACCOUNT_FORMAT(573040,"System config email smtp account format error, format such as [email protected]"), //email_smtp_account应为邮件格式 + SYS_CONFIG_LDAPOU_ISNULL(571041,"System config ldap ou can not be empty"), // ldap_ou 不能为空 + SYS_CONFIG_TEST_ISNULL(571042,"System config test can not be empty"), // test 不能为空 + SYS_CONFIG_EMAIL_AUTHENTICATIONFAIL(570043,"Failed to connect to SMTP service: username/password wrong"), + SYS_CONFIG_EMAIL_CONNECTFAIL(570044,"Unable to establish a connection with the SMTP service. Please check whether the SMTP service is running normally and can connect externally, such as host and port information."), + SYS_CONFIG_EMAIL_OTHERFAILURES(570045,"The connection to the SMTP service timed out. Please check the network condition"), + SYS_CONFIG_LDAP_AUTHENTICATIONFAIL(570046,"ldap service config connection failed : username/password wrong"), + SYS_CONFIG_LDAP_CONNECTIONFAILED(570047,"Unable to establish a connection with the ldap service. Please check whether the LDAP service is running normally and can connect externally."), + SYS_CONFIG_TIMEZONE_ISNULL(571048,"System config timezone can not be empty"), // timezone 不能为空 + SYS_CONFIG_TIMEZONE_INVALIDE(573049,"System config timezone should be an integer"), // timezone参数与要求不符合 + SYS_CONFIG_TIMEZONE_INTERVAL(575050,"The interval value of timezone is between -12 and +12"), // timezone 区间值为-12至+12之间 + SYS_CONFIG_DEFALUTCABINETU_INTERVAL(573051,"System config default cabinet usize is invalide"), // 配置表中机柜默认值有误 + SYS_CONFIG_LDAP_OU_NOT_EXIST(570052,"Ldap ou not exist"), // ldap连接ou不存在 + SYS_CONFIG_LDAPMAPPING_FORMAT_ERROR(571053,"System config ldap mapping format error"), // ldap_mapping格式错误 非正常json格式 + SYS_CONFIG_TESTEMAIL_TEMPLATE_NOTFOUND(576054,"System config test email sending template not found"),// 发送测试邮件模板未找到 + SYS_CONFIG_TESTEMAIL_TEMPLATE_FAILED(570055,"Test email template generation failed"), // freemarker生成发送邮件模板内容失败 + SYS_CONFIG_EMAILSENDCCOUNT_FORMAT(573056,"System config email send account format error"), //email_send_account应为邮件格式 + SYS_CONFIG_RESET_FAIL(573057,"System reset fail, check config and try again later"), + SYS_CONFIG_MODELCHARTTPL_NOTFOUND(576058,"System config model chart tpl not found"), + SYS_CONFIG_PROJECTCHARTTPL_NOTFOUND(576059,"System config project chart tpl not found"), + SYS_CONFIG_DEFAULTCABINETUSIZE_INVALIDE(573060,"System config default cabinet usize should be an integer"), + SYS_CONFIG_QUERYMAXSERIES_ISNULL(571061, "System config Query max series can not be empty"), + SYS_CONFIG_QUERYMAXSERIES_INVALIDE(573062, "System config Query max series should be an integer"), + SYS_CONFIG_QUERYMAXSERIES_INTERVAL(575063, "The interval value of Query max series is between -1 and +1000"), + SYS_CONFIG_EXPORT_MAX_LINE(579064,"The number of exported data than the configured max export line"), + SYS_CONFIG_UNSAVEDCHANGE_ISNULL(571065, "System config unsaved change can not be empty"), + SYS_CONFIG_CODE_FILE_ISNULL(574001,"The validate file is not exist"), //不存在校验使用的文件 + SYS_CONFIG_CODE_INVALID(574002,"The code is invalid"),//校验文件中的code与传递的值不符 + SYS_CONFIG_DB_PARAM_INVALID(574003,"The DB connect params is invalid"),//校验文件中的code与传递的值不符 + SYS_CONFIG_REDIS_PASSWORD_INVALID(574004,"The redis password is invalid"), + SYS_CONFIG_REDIS_PASSWORD_REQUIRED(574005,"The redis password is required"), + SYS_CONFIG_REDIS_PARAM_INVALID(574006,"The redis params is invalid"), + SYS_CONFIG_DB_URL_ISNULL(574007,"The DB host is null"), + SYS_CONFIG_DB_USERNAME_ISNULL(574008,"The DB username is null"), + SYS_CONFIG_DB_PASSWORD_ISNULL(574009,"The DB password is null"), + SYS_CONFIG_REDIS_HOST_ISNULL(574010,"The redis host is null"), + SYS_CONFIG_REDIS_PORT_ISNULL(574011,"The redis host is null"), + SYS_CONFIG_HAD_CONFIG(574012,"Someone has started to configure the system"), + SYS_CONFIG_SESSION_TIMEOUT_INVALID(573013,"Session timeout is not less than 15"), + SYS_CONFIGI_PROMEFEDEENABLED_NCORRECT(574014, "Prometheus federation enabled must be 0 or 1"), + SYS_CONFIGI_ASSETPINGFROM_NCORRECT(574015, "Asset ping from must be 1 or 2"), + + SYS_ROLE_ID_ISNULL(581000, "Role id is required"), + SYS_ROLE_ISNULL(586001, "Role is not exsits"), + SYS_ROLE_NAME_ISNULL(581002, "Role name is required"), + SYS_ROLE_REMARK_ISNULL(581003, "Role remark is required"), + SYS_ROLE_NAME_DUPLICATE(582004, "Role name duplicate"), + SYS_ROLE_MENUID_ISNULL(581005, "Role related menu id is required"), + SYS_ROLE_NAME_CANNOT_MODIFY(587006, "The name of the built-in role cannot be modified"), + SYS_ROLE_CANNOT_DELETE(587007, "Built-in roles cannot be deleted"), + + + LINK_ID_ISNULL(581001,"link id can not be null"), + LINK_NAME_ISNULL(581002,"link name can not be null"), + LINK_URL_ISNULL(581003,"link url can not be null"), + LINK_PREV_ISNULL(581004,"link prev can not be null"), + LINK_NEXT_ISNULL(581005,"link next can not be null"), + LINK_BUILDIN_CAN_NOT_REMOVE(587006,"This link is built-in and cannot be deleted"), + LINK_WEIGHT_PARAM_INVALID(587007,"link weight param is invalid"), + + SNMP_CREDENTIAL_ID_ISNULL(591001,"Snmp credential id can not be null"), + SNMP_CREDENTIAL_TYPE_ISNULL(591002,"Snmp credential type can not be null"), + SNMP_CREDENTIAL_REMARK_ISNULL(591003,"Snmp credential remark can not be null"), + SNMP_CREDENTIAL_CONFIG_ISNULL(591004,"Snmp credential config can not be null"), + SNMP_CREDENTIAL_NAME_ISNULL(591005,"Snmp credential name can not be null"), + SNMP_CREDENTIAL_PORT_ISNULL(591006,"Snmp credential port can not be null"), + SNMP_CREDENTIAL_NOT_FOUND(596007,"Snmp credential not found"), + SNMP_CREDENTIAL_NAME_DUPLICATE(596008,"Snmp credential name duplicate"), + SNMP_CREDENTIAL_ASSETS_EXISTS(596009,"These Snmp credential contain assets and cannot be deleted"), + /** + * webshell相关 + */ + TERMINAL_PARAM_ISNULL(611000, "Terminal param can not be null"), + TERMINAL_UUID_ISNULL(611001, "Terminal uuid can not be null"), + TERMINAL_PATH_ISNULL(611002, "Terminal path can not be null"), + TERMINAL_FILE_ISNULL(611003, "Terminal upload file can not be null"), + TERMINAL_ISNULL(611004, "Error,Terminal is null"), + TERMINAL_TELNET_TRANSFER(610005,"Telnet does not allow upload and download"), + TERMINAL_QUERYSIZE_INVALIDED(613006, "Terminal query size cannot be less than 1"), + + /** + * agent相关 + */ + AGENT_INSTALL_PARAM_MISS(711000,"Parameter of this API is missed"), + + /** + * stat相关 + */ + DIMENSION_IS_NULL(811001,"dimension param can not be null"), + SYSAPIKEY_NAME_ISNULL(811002,"sys api key name can not be empty"), + SYSAPIKEY_ROLEID_ISNULL(811003,"sys api key role id can not be empty"), + SYSAPIKEY_ID_ISNULL(811004,"sys api key id can not be empty"), + SYSAPIKEY_NAME_DUPLICATE(811005,"sys api key name is duplicate"), + /** + * 导入相关 + */ + IMPORT_EXCELFILE_TYPE(900, "Only support import XLS or XLSX file"), + IMPORT_EXCELFILE_PARSE_ERROR(901, "Import file resolution failed"), + IMPORT_EXCELFILE_HEADER_TEMPLATE_ERROR(902,"The header row of the excel import template is inconsistent with the system template"), + + NOT_NULL_ERROR(990, "not null error"), //not null错误 + NOT_NUMBER_ERROR(991, "not number error"), //not number错误 + /** + * 错误的时间格式 + */ + DateFormatWrong(40090018,"Incorrect Date Format"), + + /** + * License 相关 + */ + LICENSE_FILE_IS_NULL(711001, "license file can not be null"), + LICENSE_FILE_IS_EMPTY(716001, "The license file does not exist"), LICENSE_FILE_INVALID(715001, "Invalid license"), + LICENSE_PARAM_IS_NULL(711002, "license parameter is null"), + LICENSE_TOKEN_INVALID(715002, "Invalid license,token error"), + LICENSE_MAXIMUMASSETS_INVALID(715003, "The number of assets exceeds the maximumAssets"), + LICENSE_VERSION_INVALID(715004, "The version is not valid"), + + ERROR(999, "error"); //通用错误/未知错误 + + + + private RCode(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + + private Integer code; + private String msg; + + public Integer getCode() { + return code; + } + + public String getMsg() { + return msg; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/RSAUtils.java b/cn-admin/src/main/java/net/geedge/common/utils/RSAUtils.java new file mode 100644 index 0000000..affe927 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/RSAUtils.java @@ -0,0 +1,4 @@ +package net.geedge.common.utils; +public abstract class RSAUtils { + +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/utils/RedisKeys.java b/cn-admin/src/main/java/net/geedge/common/utils/RedisKeys.java new file mode 100644 index 0000000..400c5fd --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/RedisKeys.java @@ -0,0 +1,22 @@ +/** + + * + + * + + */ + +package net.geedge.common.utils; + +/** + * Redis所有Keys + * + + */ +public class RedisKeys { + + public static String getSysConfigKey(String key){ + return "sys:config:" + key; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/RedisUtils.java b/cn-admin/src/main/java/net/geedge/common/utils/RedisUtils.java new file mode 100644 index 0000000..91b310b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/RedisUtils.java @@ -0,0 +1,81 @@ +package net.geedge.common.utils; + +import java.util.concurrent.TimeUnit; + +import javax.annotation.Resource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; + +import com.alibaba.fastjson.JSON; + +@Component +public class RedisUtils { + @Autowired + private RedisTemplate<String, ?> redisTemplate; + @Resource(name="redisTemplate") + private ValueOperations<String, String> valueOperations; + /** 默认过期时长,单位:秒 */ + public final static long DEFAULT_EXPIRE = 60 * 60 * 24; + /** 不设置过期时长 */ + public final static long NOT_EXPIRE = -1; + + public void set(String key, Object value, long expire){ + valueOperations.set(key, toJson(value)); + if(expire != NOT_EXPIRE){ + redisTemplate.expire(key, expire, TimeUnit.SECONDS); + } + } + + public void set(String key, Object value){ + set(key, value, DEFAULT_EXPIRE); + } + + public <T> T get(String key, Class<T> clazz, long expire) { + String value = valueOperations.get(key); + if(expire != NOT_EXPIRE){ + redisTemplate.expire(key, expire, TimeUnit.SECONDS); + } + return value == null ? null : fromJson(value, clazz); + } + + public <T> T get(String key, Class<T> clazz) { + return get(key, clazz, NOT_EXPIRE); + } + + public String get(String key, long expire) { + String value = valueOperations.get(key); + if(expire != NOT_EXPIRE){ + redisTemplate.expire(key, expire, TimeUnit.SECONDS); + } + return value; + } + + public String get(String key) { + return get(key, NOT_EXPIRE); + } + + public void delete(String key) { + redisTemplate.delete(key); + } + + /** + * Object转成JSON数据 + */ + private String toJson(Object object){ + if(object instanceof Integer || object instanceof Long || object instanceof Float || + object instanceof Double || object instanceof Boolean || object instanceof String){ + return String.valueOf(object); + } + return JSON.toJSONString(object); + } + + /** + * JSON数据,转成Object + */ + private <T> T fromJson(String json, Class<T> clazz){ + return JSON.parseObject(json, clazz); + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/ResponseUtil.java b/cn-admin/src/main/java/net/geedge/common/utils/ResponseUtil.java new file mode 100644 index 0000000..bc807ec --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/ResponseUtil.java @@ -0,0 +1,52 @@ +package net.geedge.common.utils; + +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.util.ReflectUtil; +import org.springframework.http.MediaType; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; + +public class ResponseUtil { + + /** + * response 响应文件 + * @param response + * @param file + * @throws IORuntimeException + * @throws IOException + */ + public static void downloadFile(HttpServletResponse response, File file) throws IORuntimeException, IOException { + response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString()); + String fileName = Tool.URLUtil.encode(file.getName(), Tool.CharsetUtil.UTF_8); +// response.addHeader("Content-Disposition", "attachment; filename=" + fileName); +// response.addHeader("Content-Length", "" + file.length()); +// response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + ReflectUtil.invoke(response, "addHeader", "Content-Disposition", "attachment; filename=" + fileName); + ReflectUtil.invoke(response, "addHeader", "Content-Length", "" + file.length()); + ReflectUtil.invoke(response, "setHeader", "Access-Control-Expose-Headers", "Content-Disposition"); + Tool.FileUtil.writeToStream(file, response.getOutputStream()); + } + + /** + * reponse 下载 byte数据 + * @param response + * @param filename + * @param data + * @throws IORuntimeException + * @throws IOException + */ + public static void downloadFile(HttpServletResponse response, String filename, byte[] data) + throws IORuntimeException, IOException { + response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString()); + String fileName = Tool.URLUtil.encode(filename, Tool.CharsetUtil.UTF_8); +// response.addHeader("Content-Disposition", "attachment; filename=" + fileName); +// response.addHeader("Content-Length", "" + data.length); +// response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + ReflectUtil.invoke(response, "addHeader", "Content-Disposition", "attachment; filename=" + fileName); + ReflectUtil.invoke(response, "addHeader", "Content-Length", "" + data.length); + ReflectUtil.invoke(response, "setHeader", "Access-Control-Expose-Headers", "Content-Disposition"); + Tool.IoUtil.write(response.getOutputStream(), false, data); + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/SQLUtils.java b/cn-admin/src/main/java/net/geedge/common/utils/SQLUtils.java new file mode 100644 index 0000000..26dc52a --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/SQLUtils.java @@ -0,0 +1,102 @@ +package net.geedge.common.utils; + +import net.geedge.common.utils.SqlHelper.KeywordsType; + +import java.util.Map; + +public abstract class SQLUtils { + protected Map<KeywordsType, String> keywords; + + + /** + * @Description 创建表 + * @Author rui + * @Date 2019/7/31 + * @Param tableName:表名 fields:字段及其字段约束 字段名--字段约束 + * @Return + * @Exception + */ + public abstract String createTable(String tableName, Map<String,String> fields); + + /** + * @Description 根据表名查询表是否存在数据库 + * @Author rui + * @Date 2019/7/31 + * @Param tableName:表名 + * @Return + * @Exception + */ + public abstract String queryTables(String tableName); + + /** + * @Description 添加索引 + * @Author rui + * @Date 2019/7/31 + * @Param tableName:表名 indexs:索引名称及要添加索引的字段名称数组 + * @Return + * @Exception + */ + public abstract String addIndexs(String tableName,Map<String,String[]> indexs); + + /** + * @Description 删除索引 + * @Author rui + * @Date 2019/7/31 + * @Param tableName:表名 indexNames :索引名称数组 + * @Return + * @Exception + */ + public abstract String delIndexs(String tableName,String ... indexNames); + + /** + * @Description 删除表 + * @Author rui + * @Date 2019/7/31 + * @Param tableName:表名 + * @Return + * @Exception + */ + public abstract String dropTable(String tableName); + + /** + * @Description 添加表字段 + * @Author rui + * @Date 2019/7/31 + * @Param tableName:表名 fields:字段及其字段约束 字段名--字段约束 + * @Return + * @Exception + */ + public abstract String addFields(String tableName,Map<String,String> fields); + + /** + * @Description 删除表字段 + * @Author rui + * @Date 2019/7/31 + * @Param tableName:表名 fields:字段名称数组 + * @Return + * @Exception + */ + public abstract String delFields(String tableName,String ... fields); + + /** + * @Description 修改字段类型及长度 + * @Author rui + * @Date 2019/7/31 + * @Param tableName:表名 fields:字段及其字段约束 字段名--字段约束 + * @Return + * @Exception + */ + public abstract String modifyFields(String tableName,Map<String,String> fields); + + /** + * @Description 生成字段约束 + * @Author rui + * @Date 2019/7/31 + * @Param key :字段的类型 dataLenth 字段长度, + *@Param decimal类型默认及最大长度65 整数类型 mysql默认及最大长度20 postgresql默认及最大64 oracle默认及最大38 + * @Param limit 只对decimal类型生效,默认2 + * @Return + * @Exception + */ + public abstract String getRestrict(KeywordsType key, Integer dataLenth, Integer limit); +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/SftpAuthKeyUserInfo.java b/cn-admin/src/main/java/net/geedge/common/utils/SftpAuthKeyUserInfo.java new file mode 100644 index 0000000..86a0631 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/SftpAuthKeyUserInfo.java @@ -0,0 +1,48 @@ +package net.geedge.common.utils; + +import com.jcraft.jsch.UserInfo; + +/** + * 口令所需 + * sftp登录时为sshkey时,要执行密钥文件并输入口令,当前没有在使用 + */ +public class SftpAuthKeyUserInfo implements UserInfo { + /** + * ssh private key passphrase + */ + private String passphrase; + + public SftpAuthKeyUserInfo (String passphrase) { + this.passphrase = passphrase; + } + + @Override + public String getPassphrase() { + return passphrase; + } + + @Override + public String getPassword() { + return null; + } + + @Override + public boolean promptPassphrase(String s) { + return true; + } + + @Override + public boolean promptPassword(String s) { + return false; + } + + @Override + public boolean promptYesNo(String s) { + return true; + } + + @Override + public void showMessage(String message) { +// log.info ("SSH Message:{}", message); + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/utils/SftpUtils.java b/cn-admin/src/main/java/net/geedge/common/utils/SftpUtils.java new file mode 100644 index 0000000..ebd5653 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/SftpUtils.java @@ -0,0 +1,240 @@ +/* +package net.geedge.common.utils; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.log.Log; +import com.jcraft.jsch.*; +import net.geedge.common.exception.NZException; +import org.apache.commons.io.IOUtils; + +import java.io.*; +import java.util.Properties; + +*/ +/** + * 1. sftp传输文件 + * 2. 执行命令 + *//* + +public class SftpUtils { + + private static Log logger = Log.get(); + + private ChannelSftp sftp; + + // session 信息 + private Session session; + + // 连接超时时间 + private static Integer connectTimeOut = 5000; + + + */ +/** + * 登陆 + * + * @param server ip + * @param port port + * @param username username + * @param authType 1 密码 2 密钥文件 + * @param password 密码 + * @param privateKey 密钥文件 + * @throws Exception + *//* + + public void loginIn(String server, Integer port, String username, Integer authType, String pin, String privateKey, String keyPassword) throws NZException { + OutputStream out = null; + File file = null; + try { + JSch jsch = new JSch(); + + session = jsch.getSession(username, server, port); + + // 密码登录 + if (Constant.AUTH_PASSWORD.equals(authType)) { + session.setPassword(pin); + } else if (Constant.AUTH_CERTIFICATE.equals(authType)) { + + // 私钥文件登录 + file = new File("privateKey"); + out = new FileOutputStream(file); + IoUtil.write(out,false,privateKey.getBytes()); + if (StringUtils.isNotEmpty(keyPassword)) { + jsch.addIdentity(file.getAbsolutePath(), keyPassword); + } else { + jsch.addIdentity(file.getAbsolutePath()); + } + session.setUserInfo(new SftpAuthKeyUserInfo("")); + } else { + throw new NZException("account auth type not found."); + } + + Properties sshConfig = new Properties(); + sshConfig.put("StrictHostKeyChecking", "no"); + sshConfig.put("userauth.gssapi-with-mic", "no"); + session.setConfig(sshConfig); + + session.connect(connectTimeOut); + } catch (JSchException e) { + throw new NZException("user login SFTP server occur exception:" + e); + } catch (FileNotFoundException e) { + throw new NZException("user login SFTP server occur exception:" + e); + } finally { + if (out != null) { + IOUtils.closeQuietly(out); + } + if (file != null && file.exists()) { + file.delete(); + } + } + } + + */ +/** + * 上传到sftp + * + * @param targetPath 目标服务器安装目录 + * @param path 文件所在web服务地址 + * @param fileName 文件名称 + * @param shellName 脚本名称 + * @throws Exception + *//* + + public void upload(String targetPath, String path, String fileName, String shellName) throws NZException, JSchException { + // sftp通道 + Channel channel = session.openChannel("sftp"); + channel.connect(connectTimeOut); + File file = null; + sftp = (ChannelSftp) channel; + InputStream in = null; + try { + // node exporter 文件 + file = new File(path + File.separator + fileName); + in = new FileInputStream(file); + + // 上传文件 + try { + sftp.cd(targetPath); + } catch (SftpException e) { + logger.warn("directory is not exist"); + // 创建文件夹 并进入 + createDir(targetPath); + sftp.cd(targetPath); + } + // 放进sftp中进行传输 + sftp.put(in, file.getName()); + + // 脚本文件 + file = new File(path + File.separator + shellName); + in = new FileInputStream(file); + + // 放进sftp中进行传输 + sftp.put(in, file.getName()); + } catch (FileNotFoundException | SftpException e) { + // 文件上传失败 + logger.error("build node exporter upload faild {}", e); + // 抛出 controller 处理 + throw new NZException("build node exporter upload faild"); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + logger.error("inputstream close error"); + } + } + } + } + + */ +/** + * 执行命令 + * + * @param cmd + *//* + + public void exec(String cmd) { + try { + // 执行命令通道 + Channel channel = session.openChannel("exec"); + ((ChannelExec) channel).setCommand(cmd); + channel.connect(connectTimeOut); + } catch (JSchException e) { + // 执行默认启动脚本失败 + logger.error("exec init node exporter shell faild"); + } + } + + */ +/** + * 退出登陆 + *//* + + public void logout() { + if (sftp != null) { + if (sftp.isConnected()) { + sftp.disconnect(); + } + } + if (session != null) { + if (session.isConnected()) { + session.disconnect(); + } + } + } + + */ +/** + * 创建文件目录 + *//* + + private void createDir(String createpath) { + try { + if (isDirExist(createpath)) { + sftp.cd(createpath); + return; + } + String pathArry[] = createpath.split("/"); + StringBuffer filePath = new StringBuffer("/"); + for (String path : pathArry) { + if (path.equals("")) { + continue; + } + filePath.append(path + "/"); + if (isDirExist(filePath.toString())) { + sftp.cd(filePath.toString()); + } else { + // 建立目录 + sftp.mkdir(filePath.toString()); + // 进入并设置为当前目录 + sftp.cd(filePath.toString()); + } + } + sftp.cd(createpath); + } catch (SftpException e) { + logger.error("创建目标目录失败,目标路径为" + createpath,e); + } + } + + */ +/** + * 判断目录是否存在 + *//* + + public boolean isDirExist(String directory) { + boolean isDirExistFlag = false; + try { + SftpATTRS sftpATTRS = sftp.lstat(directory); + isDirExistFlag = true; + return sftpATTRS.isDir(); + } catch (SftpException e) { +// if (e.getMessage().toLowerCase().equals("no such file")) { + if (StrUtil.equals(e.getMessage().toLowerCase(),"no such file")) { + isDirExistFlag = false; + } + } + return isDirExistFlag; + } +} +*/ diff --git a/cn-admin/src/main/java/net/geedge/common/utils/SpringContextUtils.java b/cn-admin/src/main/java/net/geedge/common/utils/SpringContextUtils.java new file mode 100644 index 0000000..39c4e51 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/SpringContextUtils.java @@ -0,0 +1,49 @@ +/** + + * + + * + * + */ + +package net.geedge.common.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * Spring Context 工具类 + * + * @author Mark [email protected] + */ +@Component +public class SpringContextUtils implements ApplicationContextAware { + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + SpringContextUtils.applicationContext = applicationContext; + } + + public static Object getBean(String name) { + return applicationContext.getBean(name); + } + + public static <T> T getBean(Class<T> requiredType) { + return applicationContext.getBean(requiredType); + } + + public static <T> T getBean(String name, Class<T> requiredType) { + return applicationContext.getBean(name, requiredType); + } + + + + public static Class<? extends Object> getType(String name) { + return applicationContext.getType(name); + } + +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/KeywordsType.java b/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/KeywordsType.java new file mode 100644 index 0000000..9803443 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/KeywordsType.java @@ -0,0 +1,16 @@ +package net.geedge.common.utils.SqlHelper; + +public enum KeywordsType { + STRING("string"),//字符串类型 + NUMBER("number"),//普通数字类型 + DATE("date"),//时间戳类型 + PRIMARYKEY("primaryKey"),//主键类型,项目内主键统一为Long类型 + COMPUTE("compute");//计算类型 + + + private String key; + + KeywordsType(String key){ + this.key=key; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/MysqlHelper.java b/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/MysqlHelper.java new file mode 100644 index 0000000..9f68bbc --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/MysqlHelper.java @@ -0,0 +1,188 @@ +package net.geedge.common.utils.SqlHelper; + +import cn.hutool.log.Log; +import net.geedge.common.utils.SQLUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class MysqlHelper extends SQLUtils { + private Log log= Log.get(); + + public MysqlHelper(){ + keywords=new HashMap<KeywordsType, String>(); + + keywords.put(KeywordsType.COMPUTE,"decimal"); + + keywords.put(KeywordsType.NUMBER,"bigint"); + + keywords.put(KeywordsType.STRING,"varchar"); + + keywords.put(KeywordsType.DATE,"timestamp default current_timestamp"); + + keywords.put(KeywordsType.PRIMARYKEY,"bigint(20) primary key"); + + } + + @Override + public String createTable(String tableName, Map<String, String> fields) { + StringBuilder sb = new StringBuilder(); + sb.append("create table if not exists `"+tableName+"`("); + Set<Map.Entry<String, String>> entries = fields.entrySet(); + int i=0; + for(Map.Entry<String,String> entry:entries){ + String field=entry.getKey(); + String restrict=entry.getValue(); + sb.append("`"+field+"` "+restrict); + if(i!=entries.size()-1){ + sb.append(","); + } + i++; + } + sb.append(")"); + + log.debug("create table SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String queryTables(String tableName) { + StringBuilder sb = new StringBuilder(); + sb.append("SELECT t.table_name AS name,t.TABLE_COMMENT AS comments FROM information_schema.`TABLES` t WHERE t.TABLE_SCHEMA = (select database()) AND t.TABLE_NAME = "); + sb.append("'"+tableName+"'"); + sb.append(" ORDER BY t.TABLE_NAME"); + + log.debug("query tables SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String addIndexs(String tableName, Map<String, String[]> indexs) { + StringBuilder sb = new StringBuilder(); + sb.append("alter table `"+ tableName +"` "); + + Set<Map.Entry<String, String[]>> entries = indexs.entrySet(); + int i=0; + for(Map.Entry<String, String[]> entry:entries){ + String indexName=entry.getKey(); + String[] fieldNames=entry.getValue(); + sb.append("add index if not exists `"+indexName+"`("); + for(int j=0;j<fieldNames.length;j++){ + String fieldName=fieldNames[j]; + sb.append("`"+fieldName+"`"); + + if(j!=fieldNames.length-1){ + sb.append(","); + } + } + sb.append(")"); + if(i!=entries.size()-1){ + sb.append(","); + } + i++; + } + + log.debug("add index SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String delIndexs(String tableName, String... indexNames) { + StringBuilder sb = new StringBuilder(); + sb.append("alter table `"+ tableName +"` "); + for(int i=0;i<indexNames.length;i++){ + String indexName=indexNames[i]; + sb.append("drop index if exists `"+indexName+"`"); + if(i!=indexNames.length-1){ + sb.append(","); + } + } + log.debug("drop index SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String dropTable(String tableName) { + String sql=("drop table if exists `"+ tableName +"` "); + log.debug("drop table SQL--> "+sql); + return sql; + } + + @Override + public String addFields(String tableName, Map<String, String> fields) { + StringBuilder sb = new StringBuilder(); + sb.append("alter table `"+ tableName +"` "); + + Set<Map.Entry<String, String>> entries = fields.entrySet(); + int i=0; + for(Map.Entry<String, String> entry:entries){ + String fieldName=entry.getKey(); + String restrict=entry.getValue(); + sb.append("add column if not exists `"+fieldName+"`"+restrict); + if(i!=entries.size()-1){ + sb.append(","); + } + i++; + } + + log.debug("add fields SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String delFields(String tableName, String... fields) { + StringBuilder sb = new StringBuilder(); + sb.append("alter table `"+ tableName +"` "); + for(int i=0;i<fields.length;i++){ + String field=fields[i]; + sb.append("drop column if exists `"+field+"`"); + if(i!=fields.length-1){ + sb.append(","); + } + } + log.debug("drop fields SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String modifyFields(String tableName, Map<String, String> fields) { + StringBuilder sb = new StringBuilder(); + sb.append("alter table `"+ tableName +"` "); + + Set<Map.Entry<String, String>> entries = fields.entrySet(); + int i=0; + for(Map.Entry<String, String> entry:entries){ + String fieldName=entry.getKey(); + String restrict=entry.getValue(); + sb.append("modify column `"+fieldName+"` "+restrict); + if(i!=entries.size()-1){ + sb.append(","); + } + i++; + } + + log.debug("modify fields SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String getRestrict(KeywordsType key, Integer dataLenth, Integer limit) { + + if(key.equals(KeywordsType.PRIMARYKEY)||key.equals(KeywordsType.DATE)){ + return keywords.get(key); + }else if(key.equals(KeywordsType.COMPUTE)){ + dataLenth=(dataLenth==null||dataLenth>65||dataLenth<1)?65:dataLenth; + limit=(limit==null||limit<1)?2:limit; + return keywords.get(key)+"("+dataLenth+","+limit+")"; + }else if(key.equals(KeywordsType.NUMBER)){ + dataLenth=dataLenth>20||dataLenth<1?20:dataLenth; + return keywords.get(key)+"("+dataLenth+")"; + } else{ + dataLenth=dataLenth==null||dataLenth<1?255:dataLenth; + return keywords.get(key)+"("+dataLenth+")"; + } + } + + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/OracleHelper.java b/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/OracleHelper.java new file mode 100644 index 0000000..354b2a1 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/OracleHelper.java @@ -0,0 +1,178 @@ +package net.geedge.common.utils.SqlHelper; + +import cn.hutool.log.Log; +import net.geedge.common.utils.SQLUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * + * @author: rui + * @Date: 2019/7/31 + * @Description: oracle数据库大小写敏感,表名、表字段、索引名称等都需要大写或用双引号包裹 + * ps:使用双引号和没有双引号区别:不使用双引号,oracle会在执行时自动转为大写 + */ +public class OracleHelper extends SQLUtils { + private Log log= Log.get(); + + private final String QUOTE="\""; + + public OracleHelper(){ + keywords=new HashMap<KeywordsType, String>(); + + keywords.put(KeywordsType.COMPUTE,"DECIMAL"); + + keywords.put(KeywordsType.NUMBER,"NUMBER"); + + keywords.put(KeywordsType.STRING,"VARCHAR2"); + + keywords.put(KeywordsType.DATE,"TIMESTAMP DEFAULT CURRENT_TIMESTAMP"); + + keywords.put(KeywordsType.PRIMARYKEY,"NUMBER(20) PRIMARY KEY"); + + } + + @Override + public String createTable(String tableName, Map<String, String> fields) { + StringBuilder sb = new StringBuilder(); + sb.append("create table "+QUOTE+tableName+QUOTE+"("); + Set<Map.Entry<String, String>> entries = fields.entrySet(); + int i=0; + for(Map.Entry<String,String> entry:entries){ + String field=entry.getKey(); + String restrict=entry.getValue(); + sb.append(QUOTE+field+QUOTE+" "+restrict); + if(i!=entries.size()-1){ + sb.append(","); + } + i++; + } + sb.append(")"); + log.debug("create table SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String queryTables(String tableName) { + StringBuilder sb=new StringBuilder(); + sb.append("SELECT t.TABLE_NAME AS name,c.COMMENTS AS comments FROM user_tables t, user_tab_comments c WHERE t.table_name = c.table_name "); + sb.append("AND t.TABLE_NAME =upper('"+tableName+"') ORDER BY t.TABLE_NAME"); + + log.debug("query tables SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String addIndexs(String tableName, Map<String, String[]> indexs) { + StringBuilder sb=new StringBuilder(); + Set<Map.Entry<String, String[]>> entries = indexs.entrySet(); + sb.append("begin "); + for(Map.Entry<String, String[]> entry:entries){ + String indexName=entry.getKey(); + String[] fields=entry.getValue(); + sb.append("Execute immediate 'create index "+QUOTE+indexName+QUOTE +" on "+QUOTE+tableName+QUOTE+"("); + + for(int i=0;i<fields.length;i++){ + String field=fields[i]; + sb.append(QUOTE+field+QUOTE); + if(i<fields.length-1){ + sb.append(","); + } + } + sb.append(")';"); + } + sb.append(" end;"); + log.debug("add index SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String delIndexs(String tableName, String... indexNames) { + StringBuilder sb=new StringBuilder(); + sb.append("begin "); + for(int i=0;i<indexNames.length;i++){ + sb.append("Execute immediate 'drop index ");//多条语句一起使用mybatis执行时会报错ORA-00911: 无效字符,故采用这种拼接 + String indexName=indexNames[i]; + sb.append(QUOTE+indexName+QUOTE+"';"); + } + sb.append(" end;"); + log.debug("drop index SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String dropTable(String tableName) { + String sql=("drop table "+QUOTE+ tableName +QUOTE); + log.debug("drop table SQL--> "+sql); + return sql; + } + + @Override + public String addFields(String tableName, Map<String, String> fields) { + StringBuilder sb = new StringBuilder(); + sb.append("alter table "+ QUOTE+tableName +QUOTE); + + Set<Map.Entry<String, String>> entries = fields.entrySet(); + for(Map.Entry<String, String> entry:entries){ + String fieldName=entry.getKey(); + String restrict=entry.getValue(); + sb.append(" add ("+QUOTE+fieldName+QUOTE+" "+restrict+")"); + } + + log.debug("add fields SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String delFields(String tableName, String... fields) { + StringBuilder sb = new StringBuilder(); + sb.append("alter table "+QUOTE+ tableName +QUOTE +" drop("); + for(int i=0;i<fields.length;i++){ + String field=fields[i]; + sb.append(QUOTE+field+QUOTE); + if(i!=fields.length-1){ + sb.append(","); + } + } + sb.append(")"); + log.debug("drop fields SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String modifyFields(String tableName, Map<String, String> fields) { + StringBuilder sb=new StringBuilder(); + Set<Map.Entry<String, String>> entries = fields.entrySet(); + sb.append("begin "); + for(Map.Entry<String, String> entry:entries){ + sb.append("Execute immediate 'ALTER TABLE "+QUOTE+tableName+QUOTE); + String fieldName=entry.getKey(); + String restrict=entry.getValue(); + + sb.append(" modify("+QUOTE+fieldName+QUOTE+" "+restrict+")';"); + } + sb.append("end;"); + log.debug("modify fields SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String getRestrict(KeywordsType key, Integer dataLenth, Integer limit) { + if(key.equals(KeywordsType.PRIMARYKEY)||key.equals(KeywordsType.DATE)){ + return keywords.get(key); + }else if(key.equals(KeywordsType.COMPUTE)){ + dataLenth=(dataLenth==null||dataLenth>65||dataLenth<1)?65:dataLenth; + limit=(limit==null||limit<1)?2:limit; + return keywords.get(key)+"("+dataLenth+","+limit+")"; + }else if(key.equals(KeywordsType.NUMBER)){ + dataLenth=(dataLenth==null||dataLenth>38||dataLenth<1)?38:dataLenth; + return keywords.get(key)+"("+dataLenth+")"; + }else{ + dataLenth=dataLenth==null||dataLenth<1?255:dataLenth; + return keywords.get(key)+"("+dataLenth+")"; + } + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/PostgresqlHelper.java b/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/PostgresqlHelper.java new file mode 100644 index 0000000..093a156 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/SqlHelper/PostgresqlHelper.java @@ -0,0 +1,186 @@ +package net.geedge.common.utils.SqlHelper; + +import cn.hutool.log.Log; +import net.geedge.common.utils.SQLUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class PostgresqlHelper extends SQLUtils { + private Log log= Log.get(); + + private final String QUOTE="\""; + + public PostgresqlHelper(){ + keywords=new HashMap<KeywordsType, String>(); + + keywords.put(KeywordsType.COMPUTE,"decimal"); + + keywords.put(KeywordsType.NUMBER,"int8"); + + keywords.put(KeywordsType.STRING,"varchar"); + + keywords.put(KeywordsType.DATE,"timestamp default current_timestamp"); + + keywords.put(KeywordsType.PRIMARYKEY,"int8 primary key"); + + } + + @Override + public String createTable(String tableName, Map<String, String> fields) { + StringBuilder sb = new StringBuilder(); + sb.append("create table if not exists "+QUOTE+tableName+QUOTE+"("); + Set<Map.Entry<String, String>> entries = fields.entrySet(); + int i=0; + for(Map.Entry<String,String> entry:entries){ + String field=entry.getKey(); + String restrict=entry.getValue(); + sb.append(QUOTE+field+QUOTE+" "+restrict); + if(i!=entries.size()-1){ + sb.append(","); + } + i++; + } + sb.append(")"); + log.debug("create table SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String queryTables(String tableName) { + + StringBuilder sb=new StringBuilder(); + sb.append("select pgt.tablename as name,pgd.description as comments from pg_tables pgt join pg_class pgc on pgt.tablename=pgc.relname "); + sb.append("and pgt.schemaname='public' AND pgt.tablename ='" +tableName+"'"); + sb.append("left join pg_description pgd on pgd.objoid=pgc.oid and pgd.objsubid=0"); + + log.debug("query tables SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String addIndexs(String tableName, Map<String, String[]> indexs) { + StringBuilder sb=new StringBuilder(); + Set<Map.Entry<String, String[]>> entries = indexs.entrySet(); + for(Map.Entry<String, String[]> entry:entries){ + String indexName=entry.getKey(); + String[] fields=entry.getValue(); + sb.append("create index "+QUOTE+indexName+QUOTE +"on"+QUOTE+tableName+QUOTE+"("); + + for(int i=0;i<fields.length;i++){ + String field=fields[i]; + sb.append(QUOTE+field+QUOTE); + if(i<fields.length-1){ + sb.append(","); + } + } + sb.append(");"); + } + + log.debug("add index SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String delIndexs(String tableName, String... indexNames) { + StringBuilder sb=new StringBuilder(); + sb.append("drop index "); + for(int i=0;i<indexNames.length;i++){ + String indexName=indexNames[i]; + sb.append(QUOTE+indexName+QUOTE); + if(i<indexNames.length-1){ + sb.append(","); + } + } + log.debug("drop index SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String dropTable(String tableName) { + String sql=("drop table if exists "+QUOTE+ tableName +QUOTE); + log.debug("drop table SQL--> "+sql); + return sql; + } + + @Override + public String addFields(String tableName, Map<String, String> fields) { + StringBuilder sb = new StringBuilder(); + sb.append("alter table "+ QUOTE+tableName +QUOTE); + + Set<Map.Entry<String, String>> entries = fields.entrySet(); + int i=0; + for(Map.Entry<String, String> entry:entries){ + String fieldName=entry.getKey(); + String restrict=entry.getValue(); + sb.append(" add column "+QUOTE+fieldName+QUOTE+" "+restrict); + if(i!=entries.size()-1){ + sb.append(","); + } + i++; + } + + log.debug("add fields SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String delFields(String tableName, String... fields) { + StringBuilder sb = new StringBuilder(); + sb.append("alter table "+QUOTE+ tableName +QUOTE); + for(int i=0;i<fields.length;i++){ + String field=fields[i]; + sb.append(" drop column if exists "+QUOTE+field+QUOTE); + if(i!=fields.length-1){ + sb.append(","); + } + } + log.debug("drop fields SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String modifyFields(String tableName, Map<String, String> fields) { + StringBuilder sb=new StringBuilder(); + sb.append("ALTER TABLE "+QUOTE+tableName+QUOTE); + int i=0; + Set<Map.Entry<String, String>> entries = fields.entrySet(); + for(Map.Entry<String, String> entry:entries){ + String fieldName=entry.getKey(); + String restrict=entry.getValue(); + + sb.append("alter column "+QUOTE+fieldName+QUOTE+" type "+restrict +" using "+QUOTE+fieldName+QUOTE+"::"+restrict); + if(i<entries.size()-1){ + sb.append(","); + } + i++; + } + + log.debug("modify fields SQL--> "+sb.toString()); + return sb.toString(); + } + + @Override + public String getRestrict(KeywordsType key, Integer dataLenth, Integer limit) { + if(key.equals(KeywordsType.PRIMARYKEY)||key.equals(KeywordsType.DATE)){ + return keywords.get(key); + }else if(key.equals(KeywordsType.COMPUTE)){ + dataLenth=(dataLenth==null||dataLenth>65||dataLenth<1)?65:dataLenth; + limit=(limit==null||limit<1)?2:limit; + return keywords.get(key)+"("+dataLenth+","+limit+")"; + }else if(key.equals(KeywordsType.NUMBER)){ + if(dataLenth<=16){ + return "int2"; + }else if(dataLenth>16&&dataLenth<=32){ + return "int4"; + }else{ + return "int8"; + } + }else{ + dataLenth=dataLenth==null||dataLenth<1?255:dataLenth; + return keywords.get(key)+"("+dataLenth+")"; + } + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/TemplateUtil.java b/cn-admin/src/main/java/net/geedge/common/utils/TemplateUtil.java new file mode 100644 index 0000000..1410677 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/TemplateUtil.java @@ -0,0 +1,28 @@ +package net.geedge.common.utils; + +import freemarker.cache.StringTemplateLoader; +import freemarker.template.Configuration; +import freemarker.template.Template; + +import java.io.IOException; + +public class TemplateUtil { + + public static Template stringToTemplate(String templateStr,String templateKey) throws IOException { + + // 创建配置类 + Configuration configuration = new Configuration(Configuration.getVersion()); + //创建模板加载器 + StringTemplateLoader templateLoader = new StringTemplateLoader(); + // 存入模板 + templateLoader.putTemplate(templateKey, templateStr); //template = 虚拟名称, 用来当作获取静态文件的key + //加载模板加载器 + configuration.setTemplateLoader(templateLoader); + //得到模板 + Template template = configuration.getTemplate(templateKey, "utf-8"); + + return template; + + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/Tool.java b/cn-admin/src/main/java/net/geedge/common/utils/Tool.java new file mode 100644 index 0000000..3f87d1b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/Tool.java @@ -0,0 +1,1146 @@ +package net.geedge.common.utils; + +import java.awt.Graphics; +import java.awt.Robot; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.net.URLDecoder; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.time.LocalDateTime; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.util.Calendar; +import java.util.Collection; +import java.util.Iterator; +import java.util.Spliterator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; + +import cn.hutool.core.date.DateTime; + +public class Tool { + public static final Pattern REGEX_SPECIAL_DATE = Pattern.compile("(\\d{4}-\\d{1,2}-\\d{1,2}[T]\\d{1,2}:\\d{1,2}:\\d{1,2})(.\\d{1,10})(\\+\\d{1,2}:\\d{1,2})"); + /** + * 数据库操作工具类 + */ + public final static cn.hutool.db.DbUtil DbUtil = new cn.hutool.db.DbUtil(); + /** + * 安全相关工具类<br> + * 加密分为三种:<br> + * 1、对称加密(symmetric),例如:AES、DES等<br> + * 2、非对称加密(asymmetric),例如:RSA、DSA等<br> + * 3、摘要加密(digest),例如:MD5、SHA-1、SHA-256、HMAC等<br> + */ + public final static cn.hutool.crypto.SecureUtil SecureUtil = new cn.hutool.crypto.SecureUtil(); + /** + * 代理工具类 + */ + public final static cn.hutool.aop.ProxyUtil ProxyUtil = new cn.hutool.aop.ProxyUtil(); + /** + * 敏感词工具类 + */ + public final static cn.hutool.dfa.SensitiveUtil SensitiveUtil = new cn.hutool.dfa.SensitiveUtil(); + + /** + * 数据库元数据信息工具类 + * + * <p> + * 需要注意的是,此工具类在某些数据库(比如Oracle)下无效,此时需要手动在数据库配置中增加: + * <pre> + * remarks = true + * useInformationSchema = true + * </pre> + * + * @author looly + */ + public static class MetaUtil extends cn.hutool.db.meta.MetaUtil {} + /** + * 异常工具类 + * + * @author Looly + */ + public static class ExceptionUtil extends cn.hutool.core.exceptions.ExceptionUtil {} + /** + * 正则相关工具类<br> + * 常用正则请见 {@link cn.hutool.core.lang.Validator} + * + * @author xiaoleilu + */ + public static class ReUtil extends cn.hutool.core.util.ReUtil {} + /** + * SOAP相关工具类 + * + * @author looly + * @since 4.5.7 + */ + public static class SoapUtil extends cn.hutool.http.webservice.SoapUtil {} + /** + * 脚本工具类 + * + * @author Looly + */ + public static class ScriptUtil extends cn.hutool.script.ScriptUtil {} + /** + * 提供Unicode字符串和普通字符串之间的转换 + * + * @author 兜兜毛毛, looly + * @since 4.0.0 + */ + public static class UnicodeUtil extends cn.hutool.core.text.UnicodeUtil {} + /** + * 时间工具类 + * + * @author xiaoleilu + */ + public static class DateUtil extends cn.hutool.core.date.DateUtil { + /** + * 为了处理 2021-05-21T12:06:29.272986526+08:00 格式时间 + * @param utcString + * @return + */ + public static DateTime parseUTC(String utcString) { + if(StrUtil.isBlank(utcString)) { + return null; + } + if(utcString.length() > 29) { + Matcher matcher = REGEX_SPECIAL_DATE.matcher(utcString); + if(matcher.matches()) { + utcString = Tool.StrUtil.concat(true, matcher.group(1),matcher.group(3)); + } + } + return cn.hutool.core.date.DateUtil.parseUTC(utcString); + } + + } + /** + * EC密钥参数相关工具类封装 + * + * @author looly + * @since 5.4.3 + */ + public static class ECKeyUtil extends cn.hutool.crypto.ECKeyUtil {} + /** + * 枚举工具类 + * + * @author looly + * @since 3.3.0 + */ + public static class EnumUtil extends cn.hutool.core.util.EnumUtil {} + /** + * 数学相关方法工具类<br> + * 此工具类与{@link cn.hutool.core.util.NumberUtil}属于一类工具,NumberUtil偏向于简单数学计算的封装,MathUtil偏向复杂数学计算 + * + * @author looly + * @since 4.0.7 + */ + public static class MathUtil extends cn.hutool.core.math.MathUtil {} + /** + * Sax方式读取Excel相关工具类 + * + * @author looly + */ + public static class ExcelSaxUtil extends cn.hutool.poi.excel.sax.ExcelSaxUtil {} + /** + * 数字工具类<br> + * 对于精确值计算应该使用 {@link BigDecimal}<br> + * JDK7中<strong>BigDecimal(double val)</strong>构造方法的结果有一定的不可预知性,例如: + * + * <pre> + * new BigDecimal(0.1) + * </pre> + * <p> + * 表示的不是<strong>0.1</strong>而是<strong>0.1000000000000000055511151231257827021181583404541015625</strong> + * + * <p> + * 这是因为0.1无法准确的表示为double。因此应该使用<strong>new BigDecimal(String)</strong>。 + * </p> + * 相关介绍: + * <ul> + * <li>http://www.oschina.net/code/snippet_563112_25237</li> + * <li>https://github.com/venusdrogon/feilong-core/wiki/one-jdk7-bug-thinking</li> + * </ul> + * + * @author Looly + */ + public static class NumberUtil extends cn.hutool.core.util.NumberUtil {} + /** + * Jsch工具类<br> + * Jsch是Java Secure Channel的缩写。JSch是一个SSH2的纯Java实现。<br> + * 它允许你连接到一个SSH服务器,并且可以使用端口转发,X11转发,文件传输等。<br> + * + * @author Looly + * @since 4.0.0 + */ + public static class JschUtil extends cn.hutool.extra.ssh.JschUtil {} + /** + * 线程池工具 + * + * @author luxiaolei + */ + public static class ThreadUtil extends cn.hutool.core.thread.ThreadUtil {} + /** + * Oshi库封装的工具类,通过此工具类,可获取系统、硬件相关信息 + * + * <pre> + * 1、系统信息 + * 2、硬件信息 + * </pre> + * + * 相关内容见:https://github.com/oshi/oshi + * + * @author Looly + * @since 4.6.4 + */ + public static class OshiUtil extends cn.hutool.system.oshi.OshiUtil {} + /** + * URL(Uniform Resource Locator)统一资源定位符相关工具类 + * + * <p> + * 统一资源定位符,描述了一台特定服务器上某资源的特定位置。 + * </p> + * URL组成: + * <pre> + * 协议://主机名[:端口]/ 路径/[:参数] [?查询]#Fragment + * protocol :// hostname[:port] / path / [:parameters][?query]#fragment + * </pre> + * + * @author xiaoleilu + */ + public static class URLUtil extends cn.hutool.core.util.URLUtil {} + /** + * ID生成器工具类,此工具类中主要封装: + * + * <pre> + * 1. 唯一性ID生成器:UUID、ObjectId(MongoDB)、Snowflake + * </pre> + * + * <p> + * ID相关文章见:http://calvin1978.blogcn.com/articles/uuid.html + * + * @author looly + * @since 4.1.13 + */ + public static class IdUtil extends cn.hutool.core.util.IdUtil {} + /** + * Http请求工具类 + * + * @author xiaoleilu + */ + public static class HttpUtil extends cn.hutool.http.HttpUtil {} + /** + * 桌面相关工具(平台相关)<br> + * Desktop 类允许 Java 应用程序启动已在本机桌面上注册的关联应用程序,以处理 URI 或文件。 + * + * @author looly + * @since 4.5.7 + */ + public static class DesktopUtil extends cn.hutool.core.swing.DesktopUtil {} + /** + * 图片处理工具类:<br> + * 功能:缩放图像、切割图像、旋转、图像类型转换、彩色转黑白、文字水印、图片水印等 <br> + * 参考:http://blog.csdn.net/zhangzhikaixinya/article/details/8459400 + * + * @author Looly + */ + public static class ImgUtil extends cn.hutool.core.img.ImgUtil {} + /** + * 分页工具类 + * + * @author xiaoleilu + */ + public static class PageUtil extends cn.hutool.core.util.PageUtil {} + /** + * HTML工具类 + * + * <p> + * 比如我们在使用爬虫爬取HTML页面后,需要对返回页面的HTML内容做一定处理,<br> + * 比如去掉指定标签(例如广告栏等)、去除JS、去掉样式等等,这些操作都可以使用此工具类完成。 + * + * @author xiaoleilu + * + */ + public static class HtmlUtil extends cn.hutool.http.HtmlUtil {} + /** + * PEM(Privacy Enhanced Mail)格式相关工具类。(基于Bouncy Castle) + * + * <p> + * PEM一般为文本格式,以 -----BEGIN... 开头,以 -----END... 结尾,中间的内容是 BASE64 编码。 + * <p> + * 这种格式可以保存证书和私钥,有时我们也把PEM格式的私钥的后缀改为 .key 以区别证书与私钥。 + * + * @author looly + * @since 5.1.6 + */ + public static class PemUtil extends cn.hutool.crypto.PemUtil {} + /** + * 分词工具类 + * + * @author looly + * @since 4.3.3 + */ + public static class TokenizerUtil extends cn.hutool.extra.tokenizer.TokenizerUtil {} + /** + * {@link org.apache.poi.ss.extractor.ExcelExtractor}工具封装 + * + * @author looly + * @since 5.4.4 + */ + public static class ExcelExtractorUtil extends cn.hutool.poi.excel.ExcelExtractorUtil {} + /** + * 邮件工具类,基于javax.mail封装 + * + * @author looly + * @since 3.1.2 + */ + public static class MailUtil extends cn.hutool.extra.mail.MailUtil {} + /** + * NIO中Path对象操作封装 + * + * @author looly + * @since 5.4.1 + */ + public static class PathUtil extends cn.hutool.core.io.file.PathUtil {} + /** + * 邮件内部工具类 + * @author looly + * @since 3.2.3 + */ + public static class InternalMailUtil extends cn.hutool.extra.mail.InternalMailUtil {} + /** + * 定时任务工具类<br> + * 此工具持有一个全局{@link cn.hutool.cron.Scheduler},所有定时任务在同一个调度器中执行<br> + * {@link #setMatchSecond(boolean)} 方法用于定义是否使用秒匹配模式,如果为true,则定时任务表达式中的第一位为秒,否则为分,默认是分 + * + * @author xiaoleilu + * + */ + public static class CronUtil extends cn.hutool.cron.CronUtil {} + /** + * Java的System类封装工具类。<br> + * 参考:http://blog.csdn.net/zhongweijian/article/details/7619383 + * + * @author Looly + */ + public static class SystemUtil extends cn.hutool.system.SystemUtil {} + /** + * 压缩工具类<br> + * 基于commons-compress的压缩解压封装 + * + * @author looly + * @since 5.5.0 + */ + public static class CompressUtil extends cn.hutool.extra.compress.CompressUtil {} + /** + * {@link ClassLoader}工具类 + * + * @author Looly + * @since 3.0.9 + */ + public static class ClassLoaderUtil extends cn.hutool.core.util.ClassLoaderUtil {} + /** + * {@link Spliterator}相关工具类 + * + * @author looly + * @since 5.4.3 + */ + public static class SpliteratorUtil extends cn.hutool.core.collection.SpliteratorUtil {} + /** + * 监听工具类<br> + * 主要负责文件监听器的快捷创建 + * + * @author Looly + * @since 3.1.0 + */ + public static class WatchUtil extends cn.hutool.core.io.watch.WatchUtil {} + /** + * Excel样式工具类 + * + * @author looly + * @since 4.0.0 + */ + public static class StyleUtil extends cn.hutool.poi.excel.style.StyleUtil {} + /** + * 系统剪贴板工具类 + * + * @author looly + * @since 3.2.0 + */ + public static class ClipboardUtil extends cn.hutool.core.swing.clipboard.ClipboardUtil {} + /** + * 文件类型判断工具类 + * + * <p>此工具根据文件的前几位bytes猜测文件类型,对于文本、zip判断不准确,对于视频、图片类型判断准确</p> + * + * <p>需要注意的是,xlsx、docx等Office2007格式,全部识别为zip,因为新版采用了OpenXML格式,这些格式本质上是XML文件打包为zip</p> + * + * @author Looly + */ + public static class FileTypeUtil extends cn.hutool.core.io.FileTypeUtil {} + /** + * 引用工具类,主要针对{@link Reference} 工具化封装<br> + * 主要封装包括: + * <pre> + * 1. {@link SoftReference} 软引用,在GC报告内存不足时会被GC回收 + * 2. {@link WeakReference} 弱引用,在GC时发现弱引用会回收其对象 + * 3. {@link PhantomReference} 虚引用,在GC时发现虚引用对象,会将{@link PhantomReference}插入{@link ReferenceQueue}。 此时对象未被真正回收,要等到{@link ReferenceQueue}被真正处理后才会被回收。 + * </pre> + * + * @author looly + * @since 3.1.2 + */ + public static class ReferenceUtil extends cn.hutool.core.util.ReferenceUtil {} + /** + * 布隆过滤器工具 + * + * @author looly + * @since 4.1.5 + */ + public static class BloomFilterUtil extends cn.hutool.bloomfilter.BloomFilterUtil {} + /** + * 修饰符工具类 + * + * @author looly + * @since 4.0.5 + */ + public static class ModifierUtil extends cn.hutool.core.util.ModifierUtil {} + /** + * 集合的stream操作封装 + * + * @author [email protected] + * @since 5.5.2 + */ + public static class CollStreamUtil extends cn.hutool.core.collection.CollStreamUtil {} + /** + * 摘要算法工具类 + * + * @author Looly + */ + public static class DigestUtil extends cn.hutool.crypto.digest.DigestUtil {} + /** + * 对象工具类,包括判空、克隆、序列化等操作 + * + * @author Looly + */ + public static class ObjectUtil extends cn.hutool.core.util.ObjectUtil {} + /** + * Hash算法大全<br> + * 推荐使用FNV1算法 + * + * @author Goodzzp, Looly + */ + public static class HashUtil extends cn.hutool.core.util.HashUtil {} + /** + * Bouncy Castle相关工具类封装 + * + * @author looly + * @since 4.5.0 + */ + public static class BCUtil extends cn.hutool.crypto.BCUtil {} + /** + * 针对 {@link Type} 的工具类封装<br> + * 最主要功能包括: + * + * <pre> + * 1. 获取方法的参数和返回值类型(包括Type和Class) + * 2. 获取泛型参数类型(包括对象的泛型参数或集合元素的泛型类型) + * </pre> + * + * @author Looly + * @since 3.0.8 + */ + public static class TypeUtil extends cn.hutool.core.util.TypeUtil {} + /** + * Excel文件工具类 + * + * @author looly + * @since 4.2.1 + */ + public static class ExcelFileUtil extends cn.hutool.poi.excel.ExcelFileUtil {} + /** + * NIO工具类 + * + * @since 5.4.0 + */ + public static class NioUtil extends cn.hutool.socket.nio.NioUtil {} + /** + * 类工具类 <br> + * + * @author xiaoleilu + */ + public static class ClassUtil extends cn.hutool.core.util.ClassUtil {} + /** + * 针对{@link Calendar} 对象封装工具类 + * + * @author looly + * @since 5.3.0 + */ + public static class CalendarUtil extends cn.hutool.core.date.CalendarUtil {} + /** + * 网络相关工具 + * + * @author xiaoleilu + */ + public static class NetUtil extends cn.hutool.core.net.NetUtil {} + /** + * 源码编译工具类,主要封装{@link JavaCompiler} 相关功能 + * + * @author looly + * @since 5.5.2 + */ + public static class CompilerUtil extends cn.hutool.core.compiler.CompilerUtil {} + /** + * 锁相关工具 + * + * @author looly + * @since 5.2.5 + */ + public static class LockUtil extends cn.hutool.core.thread.lock.LockUtil {} + /** + * 文件名相关工具类 + * + * @author looly + * @since 5.4.1 + */ + public static class FileNameUtil extends cn.hutool.core.io.file.FileNameUtil {} + /** + * SM国密算法工具类<br> + * 此工具类依赖org.bouncycastle:bcpkix-jdk15on + * + * @author looly + * @since 4.3.2 + */ + public static class SmUtil extends cn.hutool.crypto.SmUtil {} + /** + * Props工具类<br> + * 提供静态方法获取配置文件 + * + * @author looly + * @since 5.1.3 + */ + public static class PropsUtil extends cn.hutool.setting.dialect.PropsUtil {} + /** + * XML工具类<br> + * 此工具使用w3c dom工具,不需要依赖第三方包。<br> + * 工具类封装了XML文档的创建、读取、写出和部分XML操作 + * + * @author xiaoleilu + */ + public static class XmlUtil extends cn.hutool.core.util.XmlUtil {} + /** + * Velocity模板引擎工具类<br> + * 使用前必须初始化工具类 + * + * @author xiaoleilu + * @deprecated 使用TemplateUtil替代 + */ + public static class VelocityUtil extends cn.hutool.extra.template.engine.velocity.VelocityUtil {} + /** + * {@link ByteBuffer} 工具类<br> + * 此工具来自于 t-io 项目以及其它项目的相关部分收集<br> + * ByteBuffer的相关介绍见:https://www.cnblogs.com/ruber/p/6857159.html + * + * @author tanyaowu, looly + * @since 4.0.0 + * + */ + public static class BufferUtil extends cn.hutool.core.io.BufferUtil {} + /** + * 表达式引擎工具类 + * + * @author looly + * @since 5.5.0 + */ + public static class ExpressionUtil extends cn.hutool.extra.expression.ExpressionUtil {} + /** + * 驱动相关工具类,包括自动获取驱动类名 + * + * @author looly + * @since 4.0.10 + */ + public static class DriverUtil extends cn.hutool.db.dialect.DriverUtil {} + /** + * IO工具类<br> + * IO工具类只是辅助流的读写,并不负责关闭流。原因是流可能被多次读写,读写关闭后容易造成问题。 + * + * @author xiaoleilu + */ + public static class IoUtil extends cn.hutool.core.io.IoUtil {} + /** + * JDK8+中的{@link LocalDateTime} 工具类封装 + * + * @author looly + * @since 5.3.9 + */ + public static class LocalDateTimeUtil extends cn.hutool.core.date.LocalDateTimeUtil {} + /** + * 规范化对象生成工具 + * + * @author looly + * @since 5.4.3 + */ + public static class InternUtil extends cn.hutool.core.lang.intern.InternUtil {} + /** + * 压缩工具类 + * + * @author Looly + */ + public static class ZipUtil extends cn.hutool.core.util.ZipUtil {} + /** + * 十六进制(简写为hex或下标16)在数学中是一种逢16进1的进位制,一般用数字0到9和字母A到F表示(其中:A~F即10~15)。<br> + * 例如十进制数57,在二进制写作111001,在16进制写作39。<br> + * 像java,c这样的语言为了区分十六进制和十进制数值,会在十六进制数的前面加上 0x,比如0x20是十进制的32,而不是十进制的20<br> + * <p> + * 参考:https://my.oschina.net/xinxingegeya/blog/287476 + * + * @author Looly + */ + public static class HexUtil extends cn.hutool.core.util.HexUtil {} + /** + * 数据大小工具类 + * + * @author looly + * @since 5.3.10 + */ + public static class DataSizeUtil extends cn.hutool.core.io.unit.DataSizeUtil {} + /** + * User-Agent工具类 + * + * @author looly + * + */ + public static class UserAgentUtil extends cn.hutool.http.useragent.UserAgentUtil {} + /** + * 统一社会信用代码工具类 + * + * <pre> + * 第一部分:登记管理部门代码1位 (数字或大写英文字母) + * 第二部分:机构类别代码1位 (数字或大写英文字母) + * 第三部分:登记管理机关行政区划码6位 (数字) + * 第四部分:主体标识码(组织机构代码)9位 (数字或大写英文字母) + * 第五部分:校验码1位 (数字或大写英文字母) + * </pre> + * + * @author looly + * @since 5.2.4 + */ + public static class CreditCodeUtil extends cn.hutool.core.util.CreditCodeUtil {} + /** + * {@link Temporal} 工具类封装 + * + * @author looly + * @since 5.4.5 + */ + public static class TemporalUtil extends cn.hutool.core.date.TemporalUtil {} + /** + * Setting工具类<br> + * 提供静态方法获取配置文件 + * + * @author looly + */ + public static class SettingUtil extends cn.hutool.setting.SettingUtil {} + /** + * Statement和PreparedStatement工具类 + * + * @author looly + * @since 4.0.10 + */ + public static class StatementUtil extends cn.hutool.db.StatementUtil {} + /** + * 基于https://github.com/vdurmont/emoji-java的Emoji表情工具类 + * <p> + * emoji-java文档以及别名列表见:https://github.com/vdurmont/emoji-java + * + * @author looly + * @since 4.2.1 + */ + public static class EmojiUtil extends cn.hutool.extra.emoji.EmojiUtil {} + /** + * Bean工具类 + * + * <p> + * 把一个拥有对属性进行set和get方法的类,我们就可以称之为JavaBean。 + * </p> + * + * @author Looly + * @since 3.1.2 + */ + public static class BeanUtil extends cn.hutool.core.bean.BeanUtil {} + /** + * Servlet相关工具类封装 + * + * @author looly + * @since 3.2.0 + */ + public static class ServletUtil extends cn.hutool.extra.servlet.ServletUtil {} + /** + * java bean 校验工具类,此工具类基于validation-api(jakarta.validation-api)封装 + * + * <p>在实际使用中,用户需引入validation-api的实现,如:hibernate-validator</p> + * <p>注意:hibernate-validator还依赖了javax.el,需自行引入。</p> + * + * @author chengqiang + * @since 5.5.0 + */ + public static class ValidationUtil extends cn.hutool.extra.validation.ValidationUtil {} + /** + * Excel工作簿{@link org.apache.poi.ss.usermodel.Workbook}相关工具类 + * + * @author looly + * @since 4.0.7 + * + */ + public static class WorkbookUtil extends cn.hutool.poi.excel.WorkbookUtil {} + /** + * 拼音工具类,封装了TinyPinyin、JPinyin、Pinyin4j,通过SPI自动识别。 + * + * @author looly + */ + public static class PinyinUtil extends cn.hutool.extra.pinyin.PinyinUtil {} + /** + * 调用者。可以通过此类的方法获取调用者、多级调用者以及判断是否被调用 + * + * @author Looly + * @since 4.1.6 + */ + public static class CallerUtil extends cn.hutool.core.lang.caller.CallerUtil {} + /** + * 定时任务表达式工具类 + * + * @author looly + * + */ + public static class CronPatternUtil extends cn.hutool.cron.pattern.CronPatternUtil {} + /** + * 系统运行时工具类,用于执行系统命令的工具 + * + * @author Looly + * @since 3.1.1 + */ + public static class RuntimeUtil extends cn.hutool.core.util.RuntimeUtil {} + /** + * {@link TemporalAccessor} 工具类封装 + * + * @author looly + * @since 5.3.9 + */ + public static class TemporalAccessorUtil extends cn.hutool.core.date.TemporalAccessorUtil {} + /** + * 图形验证码工具 + * + * @author looly + * @since 3.1.2 + */ + public static class CaptchaUtil extends cn.hutool.captcha.CaptchaUtil {} + /** + * 反射工具类 + * + * @author Looly + * @since 3.0.9 + */ + public static class ReflectUtil extends cn.hutool.core.util.ReflectUtil {} + /** + * IPV4地址工具类 + * + * <p>pr自:https://gitee.com/loolly/hutool/pulls/161</p> + * + * @author ZhuKun + * @since 5.4.1 + */ + public static class Ipv4Util extends cn.hutool.core.net.Ipv4Util {} + /** + * {@link Robot} 封装工具类,提供截屏等工具 + * + * @author looly + * @since 4.1.14 + */ + public static class RobotUtil extends cn.hutool.core.swing.RobotUtil {} + /** + * {@link Graphics}相关工具类 + * + * @author looly + * @since 4.5.2 + */ + public static class GraphicsUtil extends cn.hutool.core.img.GraphicsUtil {} + /** + * Cglib工具类 + * + * @author looly + * @since 5.4.1 + */ + public static class CglibUtil extends cn.hutool.extra.cglib.CglibUtil {} + /** + * 转义和反转义工具类Escape / Unescape<br> + * escape采用ISO Latin字符集对指定的字符串进行编码。<br> + * 所有的空格符、标点符号、特殊字符以及其他非ASCII字符都将被转化成%xx格式的字符编码(xx等于该字符在字符集表里面的编码的16进制数字)。 + * + * @author xiaoleilu + */ + public static class EscapeUtil extends cn.hutool.core.util.EscapeUtil {} + /** + * 诊断工具类 + * + * @author looly + * @since 5.5.2 + */ + public static class DiagnosticUtil extends cn.hutool.core.compiler.DiagnosticUtil {} + /** + * Excel中的行{@link org.apache.poi.ss.usermodel.Row}封装工具类 + * + * @author looly + * @since 4.0.7 + */ + public static class RowUtil extends cn.hutool.poi.excel.RowUtil {} + /** + * 密钥工具类 + * + * <p> + * 包括: + * <pre> + * 1、生成密钥(单密钥、密钥对) + * 2、读取密钥文件 + * </pre> + * + * @author looly, Gsealy + * @since 4.4.1 + */ + public static class KeyUtil extends cn.hutool.crypto.KeyUtil {} + /** + * 基于Zxing的二维码工具类 + * + * @author looly + * @since 4.0.2 + */ + public static class QrCodeUtil extends cn.hutool.extra.qrcode.QrCodeUtil {} + /** + * SQL相关工具类,包括相关SQL语句拼接等 + * + * @author looly + * @since 4.0.10 + */ + public static class SqlUtil extends cn.hutool.db.sql.SqlUtil {} + /** + * Excel工具类,不建议直接使用index直接操作sheet,在wps/excel中sheet显示顺序与index无关,还有隐藏sheet + * + * @author Looly + * + */ + public static class ExcelUtil extends cn.hutool.poi.excel.ExcelUtil {} + /** + * 缓存工具类 + * @author Looly + *@since 3.0.1 + */ + public static class CacheUtil extends cn.hutool.cache.CacheUtil {} + /** + * Word工具类 + * + * @author Looly + * @since 4.5.16 + */ + public static class WordUtil extends cn.hutool.poi.word.WordUtil {} + /** + * 注解工具类<br> + * 快速获取注解对象、注解值等工具封装 + * + * @author looly + * @since 4.0.9 + */ + public static class AnnotationUtil extends cn.hutool.core.annotation.AnnotationUtil {} + /** + * Excel图片工具类 + * + * @author looly + * @since 4.0.7 + */ + public static class ExcelPicUtil extends cn.hutool.poi.excel.ExcelPicUtil {} + /** + * 屏幕相关(当前显示设置)工具类 + * + * @author looly + * @since 4.1.14 + */ + public static class ScreenUtil extends cn.hutool.core.swing.ScreenUtil {} + /** + * 文件工具类 + * + * @author looly + */ + public static class FileUtil extends cn.hutool.core.io.FileUtil {} + /** + * Word Document工具 + * + * @author looly + * @since 4.4.1 + */ + public static class DocUtil extends cn.hutool.poi.word.DocUtil {} + /** + * 比较工具类 + * + * @author looly + */ + public static class CompareUtil extends cn.hutool.core.comparator.CompareUtil {} + /** + * Boolean类型相关工具类 + * + * @author looly + * @since 4.1.16 + */ + public static class BooleanUtil extends cn.hutool.core.util.BooleanUtil {} + /** + * {@link Iterable} 和 {@link Iterator} 相关工具类 + * + * @author Looly + * @since 3.1.0 + */ + public static class IterUtil extends cn.hutool.core.collection.IterUtil {} + /** + * 树工具类 + * + * @author liangbaikai + */ + public static class TreeUtil extends cn.hutool.core.lang.tree.TreeUtil {} + /** + * 身份证相关工具类<br> + * see https://www.oschina.net/code/snippet_1611_2881 + * + * <p> + * 本工具并没有对行政区划代码做校验,如有需求,请参阅(2018年10月): + * http://www.mca.gov.cn/article/sj/xzqh/2018/201804-12/20181011221630.html + * </p> + * + * @author Looly + * @since 3.0.4 + */ + public static class IdcardUtil extends cn.hutool.core.util.IdcardUtil {} + /** + * 字符工具类<br> + * 部分工具来自于Apache Commons系列 + * + * @author looly + * @since 4.0.1 + */ + public static class CharUtil extends cn.hutool.core.util.CharUtil {} + /** + * Socket相关工具类 + * + * @author looly + * @since 4.5.0 + */ + public static class SocketUtil extends cn.hutool.socket.SocketUtil {} + /** + * 手机号工具类 + * + * @author dahuoyzs + * @since 5.3.11 + */ + public static class PhoneUtil extends cn.hutool.core.util.PhoneUtil {} + /** + * 模板工具类 + * + * @author looly + * @since 4.1.0 + */ + public static class TemplateUtil extends cn.hutool.extra.template.TemplateUtil {} + /** + * 集合相关工具类 + * <p> + * 此工具方法针对{@link Collection}及其实现类封装的工具。 + * <p> + * 由于{@link Collection} 实现了{@link Iterable}接口,因此部分工具此类不提供,而是在{@link IterUtil} 中提供 + * + * @author xiaoleilu + * @see IterUtil + * @since 3.1.1 + */ + public static class CollUtil extends cn.hutool.core.collection.CollUtil {} + /** + * {@link JavaFileObject} 相关工具类封装 + * + * @author lzpeng, looly + * @since 5.5.2 + */ + public static class JavaFileObjectUtil extends cn.hutool.core.compiler.JavaFileObjectUtil {} + /** + * 数组工具类 + * + * @author Looly + */ + public static class ArrayUtil extends cn.hutool.core.util.ArrayUtil {} + /** + * SSL(Secure Sockets Layer 安全套接字协议)相关工具封装 + * + * @author looly + * @since 5.5.2 + */ + public static class SSLUtil extends cn.hutool.core.net.SSLUtil {} + /** + * 集合相关工具类,包括数组,是{@link CollUtil} 的别名工具类类 + * + * @author xiaoleilu + * @see CollUtil + */ + public static class CollectionUtil extends cn.hutool.core.collection.CollectionUtil {} + /** + * Excel表格中单元格工具类 + * + * @author looly + * @since 4.0.7 + */ + public static class CellUtil extends cn.hutool.poi.excel.cell.CellUtil {} + /** + * 字符集工具类 + * + * @author xiaoleilu + */ + public static class CharsetUtil extends cn.hutool.core.util.CharsetUtil {} + /** + * 字符串工具类 + * + * @author xiaoleilu + */ + public static class StrUtil extends cn.hutool.core.util.StrUtil {} + /** + * Map相关工具类 + * + * @author Looly + * @since 3.1.1 + */ + public static class MapUtil extends cn.hutool.core.map.MapUtil {} + /** + * SPI机制中的服务加载工具类,流程如下 + * + * <pre> + * 1、创建接口,并创建实现类 + * 2、ClassPath/META-INF/services下创建与接口全限定类名相同的文件 + * 3、文件内容填写实现类的全限定类名 + * </pre> + * 相关介绍见:https://www.jianshu.com/p/3a3edbcd8f24 + * + * @author looly + * @since 5.1.6 + */ + public static class ServiceLoaderUtil extends cn.hutool.core.util.ServiceLoaderUtil {} + /** + * Spring(Spring boot)工具封装,包括: + * + * <pre> + * 1、Spring IOC容器中的bean对象获取 + * </pre> + * + * @author loolly + * @since 5.1.0 + */ + public static class SpringUtil extends cn.hutool.extra.spring.SpringUtil {} + /** + * 随机工具类 + * + * @author xiaoleilu + */ + public static class RandomUtil extends cn.hutool.core.util.RandomUtil {} + public static class ListUtil extends cn.hutool.core.collection.ListUtil {} + /** + * Resource资源工具类 + * + * @author Looly + * + */ + public static class ResourceUtil extends cn.hutool.core.io.resource.ResourceUtil {} + /** + * AWT中字体相关工具类 + * + * @author looly + * @since 5.3.6 + */ + public static class FontUtil extends cn.hutool.core.img.FontUtil {} + /** + * CSV工具 + * + * @author looly + * @since 4.0.5 + */ + public static class CsvUtil extends cn.hutool.core.text.csv.CsvUtil {} + /** + * Word中表格相关工具 + * + * @author Looly + * @since 4.5.14 + */ + public static class TableUtil extends cn.hutool.poi.word.TableUtil {} + /** + * 原始类型数组工具类 + * + * @author looly + * @since 5.5.2 + */ + public static class PrimitiveArrayUtil extends cn.hutool.core.util.PrimitiveArrayUtil {} + + /** + * JSON工具类 + */ + public static class JSONUtil extends net.geedge.common.utils.JSONUtil {}; + + /** + * http response 工具类 + * @author ThinkPad + * + */ + public static class ResponseUtil extends net.geedge.common.utils.ResponseUtil{}; + + /** + * license 授权处理工具类 + * @author ThinkPad + * + */ + public static class LicenseUtil extends net.geedge.common.utils.LicenseUtil{}; + + /** + * 获取项目中各种路径 + * @author ThinkPad + * + */ + public static class WebPathUtil { + /** + * 如果已打成jar包,则返回jar包所在目录 + * 如果未打成jar,则返回target所在目录 + * @return + */ + public static String getClassPath() { + try { + // 项目的编译文件的根目录 + String path = URLDecoder.decode(Tool.class.getResource("/").getPath(), "UTF-8"); + if (path.startsWith("file:")) { + int i = path.indexOf(".jar!"); + if(i == -1){ + i = path.indexOf(".xjar!"); + } + path = path.substring(0, i); + path = path.replaceFirst("file:", ""); + // 项目所在的目录 + return Tool.FileUtil.newFile(path).getParentFile().getAbsolutePath(); + }else { + //classpath 路径 + return Tool.FileUtil.newFile(path).getAbsolutePath(); + } + } catch (UnsupportedEncodingException e) { + return null; + } + } + + public static String getRootPath() { + File file = Tool.FileUtil.file(WebPathUtil.getClassPath()); + return file.getAbsolutePath(); + } + + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/utils/TypeEnum.java b/cn-admin/src/main/java/net/geedge/common/utils/TypeEnum.java new file mode 100644 index 0000000..a53cec5 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/utils/TypeEnum.java @@ -0,0 +1,28 @@ +package net.geedge.common.utils; + +/** + * 操作日志相关枚举类型 + */ +public enum TypeEnum { + // 类型type + ASSET("asset"), ASSETACCOUNT("asset account"), ASSETACCOUNTREL("asset account rel"), + ASSETFIELDGROUP("asset field group"), ASSETFIELDMETA("asset field meta"), ENDPOINT("endpoint"), PROJECT("project"), + TOPO("project topo"), MODULE("module"), ALERTRULE("alert rule"), ALERTMESSAGE("alert message"), PANEL("panel"), + CHART("chart"), VISUALPANEL("visual panel"), VISUALCHART("visual chart"), DATACENTER("datacenter"), + CABINET("cabinet"), UNKNOWN("unknown"), MODEL("model"), PROMSERVER("promServer"), ACCOUNT("account"), MIB("mib"), + SYSTEM("system"), LINK("link"), SCRIPT("notification script"), ALERTSILENCE("alert silence"), + ALERTSEVERITY("alert severity"), ALERTNOTIFYMETHOD("alert notify method"), ASSETSTATECONF("asset state conf"), + ASSETTYPECONF("asset type conf"), EXPRESSIONTMPL("expression tmpl"), ASSETBRAND("asset brand"), + SNMPCREDENTIAL("snmp credential"), LICENSE("license"), SYSTEMAPIKEY("sys api key"); + + private String value; + + public String getValue() { + return value; + } + + private TypeEnum(String value) { + this.value = value; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/validator/Assert.java b/cn-admin/src/main/java/net/geedge/common/validator/Assert.java new file mode 100644 index 0000000..046d234 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/validator/Assert.java @@ -0,0 +1,32 @@ +/** + + * + + * + * + */ + +package net.geedge.common.validator; + +import net.geedge.common.exception.CNException; +import org.apache.commons.lang.StringUtils; + +/** + * 数据校验 + * + * @author Mark [email protected] + */ +public abstract class Assert { + + public static void isBlank(String str, String message) { + if (StringUtils.isBlank(str)) { + throw new CNException(message); + } + } + + public static void isNull(Object object, String message) { + if (object == null) { + throw new CNException(message); + } + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/validator/ValidatorUtils.java b/cn-admin/src/main/java/net/geedge/common/validator/ValidatorUtils.java new file mode 100644 index 0000000..6fa4606 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/validator/ValidatorUtils.java @@ -0,0 +1,47 @@ +/** + + * + + * + * + */ + +package net.geedge.common.validator; + + +import net.geedge.common.exception.CNException; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.Set; + +/** + * hibernate-validator校验工具类 + * + * 参考文档:http://docs.jboss.org/hibernate/validator/5.4/reference/en-US/html_single/ + * + * @author Mark [email protected] + */ +public class ValidatorUtils { + private static Validator validator; + + static { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + } + + /** + * 校验对象 + * @param object 待校验对象 + * @param groups 待校验的组 + * @throws CNException 校验不通过,则报NZException异常 + */ + public static void validateEntity(Object object, Class<?>... groups) + throws CNException { + Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups); + if (!constraintViolations.isEmpty()) { + ConstraintViolation<Object> constraint = (ConstraintViolation<Object>)constraintViolations.iterator().next(); + throw new CNException(constraint.getMessage()); + } + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/validator/group/AddGroup.java b/cn-admin/src/main/java/net/geedge/common/validator/group/AddGroup.java new file mode 100644 index 0000000..fbebf3f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/validator/group/AddGroup.java @@ -0,0 +1,17 @@ +/** + + * + + * + * + */ + +package net.geedge.common.validator.group; + +/** + * 新增数据 Group + * + * @author Mark [email protected] + */ +public interface AddGroup { +} diff --git a/cn-admin/src/main/java/net/geedge/common/validator/group/Group.java b/cn-admin/src/main/java/net/geedge/common/validator/group/Group.java new file mode 100644 index 0000000..2416406 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/validator/group/Group.java @@ -0,0 +1,21 @@ +/** + + * + + * + * + */ + +package net.geedge.common.validator.group; + +import javax.validation.GroupSequence; + +/** + * 定义校验顺序,如果AddGroup组失败,则UpdateGroup组不会再校验 + * + * @author Mark [email protected] + */ +@GroupSequence({AddGroup.class, UpdateGroup.class}) +public interface Group { + +} diff --git a/cn-admin/src/main/java/net/geedge/common/validator/group/UpdateGroup.java b/cn-admin/src/main/java/net/geedge/common/validator/group/UpdateGroup.java new file mode 100644 index 0000000..914e731 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/validator/group/UpdateGroup.java @@ -0,0 +1,18 @@ +/** + + * + + * + * + */ + +package net.geedge.common.validator.group; + +/** + * 更新数据 Group + * + * @author Mark [email protected] + */ +public interface UpdateGroup { + +} diff --git a/cn-admin/src/main/java/net/geedge/common/xss/HTMLFilter.java b/cn-admin/src/main/java/net/geedge/common/xss/HTMLFilter.java new file mode 100644 index 0000000..ede0e31 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/xss/HTMLFilter.java @@ -0,0 +1,530 @@ +package net.geedge.common.xss; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * HTML filtering utility for protecting against XSS (Cross Site Scripting). + * + * This code is licensed LGPLv3 + * + * This code is a Java port of the original work in PHP by Cal Hendersen. + * http://code.iamcal.com/php/lib_filter/ + * + * The trickiest part of the translation was handling the differences in regex handling + * between PHP and Java. These resources were helpful in the process: + * + * http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html + * http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php + * http://www.regular-expressions.info/modifiers.html + * + * A note on naming conventions: instance variables are prefixed with a "v"; global + * constants are in all caps. + * + * Sample use: + * String input = ... + * String clean = new HTMLFilter().filter( input ); + * + * The class is not thread safe. Create a new instance if in doubt. + * + * If you find bugs or have suggestions on improvement (especially regarding + * performance), please contact us. The latest version of this + * source, and our contact details, can be found at http://xss-html-filter.sf.net + * + * @author Joseph O'Connell + * @author Cal Hendersen + * @author Michael Semb Wever + */ +public final class HTMLFilter { + + /** regex flag union representing /si modifiers in php **/ + private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; + private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL); + private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); + private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL); + private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI); + private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI); + private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI); + private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI); + private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI); + private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); + private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?"); + private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?"); + private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); + private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL); + private static final Pattern P_END_ARROW = Pattern.compile("^>"); + private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_AMP = Pattern.compile("&"); + private static final Pattern P_QUOTE = Pattern.compile("<"); + private static final Pattern P_LEFT_ARROW = Pattern.compile("<"); + private static final Pattern P_RIGHT_ARROW = Pattern.compile(">"); + private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); + + // @xxx could grow large... maybe use sesat's ReferenceMap + private static final ConcurrentMap<String,Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>(); + private static final ConcurrentMap<String,Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>(); + + /** set of allowed html elements, along with allowed attributes for each element **/ + private final Map<String, List<String>> vAllowed; + /** counts of open tags for each (allowable) html element **/ + private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>(); + + /** html elements which must always be self-closing (e.g. "<img />") **/ + private final String[] vSelfClosingTags; + /** html elements which must always have separate opening and closing tags (e.g. "<b></b>") **/ + private final String[] vNeedClosingTags; + /** set of disallowed html elements **/ + private final String[] vDisallowed; + /** attributes which should be checked for valid protocols **/ + private final String[] vProtocolAtts; + /** allowed protocols **/ + private final String[] vAllowedProtocols; + /** tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />") **/ + private final String[] vRemoveBlanks; + /** entities allowed within html markup **/ + private final String[] vAllowedEntities; + /** flag determining whether comments are allowed in input String. */ + private final boolean stripComment; + private final boolean encodeQuotes; + private boolean vDebug = false; + /** + * flag determining whether to try to make tags when presented with "unbalanced" + * angle brackets (e.g. "<b text </b>" becomes "<b> text </b>"). If set to false, + * unbalanced angle brackets will be html escaped. + */ + private final boolean alwaysMakeTags; + + /** Default constructor. + * + */ + public HTMLFilter() { + vAllowed = new HashMap<>(); + + final ArrayList<String> a_atts = new ArrayList<String>(); + a_atts.add("href"); + a_atts.add("target"); + vAllowed.put("a", a_atts); + + final ArrayList<String> img_atts = new ArrayList<String>(); + img_atts.add("src"); + img_atts.add("width"); + img_atts.add("height"); + img_atts.add("alt"); + vAllowed.put("img", img_atts); + + final ArrayList<String> no_atts = new ArrayList<String>(); + vAllowed.put("b", no_atts); + vAllowed.put("strong", no_atts); + vAllowed.put("i", no_atts); + vAllowed.put("em", no_atts); + + vSelfClosingTags = new String[]{"img"}; + vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"}; + vDisallowed = new String[]{}; + vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp. + vProtocolAtts = new String[]{"src", "href"}; + vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"}; + vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"}; + stripComment = true; + encodeQuotes = true; + alwaysMakeTags = true; + } + + /** Set debug flag to true. Otherwise use default settings. See the default constructor. + * + * @param debug turn debug on with a true argument + */ + public HTMLFilter(final boolean debug) { + this(); + vDebug = debug; + + } + + /** Map-parameter configurable constructor. + * + * @param conf map containing configuration. keys match field names. + */ + public HTMLFilter(final Map<String,Object> conf) { + + assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; + assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; + assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; + assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; + assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; + assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; + assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; + assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; + + vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed")); + vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); + vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); + vDisallowed = (String[]) conf.get("vDisallowed"); + vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); + vProtocolAtts = (String[]) conf.get("vProtocolAtts"); + vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); + vAllowedEntities = (String[]) conf.get("vAllowedEntities"); + stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; + encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; + alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; + } + + private void reset() { + vTagCounts.clear(); + } + + private void debug(final String msg) { + if (vDebug) { + Logger.getAnonymousLogger().info(XssUtil.filterString(msg)); + } + } + + //--------------------------------------------------------------- + // my versions of some PHP library functions + public static String chr(final int decimal) { + return String.valueOf((char) decimal); + } + + public static String htmlSpecialChars(final String s) { + String result = s; + result = regexReplace(P_AMP, "&", result); + result = regexReplace(P_QUOTE, """, result); + result = regexReplace(P_LEFT_ARROW, "<", result); + result = regexReplace(P_RIGHT_ARROW, ">", result); + return result; + } + + //--------------------------------------------------------------- + /** + * given a user submitted input String, filter out any invalid or restricted + * html. + * + * @param input text (i.e. submitted by a user) than may contain html + * @return "clean" version of input, with only valid, whitelisted html elements allowed + */ + public String filter(final String input) { + reset(); + String s = input; + + debug("************************************************"); + debug(" INPUT: " + input); + + s = escapeComments(s); + debug(" escapeComments: " + s); + + s = balanceHTML(s); + debug(" balanceHTML: " + s); + + s = checkTags(s); + debug(" checkTags: " + s); + + s = processRemoveBlanks(s); + debug("processRemoveBlanks: " + s); + + s = validateEntities(s); + debug(" validateEntites: " + s); + + debug("************************************************\n\n"); + return s; + } + + public boolean isAlwaysMakeTags(){ + return alwaysMakeTags; + } + + public boolean isStripComments(){ + return stripComment; + } + + private String escapeComments(final String s) { + final Matcher m = P_COMMENTS.matcher(s); + final StringBuffer buf = new StringBuffer(); + if (m.find()) { + final String match = m.group(1); //(.*?) + m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->")); + } + m.appendTail(buf); + + return buf.toString(); + } + + private String balanceHTML(String s) { + if (alwaysMakeTags) { + // + // try and form html + // + s = regexReplace(P_END_ARROW, "", s); + s = regexReplace(P_BODY_TO_END, "<$1>", s); + s = regexReplace(P_XML_CONTENT, "$1<$2", s); + + } else { + // + // escape stray brackets + // + s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s); + s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s); + + // + // the last regexp causes '<>' entities to appear + // (we need to do a lookahead assertion so that the last bracket can + // be used in the next pass of the regexp) + // + s = regexReplace(P_BOTH_ARROWS, "", s); + } + + return s; + } + + private String checkTags(String s) { + Matcher m = P_TAGS.matcher(s); + + final StringBuffer buf = new StringBuffer(); + while (m.find()) { + String replaceStr = m.group(1); + replaceStr = processTag(replaceStr); + m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); + } + m.appendTail(buf); + + s = buf.toString(); + + // these get tallied in processTag + // (remember to reset before subsequent calls to filter method) + for (String key : vTagCounts.keySet()) { + for (int ii = 0; ii < vTagCounts.get(key); ii++) { + s += "</" + key + ">"; + } + } + + return s; + } + + private String processRemoveBlanks(final String s) { + String result = s; + for (String tag : vRemoveBlanks) { + if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){ + P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">")); + } + result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); + if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){ + P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); + } + result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); + } + + return result; + } + + private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) { + Matcher m = regex_pattern.matcher(s); + return m.replaceAll(replacement); + } + + private String processTag(final String s) { + // ending tags + Matcher m = P_END_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + if (allowed(name)) { + if (!inArray(name, vSelfClosingTags)) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) - 1); + return "</" + name + ">"; + } + } + } + } + + // starting tags + m = P_START_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + final String body = m.group(2); + String ending = m.group(3); + + //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); + if (allowed(name)) { + String params = ""; + + final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); + final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); + final List<String> paramNames = new ArrayList<String>(); + final List<String> paramValues = new ArrayList<String>(); + while (m2.find()) { + paramNames.add(m2.group(1)); //([a-z0-9]+) + paramValues.add(m2.group(3)); //(.*?) + } + while (m3.find()) { + paramNames.add(m3.group(1)); //([a-z0-9]+) + paramValues.add(m3.group(3)); //([^\"\\s']+) + } + + String paramName, paramValue; + for (int ii = 0; ii < paramNames.size(); ii++) { + paramName = paramNames.get(ii).toLowerCase(); + paramValue = paramValues.get(ii); + +// debug( "paramName='" + paramName + "'" ); +// debug( "paramValue='" + paramValue + "'" ); +// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) ); + + if (allowedAttribute(name, paramName)) { + if (inArray(paramName, vProtocolAtts)) { + paramValue = processParamProtocol(paramValue); + } + params += " " + paramName + "=\"" + paramValue + "\""; + } + } + + if (inArray(name, vSelfClosingTags)) { + ending = " /"; + } + + if (inArray(name, vNeedClosingTags)) { + ending = ""; + } + + if (ending == null || ending.length() < 1) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) + 1); + } else { + vTagCounts.put(name, 1); + } + } else { + ending = " /"; + } + return "<" + name + params + ending + ">"; + } else { + return ""; + } + } + + // comments + m = P_COMMENT.matcher(s); + if (!stripComment && m.find()) { + return "<" + m.group() + ">"; + } + + return ""; + } + + private String processParamProtocol(String s) { + s = decodeEntities(s); + final Matcher m = P_PROTOCOL.matcher(s); + if (m.find()) { + final String protocol = m.group(1); + if (!inArray(protocol, vAllowedProtocols)) { + // bad protocol, turn into local anchor link instead + s = "#" + s.substring(protocol.length() + 1, s.length()); + if (s.startsWith("#//")) { + s = "#" + s.substring(3, s.length()); + } + } + } + + return s; + } + + private String decodeEntities(String s) { + StringBuffer buf = new StringBuffer(); + + Matcher m = P_ENTITY.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.decode(match).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENTITY_UNICODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENCODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + s = validateEntities(s); + return s; + } + + private String validateEntities(final String s) { + StringBuffer buf = new StringBuffer(); + + // validate entities throughout the string + Matcher m = P_VALID_ENTITIES.matcher(s); + while (m.find()) { + final String one = m.group(1); //([^&;]*) + final String two = m.group(2); //(?=(;|&|$)) + m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); + } + m.appendTail(buf); + + return encodeQuotes(buf.toString()); + } + + private String encodeQuotes(final String s){ + if(encodeQuotes){ + StringBuffer buf = new StringBuffer(); + Matcher m = P_VALID_QUOTES.matcher(s); + while (m.find()) { + final String one = m.group(1); //(>|^) + final String two = m.group(2); //([^<]+?) + final String three = m.group(3); //(<|$) + m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three)); + } + m.appendTail(buf); + return buf.toString(); + }else{ + return s; + } + } + + private String checkEntity(final String preamble, final String term) { + + return ";".equals(term) && isValidEntity(preamble) + ? '&' + preamble + : "&" + preamble; + } + + private boolean isValidEntity(final String entity) { + return inArray(entity, vAllowedEntities); + } + + private static boolean inArray(final String s, final String[] array) { + for (String item : array) { + if (item != null && item.equals(s)) { + return true; + } + } + return false; + } + + private boolean allowed(final String name) { + return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); + } + + private boolean allowedAttribute(final String name, final String paramName) { + return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/xss/SQLFilter.java b/cn-admin/src/main/java/net/geedge/common/xss/SQLFilter.java new file mode 100644 index 0000000..f3b5a9b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/xss/SQLFilter.java @@ -0,0 +1,49 @@ +/** + * + */ + +package net.geedge.common.xss; + +import net.geedge.common.exception.CNException; +import net.geedge.common.utils.RCode; +import org.apache.commons.lang.StringUtils; + +import java.util.regex.Pattern; + +/** + * SQL过滤 + * + * @author Mark [email protected] + */ +public class SQLFilter { + + private static String reg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)"; + + private static Pattern sqlPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE); + + /** + * SQL注入过滤 + * @param str 待验证的字符串 + */ + public static String sqlInject(String str) { + if (StringUtils.isBlank(str)) { + return null; + } + + //转换成小写 + String str1 = str.toLowerCase(); + + String s = ""; + if (str1.startsWith("-")) { + s = str1.substring(1); + } else { + s = str1; + } + + if (sqlPattern.matcher(s).matches()) { + throw new CNException(RCode.ERROR); + } + + return str; + } +} diff --git a/cn-admin/src/main/java/net/geedge/common/xss/XssFilter.java b/cn-admin/src/main/java/net/geedge/common/xss/XssFilter.java new file mode 100644 index 0000000..79e879b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/xss/XssFilter.java @@ -0,0 +1,44 @@ +/** + + * + + * + * + */ + +package net.geedge.common.xss; + +import cn.hutool.log.Log; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; + +/** + * XSS过滤 + * + * @author Mark [email protected] + */ +public class XssFilter implements Filter { + + private final static Log logger = Log.get(); + + @Override + public void init(FilterConfig config) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){ + XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper( + (HttpServletRequest) request); + try { + chain.doFilter(xssRequest, response); + } catch (Exception e) { + logger.error(e); + } + } + + @Override + public void destroy() { + } + +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/common/xss/XssHttpServletRequestWrapper.java b/cn-admin/src/main/java/net/geedge/common/xss/XssHttpServletRequestWrapper.java new file mode 100644 index 0000000..c4d8529 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/xss/XssHttpServletRequestWrapper.java @@ -0,0 +1,158 @@ +/** + + * + + * + * + */ + +package net.geedge.common.xss; + +import cn.hutool.http.HTMLFilter; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * XSS过滤处理 + * + * @author Mark [email protected] + */ +public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { + /** + * 没被包装过的HttpServletRequest(特殊场景,需要自己过滤) + */ + HttpServletRequest orgRequest; + /** + * html过滤 + */ + private final static HTMLFilter htmlFilter = new HTMLFilter(); + + public XssHttpServletRequestWrapper(HttpServletRequest request) { + super(request); + orgRequest = request; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + String header = super.getHeader(HttpHeaders.CONTENT_TYPE); + //非json类型,直接返回 + if(!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(super.getHeader(HttpHeaders.CONTENT_TYPE))){ + return super.getInputStream(); + } + + //为空,直接返回 + String json = IOUtils.toString(super.getInputStream(), "utf-8"); + if (StringUtils.isBlank(json)) { + return super.getInputStream(); + } + + //xss过滤 + json = xssEncode(json); + + //htmlfilter会将引号处理 导致json解析异常 + json = json.replaceAll(""","\""); + + final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8")); + return new ServletInputStream() { + @Override + public boolean isFinished() { + return true; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + } + + @Override + public int read() throws IOException { + return bis.read(); + } + }; + } + + @Override + public String getParameter(String name) { + String value = super.getParameter(xssEncode(name)); + if (StringUtils.isNotBlank(value)) { + value = xssEncode(value); + } + return value; + } + + @Override + public String[] getParameterValues(String name) { + String[] parameters = super.getParameterValues(name); + if (parameters == null || parameters.length == 0) { + return null; + } + + for (int i = 0; i < parameters.length; i++) { + parameters[i] = xssEncode(parameters[i]); + } + return parameters; + } + + @Override + public Map<String,String[]> getParameterMap() { + Map<String,String[]> map = new LinkedHashMap<>(); + Map<String,String[]> parameters = super.getParameterMap(); + for (String key : parameters.keySet()) { + String[] values = parameters.get(key); + for (int i = 0; i < values.length; i++) { + values[i] = xssEncode(values[i]); + // htmlfilter会将引号处理 导致json解析异常 + values[i] = values[i].replaceAll(""","\""); + } + map.put(key, values); + } + return map; + } + + @Override + public String getHeader(String name) { + String value = super.getHeader(xssEncode(name)); + if (StringUtils.isNotBlank(value)) { + value = xssEncode(value); + } + return value; + } + + private String xssEncode(String input) { + return htmlFilter.filter(input); + } + + /** + * 获取最原始的request + */ + public HttpServletRequest getOrgRequest() { + return orgRequest; + } + + /** + * 获取最原始的request + */ + public static HttpServletRequest getOrgRequest(HttpServletRequest request) { + if (request instanceof XssHttpServletRequestWrapper) { + return ((XssHttpServletRequestWrapper) request).getOrgRequest(); + } + + return request; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/common/xss/XssUtil.java b/cn-admin/src/main/java/net/geedge/common/xss/XssUtil.java new file mode 100644 index 0000000..860d4a7 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/common/xss/XssUtil.java @@ -0,0 +1,28 @@ +package net.geedge.common.xss; + +import org.apache.commons.lang.StringUtils; +import org.springframework.web.util.HtmlUtils; + +import java.util.Map; + +public class XssUtil { + public static String filterString(String str){ + if(StringUtils.isNotBlank(str)) + return HtmlUtils.htmlEscape(str,"UTF-8"); + return str; + } + + public static Map<String,Object> filterParameters(Map<String,Object> params){ + if(params != null){ + for (Map.Entry<String,Object> entry:params.entrySet()){ + Object value = entry.getValue(); + if(value instanceof String){ + String val = filterString((String)value); + params.put(entry.getKey(),val); + } + } + return params; + } + return null; + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/galaxy/controller/GalaxyController.java b/cn-admin/src/main/java/net/geedge/modules/galaxy/controller/GalaxyController.java new file mode 100644 index 0000000..9a5e2e3 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/galaxy/controller/GalaxyController.java @@ -0,0 +1,5 @@ +package net.geedge.modules.galaxy.controller; + +public class GalaxyController { + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/AbstractController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/AbstractController.java new file mode 100644 index 0000000..d539f6c --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/AbstractController.java @@ -0,0 +1,31 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.controller; + +import cn.hutool.log.Log; +import net.geedge.modules.sys.entity.SysUserEntity; +import org.apache.shiro.SecurityUtils; + +/** + * Controller公共组件 + * + + */ +public abstract class AbstractController { + protected Log logger = Log.get(); + + protected SysUserEntity getUser() { + return (SysUserEntity) SecurityUtils.getSubject().getPrincipal(); + } + + protected Long getUserId() { + return getUser().getId(); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/LinkController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/LinkController.java new file mode 100644 index 0000000..13db604 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/LinkController.java @@ -0,0 +1,69 @@ +package net.geedge.modules.sys.controller; + +import net.geedge.common.annotation.SysLog; +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.OperationEnum; +import net.geedge.common.utils.R; +import net.geedge.common.utils.RCode; +import net.geedge.common.utils.TypeEnum; +import net.geedge.modules.sys.entity.Link; +import net.geedge.modules.sys.service.LinkService; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/link") +public class LinkController extends AbstractController{ + @Autowired + private LinkService linkService; + + @GetMapping + @SysLog(operation = OperationEnum.QUERY,type = TypeEnum.LINK) + public R list(@RequestParam Map<String, Object> params){ + List<Link> result = linkService.queryList(params); + return R.ok().putData("list",result); + } + + @PostMapping + @SysLog(operation = OperationEnum.ADD,type = TypeEnum.LINK) + @RequiresPermissions({"sys:link:save"}) + public R save(@RequestBody Link link) { + ValidateUtils.is(link.getName()).notNull(RCode.LINK_NAME_ISNULL); + ValidateUtils.is(link.getUrl()).notNull(RCode.LINK_URL_ISNULL); + linkService.saveLink(link); + return R.ok().putData("id", link.getId()); + } + + @PutMapping + @SysLog(operation = OperationEnum.UPDATE,type = TypeEnum.LINK) + @RequiresPermissions({"sys:link:update"}) + public R update(@RequestBody Link link) { + ValidateUtils.is(link.getId()).notNull(RCode.LINK_ID_ISNULL); + ValidateUtils.is(link.getName()).notNull(RCode.LINK_NAME_ISNULL); + ValidateUtils.is(link.getUrl()).notNull(RCode.LINK_URL_ISNULL); + linkService.updateById(link); + return R.ok().putData("id", link.getId()); + } + + @DeleteMapping + @SysLog(operation = OperationEnum.DELETE,type = TypeEnum.LINK) + @RequiresPermissions({"sys:link:delete"}) + public R remove(@RequestParam String ids) { + ValidateUtils.is(ids).notNull(RCode.LINK_ID_ISNULL); + String[] split = ids.split(","); + linkService.removeLinks(Arrays.asList(split)); + return R.ok(); + } + + @PutMapping("/weights") + @SysLog(operation = OperationEnum.UPDATE,type = TypeEnum.LINK) + public R modify(@RequestBody List<Link> links){ + linkService.saveWeights(links); + return R.ok(); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysApiKeyController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysApiKeyController.java new file mode 100644 index 0000000..c30eecd --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysApiKeyController.java @@ -0,0 +1,54 @@ +package net.geedge.modules.sys.controller; + +import net.geedge.common.annotation.SysLog; +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.*; +import net.geedge.modules.sys.entity.SysApiKey; +import net.geedge.modules.sys.service.SysApiKeyService; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +@RestController +@RequestMapping("/sys/apiKey") +public class SysApiKeyController { + + @Autowired + private SysApiKeyService sysApiKeyService; + + @GetMapping + @SysLog(operation = OperationEnum.QUERY,type = TypeEnum.SYSTEMAPIKEY) + public R queryCredentialList(@RequestParam Map<String,Object> params) { + PageUtils page = sysApiKeyService.queryPage(params); + return R.ok(page); + } + + @GetMapping("/{id}") + @SysLog(operation = OperationEnum.QUERY,type = TypeEnum.SYSTEMAPIKEY) + public R info(@PathVariable Integer id) { + SysApiKey apiKey = sysApiKeyService.getById(id); + return R.ok(apiKey); + } + + @PostMapping + @SysLog(operation = OperationEnum.ADD,type = TypeEnum.SYSTEMAPIKEY) + @RequiresPermissions({"sys:apiKey:save"}) + public R addSysApiKey(@RequestBody SysApiKey sysApiKey) { + ValidateUtils.is(sysApiKey.getName()).notNull(RCode.SYSAPIKEY_NAME_ISNULL) + .and(sysApiKey.getRoleId()).notNull(RCode.SYSAPIKEY_ROLEID_ISNULL); + Integer id = sysApiKeyService.addSysApiKey(sysApiKey); + return R.ok().putData("id", id); + } + + @DeleteMapping + @SysLog(operation = OperationEnum.DELETE,type = TypeEnum.SYSTEMAPIKEY) + @RequiresPermissions({"sys:apiKey:delete"}) + public R removeSysApiKey(@RequestParam String ids) { + ValidateUtils.is(ids).notNull(RCode.SYSAPIKEY_ID_ISNULL); + sysApiKeyService.removeSysApiKeys(ids); + return R.ok(); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysConfigController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysConfigController.java new file mode 100644 index 0000000..a43d4cc --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysConfigController.java @@ -0,0 +1,94 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.controller; + + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import net.geedge.common.annotation.SysLog; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.R; +import net.geedge.common.validator.ValidatorUtils; +import net.geedge.modules.sys.entity.SysConfigEntity; +import net.geedge.modules.sys.service.SysConfigService; + +/** + * 系统配置信息 + * + + */ +@RestController +@RequestMapping("/sys/config") +public class SysConfigController extends AbstractController { + @Autowired + private SysConfigService sysConfigService; + + /** + * 所有配置列表 + */ + @GetMapping + public R list(@RequestParam Map<String, Object> params){ + PageUtils page = sysConfigService.queryPage(params); + return R.ok().put("page", page); + } + + + /** + * 配置信息 + */ + @GetMapping("/{id}") + public R info(@PathVariable("id") Long id){ + SysConfigEntity config = sysConfigService.getById(id); + return R.ok().put("config", config); + } + + /** + * 保存配置 + */ + @SysLog + @PostMapping() + public R save(@RequestBody SysConfigEntity config){ + ValidatorUtils.validateEntity(config); + sysConfigService.saveConfig(config); + return R.ok(); + } + + /** + * 修改配置 + */ + @SysLog + @PutMapping() + public R update(@RequestBody SysConfigEntity config){ + ValidatorUtils.validateEntity(config); + sysConfigService.update(config); + return R.ok().putData("id", config.getId()); + } + + /** + * 删除配置 + */ + @SysLog + @DeleteMapping() + public R delete(@RequestBody Long[] ids){ + sysConfigService.deleteBatch(ids); + return R.ok(); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysDictController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysDictController.java new file mode 100644 index 0000000..8c1b43c --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysDictController.java @@ -0,0 +1,99 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.controller; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.R; +import net.geedge.common.utils.RCode; +import net.geedge.modules.sys.entity.SysDictEntity; +import net.geedge.modules.sys.service.SysDictService; + + +@RestController +@RequestMapping("sys/dict") +public class SysDictController extends AbstractController { + @Autowired + private SysDictService sysDictService; + + /** + * 列表 + */ + @GetMapping() + public R list(@RequestParam Map<String, Object> params){ + PageUtils page = sysDictService.queryPage(params); + R re = R.ok(page); + return re; + } + + /** + * 信息 + */ + @RequestMapping("/{id}") + public R info(@PathVariable("id") Long id){ + SysDictEntity dict = sysDictService.getById(id); + return R.ok(dict); + } + + /** + * 保存 + */ + @PostMapping() + public R save(@RequestBody SysDictEntity dict){ + ValidateUtils.is(dict.getType()).notNull(RCode.SYS_DICT_TYPE_ISNULL); + ValidateUtils.is(dict.getValue()).notNull(RCode.SYS_DICT_VALUE_ISNULL); + sysDictService.saveSysDict(dict); + return R.ok().putData("id", dict.getId()); + } + + /** + * 修改 + */ + @PutMapping() + public R update(@RequestBody SysDictEntity dict){ + //校验类型 + ValidateUtils.is(dict.getType()).notNull(RCode.SYS_DICT_TYPE_ISNULL); + ValidateUtils.is(dict.getValue()).notNull(RCode.SYS_DICT_VALUE_ISNULL); + ValidateUtils.is(dict.getCode()).notNull(RCode.SYS_DICT_CODE_ISNULL); + //字典名称,非必填项,为空后台自动添加value值 + if(StringUtils.isBlank(dict.getName())){ + dict.setName(dict.getValue()); + } + dict.setOperator(getUserId()); + dict.setOpTime(new Date()); + sysDictService.update(dict); + return R.ok().putData("id", dict.getId()); + } + + /** + * 删除 + */ + @DeleteMapping() + public R delete(@RequestParam String ids){ + ValidateUtils.is(ids).notNull(RCode.SYS_DICT_ID_ISNULL); + sysDictService.delete(ids); + return R.ok(); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysI18nController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysI18nController.java new file mode 100644 index 0000000..771c742 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysI18nController.java @@ -0,0 +1,125 @@ +package net.geedge.modules.sys.controller; + +import net.geedge.common.config.I18nConfig; +import net.geedge.common.exception.CNException; +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.smartvalidate.utils.CommonUtil; +import net.geedge.common.utils.*; +import net.geedge.modules.sys.entity.SysI18nEntity; +import net.geedge.modules.sys.service.SysDictService; +import net.geedge.modules.sys.service.SysI18nService; +import net.geedge.modules.sys.shiro.ShiroUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + + +/** + * i18n + * @author song + * @date 2019-08-05 14:35:21 + */ +@RestController +@RequestMapping("sys/i18n") +public class SysI18nController { + + @Autowired + private SysI18nService sysI18nService; + @Autowired + private SysDictService dictService; + @Autowired + private I18nConfig i18nConfig; + + /** + * 列表 + */ + @GetMapping + public R list(@RequestParam Map<String, Object> params){ + PageUtils page = sysI18nService.queryPage(params); + return R.ok(page); + } + + @GetMapping("/{id}") + public R detail(@PathVariable Long id) { + ValidateUtils.is(id).notNull(); + SysI18nEntity byId = sysI18nService.getById(id); + return R.ok(byId); + } + + /** + * 保存 + */ + @PostMapping + public R save(@RequestBody SysI18nEntity sysI18n){ + ValidateUtils.is(sysI18n.getCode()).notNull() + .and(sysI18n.getLang()).notNull() + .and(sysI18n.getValue()).notNull(); + if (!checkLang(sysI18n.getLang())) { //检查lang是否合法 + throw new CNException(RCode.SYS_I18N_NOSUCHLANG); + } + if (sysI18nService.check(sysI18n)) { //检查是否重复,true为重复 + throw new CNException(RCode.SYS_I18N_DUPLICATE); + } else { + sysI18n.setOperator(ShiroUtils.getUserId()); + sysI18n.setOpTime(new Date()); + sysI18nService.save(sysI18n); + //刷新缓存 + i18nConfig.reload(); + return R.ok(); + } + } + + /** + * 修改 + */ + @PutMapping + public R update(@RequestBody SysI18nEntity sysI18n){ + ValidateUtils.is(sysI18n.getCode()).notNull() + .and(sysI18n.getLang()).notNull() + .and(sysI18n.getValue()).notNull() + .and(sysI18n.getId()).notNull(); + if (!checkLang(sysI18n.getLang())) { //检查lang是否合法 + throw new CNException(RCode.SYS_I18N_NOSUCHLANG); + } + if (sysI18nService.check(sysI18n)) { //检查是否重复,true为重复 + throw new CNException(RCode.SYS_I18N_DUPLICATE); + } else { + sysI18n.setOperator(ShiroUtils.getUserId()); + sysI18n.setOpTime(new Date()); + sysI18nService.updateById(sysI18n); + //刷新缓存 + i18nConfig.reload(); + return R.ok(); + } + } + + /** + * 删除 + */ + @DeleteMapping + public R delete(@RequestBody Long[] ids){ + ValidateUtils.is(ids).notNull(); + sysI18nService.removeByIds(Arrays.asList(ids)); + //刷新缓存 + i18nConfig.reload(); + return R.ok(); + } + + /** + * 校验语种是否合法 + * @param lang + * @return true:合法 false:不合法 + */ + private boolean checkLang(String lang) { + if (CommonUtil.isNull(Constant.langList)) { + dictService.updateLangCache(); + } + for (Map<String, String> l : Constant.langList) { + if (l.get("value").equals(lang)) { + return true; + } + } + return false; + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysInfoController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysInfoController.java new file mode 100644 index 0000000..dffffa0 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysInfoController.java @@ -0,0 +1,37 @@ +package net.geedge.modules.sys.controller; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import net.geedge.common.utils.R; +import net.geedge.modules.sys.service.SysInfoService; + +/** + * 系统基本信息 + */ + +@RestController +public class SysInfoController { + + @Autowired + private SysInfoService sysInfoService; + + @GetMapping("/healthy") + public R healthy() { + return R.ok(); + } + + @GetMapping("/about") + public R about() { + Map<?, ?> aboutInfo = sysInfoService.getAboutInfo(); + return R.ok(aboutInfo); + } + + @GetMapping("/buildInfo") + public R getVersionInfo() { + return R.ok(sysInfoService.getGitVersionInfo()); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysLicenseController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysLicenseController.java new file mode 100644 index 0000000..ae4a73f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysLicenseController.java @@ -0,0 +1,190 @@ +package net.geedge.modules.sys.controller; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.security.PrivateKey; +import java.util.TimeZone; + +import javax.servlet.http.HttpServletResponse; + +import cn.hutool.core.exceptions.UtilException; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; +import org.w3c.dom.Document; + +import net.geedge.common.annotation.SysLog; +import net.geedge.common.exception.CNException; +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.OperationEnum; +import net.geedge.common.utils.R; +import net.geedge.common.utils.RCode; +import net.geedge.common.utils.Tool; +import net.geedge.common.utils.TypeEnum; +import net.geedge.modules.sys.entity.LicenseEntity; +import net.geedge.modules.sys.entity.LicenseEntity.Signature; +import net.geedge.modules.sys.service.LicenseService; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.log.Log; + +@RestController +@RequestMapping("/sys/license") +public class SysLicenseController extends AbstractController { + private static final Log log = Log.get(); + + @Autowired + private LicenseService licenseService; + + /** + * 私钥存储路径,gen生成证书时使用 + */ + @Value("${license.privatekey.path:license/license.key}") + private String prikeyPath; + + @Value("${license.fileName:license.xml}") + private String licenseFileName; + + /** + * 获取license + */ + @RequestMapping + @SysLog(operation = OperationEnum.QUERY,type = TypeEnum.LICENSE) + public R getLicense(){ + LicenseEntity licenseEntity = licenseService.getLicenseEntity(); + return R.ok().putData("license", licenseEntity); + } + + /** + * 获取license state + */ + @RequestMapping("/state") + @SysLog(operation = OperationEnum.QUERY,type = TypeEnum.LICENSE) + public R getLicenseState(){ + //获取本机token + String token = licenseService.getLicenseToken(); + R result = R.ok(); + //读取sys_config表中license + try { + LicenseEntity licenseEntity = licenseService.getAndSetLicenseCache(); + licenseService.verify(licenseEntity); + } catch (CNException e) { + int code = e.getCode(); + String msg = e.getMsg(); + result = R.error(code, msg); + } + result.put("token", token); + return result; + } + + /** + * @throws IOException + * 上传license + * @throws + */ + @PostMapping("/upload") + @SysLog(operation = OperationEnum.UPDATE,type = TypeEnum.LICENSE) + public R uploadLicense(@RequestParam("file") MultipartFile file) throws IOException { + ValidateUtils.is(file).notNull(RCode.LICENSE_FILE_IS_NULL); + byte[] bytes = file.getBytes(); + //获取文件内容 + String xml = null; + ByteArrayInputStream stream = null; + try { + stream = Tool.IoUtil.toStream(bytes); + Document document = Tool.XmlUtil.readXML(stream); + xml = Tool.XmlUtil.toStr(document, Constant.DEFAULT_CHARTSET_NAME, false); + } catch (UtilException e) { + logger.error("upload License error", e); + throw new CNException(RCode.ERROR); + } finally { + if(stream != null){ + IOUtils.closeQuietly(stream); + } + } + + //将内容转换为 javabean + LicenseEntity licenseEntity = Tool.LicenseUtil.xmlToLicenseBean(xml); + //校验证书内容是否缺失 + ValidateUtils.is(licenseEntity).notNull(RCode.LICENSE_FILE_IS_EMPTY) + .and(licenseEntity.getSignature()).notNull(RCode.LICENSE_FILE_INVALID) + .and(licenseEntity.getSignature().getSignatureValue()).notNull(RCode.LICENSE_FILE_INVALID); + boolean verifyLicense = Tool.LicenseUtil.verifyLicenseSign(licenseEntity, licenseService.getPublicKey(), licenseService.getSignAlgorithm()); + if(!verifyLicense) { + throw new CNException(RCode.LICENSE_FILE_INVALID); + } + //校验证书是否有效 + licenseService.verify(licenseEntity); + //更新证书 + licenseService.uploadLicenseEntity(licenseEntity); + return R.ok(); + } + + /** + * 下载license + * @throws IOException + * @throws UnsupportedEncodingException + * @throws + */ + @RequestMapping("/download") + public void download(HttpServletResponse response) throws IOException{ + LicenseEntity licenseEntity = licenseService.getLicenseEntity(); + if(licenseEntity == null) { + throw new CNException(RCode.LICENSE_FILE_IS_EMPTY); + } + String licenseXml = Tool.LicenseUtil.licenseBeanToXml(licenseEntity, true); + Tool.ResponseUtil.downloadFile(response, licenseFileName,licenseXml.getBytes(Constant.DEFAULT_CHARTSET_NAME)); + } + + /** + * 生成 license + * @throws IOException + */ + @PostMapping("/gen") + public void genLicense(@RequestBody LicenseEntity license,HttpServletResponse response){ + //验证参数是否为空 + ValidateUtils.is(license).notNull(RCode.LICENSE_PARAM_IS_NULL); + //计算摘要和签名 + File file = Tool.FileUtil.newFile(prikeyPath); + log.debug("pk path : {} ,exist : {}", file.getAbsolutePath(),file.exists()); + InputStream inputStream = null; + try { + inputStream = file.exists() ? Tool.FileUtil.getInputStream(file) : this.getClass().getResourceAsStream(prikeyPath); + DateTime now = Tool.DateUtil.date().setTimeZone(TimeZone.getTimeZone("UTC")); + license.setGenDate(Tool.DateUtil.format(now, DatePattern.UTC_PATTERN)); + //算config + String digestLicense = license.genLicenseDigest(); + PrivateKey privateKey = Tool.PemUtil.readPemPrivateKey(inputStream); + //使用私钥对摘要签名 + String sign = Tool.LicenseUtil.genSign(license, privateKey, licenseService.getSignAlgorithm()); + Signature signature = license.newSignature(); + signature.setDigestValue(digestLicense); + signature.setSignatureValue(sign); + //保存签名信息 + license.setSignature(signature); + + //转为xml + String xmlStr = Tool.LicenseUtil.licenseBeanToXml(license, true); + //下载文件 + Tool.ResponseUtil.downloadFile(response, licenseFileName, Tool.StrUtil.bytes(xmlStr,Constant.DEFAULT_CHARTSET_NAME)); + } catch (IOException e) { + logger.error("generate License error", e); + throw new CNException(RCode.ERROR); + } finally { + if(inputStream != null){ + IOUtils.closeQuietly(inputStream); + } + } + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysLogController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysLogController.java new file mode 100644 index 0000000..498a8fe --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysLogController.java @@ -0,0 +1,36 @@ +package net.geedge.modules.sys.controller; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.R; +import net.geedge.modules.sys.service.SysLogService; + + +/** + * 系统日志 + * + + */ +@RestController +@RequestMapping("/sys/log") +public class SysLogController { + @Autowired + private SysLogService sysLogService; + + /** + * 列表 + */ + @GetMapping + public R list(@RequestParam Map<String, Object> params){ + PageUtils page = sysLogService.queryPage(params); + return R.ok(page); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysLoginController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysLoginController.java new file mode 100644 index 0000000..bbfce6f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysLoginController.java @@ -0,0 +1,159 @@ +package net.geedge.modules.sys.controller; + + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.imageio.ImageIO; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.IncorrectCredentialsException; +import org.apache.shiro.authc.LockedAccountException; +import org.apache.shiro.authc.UnknownAccountException; +import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.subject.Subject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Controller; +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.ResponseBody; + +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.google.code.kaptcha.Constants; +import com.google.code.kaptcha.Producer; + +import cn.hutool.core.util.StrUtil; +import net.geedge.common.annotation.SysLog; +import net.geedge.common.exception.CNException; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.HttpContextUtils; +import net.geedge.common.utils.IPUtils; +import net.geedge.common.utils.OperationEnum; +import net.geedge.common.utils.R; +import net.geedge.common.utils.RCode; +import net.geedge.common.utils.Tool; +import net.geedge.common.utils.TypeEnum; +import net.geedge.modules.sys.entity.SysConfigEntity; +import net.geedge.modules.sys.entity.SysUserEntity; +import net.geedge.modules.sys.entity.Timezone; +import net.geedge.modules.sys.service.SysConfigService; +import net.geedge.modules.sys.service.SysUserService; +import net.geedge.modules.sys.service.TimezoneService; +import net.geedge.modules.sys.shiro.ShiroUtils; + +/** + * 登录相关 + * + + */ +@Controller +public class SysLoginController extends AbstractController { + @Autowired + private Producer producer; + @Autowired + private RedisTemplate<String,String> redisTemplate; + @Autowired + private SysConfigService configService; + @Autowired + private SysUserService sysUserService; + + @Autowired + private TimezoneService timezoneService; + + @RequestMapping("captcha.jpg") + public void captcha(HttpServletResponse response)throws IOException { + response.setHeader("Cache-Control", "no-store, no-cache"); + response.setContentType("image/jpeg"); + + //生成文字验证码 + String text = producer.createText(); + //生成图片验证码 + BufferedImage image = producer.createImage(text); + //保存到shiro session + ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text); + + ServletOutputStream out = response.getOutputStream(); + ImageIO.write(image, "jpg", out); + } + + /** + * 登录 + */ + @ResponseBody + @RequestMapping(value = "/sys/login", method = RequestMethod.POST) + @SysLog(operation = OperationEnum.LOGIN,type = TypeEnum.SYSTEM) + public R login(@RequestBody SysUserEntity sysUser) { + String username = sysUser.getUsername(); + String pin = StrUtil.str(sysUser.getPin()); + try{ + Subject subject = ShiroUtils.getSubject(); + UsernamePasswordToken token = new UsernamePasswordToken(username, pin); + subject.login(token); //登录 + String loginToken= Tool.IdUtil.simpleUUID(); + subject.getSession().setAttribute("token",loginToken); + Map<String, Object> obj = new HashMap<>(); + obj.put("token", subject.getSession().getId().toString()); + // 查询系统配置信息 + String[] paramkeys = {"system_name", "system_logo", "timezone", "default_cabinet_usize", "map_center_config", "unsaved_change","prometheus_federation_enabled"}; + List<SysConfigEntity> configEntityList = configService.list(new LambdaUpdateWrapper<SysConfigEntity>().in(SysConfigEntity::getParamKey, paramkeys)); + for (SysConfigEntity configEntity : configEntityList) { + if ("timezone".equals(configEntity.getParamKey())) { + Timezone timezoneEntity = timezoneService.getOne(new LambdaUpdateWrapper<Timezone>().eq(Timezone::getName, configEntity.getParamValue())); + obj.put("offset", timezoneEntity.getOffset()); + } + obj.put(Tool.StrUtil.toCamelCase(configEntity.getParamKey()), configEntity.getParamValue()); + } + + // 获取request + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + SysUserEntity userEntity = ShiroUtils.getUserEntity(); + userEntity.setLastLoginTime(new Date()); + // 设置IP地址 + userEntity.setLastLoginIp(IPUtils.getIpAddr(request)); + sysUserService.updateById(userEntity); + return R.ok(obj); + }catch (UnknownAccountException e) { + throw new CNException(RCode.SYS_LOGIN_UNKNOWNACCOUNT); + }catch (IncorrectCredentialsException e) { + throw new CNException(RCode.SYS_LOGIN_USERPWD); + }catch (LockedAccountException e) { + throw new CNException(RCode.SYS_LOGIN_LOCK); + }catch (AuthenticationException e) { + throw new CNException(RCode.SYS_LOGIN_ACCOUNTAUTH); + } + } + + + /** + * 退出 + */ + @RequestMapping(value = "logout", method = RequestMethod.GET) + @ResponseBody + @SysLog(operation = OperationEnum.LOGOUT,type = TypeEnum.SYSTEM) + public R logout(HttpServletRequest request) { + ShiroUtils.logout(); + String requestToken=request.getHeader(Constant.AUTH_TOKEN_CODE); + if(StringUtils.isBlank(requestToken)){ + requestToken=request.getParameter(Constant.AUTH_TOKEN_CODE); + } + try { + redisTemplate.delete(requestToken); + }catch (RuntimeException e){ + logger.debug("登出操作删除redis信息失败,失败key:{}",requestToken); + } + + + return R.ok(); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysMenuController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysMenuController.java new file mode 100644 index 0000000..0ce386e --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysMenuController.java @@ -0,0 +1,73 @@ +package net.geedge.modules.sys.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.R; +import net.geedge.common.utils.RCode; +import net.geedge.modules.sys.entity.SysMenuEntity; +import net.geedge.modules.sys.service.SysMenuService; + +@RestController +@RequestMapping("/sys/menu") +public class SysMenuController extends AbstractController { + + @Autowired + private SysMenuService sysMenuService; + + /** + * 所有菜单列表 + * @param id + * @return + */ + @GetMapping + public R list(Integer id) { + List<SysMenuEntity> menuList = sysMenuService.getMenuList(id); + return R.ok().putData("list", menuList); + } + + /** + * 保存 + * @param menu + * @return + */ + @PostMapping + public R save(@RequestBody SysMenuEntity menu) { + sysMenuService.saveMenu(menu); + return R.ok().put("id", menu.getId()); + } + + /** + * 修改 + * @param menu + * @return + */ + @PutMapping + public R update(@RequestBody SysMenuEntity menu) { + ValidateUtils.is(menu.getId()).notNull(RCode.SYS_MENU_ID_ISNULL); + sysMenuService.updateMenu(menu); + return R.ok().put("id", menu.getId()); + } + + /** + * 删除 + * @param ids + * @return + */ + @DeleteMapping + public R delete(@RequestParam Integer... ids) { + ValidateUtils.is(ids).notNull(RCode.SYS_MENU_ID_ISNULL); + sysMenuService.delete(ids); + return R.ok(); + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysPageController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysPageController.java new file mode 100644 index 0000000..9144431 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysPageController.java @@ -0,0 +1,53 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * 系统页面视图 + * + + */ +@Controller +public class SysPageController { + + @RequestMapping("modules/{module}/{url}.html") + public String module(@PathVariable("module") String module, @PathVariable("url") String url){ + return "modules/" + module + "/" + url; + } + + /*@RequestMapping(value = {"/", "index.html"}) + public String index(){ + return "index"; + }*/ + + @RequestMapping("index1.html") + public String index1(){ + return "index1"; + } + + @RequestMapping("login.html") + public String login(){ + return "login"; + } + + @RequestMapping("main.html") + public String main(){ + return "main"; + } + + @RequestMapping("404.html") + public String notFound(){ + return "404"; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysRoleController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysRoleController.java new file mode 100644 index 0000000..7ca25e8 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysRoleController.java @@ -0,0 +1,103 @@ +package net.geedge.modules.sys.controller; + +import java.util.Map; + +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import net.geedge.common.annotation.SysLog; +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.OperationEnum; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.R; +import net.geedge.common.utils.RCode; +import net.geedge.common.utils.TypeEnum; +import net.geedge.modules.sys.entity.SysRoleEntity; +import net.geedge.modules.sys.service.SysRoleService; + +/** + * 角色管理 + */ +@RestController +@RequestMapping("/sys/role") +public class SysRoleController extends AbstractController { + + @Autowired + private SysRoleService sysRoleService; + + /** + * 角色列表查询 + * @param params + * @return + */ + @GetMapping + @SysLog(operation = OperationEnum.QUERY,type = TypeEnum.SYSTEM) + public R list(@RequestParam Map<String, Object> params){ + PageUtils page = sysRoleService.queryPage(params); + return R.ok(page); + } + + /** + * 角色菜单查询 + * @param roleId + * @return + */ + @GetMapping("/menu/{id}") + @SysLog(operation = OperationEnum.QUERY,type = TypeEnum.SYSTEM) + public R list(@PathVariable("id") Integer roleId) { + ValidateUtils.is(roleId).notNull(RCode.SYS_ROLE_ID_ISNULL); + return R.ok(sysRoleService.getMenuListByRoleId(roleId)); + } + + + /** + * 角色保存 + * @param role + * @return + */ + @PostMapping + @SysLog(operation = OperationEnum.ADD,type = TypeEnum.SYSTEM) + @RequiresPermissions("sys:role:save") + public R save(@RequestBody SysRoleEntity role){ + sysRoleService.saveRole(role); + return R.ok().put("id", role.getId()); + } + + /** + * 修改角色 + * @param role + * @return + */ + @PutMapping + @SysLog(operation = OperationEnum.UPDATE,type = TypeEnum.SYSTEM) + @RequiresPermissions("sys:role:update") + public R update(@RequestBody SysRoleEntity role){ + ValidateUtils.is(role.getId()).notNull(RCode.SYS_ROLE_ID_ISNULL); + sysRoleService.update(role); + return R.ok().put("id", role.getId()); + } + + /** + * 删除角色 + * @param ids + * @return + */ + @DeleteMapping + @SysLog(operation = OperationEnum.DELETE,type = TypeEnum.SYSTEM) + @RequiresPermissions("sys:role:delete") + public R delete(@RequestParam Integer... ids) { + ValidateUtils.is(ids).notNull(RCode.SYS_ROLE_ID_ISNULL); + + sysRoleService.deleteBatch(ids); + return R.ok(); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysUserController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysUserController.java new file mode 100644 index 0000000..64208ea --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/SysUserController.java @@ -0,0 +1,123 @@ +package net.geedge.modules.sys.controller; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import net.geedge.common.annotation.SysLog; +import net.geedge.common.exception.CNException; +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.OperationEnum; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.R; +import net.geedge.common.utils.RCode; +import net.geedge.common.utils.TypeEnum; +import net.geedge.modules.sys.entity.SysUserEntity; +import net.geedge.modules.sys.service.SysUserService; +import net.geedge.modules.sys.shiro.ShiroUtils; + +@RestController +@RequestMapping("/sys/user") +public class SysUserController extends AbstractController { + + @Autowired + private SysUserService sysUserService; + + /** + * 所有用户列表 + */ + @RequestMapping + @SysLog(operation = OperationEnum.QUERY,type = TypeEnum.ACCOUNT) + public R list(@RequestParam Map<String, Object> params){ + PageUtils page = sysUserService.queryPage(params); + return R.ok(page); + } + + /** + * 修改登录用户密码 + */ + @PutMapping("/pin") + public R password(@RequestBody Map<String,Object> params){ + Long id = (Long)params.getOrDefault("id", this.getUserId()); + String oldPin = (String)params.get("oldPin"); + String newPin = (String)params.get("newPin"); + SysUserEntity user = sysUserService.getById(id); + //原密码 + oldPin = ShiroUtils.sha256(oldPin, user.getSalt()); + //新密码 + newPin = ShiroUtils.sha256(newPin, user.getSalt()); + //更新密码 + boolean flag = sysUserService.updatePassword(id, oldPin, newPin); + if(!flag){ + throw new CNException(RCode.SYS_USER_OLDPWD); + } + return R.ok(); + } + + /** + * 用户信息 + */ + @GetMapping("/{id}") + public R info(@PathVariable("id") Long id){ + ValidateUtils.is(id).notNull(RCode.SYS_USER_ID_ISNULL); + SysUserEntity user = sysUserService.queryUserInfo(id); + return R.ok().put("user", user); + } + + /** + * 保存用户 + */ + @PostMapping + @SysLog(operation = OperationEnum.ADD,type = TypeEnum.ACCOUNT) + @RequiresPermissions("sys:user:save") + public R save(@RequestBody SysUserEntity user){ + Integer id = sysUserService.saveUser(user); + return R.ok().putData("id", id); + } + + /** + * 修改用户 + */ + @PutMapping + @SysLog(operation = OperationEnum.UPDATE,type = TypeEnum.ACCOUNT) + @RequiresPermissions("sys:user:update") + public R update(@RequestBody SysUserEntity user){ + ValidateUtils.is(user).notNull(RCode.SYS_USER_ID_ISNULL) + .and(user.getId()).notNull(RCode.SYS_USER_ID_ISNULL); + Integer id = sysUserService.update(user); + return R.ok().putData("id", id); + } + + /** + * 删除用户 + */ + @DeleteMapping + @SysLog(operation = OperationEnum.DELETE,type = TypeEnum.ACCOUNT) + @RequiresPermissions("sys:user:delete") + public R delete(String ids) { + sysUserService.deleteUsers(ids); + return R.ok(); + } + + /** + * 用户权限查询接口 + * @param request + * @return + */ + @PostMapping("/permissions") + public R permissions(HttpServletRequest request){ + return R.ok(sysUserService.getUserPermissions(request)); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/controller/TimezoneController.java b/cn-admin/src/main/java/net/geedge/modules/sys/controller/TimezoneController.java new file mode 100644 index 0000000..9b46d51 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/controller/TimezoneController.java @@ -0,0 +1,26 @@ +package net.geedge.modules.sys.controller; + +import net.geedge.common.utils.R; +import net.geedge.modules.sys.entity.Timezone; +import net.geedge.modules.sys.service.TimezoneService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("sys/timezone") +public class TimezoneController { + + @Autowired + private TimezoneService timezoneService; + + @GetMapping + public R timezone(@RequestParam(required = false) String name){ + List<Timezone> list = timezoneService.queryTimezone(name); + return R.ok().putData("list",list); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/LinkDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/LinkDao.java new file mode 100644 index 0000000..e5701c9 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/LinkDao.java @@ -0,0 +1,15 @@ +package net.geedge.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.geedge.modules.sys.entity.Link; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface LinkDao extends BaseMapper<Link>{ + + List<Link> queryList(@Param("params") Map<String, Object> params); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysApiKeyDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysApiKeyDao.java new file mode 100644 index 0000000..ee58e17 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysApiKeyDao.java @@ -0,0 +1,18 @@ +package net.geedge.modules.sys.dao; + +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import net.geedge.modules.sys.entity.SysApiKey; + +@Mapper +public interface SysApiKeyDao extends BaseMapper<SysApiKey>{ + + List<SysApiKey> queryList(IPage page,@Param("params") Map<String, Object> params); + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysConfigDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysConfigDao.java new file mode 100644 index 0000000..df23751 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysConfigDao.java @@ -0,0 +1,44 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.dao; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.geedge.modules.sys.entity.SysConfigEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + * 系统配置信息 + * + + */ +@Mapper +public interface SysConfigDao extends BaseMapper<SysConfigEntity> { + + /** + * 根据key,查询value + */ + SysConfigEntity queryByKey(String paramKey); + + /** + * 根据key,更新value + */ + int updateValueByKey(@Param("paramKey") String paramKey, @Param("paramValue") String paramValue); + + /** + * 系统重置删除用户输入的内容 + * @param tableName + */ + void clearData(@Param("sql") String sql); + + @Select("SELECT version();") + String getDataBasesVersion(); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysDictDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysDictDao.java new file mode 100644 index 0000000..890131b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysDictDao.java @@ -0,0 +1,33 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import net.geedge.modules.sys.entity.SysDictEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 数据字典 + * + + */ +@Mapper +public interface SysDictDao extends BaseMapper<SysDictEntity> { + List<SysDictEntity> queryNodeImgList(); + + List<SysDictEntity> querySysDictListWithPage(IPage<SysDictEntity> page, @Param("params")Map<String, Object> params); + List<SysDictEntity> querySysDictList(@Param("params")Map<String, Object> params); + + Integer getMaxTypeCode(@Param("type")String type); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysI18nDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysI18nDao.java new file mode 100644 index 0000000..ef1e191 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysI18nDao.java @@ -0,0 +1,17 @@ +package net.geedge.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.geedge.modules.sys.entity.SysI18nEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * i18n信息表 + * + * @author song + * @email + * @date 2019-08-05 14:35:21 + */ +@Mapper +public interface SysI18nDao extends BaseMapper<SysI18nEntity> { + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysLogDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysLogDao.java new file mode 100644 index 0000000..743e73a --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysLogDao.java @@ -0,0 +1,30 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.dao; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import net.geedge.modules.sys.entity.SysLogEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 系统日志 + * + + */ +@Mapper +public interface SysLogDao extends BaseMapper<SysLogEntity> { + + List<SysLogEntity> queryList(IPage page, @Param("params") Map<String, Object> params); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysMenuDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysMenuDao.java new file mode 100644 index 0000000..aed5bc2 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysMenuDao.java @@ -0,0 +1,17 @@ +package net.geedge.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.geedge.modules.sys.entity.SysMenuEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface SysMenuDao extends BaseMapper<SysMenuEntity> { + + /** + * 根据角色获取 菜单列表 + */ + List<SysMenuEntity> getRoleMenuList(@Param("roleId") Integer roleId); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysRoleDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysRoleDao.java new file mode 100644 index 0000000..014ea8b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysRoleDao.java @@ -0,0 +1,16 @@ +package net.geedge.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.geedge.modules.sys.entity.SysRoleEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface SysRoleDao extends BaseMapper<SysRoleEntity> { + + List<SysRoleEntity> getRolesByUesrId(@Param("userId") Integer userId); + + List<SysRoleEntity> getRolesBySysApiKeyId(@Param("sysApiKeyId") Integer sysApiKeyId); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysRoleMenuDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysRoleMenuDao.java new file mode 100644 index 0000000..d0e09a8 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysRoleMenuDao.java @@ -0,0 +1,24 @@ +package net.geedge.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.geedge.modules.sys.entity.SysRoleMenuEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 角色与菜单对应关系 + */ +@Mapper +public interface SysRoleMenuDao extends BaseMapper<SysRoleMenuEntity> { + + /** + * 根据角色ID,获取菜单ID列表 + */ + List<Integer> queryMenuIdList(Integer roleId); + + /** + * 根据角色ID数组,批量删除 + */ + int deleteBatch(Integer[] roleIds); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysUserDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysUserDao.java new file mode 100644 index 0000000..9d8ca10 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysUserDao.java @@ -0,0 +1,38 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import net.geedge.modules.sys.entity.SysUserEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 系统用户 + * + + */ +@Mapper +public interface SysUserDao extends BaseMapper<SysUserEntity> { + + /** + * 查询用户的所有菜单ID + */ + List<Long> queryAllMenuId(Long userId); + + + List<SysUserEntity> queryList(IPage page, @Param("params") Map<String, Object> params); + + // 根据角色ID 获取所属用户 + List<SysUserEntity> getUserListByRoleId(@Param("roleId") Integer roleId); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysUserRoleDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysUserRoleDao.java new file mode 100644 index 0000000..1f06ce8 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/SysUserRoleDao.java @@ -0,0 +1,34 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.geedge.modules.sys.entity.SysUserRoleEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 用户与角色对应关系 + * + + */ +@Mapper +public interface SysUserRoleDao extends BaseMapper<SysUserRoleEntity> { + + /** + * 根据用户ID,获取角色ID列表 + */ + List<Integer> queryRoleIdList(Integer userId); + + /** + * 根据角色ID数组,批量删除 + */ + int deleteBatch(Integer[] roleIds); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/dao/TimezoneDao.java b/cn-admin/src/main/java/net/geedge/modules/sys/dao/TimezoneDao.java new file mode 100644 index 0000000..90f4cad --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/dao/TimezoneDao.java @@ -0,0 +1,9 @@ +package net.geedge.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.geedge.modules.sys.entity.Timezone; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TimezoneDao extends BaseMapper<Timezone> { +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/LicenseEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/LicenseEntity.java new file mode 100644 index 0000000..12b4f75 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/LicenseEntity.java @@ -0,0 +1,119 @@ +package net.geedge.modules.sys.entity; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Date; + +import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonIgnore; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.Tool; + +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.crypto.asymmetric.SignAlgorithm; +import lombok.Data; +/** + * license证书实体 + * @author fang + * + */ +@Data +public class LicenseEntity implements Serializable,Cloneable{ + + private static final long serialVersionUID = 4633547881083628433L; + @JSONField(ordinal=1) + private String licenseId; + @JSONField(ordinal=2) + private String customer; + @JSONField(ordinal=3) + private String contract; + @JSONField(ordinal=4) + private String by; + @JSONField(ordinal=5) + private String genDate; + @JSONField(ordinal=6) + private String startDate; + @JSONField(ordinal=7) + private String endDate; + @JSONField(ordinal=8) + private String comment; + @JSONField(ordinal=9) + private Tokens tokens; + @JSONField(ordinal=10) + private Product product; + @JSONField(ordinal=11) + private Signature signature; + + @Data + public class Tokens implements Serializable,Cloneable{ + /** + * + */ + private static final long serialVersionUID = 4812749370562684544L; + @JSONField(ordinal=1) + private String[] token; + } + + @Data + public class Product implements Serializable,Cloneable{ + /** + * + */ + private static final long serialVersionUID = -2658149618046598534L; + @JSONField(ordinal=1) + private String name; + @JSONField(ordinal=2) + private String version; + @JSONField(ordinal=3) + private Integer maximumAssets; + } + + @Data + public class Signature implements Serializable,Cloneable{ + /** + * + */ + private static final long serialVersionUID = -2293105833290860463L; + @JSONField(ordinal=1) + private String digestValue; + @JSONField(ordinal=2) + private String signatureValue; + } + + /** + * 返回不包含 Signature + * @return + */ + public LicenseEntity genConfig() { + LicenseEntity clone = Tool.ObjectUtil.clone(this); + clone.setSignature(null); + return clone; + } + /** + * 获取 config string ,用于计算摘要 + * @return + */ + public String genConfigStr() { + LicenseEntity config = this.genConfig(); + return config.toString(); + } + + /** + * 计算config 摘要 + * @return + */ + public String genLicenseDigest() { + String configStr = this.genConfigStr(); + return SecureUtil.sha1(configStr); + } + + + @JSONField(serialize=false) + public Signature newSignature() { + return new Signature(); + } + +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/Link.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/Link.java new file mode 100644 index 0000000..a421c68 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/Link.java @@ -0,0 +1,23 @@ +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +@Data +@TableName("link") +public class Link implements Serializable{ + @TableId + private Integer id; + private String name; + private Long createBy; + private String url; + private Integer buildIn; + private Integer weight; + + @TableField(exist = false) + private SysUserEntity creator; +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysApiKey.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysApiKey.java new file mode 100644 index 0000000..2e16b0f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysApiKey.java @@ -0,0 +1,33 @@ +package net.geedge.modules.sys.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +@Data +@TableName("sys_api_key") +public class SysApiKey { + + private Integer id; + + private String name; + + private String token; + + private Integer roleId; + + private Integer createBy; + + private Date createAt; + + private Date expireAt; + + @TableField(exist = false) + private SysUserEntity createUser; + + @TableField(exist = false) + private SysRoleEntity role; +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysConfigEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysConfigEntity.java new file mode 100644 index 0000000..7ec868c --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysConfigEntity.java @@ -0,0 +1,34 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 系统配置信息 + * + + */ +@Data +@TableName("sys_config") +public class SysConfigEntity { + @TableId + private Long id; + @NotBlank(message="参数名不能为空") + private String paramKey; + @NotBlank(message="参数值不能为空") + private String paramValue; + private String status; + private String remark; + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysDictEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysDictEntity.java new file mode 100644 index 0000000..74f9831 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysDictEntity.java @@ -0,0 +1,92 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.Date; + +/** + * 数据字典 + * + + */ +@Data +@TableName("sys_dict") +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SysDictEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId + private Long id; + /** + * 字典名称 + */ + @NotBlank(message="字典名称不能为空") + private String name; + /** + * 字典类型 + */ + @NotBlank(message="字典类型不能为空") + private String type; + /** + * 字典码 + */ + @NotBlank(message="字典码不能为空") + private Integer code; + /** + * 字典值 + */ + @NotBlank(message="字典值不能为空") + private String value; + /** + * 排序 + */ + private Integer orderNum; + /** + * 备注 + */ + private String remark; + /** + * 删除标记 -1:已删除 0:正常 + */ + @TableLogic + private Integer delFlag; + + /** + * 操作人 + */ + private Long operator; + + /** + * 操作时间 + */ + private Date opTime; + + /** + * 国际化code + */ + private String i18nCode; + + /** + * 用于撤销具体某次批量导入的uuid + */ + private String seq; + + @TableField(exist = false) + private SysUserEntity operatorUser; + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysI18nEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysI18nEntity.java new file mode 100644 index 0000000..a86c47c --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysI18nEntity.java @@ -0,0 +1,58 @@ +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * i18n信息表 + * + * @author song + * @email + * @date 2019-08-05 14:35:21 + */ +@Data +@TableName("sys_i18n") +@KeySequence(value="seq_sys_i18n") +public class SysI18nEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(type=IdType.INPUT) + private Long id; + /** + * i18n code + */ + private String code; + /** + * 语言 + */ + private String lang; + /** + * 翻译值 + */ + private String value; + /** + * 备注信息 + */ + private String remark; + /** + * 操作人 + */ + @JsonIgnore + private Long operator; + /** + * 操作时间 + */ + @JsonIgnore + private Date opTime; + @JsonIgnore + @TableLogic + private String delFlag; + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysLogEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysLogEntity.java new file mode 100644 index 0000000..753d8d4 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysLogEntity.java @@ -0,0 +1,85 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + + +/** + * 系统日志 + * + + */ +@Data +@TableName("sys_log") +public class SysLogEntity implements Serializable { + private static final long serialVersionUID = 1L; + @TableId + private Long id; + /** + * 用户名 + */ + private Integer userId; + + @TableField(exist = false) + private String username; + /** + * 用户操作 + */ + private String operation; + /** + * 请求方法 + */ + private String method; + /** + * 请求参数 + */ + private String params; + /** + * 执行时长(毫秒) + */ + private Long time; + /** + * IP地址 + */ + private String ip; + /** + *类型 + */ + private String type; + /** + * + */ + private String operaId; + /** + * + */ + private String state; + private String response; + /** + * + */ + private String exception; + + /** + * 创建时间 + */ + private Date createDate; + + @TableField(exist = false) + private SysApiKey apiKey; + + private Integer apiKeyId; +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysMenuEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysMenuEntity.java new file mode 100644 index 0000000..e4d4d5f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysMenuEntity.java @@ -0,0 +1,55 @@ +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +@TableName("sys_menu") +public class SysMenuEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId + private Integer id; + + private String name; + + // 前端使用 唯一标识 标记按钮或者菜单 + private String code; + + private String i18n; + + @TableField(strategy = FieldStrategy.IGNORED) + private Integer parentId; + + // 后端使用 shiro 权限管理 多个用逗号分隔 + private String perms; + + // 类型 1:菜单 2:按钮 + private Integer type; + + // 路由 + private String route; + + // 排序 默认:1 + private Integer orderNum; + + /** + * 图标 + */ + private String icon; + + /** + * 必要权限,如编辑按钮需要 勾选查看权限 + * 填写内容为 sys_menu.id,多个逗号分隔 + */ + private String required; + + @TableField(exist = false) + private List<SysMenuEntity> children; +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysRoleEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysRoleEntity.java new file mode 100644 index 0000000..e1bf4a9 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysRoleEntity.java @@ -0,0 +1,31 @@ +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +@TableName("sys_role") +public class SysRoleEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId + private Integer id; + + private String name; + + private String i18n; + + @TableField(strategy = FieldStrategy.IGNORED) + private String remark; + + private Integer buildIn; + + @TableField(exist = false) + private List<Integer> menuIds; +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysRoleMenuEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysRoleMenuEntity.java new file mode 100644 index 0000000..b22eb63 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysRoleMenuEntity.java @@ -0,0 +1,35 @@ +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +@Data +@TableName("sys_role_menu") +public class SysRoleMenuEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId + private Integer id; + + /** + * 角色ID + */ + private Integer roleId; + + /** + * 菜单ID + */ + private Integer menuId; + + public SysRoleMenuEntity(Integer id, Integer roleId, Integer menuId) { + this.id = id; + this.roleId = roleId; + this.menuId = menuId; + } + + public SysRoleMenuEntity() { + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysUserEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysUserEntity.java new file mode 100644 index 0000000..27fddc0 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysUserEntity.java @@ -0,0 +1,109 @@ +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonProperty; +import net.geedge.common.validator.group.AddGroup; +import net.geedge.common.validator.group.UpdateGroup; +import lombok.Data; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 系统用户 + */ +@Data +@TableName("sys_user") +public class SysUserEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @TableId + private Long id; + + /** + * 用户名 + */ + @NotBlank(message="登录用户名不能为空", groups = {AddGroup.class, UpdateGroup.class}) + private String username; + + /** + * 密码 + */ + @NotBlank(message="密码不能为空", groups = AddGroup.class) + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String pin; + + /** + * 盐 + */ + private String salt; + + /** + * 邮箱 + */ + @NotBlank(message="邮箱不能为空", groups = {AddGroup.class, UpdateGroup.class}) + @Email(message="邮箱格式不正确", groups = {AddGroup.class, UpdateGroup.class}) + private String email; + + /** + * 状态 0:禁用 1:正常 + */ + private Integer status; + + /** + * 语言 + */ + private String lang; + + /** + * 角色ID列表 + */ + @TableField(exist = false) + private String roleIds; + + /** + * 用户组ID列表 + */ + @TableField(exist=false) + private List<Long> usergroupIds; + + private String mobile; + + /** + * 创建时间 + */ + private Date createAt; + + private Integer createBy; + + private String name; + + /** + * 来源 + */ + private String source; + + private String lastLoginIp; + + private Date lastLoginTime; + + /** + * 用户关联角色列表 + */ + @TableField(exist = false) + private List<SysRoleEntity> roles; + + @TableField(exist = false) + private String userName; + + @TableField(exist = false) + private Integer apiKeyId; +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysUserRoleEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysUserRoleEntity.java new file mode 100644 index 0000000..9ec148f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SysUserRoleEntity.java @@ -0,0 +1,26 @@ +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +@Data +@TableName("sys_user_role") +public class SysUserRoleEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId + private Integer id; + + /** + * 用户ID + */ + private Integer userId; + + /** + * 角色ID + */ + private Integer roleId; +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/SystemUsergroupEntity.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SystemUsergroupEntity.java new file mode 100644 index 0000000..c2c451f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/SystemUsergroupEntity.java @@ -0,0 +1,61 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 系统用户 + * + + */ +@Data +@TableName("system_usergroup_rel") +@KeySequence(value="seq_system_usergroup_rel") +public class SystemUsergroupEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(type=IdType.INPUT) + private Long id; + + /** + * 业务系统ID + */ + private Long systemId; + + /** + * 用户组ID + */ + private Long usergroupId; + + /** + * 删除标识,1:删除,0:未删除 + */ + private String delFlag; + + /** + * 操作人 + */ + private Long operator; + + /** + * 操作时间 + */ + private Date opTime; +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/entity/Timezone.java b/cn-admin/src/main/java/net/geedge/modules/sys/entity/Timezone.java new file mode 100644 index 0000000..7ee2739 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/entity/Timezone.java @@ -0,0 +1,15 @@ +package net.geedge.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("sys_timezone") +public class Timezone { + @TableId + private Integer id; + private String name; + private Integer offset; + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/job/SessionTimeOutJob.java b/cn-admin/src/main/java/net/geedge/modules/sys/job/SessionTimeOutJob.java new file mode 100644 index 0000000..8b4746e --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/job/SessionTimeOutJob.java @@ -0,0 +1,58 @@ +package net.geedge.modules.sys.job; + +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import cn.hutool.log.Log; + +@DisallowConcurrentExecution +public class SessionTimeOutJob extends QuartzJobBean { + + private Log log = Log.get(); + + + @SuppressWarnings("unchecked") + @Override + protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException { + /*// 获取redis中所有的token信息 + Map<String, SysUserEntity> shiroSessionInfoMap = ShiroUtils.getShiroSessionInfoMap(); + + // 获取所有登录用户的信息 + List<SysUserEntity> users = new ArrayList<SysUserEntity>(shiroSessionInfoMap.values()); + List<Long> onlineUserIds = users.stream().map(SysUserEntity::getId).collect(Collectors.toList()); + + // 获取terminal session表中所有正在连接的用户信息 + List<TerminalSessionEntity> tableSessions = terminalSessionService.list(new QueryWrapper<TerminalSessionEntity>().lambda().eq(TerminalSessionEntity::getStatus, 0)); + List<Long> allUserTerminals = tableSessions.stream().map(TerminalSessionEntity::getUserId).collect(Collectors.toList()); + Map<Long, List<TerminalSessionEntity>> userIdAndTerminal = tableSessions.stream().collect(Collectors.groupingBy(TerminalSessionEntity::getUserId)); + + List<Long> removeUserIds = allUserTerminals.stream().filter(item -> !onlineUserIds.contains(item)).collect(Collectors.toList()); + + List<TerminalSessionEntity> updateDatas = new ArrayList<TerminalSessionEntity>(); + // 将登录超时的用户terminal连接关闭 + for(Long userId : removeUserIds) { + List<TerminalSessionEntity> userTerminals = userIdAndTerminal.get(userId); + for(TerminalSessionEntity userTerminal : userTerminals) { + userTerminal.setEndTime(new Date()); + userTerminal.setStatus(Constants.SessionStatus.FORCE_QUIT.getValue()); + updateDatas.add(userTerminal); + WebSocketSession session = TerminalSession.findSession(userTerminal.getUuid()); + try { + TerminalSession.remove(session); + // TerminalHandler.unloginUserHandle(session); + StringBuilder sb = new StringBuilder(); + sb.append("\u001B[01;31m\u001B[K Administrator disconnected \u001B[m\u001B[K \r\n"); + sb.append("$: "); + session.sendMessage(new TextMessage(sb.toString())); + } catch (IOException e) { + log.error(String.format("terminal session kill failed,uuid = %s,错误信息 = %s", userTerminal.getUuid(), e.getMessage()), e); + } + // kill 之后,将剩余文件写到数据库中 + TerminalHandler.handleRecodeAfterClientClose(userTerminal.getUuid(), terminalRecordService); + } + } */ + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/redis/SysConfigRedis.java b/cn-admin/src/main/java/net/geedge/modules/sys/redis/SysConfigRedis.java new file mode 100644 index 0000000..76d67de --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/redis/SysConfigRedis.java @@ -0,0 +1,45 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.redis; + + +import net.geedge.common.utils.RedisKeys; +import net.geedge.common.utils.RedisUtils; +import net.geedge.modules.sys.entity.SysConfigEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 系统配置Redis + * + + */ +@Component +public class SysConfigRedis { + @Autowired + private RedisUtils redisUtils; + + public void saveOrUpdate(SysConfigEntity config) { + if(config == null){ + return ; + } + String key = RedisKeys.getSysConfigKey(config.getParamKey()); + redisUtils.set(key, config); + } + + public void delete(String configKey) { + String key = RedisKeys.getSysConfigKey(configKey); + redisUtils.delete(key); + } + + public SysConfigEntity get(String configKey){ + String key = RedisKeys.getSysConfigKey(configKey); + return redisUtils.get(key, SysConfigEntity.class); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/LicenseService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/LicenseService.java new file mode 100644 index 0000000..04cfe5f --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/LicenseService.java @@ -0,0 +1,56 @@ +package net.geedge.modules.sys.service; + +import java.io.IOException; +import java.security.PublicKey; + +import net.geedge.modules.sys.entity.LicenseEntity; + +public interface LicenseService { + + /** + * 获取token 首先尝试获取 硬件token 硬件token获取失败从数据库读取 数据库不存在 通过uuid 生成,保存到数据库 + * + * @param key + * @return + */ + String getLicenseToken(); + + /** + * 获取 license + * + * @return + */ + LicenseEntity getLicenseEntity(); + + /** + * 更新 license + */ + void uploadLicenseEntity(LicenseEntity license); + + /** + * 获取系统版本 + * + * @return + */ + String getSystemVersion(); + + /** + * 验证license 签名,以及 开始时间,结束时间等是否有效 + * + * @return + */ + boolean verify(LicenseEntity license); + + /** + * 获取license 缓存,没有从数据库读取 + * + * @return + * @throws IOException + */ + LicenseEntity getAndSetLicenseCache(); + + String getSignAlgorithm(); + + PublicKey getPublicKey(); + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/LinkService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/LinkService.java new file mode 100644 index 0000000..d2d75b5 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/LinkService.java @@ -0,0 +1,19 @@ +package net.geedge.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.modules.sys.entity.Link; + +import java.util.List; +import java.util.Map; + +public interface LinkService extends IService<Link>{ + + List<Link> queryList(Map<String, Object> params); + + + void saveLink(Link link); + + void removeLinks(List<String> ids); + + void saveWeights(List<Link> links); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysApiKeyService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysApiKeyService.java new file mode 100644 index 0000000..e65087a --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysApiKeyService.java @@ -0,0 +1,16 @@ +package net.geedge.modules.sys.service; + +import java.util.Map; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.common.utils.PageUtils; +import net.geedge.modules.sys.entity.SysApiKey; + +public interface SysApiKeyService extends IService<SysApiKey>{ + + PageUtils queryPage(Map<String,Object> params); + + Integer addSysApiKey(SysApiKey sysApiKey); + + void removeSysApiKeys(String ids); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysConfigService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysConfigService.java new file mode 100644 index 0000000..04a8130 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysConfigService.java @@ -0,0 +1,64 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.R; +import net.geedge.modules.sys.entity.SysConfigEntity; + +import java.io.IOException; +import java.util.Map; + +/** + * 系统配置信息 + * + + */ +public interface SysConfigService extends IService<SysConfigEntity> { + + PageUtils queryPage(Map<String, Object> params); + + /** + * 保存配置信息 + */ + void saveConfig(SysConfigEntity config); + + /** + * 更新配置信息 + */ + void update(SysConfigEntity config); + + /** + * 根据key,更新value + */ + void updateValueByKey(String key, String value); + + /** + * 删除配置信息 + */ + void deleteBatch(Long[] ids); + + /** + * 根据key,获取配置的value值 + * + * @param key key + */ + String getValue(String key); + + /** + * 根据key,获取value的Object对象 + * @param key key + * @param clazz Object对象 + */ + <T> T getConfigObject(String key, Class<T> clazz); + + Map getConfigListByTypes(String[] types, String[] paramKey); + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysDictService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysDictService.java new file mode 100644 index 0000000..2700814 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysDictService.java @@ -0,0 +1,56 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.RCode; +import net.geedge.modules.sys.entity.SysDictEntity; + +import java.util.List; +import java.util.Map; + +/** + * 数据字典 + * + + */ +public interface SysDictService extends IService<SysDictEntity> { + + PageUtils queryPage(Map<String, Object> params); + + List<SysDictEntity> queryList(Map<String, Object> params); + + void delete(String ids); + + boolean update(SysDictEntity dict); + + void updateLangCache(); + + /** + * name type 下 value 值不能重复 + * @param id + * @param name 字典名称 + * @param type 字典类型 + * @param value 字典值 + * @return + */ + boolean dictValueCheck(Long id, String name, String type, String value); + + Integer queryMaxTypeCode(String type); + + void checkSysDicValue(String type, String value, RCode errCode); + + void checkSysDicCode(String type, Integer code, RCode errCode); + + List<SysDictEntity> querySysDicByType(String type); + + void saveSysDict(SysDictEntity dict); +} + diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysI18nService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysI18nService.java new file mode 100644 index 0000000..b8a8253 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysI18nService.java @@ -0,0 +1,36 @@ +package net.geedge.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.common.utils.PageUtils; +import net.geedge.modules.sys.entity.SysI18nEntity; + +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * i18n信息表 + * + * @author song + * @email + * @date 2019-08-05 14:35:21 + */ +public interface SysI18nService extends IService<SysI18nEntity> { + + PageUtils queryPage(Map<String, Object> params); + + boolean check(SysI18nEntity sysI18n); + + String queryValue(String code); + + public String queryValue(String code, String lang); + + String queryValue(String code, Locale locale); + + List<SysI18nEntity> queryAll(); + + Map<String, String> getCurrLang(); + + Locale getLocale(); +} + diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysInfoService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysInfoService.java new file mode 100644 index 0000000..4d3fe35 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysInfoService.java @@ -0,0 +1,10 @@ +package net.geedge.modules.sys.service; + +import java.util.Map; + +public interface SysInfoService { + + Map getAboutInfo(); + + Map getGitVersionInfo(); +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysLogService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysLogService.java new file mode 100644 index 0000000..8c0df6a --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysLogService.java @@ -0,0 +1,28 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.common.utils.PageUtils; +import net.geedge.modules.sys.entity.SysLogEntity; + +import java.util.Map; + + +/** + * 系统日志 + * + + */ +public interface SysLogService extends IService<SysLogEntity> { + + PageUtils queryPage(Map<String, Object> params); + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysMenuService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysMenuService.java new file mode 100644 index 0000000..d83dfbb --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysMenuService.java @@ -0,0 +1,48 @@ +package net.geedge.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.modules.sys.entity.SysMenuEntity; + +import java.util.List; +import java.util.Map; + +public interface SysMenuService extends IService<SysMenuEntity> { + + /** + * 菜单列表 + * @param id + * @return + */ + List<SysMenuEntity> getMenuList(Integer id); + + void saveMenu(SysMenuEntity menu); + + void updateMenu(SysMenuEntity menu); + + void delete(Integer[] ids); + + /** + * 根据角色获取 菜单列表 + * @param roleId + * @return + */ + List<SysMenuEntity> getRoleMenuList(Integer roleId); + + + Map<String, Object> getMenuInfoByRoles(List<Integer> roleIds); + + + /** + * 根据叶子节点 得到关联完整节点集合 + * @param leafMenuList + * @return + */ + List<SysMenuEntity> getMenuByLeafMenu(List<SysMenuEntity> leafMenuList); + + /** + * 获取选中 所有 Menu(树结构) 的 ids + * @param roleMenuList + * @return + */ + List<Integer> getSelectedMenuIds(List<SysMenuEntity> roleMenuList); +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysRoleMenuService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysRoleMenuService.java new file mode 100644 index 0000000..efbd98a --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysRoleMenuService.java @@ -0,0 +1,21 @@ +package net.geedge.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.modules.sys.entity.SysRoleMenuEntity; + +import java.util.List; + +public interface SysRoleMenuService extends IService<SysRoleMenuEntity> { + + void saveOrUpdate(Integer roleId, List<Integer> menuIdList); + + /** + * 根据角色ID,获取菜单ID列表 + */ + List<Integer> queryMenuIdList(Integer roleId); + + /** + * 根据角色ID数组,批量删除 + */ + int deleteBatch(Integer[] roleIds); +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysRoleService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysRoleService.java new file mode 100644 index 0000000..73db1ae --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysRoleService.java @@ -0,0 +1,20 @@ +package net.geedge.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.common.utils.PageUtils; +import net.geedge.modules.sys.entity.SysRoleEntity; + +import java.util.Map; + +public interface SysRoleService extends IService<SysRoleEntity> { + + PageUtils queryPage(Map<String, Object> params); + + void saveRole(SysRoleEntity role); + + void update(SysRoleEntity role); + + void deleteBatch(Integer[] roleIds); + + Map getMenuListByRoleId(Integer roleId); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysUserRoleService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysUserRoleService.java new file mode 100644 index 0000000..e75a360 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysUserRoleService.java @@ -0,0 +1,21 @@ +package net.geedge.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.modules.sys.entity.SysUserRoleEntity; + +import java.util.List; + +public interface SysUserRoleService extends IService<SysUserRoleEntity> { + + void saveOrUpdate(Long userId, String roleIds); + + /** + * 根据用户ID,获取角色ID列表 + */ + List<Integer> queryRoleIdList(Integer userId); + + /** + * 根据角色ID数组,批量删除 + */ + int deleteBatch(Integer[] roleIds); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/SysUserService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysUserService.java new file mode 100644 index 0000000..abf403a --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/SysUserService.java @@ -0,0 +1,62 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.common.utils.PageUtils; +import net.geedge.modules.sys.entity.SysUserEntity; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Map; + + +/** + * 系统用户 + * + + */ +public interface SysUserService extends IService<SysUserEntity> { + + SysUserEntity queryUserInfo(Long userId); + + PageUtils queryPage(Map<String, Object> params); + + /** + * 保存用户 + */ + Integer saveUser(SysUserEntity user); + + /** + * 修改用户 + */ + Integer update(SysUserEntity user); + + /** + * 修改密码 + * @param userId 用户ID + * @param password 原密码 + * @param newPassword 新密码 + */ + boolean updatePassword(Long userId, String password, String newPassword); + + /** + * 校验用户名是否重复 + * @param queryParam + * @return + */ + boolean checkName(SysUserEntity queryParam); + + void deleteUsers(String userIds); + + Map<String, Object> getUserPermissions(HttpServletRequest request); + + // 根据角色ID 获取所属用户 + List<SysUserEntity> getUserListByRoleId(Integer roleId); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/TimezoneService.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/TimezoneService.java new file mode 100644 index 0000000..136c9d5 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/TimezoneService.java @@ -0,0 +1,10 @@ +package net.geedge.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import net.geedge.modules.sys.entity.Timezone; + +import java.util.List; + +public interface TimezoneService extends IService<Timezone> { + List<Timezone> queryTimezone(String name); +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/LicenseServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/LicenseServiceImpl.java new file mode 100644 index 0000000..998d7ab --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/LicenseServiceImpl.java @@ -0,0 +1,274 @@ +package net.geedge.modules.sys.service.impl; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.security.PublicKey; +import java.util.Date; +import java.util.TimeZone; + +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import net.geedge.common.exception.CNException; +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.RCode; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.entity.LicenseEntity; +import net.geedge.modules.sys.entity.LicenseEntity.Product; +import net.geedge.modules.sys.entity.LicenseEntity.Tokens; +import net.geedge.modules.sys.entity.SysConfigEntity; +import net.geedge.modules.sys.service.LicenseService; +import net.geedge.modules.sys.service.SysConfigService; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.log.Log; + +@Service +public class LicenseServiceImpl implements LicenseService { + private static final Log log = Log.get(); + /** + * 公钥缓存 + */ + private static PublicKey publickeyCache; + /** + * 缓存license ,避免重复计算sign + */ + private static LicenseEntity licenseCache; + @Autowired + private SysConfigService sysConfigService; + + + @Value("${license.config.key:license}") + private String licenseConfigKey; + @Value("${license.token.key:license_token}") + private String licenseTokenKey; + /** + * 系统版本sys_config 表key + */ + @Value("${system.version.key:system_version}") + private String systemVersionKey; + + /** + * 签名算法 + */ + @Value("${license.sign.algorithm:NONEwithRSA}") + private String signAlgorithm; + + /** + * 公钥路径,首先在jar包外查找,未找到在jar包中查找 + */ + @Value("${license.publickey.path:/license/license.pem}") + public String publicKeyPath = "/license/license.pem"; + + + /** + * base 不校验版本 + */ + @Value("${license.base.version:base}") + private String baseVersion; + + /** + * 获取token 首先尝试获取 硬件token 硬件token获取失败从数据库读取 数据库不存在 通过uuid 生成,保存到数据库 + * + * @param key + * @return + */ + @Override + public String getLicenseToken() { + String token = Tool.LicenseUtil.getMachineID(); + if (Tool.StrUtil.isBlank(token)) { + SysConfigEntity entity = sysConfigService + .getOne(new QueryWrapper<SysConfigEntity>().eq("param_key", licenseTokenKey)); + if (entity == null || Tool.StrUtil.isBlank(entity.getParamValue())) { + token = Tool.IdUtil.fastSimpleUUID(); + if (entity == null) { + entity = new SysConfigEntity(); + } + entity.setParamKey(licenseTokenKey); + entity.setParamValue(token); + entity.setRemark("Automatic generated"); + sysConfigService.saveOrUpdate(entity); + } + token = entity.getParamValue(); + } + return token; + } + + @Override + public LicenseEntity getLicenseEntity() { + SysConfigEntity entity = sysConfigService + .getOne(new QueryWrapper<SysConfigEntity>().eq("param_key", licenseConfigKey)); + if (entity == null || Tool.StrUtil.isBlank(entity.getParamValue())) { + return null; + } + // 证书由xml转为 map + LicenseEntity licenseEntity = Tool.LicenseUtil.xmlToLicenseBean(entity.getParamValue()); + return licenseEntity; + } + + /** + * 更新license + */ + @Override + public void uploadLicenseEntity(LicenseEntity license) { + SysConfigEntity entity = sysConfigService + .getOne(new QueryWrapper<SysConfigEntity>().eq("param_key", licenseConfigKey)); + if (entity == null) { + entity = new SysConfigEntity(); + } + entity.setParamKey(licenseConfigKey); + entity.setParamValue(Tool.LicenseUtil.licenseBeanToXml(license, false)); + entity.setRemark(license.getSignature().getDigestValue()); + sysConfigService.saveOrUpdate(entity); + + } + + /** + * 获取系统版本 + * + * @return + */ + @Override + public String getSystemVersion() { + return sysConfigService.getValue(systemVersionKey); + } + + /** + * 开始验证 + * + * @param license + * @return + */ + @Override + public boolean verify(LicenseEntity license) { + // 当前时间 + Date now = new DateTime(TimeZone.getTimeZone("UTC")); + // license 开始时间 + String startDateStr = license.getStartDate(); + // license 结束时间 + String endDateStr = license.getEndDate(); + // license 授权token + Tokens tokens = license.getTokens(); + Product product = license.getProduct(); + // 开始时间不为空 并且大于当前时间 + if (Tool.StrUtil.isNotBlank(startDateStr)) { + Date startDate = Tool.DateUtil.parse(startDateStr, DatePattern.UTC_PATTERN) + .setTimeZone(TimeZone.getTimeZone("UTC")); + if (startDate != null && Tool.DateUtil.compare(startDate, now) > 0) { + throw new CNException(RCode.LICENSE_FILE_INVALID); + } + } + // 验证结束时间 + if (Tool.StrUtil.isNotBlank(endDateStr)) { + Date endDate = Tool.DateUtil.parse(endDateStr, DatePattern.UTC_PATTERN) + .setTimeZone(TimeZone.getTimeZone("UTC")); + if (endDate != null && Tool.DateUtil.compare(now, endDate) > 0) { + throw new CNException(RCode.LICENSE_FILE_INVALID); + } + } + // 验证 tokens 是否有效 + if (tokens != null && tokens.getToken() != null) { + String[] token = tokens.getToken(); + String currentToken = this.getLicenseToken(); + // license中不包含 token + if (!Tool.ArrayUtil.contains(token, currentToken)) { + throw new CNException(RCode.LICENSE_TOKEN_INVALID); + } + } + + if (product != null) { + // 验证asset数量 + String version = product.getVersion(); + // 校验版本 + if (Tool.StrUtil.isNotBlank(version) && !Tool.StrUtil.equalsIgnoreCase(version, baseVersion)) { + // 当前版本 + String systemVersion = this.getSystemVersion(); + if (Tool.StrUtil.isNotBlank(systemVersion) && !Tool.StrUtil.equalsIgnoreCase(version, systemVersion)) { + throw new CNException(RCode.LICENSE_VERSION_INVALID); + } + } + } + return true; + } + + /** + * + * @return + * @throws IOException + */ + @Override + public LicenseEntity getAndSetLicenseCache() { + // 从本地缓存获取 + LicenseEntity license = LicenseServiceImpl.licenseCache; + // 数据库获取license + LicenseEntity licenseDB = this.getLicenseEntity(); + ValidateUtils.is(licenseDB).notNull(RCode.LICENSE_FILE_IS_NULL); + // 获取公钥证书 + PublicKey pk = this.getPublicKey(); + if (license != null) { + // 通过digest验证数据库中内容 是否和 缓存一致 + String digestValueDB = licenseDB.getSignature().getDigestValue(); + String digestValueCache = license.getSignature().getDigestValue(); + // verify 耗时较长,通过比较digest判断是否变更 + if (!Tool.StrUtil.equals(digestValueDB, digestValueCache)) { + log.info("license change,db:{},cache:{}", digestValueDB, digestValueCache); + // 验证签名,digest不一致说明数据库中内容已变更,需要重新校验并修改 LicenseCache + boolean verifyLicense = Tool.LicenseUtil.verifyLicenseSign(licenseDB, pk, signAlgorithm); + log.info("license verify result: {}", verifyLicense); + if (!verifyLicense) {// 验证失败,证书无效 + throw new CNException(RCode.LICENSE_FILE_INVALID); + } + // 更新缓存 + LicenseServiceImpl.licenseCache = licenseDB; + } + } else { + // 更新缓存 + LicenseServiceImpl.licenseCache = licenseDB; + } + return LicenseServiceImpl.licenseCache; + } + + /** + * 获取 publickey ,首先查找内存中查找,否则本地路径查找 + * + * @return @throws IOException @throws + */ + @Override + public PublicKey getPublicKey() { + PublicKey cache = LicenseServiceImpl.publickeyCache; + if (cache == null) { + File file = Tool.FileUtil.newFile(publicKeyPath); + log.debug("pubk path : {} ,exist : {}", file.getAbsolutePath(),file.exists()); + // 通过 getResourceAsStream 确保jar包中也能够读取 + InputStream is = null; + try { + is = file.exists() ? Tool.FileUtil.getInputStream(file) : this.getClass().getResourceAsStream(publicKeyPath); + cache = Tool.PemUtil.readPemPublicKey(is); + log.info("license public key load success"); + if (log.isDebugEnabled()) { + log.debug("public key content: {}", cache); + } + LicenseServiceImpl.publickeyCache = cache; + } catch (IORuntimeException e) { + log.error(e); + throw new CNException("license public key load error", 999); + } finally { + if(is != null){ + IOUtils.closeQuietly(is); + } + } + } + return cache; + } + + @Override + public String getSignAlgorithm() { + return this.signAlgorithm; + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/LinkServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/LinkServiceImpl.java new file mode 100644 index 0000000..b348c60 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/LinkServiceImpl.java @@ -0,0 +1,104 @@ +package net.geedge.modules.sys.service.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import net.geedge.common.exception.CNException; +import net.geedge.common.utils.RCode; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.dao.LinkDao; +import net.geedge.modules.sys.entity.Link; +import net.geedge.modules.sys.service.LinkService; + +@Service +public class LinkServiceImpl extends ServiceImpl<LinkDao, Link> implements LinkService { + + @Autowired + private LinkDao linkDao; + + @Override + public List<Link> queryList(Map<String, Object> params) { + List<Link> list = linkDao.queryList(params); + return list; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveLink(Link link) { + Link max = this.getOne(new QueryWrapper<Link>().select("id","weight").orderByDesc("id").last("limit 1")); + if(Tool.ObjectUtil.isEmpty(max)){ + link.setWeight(0); + }else{ + link.setWeight(max.getWeight()+1); + } + this.save(link); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void removeLinks(List<String> ids) { + if (Tool.ObjectUtil.isEmpty(ids)) { + return; + } + + List<Link> links = this.list(); + + + // 内置chart不能删除 + this.validateBuildInLinks(ids); + + List<Integer> linkIdList = links.stream().map(Link::getId).collect(Collectors.toList()); + + List<String> deleteIds = new ArrayList<>(); + for (String id : ids) { + if (linkIdList.contains(Integer.valueOf(id))) { + deleteIds.add(id); + } + } + + if (CollectionUtils.isNotEmpty(deleteIds)) { + // 删除自身 + this.baseMapper.deleteBatchIds(deleteIds); + } + + } + + @Override + public void saveWeights(List<Link> links) { + Link link = links.stream().filter(t -> Tool.ObjectUtil.isEmpty(t.getId()) || Tool.ObjectUtil.isEmpty(t.getWeight())).findAny().orElse(null); + if(Tool.ObjectUtil.isNotEmpty(link)){ + throw new CNException(RCode.LINK_WEIGHT_PARAM_INVALID); + } + + this.saveOrUpdateBatch(links); + } + + /** + * 校验是否是内置link + * + * @param linkIds + */ + private void validateBuildInLinks(List<String> linkIds) { + // 内置charts + List<Link> buildInLinks = this.list(new QueryWrapper<Link>().lambda().eq(Link::getBuildIn, 1)); + Map<Integer, String> buildInLinkIdAndNameMap = buildInLinks.stream().collect(Collectors.toMap(Link::getId, Link::getName)); + + + linkIds.forEach(id -> { + if (Tool.ObjectUtil.isNotEmpty(buildInLinkIdAndNameMap.get(Integer.valueOf(id)))) { + throw new CNException(buildInLinkIdAndNameMap.get(Integer.valueOf(id)) + " link is built-in and cannot be deleted", RCode.LINK_BUILDIN_CAN_NOT_REMOVE.getCode()); + } + }); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysApiKeyServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysApiKeyServiceImpl.java new file mode 100644 index 0000000..87656f9 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysApiKeyServiceImpl.java @@ -0,0 +1,72 @@ +package net.geedge.modules.sys.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import cn.hutool.core.lang.UUID; +import cn.hutool.core.util.StrUtil; +import net.geedge.common.exception.CNException; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.Query; +import net.geedge.common.utils.RCode; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.dao.SysApiKeyDao; +import net.geedge.modules.sys.entity.SysApiKey; +import net.geedge.modules.sys.service.SysApiKeyService; +import net.geedge.modules.sys.shiro.ShiroUtils; + +@Service +public class SysApiKeyServiceImpl extends ServiceImpl<SysApiKeyDao,SysApiKey> implements SysApiKeyService{ + + @Override + public PageUtils queryPage(Map<String, Object> params) { + IPage result = new Query(SysApiKey.class).getPage(params); + String ids = (String) params.get("ids"); + if(StrUtil.isNotBlank(ids)) { + List<String> listIds = Arrays.asList(ids.split(",")); + params.put("ids",listIds); + } + List<SysApiKey> rows = this.baseMapper.queryList(result, params); + result.setRecords(rows); + return new PageUtils(result); + } + + @Override + public Integer addSysApiKey(SysApiKey sysApiKey) { + // 校验名称不重复 + List<SysApiKey> sysApiKeys = this.list(new QueryWrapper<SysApiKey>().lambda().eq(SysApiKey::getName, sysApiKey.getName())); + if(Tool.ObjectUtil.isNotEmpty(sysApiKeys)) { + throw new CNException(RCode.SYSAPIKEY_NAME_DUPLICATE); + } + + // 生成唯一uuid + String uuid = UUID.randomUUID().toString(); + + sysApiKey.setToken(uuid); + sysApiKey.setCreateBy(ShiroUtils.getUserId().intValue()); + sysApiKey.setCreateAt(new Date()); + this.save(sysApiKey); + return sysApiKey.getId(); + } + + @Override + public void removeSysApiKeys(String ids) { + List<SysApiKey> sysApiKeys = this.list(new QueryWrapper<SysApiKey>().lambda().in(SysApiKey::getId, Arrays.asList(ids.split(",")))); + List<String> tokens = new ArrayList<String>(); + for(SysApiKey sysApiKey : sysApiKeys) { + tokens.add(StrUtil.str(ShiroUtils.REDIS_KEYPREFIX+sysApiKey.getToken())); + } + ShiroUtils.removeRedisCacheByToken(tokens); + this.removeByIds(Arrays.asList(ids.split(","))); + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysConfigServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysConfigServiceImpl.java new file mode 100644 index 0000000..e564b7c --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,176 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.gson.Gson; + +import net.geedge.common.exception.CNException; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.Query; +import net.geedge.modules.sys.dao.SysConfigDao; +import net.geedge.modules.sys.entity.SysConfigEntity; +import net.geedge.modules.sys.redis.SysConfigRedis; +import net.geedge.modules.sys.service.SysConfigService; + +@Service("sysConfigService") +public class SysConfigServiceImpl extends ServiceImpl<SysConfigDao, SysConfigEntity> implements SysConfigService { + + + @Autowired + private SysConfigRedis sysConfigRedis; + + @Override + public PageUtils queryPage(Map<String, Object> params) { + String paramKey = (String)params.get("paramKey"); + + IPage<SysConfigEntity> page = this.page( + new Query(SysConfigEntity.class).getPage(params), + new QueryWrapper<SysConfigEntity>() + .like(StringUtils.isNotBlank(paramKey),"param_key", paramKey) + .eq("status", 1) + ); + + return new PageUtils(page); + } + + @Override + public void saveConfig(SysConfigEntity config) { + this.save(config); + sysConfigRedis.saveOrUpdate(config); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(SysConfigEntity config) { + this.updateById(config); + sysConfigRedis.saveOrUpdate(config); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateValueByKey(String key, String value) { + baseMapper.updateValueByKey(key, value); + sysConfigRedis.delete(key); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteBatch(Long[] ids) { + for(Long id : ids){ + SysConfigEntity config = this.getById(id); + sysConfigRedis.delete(config.getParamKey()); + } + + this.removeByIds(Arrays.asList(ids)); + } + + @Override + public String getValue(String key) { + SysConfigEntity config = sysConfigRedis.get(key); + if(config == null){ + config = baseMapper.queryByKey(key); + sysConfigRedis.saveOrUpdate(config); + } + + return config == null ? null : config.getParamValue(); + } + + @Override + public <T> T getConfigObject(String key, Class<T> clazz) { + String value = getValue(key); + if(StringUtils.isNotBlank(value)){ + return new Gson().fromJson(value, clazz); + } + + try { + return clazz.newInstance(); + } catch (IllegalAccessException e) { + throw new CNException("获取参数失败"); + } catch (InstantiationException e) { + throw new CNException("获取参数失败"); + } + } + @Override + public Map getConfigListByTypes(String[] types, String[] paramKey) { + + List<String> paramKeys = paramKey == null || paramKey.length == 0 ? new ArrayList<>() : new ArrayList<>(Arrays.asList(paramKey)); + + boolean typeFlag = false; + if(types != null && types.length > 0){ + typeFlag = true; + for (String type : types) { + paramKeys.addAll(Constant.SYSCONFIG_TYPEWITHKEYS_MAP.get(type)); + } + } + + List<SysConfigEntity> list = this.list(new QueryWrapper<SysConfigEntity>() + .eq("status", 1) + .in(CollectionUtils.isNotEmpty(paramKeys), "param_key", paramKeys)); + + Map<String, String> paramKeyWithValueMap = new HashMap<>(); + for (SysConfigEntity entity: list) { + paramKeyWithValueMap.put(entity.getParamKey(), entity.getParamValue()); + } + + + // 组织返回数据 + Map resultMap = new HashMap(), values; + + // 如果type存在 则返回此type包含的所有内容 + if(typeFlag){ + List<String> keys; + String value; + for (String typeName : types) { + values = new HashMap(); + + keys = Constant.SYSCONFIG_TYPEWITHKEYS_MAP.get(typeName); + for (String str : keys) { + value = paramKeyWithValueMap.get(str); + if(StringUtils.isNotEmpty(value)){ + values.put(str, value); + } + } + + resultMap.put(typeName, values); + } + } + + // 处理 paramKey参数查询 + if(paramKey != null && paramKey.length > 0){ + String value; + Map paramValues = new HashMap(); + for (String key : paramKey) { + value = paramKeyWithValueMap.get(key); + if(StringUtils.isNotEmpty(value)){ + paramValues.put(key, value); + } + } + resultMap.put("paramKey",paramValues); + } + + return resultMap; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysDictServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysDictServiceImpl.java new file mode 100644 index 0000000..b1a33fa --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysDictServiceImpl.java @@ -0,0 +1,209 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.geedge.common.exception.CNException; +import net.geedge.common.smartvalidate.utils.CommonUtil; +import net.geedge.common.utils.*; +import net.geedge.modules.sys.dao.SysDictDao; +import net.geedge.modules.sys.entity.SysDictEntity; +import net.geedge.modules.sys.service.SysDictService; +import net.geedge.modules.sys.service.SysI18nService; +import net.geedge.modules.sys.shiro.ShiroUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + + +@Service("sysDictService") +public class SysDictServiceImpl extends ServiceImpl<SysDictDao, SysDictEntity> implements SysDictService { + + @Autowired + private SysI18nService i18nService; + + @Override + public PageUtils queryPage(Map<String, Object> params) { + IPage<SysDictEntity> page=this.page(new Query(SysDictEntity.class).getPage(params)); + + List<SysDictEntity> list=this.baseMapper.querySysDictListWithPage(page,params); + + page.setRecords(list); + return new PageUtils(page); + } + + @Override + public List<SysDictEntity> queryList(Map<String, Object> params) { + List<SysDictEntity> list = this.baseMapper.querySysDictList(params); + if (!CommonUtil.isNull(list)) { + for (SysDictEntity s : list) { + if (!CommonUtil.isNull(s.getI18nCode())) { + String queryValue = i18nService.queryValue(s.getI18nCode()); + s.setValue(queryValue); + } + } + } + + return list; + } + + @Override + public void delete(String ids) { + if(Tool.ObjectUtil.isEmpty(ids)) { + return; + } + String[] idArr=ids.split(","); + ArrayList<Integer> delIds=new ArrayList<Integer>(); + for(String idStr:idArr){ + try { + Integer id = Integer.parseInt(idStr); + delIds.add(id); + }catch (NumberFormatException e){ + throw new CNException(RCode.SYS_DICT_ID_INVALIDE); + } + } + + this.removeByIds(delIds); + + } + + @Override + public boolean save(SysDictEntity dict) { + super.save(dict); + if(StrUtil.equals(dict.getType(),Constant.DICT_NAME_LANG)) { + updateLangCache(); + } + return true; + } + + @Override + public boolean update(SysDictEntity dict) { + SysDictEntity old =null; + if(dict.getId()!=null){ + old = getById(dict.getId()); + }else{ + old = this.baseMapper.selectOne( + new QueryWrapper<SysDictEntity>().lambda() + .eq(SysDictEntity::getType,dict.getType()) + .eq(SysDictEntity::getCode,dict.getCode()) + ); + } + if(old == null){ + throw new CNException(RCode.SYS_ERROR); + } + + dict.setId(old.getId()); + + boolean langUpdate = false; + //若更新了语言,刷新语言缓存 + if (dict.getType().equals(Constant.DICT_NAME_LANG) && !old.getValue().equals(dict.getValue())) { + langUpdate = true; + } + + updateById(dict); + + if (langUpdate) { + updateLangCache(); + } + return true; + } + + @Override + public void updateLangCache() { + Constant.langList.clear(); + HashMap<String, Object> params = new HashMap<>(); + params.put("type", Constant.DICT_NAME_LANG); + List<SysDictEntity> queryList = queryList(params); + for (SysDictEntity d : queryList) { + Map<String, String> lang = new HashMap<>(); + lang.put("name", d.getRemark()); + lang.put("value", d.getValue()); + Constant.langList.add(lang); + } + } + + + /** + * name type 下 value 值不能重复 + * @param id + * @param name 字典名称 + * @param type 字典类型 + * @param value 字典值 + * @return + */ + @Override + public boolean dictValueCheck(Long id, String name, String type, String value) { + List<SysDictEntity> list = this.list(new QueryWrapper<SysDictEntity>().lambda().eq(SysDictEntity::getName, name).eq(SysDictEntity::getType, type).eq(SysDictEntity::getValue, value)); + + boolean flag = false; + if (list == null || list.size() == 0 || (list != null && list.size() == 1 && list.get(0).getId().equals(id))) { + flag = true; + } + return flag; + } + + @Override + public Integer queryMaxTypeCode(String type) { + Integer maxCode=this.baseMapper.getMaxTypeCode(type); + return maxCode; + } + + @Override + public void checkSysDicValue(String type, String value, RCode errCode) { + List<SysDictEntity> list = this.list(new QueryWrapper<SysDictEntity>().lambda().eq(SysDictEntity::getType, type).eq(SysDictEntity::getValue, value).eq(SysDictEntity::getDelFlag, 0)); + if(list==null ||list.size()<1){ + throw new CNException(errCode); + } + } + @Override + public void checkSysDicCode(String type, Integer code, RCode errCode) { + List<SysDictEntity> list = this.list(new QueryWrapper<SysDictEntity>().lambda().eq(SysDictEntity::getType, type).eq(SysDictEntity::getCode, code).eq(SysDictEntity::getDelFlag, 0)); + if(list==null ||list.size()<1){ + throw new CNException(errCode); + } + } + + @Override + public List<SysDictEntity> querySysDicByType(String type) { + List<SysDictEntity> list = this.list(new QueryWrapper<SysDictEntity>().lambda().eq(SysDictEntity::getType, type).eq(SysDictEntity::getDelFlag, 0)); + return list; + } + + @Override + public void saveSysDict(SysDictEntity dict) { + //字典名称,非必填项,为空后台自动添加value值 + if(StringUtils.isBlank(dict.getName())){ + dict.setName(dict.getValue()); + } + //字典码,后台根据已有最大code值 +1 填写 + if( dict.getCode()==null){ + Integer maxCode=this.queryMaxTypeCode(dict.getType()); + if(maxCode != null){ + maxCode+=1; + }else{ + maxCode=1; + } + + dict.setCode(maxCode); + }else{ + throw new CNException(RCode.SYS_DICT_CODE_ISNULL); + } + + Long userId = ShiroUtils.getUserId(); + dict.setOperator(userId); + dict.setOpTime(new Date()); + this.save(dict); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysI18nServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysI18nServiceImpl.java new file mode 100644 index 0000000..cdb035d --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysI18nServiceImpl.java @@ -0,0 +1,113 @@ +package net.geedge.modules.sys.service.impl; + +import com.alibaba.druid.util.StringUtils; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.geedge.common.config.I18nConfig; +import net.geedge.common.smartvalidate.utils.CommonUtil; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.Query; +import net.geedge.modules.sys.dao.SysI18nDao; +import net.geedge.modules.sys.entity.SysI18nEntity; +import net.geedge.modules.sys.service.SysDictService; +import net.geedge.modules.sys.service.SysI18nService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; +import org.springframework.web.util.WebUtils; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Locale; +import java.util.Map; + + +@Service("sysI18nService") +public class SysI18nServiceImpl extends ServiceImpl<SysI18nDao, SysI18nEntity> implements SysI18nService { + + @Autowired + private Environment env; + @Autowired + private SysDictService dictService; + @Autowired + private I18nConfig i18nConfig; + + @Override + public PageUtils queryPage(Map<String, Object> params) { + IPage<SysI18nEntity> page = this.page( + new Query(SysI18nEntity.class).getPage(params), + new QueryWrapper<SysI18nEntity>() + .like(!StringUtils.isEmpty((String)params.get("code")), "code", (String)params.get("code")) + .eq(!StringUtils.isEmpty((String)params.get("lang")), "lang", (String)params.get("lang")) + .like(!StringUtils.isEmpty((String)params.get("value")), "value", (String)params.get("value")) + ); + + return new PageUtils(page); + } + + public List<SysI18nEntity> queryAll() { + QueryWrapper<SysI18nEntity> qw = new QueryWrapper<>(); + List<SysI18nEntity> list = list(qw); + return list; + } + + public Locale getLocale() { + HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); + //从session中获取lang + Locale locale = (Locale) WebUtils.getSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME); + if (locale == null) { + String defaultLang = env.getProperty("default.locale", "en_US"); + String[] split = defaultLang.split("_"); + locale = new Locale(split[0], split[1]); + } + return locale; + } + + /** + * 根据code查询国际化值,自动获取当前语言 + */ + public String queryValue(String code) { + return queryValue(code, getLocale()); + } + + public String queryValue(String code, String lang) { + return queryValue(code, new Locale(lang)); + } + + public String queryValue(String code, Locale locale) { + return i18nConfig.getSourceFromCache(code, locale); + } + + public Map<String, String> getCurrLang() { + String lang = getLocale().getLanguage(); + if (CommonUtil.isNull(Constant.langList)) { + dictService.updateLangCache(); + } + for (Map<String, String> l : Constant.langList){ + if (l.get("value").equals(lang)) { + return l; + } + } + return null; + } + + @Override + public boolean check(SysI18nEntity sysI18n) { + boolean dumpFlag = true; //记录是否重复(code+lang),true为重复 + List<SysI18nEntity> list = list(new QueryWrapper<SysI18nEntity>() + .eq(true, "code", sysI18n.getCode()) + . eq(true, "lang", sysI18n.getLang()) + . eq(true, "del_flag", Constant.DELFLAG_FALSE)); + //当只有一个结果并且这个结果是自身时,或没有结果时,说明不重复 + if ((list == null || list.size() == 0) || + (list != null && list.size() == 1 && list.get(0).getId().longValue() == sysI18n.getId().longValue())) { + dumpFlag = false; + } + return dumpFlag; + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysInfoServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysInfoServiceImpl.java new file mode 100644 index 0000000..04c21c1 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysInfoServiceImpl.java @@ -0,0 +1,138 @@ +package net.geedge.modules.sys.service.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; + +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.RedisServerCommands; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; + +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.log.Log; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.dao.SysConfigDao; +import net.geedge.modules.sys.entity.SysConfigEntity; +import net.geedge.modules.sys.service.SysInfoService; + +@Service("sysInfoService") +public class SysInfoServiceImpl implements SysInfoService { + + private static Log log = Log.get(); + + @Autowired + private SysConfigDao sysConfigDao; + + + @Autowired + private RedisTemplate redisTemplate; + + @Override + public Map getAboutInfo() { + Map resultMap = new HashMap(4); + // 1. nehza 系统版本 + SysConfigEntity sysVersion = sysConfigDao.selectOne(new QueryWrapper<SysConfigEntity>().lambda().eq(SysConfigEntity::getParamKey, Constant.SYSCONFIG_KEY_SYSTEM_VERSION)); + Map sysVersionMap = new HashMap(4); + sysVersionMap.put("name", "cn Monitoring System"); + sysVersionMap.put("version", sysVersion.getParamValue()); + + resultMap.put("cn", sysVersionMap); + + // 2. 组件版本信息 mariaDB redis prometheus + List<Map> componentVersionInfoList = new ArrayList<>(); + + // ① mariaDB version + Map componentVersion = new HashMap(4); + String dataBasesVersion = sysConfigDao.getDataBasesVersion(); + componentVersion.put("name", "Mariadb"); + componentVersion.put("version", dataBasesVersion); + componentVersionInfoList.add(componentVersion); + + // ② redis version + Object redisVersion = redisTemplate.execute(new RedisCallback<String>() { + @Override + public String doInRedis(RedisConnection connection) throws DataAccessException { + RedisServerCommands redisServerCommands = connection.serverCommands(); + Properties info = redisServerCommands.info(); + return info.get("redis_version").toString(); + } + }); + componentVersion = new HashMap(4); + componentVersion.put("name", "Redis"); + componentVersion.put("version", redisVersion.toString()); + componentVersionInfoList.add(componentVersion); + + + resultMap.put("components", componentVersionInfoList); + return resultMap; + } + + @Override + public Map getGitVersionInfo() { + try { + String versionJson = Tool.FileUtil.readUtf8String("git.properties"); + JSONObject jsonObject = JSON.parseObject(versionJson.toString()); + Set<Map.Entry<String, Object>> entrySet = jsonObject.entrySet(); + if (CollectionUtils.isNotEmpty(entrySet)) { + // 默认排序 a-z + Map<String, Object> sortMap = new TreeMap<>(new Comparator<String>() { + public int compare(String obj1, String obj2) { + return obj1.compareTo(obj2); + } + }); + Map<String, Object> collect = entrySet.stream() + .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue(), (o, n) -> n)); + sortMap.putAll(collect); + return sortMap; + } + } catch (IORuntimeException e) { + log.error("读取 git.properties 文件信息失败,错误信息是:" + e); + } + + /*ClassLoader classLoader = getClass().getClassLoader(); + try (InputStream inputStream = classLoader.getResourceAsStream("git.properties"); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));) { + StringBuilder versionJson = null; + String line; + versionJson = new StringBuilder(); + while ((line = reader.readLine()) != null) { + versionJson.append(line); + } + + JSONObject jsonObject = JSON.parseObject(versionJson.toString()); + Set<Map.Entry<String, Object>> entrySet = jsonObject.entrySet(); + if (CollectionUtils.isNotEmpty(entrySet)) { + // 默认排序 a-z + Map<String, Object> sortMap = new TreeMap<>(new Comparator<String>() { + public int compare(String obj1, String obj2) { + return obj1.compareTo(obj2); + } + }); + Map<String, Object> collect = entrySet.stream() + .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue(), (o, n) -> n)); + sortMap.putAll(collect); + return sortMap; + } + } catch (IOException e) { + log.error("读取 git.properties 文件信息失败,错误信息是:" + e); + }*/ + return Collections.emptyMap(); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysLogServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysLogServiceImpl.java new file mode 100644 index 0000000..4e6385c --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysLogServiceImpl.java @@ -0,0 +1,66 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.service.impl; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import net.geedge.common.utils.PageUtils; +import net.geedge.common.utils.Query; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.dao.SysLogDao; +import net.geedge.modules.sys.entity.SysLogEntity; +import net.geedge.modules.sys.entity.SysUserEntity; +import net.geedge.modules.sys.service.SysLogService; +import net.geedge.modules.sys.service.SysUserService; + + +@Service("sysLogService") +@AllArgsConstructor +public class SysLogServiceImpl extends ServiceImpl<SysLogDao, SysLogEntity> implements SysLogService { + + @Autowired + private SysUserService userService; + + @Autowired + private SysLogDao sysLogDao; + + @Override + public PageUtils queryPage(Map<String, Object> params) { + String username = (String) params.get("username"); + if (Tool.ObjectUtil.isNotEmpty(username)) { + List<SysUserEntity> userList = userService.list(new LambdaQueryWrapper<SysUserEntity>().like(SysUserEntity::getName, username)); + List<Long> userIds = userList.stream().map(SysUserEntity::getId).distinct().collect(Collectors.toList()); + params.put("userIds", userIds); + } + + String ids = (String) params.get("operaId"); + if(StrUtil.isNotBlank(ids)) { + List<String> listIds = Arrays.asList(ids.split(",")); + params.put("operaId",listIds); + } + IPage page = new Query(SysLogEntity.class).getPage(params); + List<SysLogEntity> sysLogEntities = sysLogDao.queryList(page, params); + + page.setRecords(sysLogEntities); + + return new PageUtils(page); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysMenuServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000..eb6482d --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,252 @@ +package net.geedge.modules.sys.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.geedge.common.exception.CNException; +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.RCode; +import net.geedge.modules.sys.dao.SysMenuDao; +import net.geedge.modules.sys.entity.SysMenuEntity; +import net.geedge.modules.sys.entity.SysRoleMenuEntity; +import net.geedge.modules.sys.service.SysMenuService; +import net.geedge.modules.sys.service.SysRoleMenuService; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + + +@Service("sysMenuService") +public class SysMenuServiceImpl extends ServiceImpl<SysMenuDao, SysMenuEntity> implements SysMenuService { + + @Autowired + private SysRoleMenuService sysRoleMenuService; + + @Autowired + private SysMenuDao sysMenuDao; + + @Override + public List<SysMenuEntity> getMenuList(Integer id) { + List<SysMenuEntity> menuList = this.list(new LambdaQueryWrapper<SysMenuEntity>().eq(id != null, SysMenuEntity::getId, id).orderByAsc(SysMenuEntity::getOrderNum)); + if (CollectionUtils.isEmpty(menuList) || menuList.size() == 1) + return menuList; + menuList = this.getMenuTreeList(menuList, 0); + return menuList; + } + + + /** + * 1. 参数非空 + * 2. code 唯一 + * 3. type 有效性 + * 4. parent 是否存在 + * 5. button 上级必须是 菜单 类型 + * + * @param menu + */ + private void validateMenuInfo(SysMenuEntity menu) { + ValidateUtils.is(menu.getName()).notNull(RCode.SYS_MENU_NAME_ISNULL) + .and(menu.getCode()).notNull(RCode.SYS_MENU_CODE_ISNULL) + .and(menu.getI18n()).notNull(RCode.SYS_MENU_I18N_ISNULL) + .and(menu.getType()).notNull(RCode.SYS_MENU_TYPE_ISNULL) + .and(menu.getOrderNum()).notNull(RCode.SYS_MENU_ORDERNUM_ISNULL); + + // code 唯一 校验 + List<SysMenuEntity> list = this.list(new QueryWrapper<SysMenuEntity>().lambda().eq(SysMenuEntity::getCode, menu.getCode())); + + boolean flag = false; + if ((list == null || list.size() == 0) || (list != null && list.size() == 1 && list.get(0).getId().equals(menu.getId()))) { + flag = true; + } + if (!flag) { + throw new CNException(RCode.SYS_MENU_CODE_DUPLICATE); + } + + // type 合法性校验 + boolean typeExist = false; + for (Constant.MenuType menuType : Constant.MenuType.values()) { + if(menu.getType().equals(menuType.getValue())){ + typeExist = true; + break; + } + } + if(!typeExist){ + throw new CNException(RCode.SYS_MENU_TYPE_INVALIDE); + } + + // 存在上级ID时间,校验上级菜单是否存在 + if (menu.getParentId() != null && menu.getParentId() != 0) { + SysMenuEntity parent = this.getById(menu.getParentId()); + if (parent == null) + throw new CNException(RCode.SYS_MENU_ISNULL); + + // 校验 上级菜单类型是否是 菜单 ,按钮不可以做为上级菜单 + if (parent.getType() == Constant.MenuType.BUTTON.getValue()) + throw new CNException(RCode.SYS_MENU_BUTTON_PARENTTYPE_INVALIDE); + + // 校验 上级菜单类型是否是 菜单 ,Tab 不可以做为上级菜单 + if(parent.getType() == Constant.MenuType.TAB.getValue()){ + throw new CNException(RCode.SYS_MENU_TAB_PARENTTYPE_INVALIDE); + } + } + } + + @Override + public void saveMenu(SysMenuEntity menu) { + // 参数信息校验 + this.validateMenuInfo(menu); + + if (menu.getParentId() == null) + menu.setParentId(0); + + this.save(menu); + } + + @Override + public void updateMenu(SysMenuEntity menu) { + // 参数信息校验 + this.validateMenuInfo(menu); + + if (menu.getParentId() == null) + menu.setParentId(0); + + this.updateById(menu); + } + + @Override + public void delete(Integer[] ids) { + List<SysMenuEntity> menuList = this.list(); + Set<Integer> parentIds = menuList.stream().map(SysMenuEntity::getParentId).collect(Collectors.toSet()); + + // 判断是否有子菜单或按钮 + for (Integer id : ids) { + if (parentIds.contains(id)) + throw new CNException(RCode.SYS_MENU_DELSUB); + } + + // 删除菜单 + this.removeByIds(Arrays.asList(ids)); + + // 删除与角色关联关系 + sysRoleMenuService.remove(new LambdaQueryWrapper<SysRoleMenuEntity>().in(SysRoleMenuEntity::getMenuId, Arrays.asList(ids))); + } + + /** + * 根据角色获取 菜单列表 + * + * @param roleId + * @return + */ + @Override + public List<SysMenuEntity> getRoleMenuList(Integer roleId) { + List<SysMenuEntity> roleMenuList = sysMenuDao.getRoleMenuList(roleId); + if (CollectionUtils.isEmpty(roleMenuList)) + return Collections.emptyList(); + // 递归获取树结构 + return this.getMenuTreeList(roleMenuList, 0); + } + + @Override + public List<Integer> getSelectedMenuIds(List<SysMenuEntity> roleMenuList) { + List<SysMenuEntity> allMenuList = new ArrayList<>(); + for (SysMenuEntity entity : roleMenuList) { + getAllChildrenMenuList(entity, allMenuList); + } + List<Integer> allMenuIdList = allMenuList.stream().map(SysMenuEntity::getId).collect(Collectors.toList()); + return allMenuIdList; + } + + /** + * 平铺 获取所有 menu 节点 + * + * @param menu + * @param menuList + */ + public void getAllChildrenMenuList(SysMenuEntity menu, List<SysMenuEntity> menuList) { + menuList.add(menu); + if (CollectionUtils.isNotEmpty(menu.getChildren())) { + for (SysMenuEntity pojo : menu.getChildren()) { + getAllChildrenMenuList(pojo, menuList); + } + } + } + + /** + * 递归获取树结构 + * + * @param menuList + * @param parentId + * @return + */ + private List<SysMenuEntity> getMenuTreeList(List<SysMenuEntity> menuList, Integer parentId) { + List<SysMenuEntity> resultList = new ArrayList<>(); + for (SysMenuEntity menu : menuList) { + Integer id = menu.getId(); + Integer pid = menu.getParentId(); + if (parentId.equals(pid)) { + menu.setChildren(this.getMenuTreeList(menuList, id)); + resultList.add(menu); + } + } + return resultList; + } + + @Override + public Map<String, Object> getMenuInfoByRoles(List<Integer> roleIds) { + if (CollectionUtils.isEmpty(roleIds)) + return Collections.emptyMap(); + + // 根据角色 ID 得到 关联得所有 menuID + List<SysRoleMenuEntity> sysRoleMenuEntities = sysRoleMenuService.list(new LambdaQueryWrapper<SysRoleMenuEntity>().in(SysRoleMenuEntity::getRoleId, roleIds)); + Set<Integer> menuIds = sysRoleMenuEntities.stream().map(SysRoleMenuEntity::getMenuId).collect(Collectors.toSet()); + + Map<String, Object> resultMap = new HashMap<>(4); + if (CollectionUtils.isEmpty(menuIds)) { + resultMap.put("menus", Collections.emptyList()); + resultMap.put("buttons", Collections.emptyList()); + return resultMap; + } + + // 查到的所有子节点 + List<SysMenuEntity> list = sysMenuDao.selectList(new LambdaQueryWrapper<SysMenuEntity>().in(SysMenuEntity::getId, menuIds)); + + List<SysMenuEntity> menus = this.getMenuByLeafMenu(list); + List<SysMenuEntity> menuTreeList = this.getMenuTreeList(menus, 0); + + // 因为按钮不能作为父级节点,所以可以直接进行过滤 + List<SysMenuEntity> buttonList = list.stream().filter(sysMenuEntity -> sysMenuEntity.getType() == Constant.MenuType.BUTTON.getValue()).collect(Collectors.toList()); + List<String> buttonCodes = buttonList.stream().map(SysMenuEntity::getCode).collect(Collectors.toList()); + resultMap.put("menus", menuTreeList); + resultMap.put("buttons", buttonCodes); + return resultMap; + } + + @Override + public List<SysMenuEntity> getMenuByLeafMenu(List<SysMenuEntity> leafMenuList) { + List<SysMenuEntity> menuList = this.list(new LambdaQueryWrapper<SysMenuEntity>().orderByAsc(SysMenuEntity::getOrderNum)); + Map<Integer, SysMenuEntity> idAndMenuList = new HashMap<>(); + for (SysMenuEntity entity : menuList) { + idAndMenuList.put(entity.getId(), entity); + } + + List<SysMenuEntity> list = new ArrayList<>(); + for (SysMenuEntity pojo : leafMenuList) { + this.getParentMenu(idAndMenuList, pojo, list); + } + list.addAll(leafMenuList); + list = list.stream().sorted(Comparator.comparing(SysMenuEntity::getOrderNum)).distinct().collect(Collectors.toList()); + return list; + } + + private void getParentMenu(Map<Integer, SysMenuEntity> idAndMenuList, SysMenuEntity pojo, List<SysMenuEntity> list) { + SysMenuEntity parentMenu = idAndMenuList.get(pojo.getParentId()); + if (parentMenu != null) { + list.add(parentMenu); + this.getParentMenu(idAndMenuList, parentMenu, list); + } + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysRoleMenuServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysRoleMenuServiceImpl.java new file mode 100644 index 0000000..5b4b37b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysRoleMenuServiceImpl.java @@ -0,0 +1,44 @@ +package net.geedge.modules.sys.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.geedge.modules.sys.dao.SysRoleMenuDao; +import net.geedge.modules.sys.entity.SysRoleMenuEntity; +import net.geedge.modules.sys.service.SysRoleMenuService; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Service("sysRoleMenuService") +public class SysRoleMenuServiceImpl extends ServiceImpl<SysRoleMenuDao, SysRoleMenuEntity> implements SysRoleMenuService { + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveOrUpdate(Integer roleId, List<Integer> menuIdList) { + // 先删除角色与菜单关系 + this.deleteBatch(new Integer[]{roleId}); + + if (CollectionUtils.isEmpty(menuIdList)) return; + + List<SysRoleMenuEntity> saveList = new ArrayList<>(menuIdList.size()); + SysRoleMenuEntity sysRoleMenuEntity; + for (Integer menuId : menuIdList) { + sysRoleMenuEntity = new SysRoleMenuEntity(null, roleId, menuId); + saveList.add(sysRoleMenuEntity); + } + + this.saveBatch(saveList); + } + + @Override + public List<Integer> queryMenuIdList(Integer roleId) { + return baseMapper.queryMenuIdList(roleId); + } + + @Override + public int deleteBatch(Integer[] roleIds){ + return baseMapper.deleteBatch(roleIds); + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysRoleServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000..9081359 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,233 @@ +package net.geedge.modules.sys.service.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.log.Log; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.geedge.common.exception.CNException; +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.*; +import net.geedge.modules.sys.dao.SysMenuDao; +import net.geedge.modules.sys.dao.SysRoleDao; +import net.geedge.modules.sys.entity.SysMenuEntity; +import net.geedge.modules.sys.entity.SysRoleEntity; +import net.geedge.modules.sys.entity.SysRoleMenuEntity; +import net.geedge.modules.sys.entity.SysUserEntity; +import net.geedge.modules.sys.service.*; +import net.geedge.modules.sys.shiro.ShiroUtils; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +@Service("sysRoleService") +public class SysRoleServiceImpl extends ServiceImpl<SysRoleDao, SysRoleEntity> implements SysRoleService { + + private static Log log = Log.get(); + + @Autowired + private SysRoleMenuService sysRoleMenuService; + + @Autowired + private SysUserRoleService sysUserRoleService; + + @Autowired + private SysMenuService sysMenuService; + + @Autowired + private SysUserService sysUserService; + + @Autowired + private SysMenuDao sysMenuDao; + + @Autowired + private RedisTemplate redisTemplate; + + @Override + public PageUtils queryPage(Map<String, Object> params) { + IPage<SysRoleEntity> page = this.page( + new Query(SysRoleEntity.class).getPage(params), + new LambdaUpdateWrapper<SysRoleEntity>() + .eq(Tool.ObjectUtil.isNotEmpty(params.get("id")), SysRoleEntity::getId, params.get("id")) + .like(Tool.ObjectUtil.isNotEmpty(params.get("name")), SysRoleEntity::getName, params.get("name")) + ); + + return new PageUtils(page); + } + + /** + * 校验 role 是否存在 + * + * @param roleId + */ + private void validateRoleExist(Integer roleId) { + SysRoleEntity role = this.getById(roleId); + + if (role == null) + throw new CNException(RCode.SYS_ROLE_ISNULL); + } + + /** + * 校验 角色 相关信息 + * + * @param role + */ + private void validateRoleInfo(SysRoleEntity role) { + String name = role.getName(); + ValidateUtils.is(name).notNull(RCode.SYS_ROLE_NAME_ISNULL); + + // 校验名称重复 + List<SysRoleEntity> list = this.list(new QueryWrapper<SysRoleEntity>().lambda().eq(SysRoleEntity::getName, name)); + + boolean flag = false; + if ((list == null || list.size() == 0) || (list != null && list.size() == 1 && list.get(0).getId().equals(role.getId()))) { + flag = true; + } + if (!flag) + throw new CNException(RCode.SYS_ROLE_NAME_DUPLICATE); + + + List<Integer> menuIds = role.getMenuIds(); + if (CollectionUtils.isEmpty(menuIds)) + throw new CNException(RCode.SYS_ROLE_MENUID_ISNULL); + + List<SysMenuEntity> menuList = sysMenuService.list(); + List<Integer> menuIdList = menuList.stream().map(SysMenuEntity::getId).collect(Collectors.toList()); + + for (Integer menuId : menuIds) { + if (!menuIdList.contains(menuId)) + throw new CNException(RCode.SYS_MENU_ISNULL); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveRole(SysRoleEntity role) { + // 校验 角色 相关信息 + this.validateRoleInfo(role); + + // i18n 默认与 name 保持一致 + if (Tool.ObjectUtil.isEmpty(role.getI18n())) { + role.setI18n(role.getName()); + } + + this.save(role); + + sysRoleMenuService.saveOrUpdate(role.getId(), role.getMenuIds()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(SysRoleEntity role) { + // 校验 角色 相关信息 + this.validateRoleInfo(role); + + SysRoleEntity oldRole = this.getById(role.getId()); + if (oldRole == null) + throw new CNException(RCode.SYS_ROLE_ISNULL); + + // 内置角色 name 不允许修改 + if (oldRole.getBuildIn() == 1) { + if(!StrUtil.equals(oldRole.getName(),role.getName())) + throw new CNException(RCode.SYS_ROLE_NAME_CANNOT_MODIFY); + } + + this.updateById(role); + + // 处理角色菜单关系 + this.handleRoleMenuRelation(role.getId(), role.getMenuIds()); + } + + /** + * 处理 角色 和 菜单 关联关系 + * @param roleId + * @param menuIds + */ + private void handleRoleMenuRelation(Integer roleId, List<Integer> menuIds) { + // 当前角色关联的菜单 + List<SysRoleMenuEntity> menus = sysRoleMenuService.list(new LambdaQueryWrapper<SysRoleMenuEntity>().eq(SysRoleMenuEntity::getRoleId, roleId)); + List<Integer> menuIdList = menus.stream().map(SysRoleMenuEntity::getMenuId).distinct().collect(Collectors.toList()); + + // menu 信息未改变 不进行处理 + if (menuIdList.size() == menuIds.size() && Tool.CollUtil.containsAll(menuIdList, menuIds)) + return; + + // 更新角色与菜单关系 + sysRoleMenuService.saveOrUpdate(roleId, menuIds); + + // 角色关联 用户 + List<SysUserEntity> userList = sysUserService.getUserListByRoleId(roleId); + if (CollectionUtils.isEmpty(userList)) + return; + + List<Long> userIds = userList.stream().map(SysUserEntity::getId).distinct().collect(Collectors.toList()); + + // 删除 redis 中的 token + List<String> removeKeys = new ArrayList<>(); + try { + Map<String, SysUserEntity> shiroSessionInfoMap = ShiroUtils.getShiroSessionInfoMap(); + for (Map.Entry<String, SysUserEntity> entry : shiroSessionInfoMap.entrySet()) { + SysUserEntity userEntity = entry.getValue(); + if (userIds.contains(userEntity.getId())) { + removeKeys.add(entry.getKey()); + } + } + } catch (RuntimeException e) { + log.error(String.format("从redis中获取用户登录信息失败,错误信息是:%s,角色Id是:%s", e.getMessage(), roleId), e); + } finally { + // 删除 关联key + if (CollectionUtils.isNotEmpty(removeKeys)) { + redisTemplate.delete(removeKeys); + } + } + } + + @Override + public Map getMenuListByRoleId(Integer roleId) { + // 校验 role 是否存在 + this.validateRoleExist(roleId); + + Map resultData = new HashMap(4); + List<SysMenuEntity> menuList = sysMenuService.getMenuList(null); + + /* List<SysMenuEntity> roleMenuList = sysMenuService.getRoleMenuList(roleId); + List<Integer> selectedIds = Collections.emptyList(); + if(CollectionUtils.isNotEmpty(roleMenuList)) + selectedIds = sysMenuService.getSelectedMenuIds(roleMenuList);*/ + List<SysMenuEntity> roleMenuList = sysMenuDao.getRoleMenuList(roleId); + Set<Integer> selectedIds = roleMenuList.stream().filter(Objects::nonNull).map(SysMenuEntity::getId).collect(Collectors.toSet()); + + resultData.put("menus", menuList); + resultData.put("selectedIds", selectedIds); + + return resultData; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteBatch(Integer[] roleIds) { + // 内置角色不允许删除 + List<SysRoleEntity> buildInList = this.list(new LambdaQueryWrapper<SysRoleEntity>().eq(SysRoleEntity::getBuildIn, 1)); + List<Integer> buildInRoleIdList = buildInList.stream().map(SysRoleEntity::getId).collect(Collectors.toList()); + for (Integer roleId : roleIds) { + if (buildInRoleIdList.contains(roleId)) + throw new CNException(RCode.SYS_ROLE_CANNOT_DELETE); + } + + // 删除角色 + this.removeByIds(Arrays.asList(roleIds)); + + // 删除角色与菜单关联 + sysRoleMenuService.deleteBatch(roleIds); + + // 删除角色与用户关联 + sysUserRoleService.deleteBatch(roleIds); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysUserRoleServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysUserRoleServiceImpl.java new file mode 100644 index 0000000..1511895 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysUserRoleServiceImpl.java @@ -0,0 +1,50 @@ +package net.geedge.modules.sys.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.dao.SysUserRoleDao; +import net.geedge.modules.sys.entity.SysUserRoleEntity; +import net.geedge.modules.sys.service.SysUserRoleService; + + +@Service("sysUserRoleService") +public class SysUserRoleServiceImpl extends ServiceImpl<SysUserRoleDao, SysUserRoleEntity> implements SysUserRoleService { + + @Override + public void saveOrUpdate(Long userId, String roleIds) { + // 先删除用户与角色关系 + this.remove(new LambdaQueryWrapper<SysUserRoleEntity>().eq(SysUserRoleEntity::getUserId, userId)); + + if (Tool.StrUtil.isEmpty(roleIds)) return; + + // 保存用户与角色关系 + List<SysUserRoleEntity> saveList = new ArrayList<>(); + SysUserRoleEntity entity; + for (String roleId : Arrays.asList(roleIds.split(","))) { + entity = new SysUserRoleEntity(); + entity.setUserId(userId.intValue()); + entity.setRoleId(Integer.valueOf(roleId)); + saveList.add(entity); + } + + this.saveBatch(saveList); + } + + @Override + public List<Integer> queryRoleIdList(Integer userId) { + return baseMapper.queryRoleIdList(userId); + } + + @Override + public int deleteBatch(Integer[] roleIds){ + return baseMapper.deleteBatch(roleIds); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysUserServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..83b2dab --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/SysUserServiceImpl.java @@ -0,0 +1,363 @@ +package net.geedge.modules.sys.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.log.Log; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.geedge.common.exception.CNException; +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.*; +import net.geedge.modules.sys.dao.SysRoleDao; +import net.geedge.modules.sys.dao.SysUserDao; +import net.geedge.modules.sys.entity.SysRoleEntity; +import net.geedge.modules.sys.entity.SysUserEntity; +import net.geedge.modules.sys.entity.SysUserRoleEntity; +import net.geedge.modules.sys.service.SysMenuService; +import net.geedge.modules.sys.service.SysRoleService; +import net.geedge.modules.sys.service.SysUserRoleService; +import net.geedge.modules.sys.service.SysUserService; +import net.geedge.modules.sys.shiro.ShiroUtils; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.session.mgt.SimpleSession; +import org.apache.shiro.subject.SimplePrincipalCollection; +import org.apache.shiro.subject.support.DefaultSubjectContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; +import java.util.stream.Collectors; + +@Service("sysUserService") +public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUserEntity> implements SysUserService { + + private static Log log = Log.get(); + + @Autowired + private SysRoleService sysRoleService; + + @Autowired + private SysUserRoleService sysUserRoleService; + + @Autowired + private SysRoleDao sysRoleDao; + + @Autowired + private SysMenuService sysMenuService; + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private RedisConnectionFactory factory; + + @Override + public PageUtils queryPage(Map<String, Object> params) { + String ids = (String) params.get("ids"); + if(StrUtil.isNotBlank(ids)) { + List<String> listIds = Arrays.asList(ids.split(",")); + params.put("ids",listIds); + } + IPage page = new Query(SysUserEntity.class).getPage(params); + List<SysUserEntity> userList = baseMapper.queryList(page, params); + + // 补充 Notificationscript roles 信息 + if (CollectionUtils.isNotEmpty(userList)) { + List<SysUserRoleEntity> userRoleList = sysUserRoleService.list(); + Map<Integer, List<SysUserRoleEntity>> userRoleMap = userRoleList.stream().collect(Collectors.groupingBy(SysUserRoleEntity::getUserId)); + List<SysRoleEntity> roleList = sysRoleService.list(); + Map<Integer, SysRoleEntity> roleIdAndEntityMap = new HashMap<>(); + for (SysRoleEntity sysRoleEntity : roleList) { + roleIdAndEntityMap.put(sysRoleEntity.getId(), sysRoleEntity); + } + + for (SysUserEntity userEntity : userList) { + List<SysUserRoleEntity> userRoleEntities = userRoleMap.get(userEntity.getId().intValue()); + if (CollectionUtils.isEmpty(userRoleEntities)) { + userEntity.setRoles(Collections.emptyList()); + } else { + List<SysRoleEntity> roles = new ArrayList<>(); + for (SysUserRoleEntity userRoleEntity : userRoleEntities) { + roles.add(roleIdAndEntityMap.get(userRoleEntity.getRoleId())); + } + userEntity.setRoles(roles); + } + } + } + + page.setRecords(userList); + return new PageUtils(page); + } + + private void validateUserInfo(SysUserEntity user) { + Integer status = user.getStatus(); + ValidateUtils.is(user.getUsername()).notNull(RCode.SYS_USER_USERNAME_ISNULL) + .and(status).notNull(RCode.SYS_USER_STATUS_ISNULL).and(user.getName()).notNull(RCode.SYS_USER_NAME_ISNULL); + + List<SysUserEntity> list = this.list(new QueryWrapper<SysUserEntity>().lambda().eq(SysUserEntity::getName, user.getName()).ne(ObjectUtil.isNotEmpty(user.getId()),SysUserEntity::getId, user.getId())); + if(ObjectUtil.isNotEmpty(list)) { + throw new CNException(RCode.SYS_USER_NAME_DUPLICATE); + } + + if(status != 0 && status != 1){ + throw new CNException(RCode.SYS_USER_STATUS_INVALIDE); + } + String email = user.getEmail(); + if(StringUtils.isNotEmpty(email)){ + ValidateUtils.is(email).email(RCode.SYS_USER_EMAIL_FORMAT); + } + + // 校验角色 + String roleIds = user.getRoleIds(); + if (StringUtils.isEmpty(roleIds)) throw new CNException(RCode.SYS_ROLE_ID_ISNULL); + + List<SysRoleEntity> roleList = sysRoleService.list(); + List<Integer> roleIdList = roleList.stream().map(SysRoleEntity::getId).collect(Collectors.toList()); + + for (String roleId : Arrays.asList(roleIds.split(","))) { + if (!roleIdList.contains(Integer.valueOf(roleId))) + throw new CNException(RCode.SYS_ROLE_ISNULL); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Integer saveUser(SysUserEntity user) { + + // 校验 user 相关信息 + this.validateUserInfo(user); + + user.setCreateAt(new Date()); + //sha256加密 + String salt = RandomStringUtils.randomAlphanumeric(20); + user.setSalt(salt); + user.setPin(ShiroUtils.sha256(user.getPin(), user.getSalt())); + user.setCreateBy(ShiroUtils.getUserId().intValue()); + this.save(user); + + // 保存用户 和 角色 关联关系 + sysUserRoleService.saveOrUpdate(user.getId(), user.getRoleIds()); + + return user.getId().intValue(); + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public Integer update(SysUserEntity user) { + + // 校验 user 相关信息 + this.validateUserInfo(user); + + if (StringUtils.isBlank(user.getPin())) { + user.setPin(null); + } else { + // 如果不是本人更改 自己密码的话,删除 redis 中用户session + Long loginUserId = ShiroUtils.getUserId(); + if (!loginUserId.equals(user.getId())) { + // 通过 userId 删除 redis 中记录的 登录信息 + this.removeUserInfoInRedis(user.getId()); + } + SysUserEntity userEntity = this.getById(user.getId()); + user.setPin(ShiroUtils.sha256(user.getPin(), userEntity.getSalt())); + } + + user.setCreateBy(ShiroUtils.getUserId().intValue()); + this.updateById(user); + + // 处理用户角色关系 + this.handleUserRoleRelation(user.getId(), user.getRoleIds()); + + return user.getId().intValue(); + } + + /** + * 处理用户 和 角色 关联关系 + * @param userId + * @param roleIds + */ + private void handleUserRoleRelation(Long userId, String roleIds) { + // 当前用户关联的角色 + List<SysUserRoleEntity> roles = sysUserRoleService.list(new LambdaQueryWrapper<SysUserRoleEntity>().eq(SysUserRoleEntity::getUserId, userId.intValue())); + List<Integer> idList = roles.stream().map(SysUserRoleEntity::getRoleId).distinct().collect(Collectors.toList()); + + // 角色信息未改变 不进行处理 + List<Integer> roleIdList = new ArrayList<>(); + for (String s : Arrays.asList(roleIds.split(","))) { + roleIdList.add(Integer.valueOf(s)); + } + if (idList.size() == roleIdList.size() && Tool.CollUtil.containsAll(idList, roleIdList)) + return; + + // 角色变更 + sysUserRoleService.saveOrUpdate(userId, roleIds); + + // 通过 userId 删除 redis 中记录的 登录信息 + this.removeUserInfoInRedis(userId); + } + + /** + * 通过 userId 删除 redis 中记录的 登录信息 + * + * @param userId + */ + private void removeUserInfoInRedis(Long userId) { + // 删除 redis 中的 token + List<String> removeKeys = new ArrayList<>(); + try { + Map<String, SysUserEntity> shiroSessionInfoMap = ShiroUtils.getShiroSessionInfoMap(); + for (Map.Entry<String, SysUserEntity> entry : shiroSessionInfoMap.entrySet()) { + SysUserEntity userEntity = entry.getValue(); + if (userId.equals(userEntity.getId())) { + removeKeys.add(entry.getKey()); + } + } + } catch (RuntimeException e) { + log.error(String.format("从redis中获取用户登录信息失败,错误信息是:%s,当前用户是:%s", e.getMessage(), userId), e); + } finally { + // 删除 关联key + if (CollectionUtils.isNotEmpty(removeKeys)) { + redisTemplate.delete(removeKeys); + } + } + } + + + @Override + public boolean updatePassword(Long userId, String pin, String newPin) { + SysUserEntity userEntity = new SysUserEntity(); + userEntity.setPin(newPin); + return this.update(userEntity, + new LambdaUpdateWrapper<SysUserEntity>() + .eq(Tool.ObjectUtil.isNotEmpty(userId),SysUserEntity::getId, userId) + .eq(Tool.ObjectUtil.isNotEmpty(pin),SysUserEntity::getPin, pin)); + } + + @Override + public boolean checkName(SysUserEntity user) { + List<SysUserEntity> list = this.list(new LambdaUpdateWrapper<SysUserEntity>() + .eq(Tool.ObjectUtil.isNotEmpty(user.getUsername()), SysUserEntity::getUsername, user.getUsername()) + .eq(Tool.ObjectUtil.isNotEmpty(user.getStatus()), SysUserEntity::getStatus, 1)); + boolean dumpFlag = true; //是否名称重复,true为重复 + + //当只有一个结果并且这个结果是自身时,或没有结果时,说明名称不重复 + if ((list == null || list.size() == 0) || + (list.size() == 1 && list.get(0).getId().longValue() == user.getId().longValue())) { + dumpFlag = false; + } + return dumpFlag; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteUsers(String userIds) { + ValidateUtils.is(userIds).notNull(RCode.SYS_USER_ID_ISNULL); + String[] split = userIds.split(","); + if (ArrayUtils.contains(split, "1")) { + throw new CNException(RCode.SYS_USER_DELADMIN); + } + + SysUserEntity userEntity = (SysUserEntity) SecurityUtils.getSubject().getPrincipal(); + if (ArrayUtils.contains(split, userEntity.getId().toString())) { + throw new CNException(RCode.SYS_USER_CANNOTDEL); + } + + // 删除 user + this.removeByIds(Arrays.asList(split)); + + // 删除 关联 role 关系 + sysUserRoleService.remove(new LambdaQueryWrapper<SysUserRoleEntity>().in(SysUserRoleEntity::getUserId, Arrays.asList(split))); + + // 删除 redis 中 用户token 信息 + List<String> removeKeys = new ArrayList<>(); + List<Long> userIdList = new ArrayList<>(split.length); + for (int i = 0; i < split.length; i++) { + userIdList.add(Long.valueOf(split[i])); + } + try { + Map<String, SysUserEntity> shiroSessionInfoMap = ShiroUtils.getShiroSessionInfoMap(); + for (Map.Entry<String, SysUserEntity> entry : shiroSessionInfoMap.entrySet()) { + SysUserEntity userInfo = entry.getValue(); + if (userIdList.contains(userInfo.getId())) { + removeKeys.add(entry.getKey()); + } + } + } catch (RuntimeException e) { + log.error(String.format("从redis中获取用户登录信息失败,错误信息是:%s,删除用户ID:%s", e.getMessage(), userIdList.toString()), e); + } finally { + // 删除 关联key + if (CollectionUtils.isNotEmpty(removeKeys)) { + redisTemplate.delete(removeKeys); + } + } + } + + @Override + public Map<String, Object> getUserPermissions(HttpServletRequest request) { + String requestToken = request.getHeader(Constant.AUTH_TOKEN_CODE); + requestToken = StringUtils.isEmpty(requestToken) ? request.getParameter(Constant.AUTH_TOKEN_CODE) : requestToken; + if (StringUtils.isEmpty(requestToken)) + throw new CNException(RCode.SYS_TOKEN_ISNULL); + + RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); + redisTemplate.setConnectionFactory(factory); + + redisTemplate.afterPropertiesSet(); + + Boolean exist = redisTemplate.hasKey(ShiroUtils.REDIS_KEYPREFIX + requestToken); + if (!exist) + throw new CNException(RCode.SYS_LOGIN_REQUIRED); + + ValueOperations ops = redisTemplate.opsForValue(); + Object obj = ops.get(ShiroUtils.REDIS_KEYPREFIX + requestToken); + SimpleSession session = (SimpleSession) obj; + SimplePrincipalCollection primaryPrincipal = (SimplePrincipalCollection) session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); + SysUserEntity userEntity = (SysUserEntity) primaryPrincipal.getPrimaryPrincipal(); + + SysUserEntity user = this.getById(userEntity.getId()); + if (user == null) + throw new CNException(RCode.SYS_USER_NOT_EXIST); + + Map<String, Object> resultMap = new HashMap<>(4); + List<SysRoleEntity> rolesByUesr = sysRoleDao.getRolesByUesrId(user.getId().intValue()); + resultMap.put("roles", rolesByUesr); + + List<Integer> roleIdList = rolesByUesr.stream().map(SysRoleEntity::getId).collect(Collectors.toList()); + Map<String, Object> menuInfoByRoles = sysMenuService.getMenuInfoByRoles(roleIdList); + resultMap.put("menus", menuInfoByRoles.get("menus")); + resultMap.put("buttons", menuInfoByRoles.get("buttons")); + return resultMap; + } + + @Override + public List<SysUserEntity> getUserListByRoleId(Integer roleId) { + List<SysUserEntity> userList = this.getBaseMapper().getUserListByRoleId(roleId); + return userList; + } + + @Override + public SysUserEntity queryUserInfo(Long userId) { + SysUserEntity user = this.getById(userId); + //获取用户所属的角色列表 + List<Integer> roleIdList = sysUserRoleService.queryRoleIdList(userId.intValue()); + List<SysRoleEntity> roles = sysRoleService.list(new QueryWrapper<SysRoleEntity>().lambda().in(SysRoleEntity::getId, roleIdList)); + user.setRoles(roles); + return user; + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/TimezoneServiceImpl.java b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/TimezoneServiceImpl.java new file mode 100644 index 0000000..0050254 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/service/impl/TimezoneServiceImpl.java @@ -0,0 +1,20 @@ +package net.geedge.modules.sys.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.dao.TimezoneDao; +import net.geedge.modules.sys.entity.Timezone; +import net.geedge.modules.sys.service.TimezoneService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class TimezoneServiceImpl extends ServiceImpl<TimezoneDao, Timezone> implements TimezoneService{ + @Override + public List<Timezone> queryTimezone(String name) { + List<Timezone> list = this.list(new QueryWrapper<Timezone>().lambda().like(Tool.StrUtil.isNotBlank(name), Timezone::getName, name)); + return list; + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/shiro/MySessionManager.java b/cn-admin/src/main/java/net/geedge/modules/sys/shiro/MySessionManager.java new file mode 100644 index 0000000..ea33f4d --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/shiro/MySessionManager.java @@ -0,0 +1,39 @@ +package net.geedge.modules.sys.shiro; + +import net.geedge.common.utils.Constant; +import org.apache.shiro.web.servlet.ShiroHttpServletRequest; +import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; +import org.springframework.util.StringUtils; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.Serializable; + +public class MySessionManager extends DefaultWebSessionManager { + + private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request"; + + public MySessionManager() { + super(); + } + + @Override + protected Serializable getSessionId(ServletRequest request, ServletResponse response) { + HttpServletRequest req = (HttpServletRequest) request; + String token = req.getHeader(Constant.AUTH_TOKEN_CODE); + if (StringUtils.isEmpty(token)) { + token = request.getParameter(Constant.AUTH_TOKEN_CODE); + } + // 如果请求头中有 token 则其值为 sessionId + if (!StringUtils.isEmpty(token)) { + request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE); + request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, token); + request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); + return token; + } else { + // 否则按默认规则从cookie取sessionId + return super.getSessionId(request, response); + } + } +}
\ No newline at end of file diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/shiro/ShiroTag.java b/cn-admin/src/main/java/net/geedge/modules/sys/shiro/ShiroTag.java new file mode 100644 index 0000000..a2056e5 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/shiro/ShiroTag.java @@ -0,0 +1,22 @@ +/** + + * + + * + + */ + +package net.geedge.modules.sys.shiro; + +import org.springframework.stereotype.Component; + +/** + * Shiro权限标签 + * + + */ +@Component +public class ShiroTag { + + +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/shiro/ShiroUtils.java b/cn-admin/src/main/java/net/geedge/modules/sys/shiro/ShiroUtils.java new file mode 100644 index 0000000..d8287ac --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/shiro/ShiroUtils.java @@ -0,0 +1,122 @@ +package net.geedge.modules.sys.shiro; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.crypto.hash.SimpleHash; +import org.apache.shiro.session.Session; +import org.apache.shiro.session.mgt.SimpleSession; +import org.apache.shiro.subject.SimplePrincipalCollection; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.subject.support.DefaultSubjectContext; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import net.geedge.common.utils.SpringContextUtils; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.entity.SysUserEntity; + +/** + * Shiro工具类 + */ +public class ShiroUtils { + /** 加密算法 */ + public final static String hashAlgorithmName = "SHA-256"; + /** 循环次数 */ + public final static int hashIterations = 16; + + // redis 中 shiro key 前缀 + public final static String REDIS_KEYPREFIX = "shiro_redis_session:"; + + public static String sha256(String pin, String salt) { + return new SimpleHash(hashAlgorithmName, pin, salt, hashIterations).toString(); + } + + public static Session getSession() { + return SecurityUtils.getSubject().getSession(); + } + + public static Subject getSubject() { + return SecurityUtils.getSubject(); + } + + public static SysUserEntity getUserEntity() { + return (SysUserEntity)SecurityUtils.getSubject().getPrincipal(); + } + + public static Long getUserId() { + return getUserEntity().getId(); + } + + public static void setSessionAttribute(Object key, Object value) { + getSession().setAttribute(key, value); + } + + public static Object getSessionAttribute(Object key) { + return getSession().getAttribute(key); + } + + public static boolean isLogin() { + return SecurityUtils.getSubject().getPrincipal() != null; + } + + public static void logout() { + SecurityUtils.getSubject().logout(); + } + + /** + * 从 redis 中获取 token 和 用户信息 + * + * @return + */ + public static Map<String, SysUserEntity> getShiroSessionInfoMap() { + RedisConnectionFactory factory = SpringContextUtils.getBean("redisConnectionFactory", RedisConnectionFactory.class); + RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); + redisTemplate.setConnectionFactory(factory); + + redisTemplate.afterPropertiesSet(); + + ValueOperations ops = redisTemplate.opsForValue(); + + Set keys = redisTemplate.keys(ShiroUtils.REDIS_KEYPREFIX + "*"); + List<String> keyList = new ArrayList<>(keys); + List<Object> values = ops.multiGet(keyList); + Map<String, Object> map = new HashMap(); + + int size = keyList.size(); + for (int i = 0; i < size; i++) { + map.put(keyList.get(i), values.get(i)); + } + + Map<String, SysUserEntity> resultMap = new HashMap(map.size()); + for (Map.Entry<String, Object> entry : map.entrySet()) { + Object obj = entry.getValue(); + SimpleSession session = (SimpleSession) obj; + if (Tool.ObjectUtil.isEmpty(session.getAttributes())) + continue; + SimplePrincipalCollection primaryPrincipal = (SimplePrincipalCollection) session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); + resultMap.put(entry.getKey(), (SysUserEntity) primaryPrincipal.getPrimaryPrincipal()); + } + return resultMap; + } + + public static void removeRedisCacheByToken(List<String> tokens) { + RedisConnectionFactory factory = SpringContextUtils.getBean("redisConnectionFactory", RedisConnectionFactory.class); + RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); + redisTemplate.setConnectionFactory(factory); + + redisTemplate.afterPropertiesSet(); + redisTemplate.delete(tokens); + } +} diff --git a/cn-admin/src/main/java/net/geedge/modules/sys/shiro/UserRealm.java b/cn-admin/src/main/java/net/geedge/modules/sys/shiro/UserRealm.java new file mode 100644 index 0000000..9a2fc71 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/modules/sys/shiro/UserRealm.java @@ -0,0 +1,337 @@ +package net.geedge.modules.sys.shiro; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.naming.NamingException; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.ldap.LdapName; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.IncorrectCredentialsException; +import org.apache.shiro.authc.LockedAccountException; +import org.apache.shiro.authc.SimpleAuthenticationInfo; +import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.authc.credential.CredentialsMatcher; +import org.apache.shiro.authc.credential.HashedCredentialsMatcher; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.subject.PrincipalCollection; +import org.apache.shiro.util.ByteSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.ldap.core.AuthenticatedLdapEntryContextMapper; +import org.springframework.ldap.core.LdapEntryIdentification; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.support.LdapContextSource; +import org.springframework.ldap.filter.AndFilter; +import org.springframework.ldap.filter.EqualsFilter; +import org.springframework.ldap.filter.HardcodedFilter; +import org.springframework.ldap.filter.OrFilter; +import org.springframework.ldap.query.LdapQuery; +import org.springframework.ldap.query.LdapQueryBuilder; +import org.springframework.ldap.support.LdapUtils; +import org.springframework.stereotype.Component; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import cn.hutool.log.Log; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.Tool; +import net.geedge.modules.sys.dao.SysRoleDao; +import net.geedge.modules.sys.dao.SysRoleMenuDao; +import net.geedge.modules.sys.dao.SysUserDao; +import net.geedge.modules.sys.dao.SysUserRoleDao; +import net.geedge.modules.sys.entity.SysMenuEntity; +import net.geedge.modules.sys.entity.SysRoleEntity; +import net.geedge.modules.sys.entity.SysRoleMenuEntity; +import net.geedge.modules.sys.entity.SysUserEntity; +import net.geedge.modules.sys.entity.SysUserRoleEntity; +import net.geedge.modules.sys.service.SysConfigService; +import net.geedge.modules.sys.service.SysMenuService; + +/** + * 认证 + */ +@Component +public class UserRealm extends AuthorizingRealm { + + private static final Log log = Log.get(); + @Autowired + private SysUserDao sysUserDao; + + @Autowired + private SysRoleDao sysRoleDao; + + @Autowired + private SysRoleMenuDao sysRoleMenuDao; + + @Autowired + private SysMenuService sysMenuService; + + @Autowired + private SysConfigService sysConfigService; + + @Autowired + private SysUserRoleDao sysUserRoleDao; + + @Value("${ldap.default.mapping:{\"email\":\"mail\",\"username\":\"uid|sAMAccountName|cn\"}}") + private String defaultMappingStr; + + private static final String LDAP_MAPPING_USERNAME_KEY = "username"; + + /** + * 授权(验证权限时调用) + */ + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + SysUserEntity user = (SysUserEntity) principals.getPrimaryPrincipal(); + + // 查看用户所有角色 + List<SysRoleEntity> rolesByUesr = null; + + if(Tool.ObjectUtil.isNotEmpty(user.getApiKeyId())) { + rolesByUesr = sysRoleDao.getRolesBySysApiKeyId(user.getApiKeyId()); + }else { + rolesByUesr = sysRoleDao.getRolesByUesrId(user.getId().intValue()); + } + + List<String> permsList; + if (CollectionUtils.isEmpty(rolesByUesr)) { + permsList = Collections.emptyList(); + } else { + SysRoleEntity buildRole = rolesByUesr.stream() + .filter(sysRoleEntity -> sysRoleEntity.getId().equals(Constant.SUPER_ADMIN)).findAny().orElse(null); + // admin 角色 拥有所有接口权限 + List<SysMenuEntity> menuList; + if (buildRole != null) { + menuList = sysMenuService.list(); + } else { + Set<Integer> roleIds = rolesByUesr.stream().map(SysRoleEntity::getId).collect(Collectors.toSet()); + List<SysRoleMenuEntity> sysRoleMenuEntities = sysRoleMenuDao.selectList( + new LambdaQueryWrapper<SysRoleMenuEntity>().in(SysRoleMenuEntity::getRoleId, roleIds)); + if (CollectionUtils.isNotEmpty(sysRoleMenuEntities)) { + // 所有叶子节点 + Set<Integer> menuIds = sysRoleMenuEntities.stream().map(SysRoleMenuEntity::getMenuId) + .collect(Collectors.toSet()); + menuList = sysMenuService + .list(new LambdaQueryWrapper<SysMenuEntity>().in(SysMenuEntity::getId, menuIds)); + // 根据叶子节点得到完整的权限 + menuList = sysMenuService.getMenuByLeafMenu(menuList); + } else { + menuList = Collections.emptyList(); + } + } + + permsList = new ArrayList<>(); + for (SysMenuEntity menu : menuList) { + permsList.add(menu.getPerms()); + } + } + + // 用户权限列表 + Set<String> permsSet = new HashSet<>(); + for (String perms : permsList) { + if (StringUtils.isEmpty(perms)) + continue; + permsSet.addAll(Arrays.asList(perms.trim().split(","))); + } + + SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); + info.setStringPermissions(permsSet); + return info; + } + + /** + * 认证(登录时调用) + */ + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) + throws AuthenticationException { + UsernamePasswordToken token = (UsernamePasswordToken) authcToken; + + // 查询用户信息 + SysUserEntity user = sysUserDao.selectOne(new QueryWrapper<SysUserEntity>().eq("username", token.getUsername())); + // 账号不存在,使用ldap验证 + if (user == null) { + StringBuilder sb = new StringBuilder(); + sb.append(token.getPassword()); + user = getLdapAuthentication(token.getUsername(), sb.toString()); + if (user == null) { + throw new IncorrectCredentialsException("账号或密码不正确"); + } + user.setSource("ldap"); + user.setStatus(1); + sysUserDao.insert(user); + + // ldap 登录用户默认分配 common 角色 + SysUserRoleEntity sysUserRole = new SysUserRoleEntity(); + sysUserRole.setUserId(user.getId().intValue()); + sysUserRole.setRoleId(Constant.SYSTEM_COMMON_ROLE); + sysUserRoleDao.insert(sysUserRole); + String salt = RandomStringUtils.randomAlphanumeric(20); + user.setSalt(salt); + user.setPin(ShiroUtils.sha256(sb.toString(), salt)); + } else if(user.getSource().equals("ldap")){ + //ldap非首次登陆,更新同步内容 + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(token.getPassword()); + SysUserEntity tmpUser = getLdapAuthentication(token.getUsername(), stringBuilder.toString()); + if(tmpUser == null) { + // 验证失败 则登录失败 + throw new IncorrectCredentialsException("账号或密码不正确"); + } + @SuppressWarnings("unchecked") + Map<String,String> defaultMapping = JSONUtil.toBean(defaultMappingStr, HashMap.class); + for(Entry<String,String> entry : defaultMapping.entrySet()) { + String key = entry.getKey(); + String value = BeanUtil.getProperty(tmpUser, key); + BeanUtil.setProperty(user, key, value); + } + sysUserDao.updateById(user); + String salt = RandomStringUtils.randomAlphanumeric(20); + user.setSalt(salt); + user.setPin(ShiroUtils.sha256(stringBuilder.toString(), salt)); + } else { + // 判断系统内用户账号是否锁定 + if (user.getStatus() == 0) { + throw new LockedAccountException("账号已被锁定,请联系管理员"); + } + } + SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPin(),ByteSource.Util.bytes(user.getSalt()), getName()); + return info; + } + + @Override + public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) { + HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher(); + shaCredentialsMatcher.setHashAlgorithmName(ShiroUtils.hashAlgorithmName); + shaCredentialsMatcher.setHashIterations(ShiroUtils.hashIterations); + super.setCredentialsMatcher(shaCredentialsMatcher); + } + + /** + * ldap登录验证 + * + * @return + */ + @SuppressWarnings("unchecked") + public SysUserEntity getLdapAuthentication(String userName, String pin) { + // 获取sys_config中的ldap信息 判断是否支持ldap登录 + Map<String, Object> ldapInfos = sysConfigService.getConfigListByTypes(new String[] { "ldap" }, null); + Map<String, String> ldap = (Map<String, String>) ldapInfos.get("ldap"); + // 判断是否开启 ldap 认证 + if (ObjectUtils.isEmpty(ldap) || StrUtil.isBlank(ldap.get("ldap_enable")) + || "off".equalsIgnoreCase(ldap.get("ldap_enable"))) { + return null; + } + String ldapAddress = ldap.get("ldap_address"); + String ldapDN = ldap.get("ldap_dn"); + String ldapPassword = ldap.get("ldap_password"); + ldapPassword = StrUtil.str(Base64.getDecoder().decode(ldapPassword), "UTF-8"); + String ldapUserFilter = ldap.get("ldap_user_filter"); + String ldapMapping = ldap.get("ldap_mapping"); + String ldapOu = ldap.get("ldap_ou"); + + if (StrUtil.isBlank(ldapAddress) || StrUtil.isBlank(ldapDN) || StrUtil.isBlank(ldapPassword) + || StrUtil.isBlank(ldapUserFilter)) { + // 参数不正确 + return null; + } + //用户配置 mapping + Map<String, String> configMapping = JSONUtil.toBean(ldapMapping, HashMap.class); + Map<String,String> defaultMapping = JSONUtil.toBean(defaultMappingStr, HashMap.class); + LdapContextSource ldapContextSource = new LdapContextSource(); + ldapContextSource.setUrl(ldapAddress); + ldapContextSource.setUserDn(ldapDN); + ldapContextSource.setPassword(ldapPassword); + ldapContextSource.setReferral("follow"); + ldapContextSource.afterPropertiesSet(); // important + + LdapTemplate ldapTemplate = new LdapTemplate(ldapContextSource); + // 组织filter + AndFilter queryFilter = new AndFilter(); + // username filter + String uname = StrUtil.isNotBlank(configMapping.get(LDAP_MAPPING_USERNAME_KEY)) + ? configMapping.get(LDAP_MAPPING_USERNAME_KEY) + : defaultMapping.get(LDAP_MAPPING_USERNAME_KEY); + List<String> unameList = StrUtil.splitTrim(uname, "|"); + OrFilter orFilter = new OrFilter(); + for (String n : unameList) { + orFilter.append(new EqualsFilter(n, userName)); + } + queryFilter.append(orFilter); + if (StrUtil.isNotEmpty(ldapUserFilter)) { + queryFilter.append(new HardcodedFilter(ldapUserFilter)); + } + // 支持配置多个 ou 搜索用户 + List<String> baseList = StrUtil.splitTrim(ldapOu, "|"); + SysUserEntity entity = null; + for (String base : baseList) { + LdapQuery query = LdapQueryBuilder.query().base(base).timeLimit(20000).countLimit(1000).filter(queryFilter); + try { + // 开始认证 + entity = ldapTemplate.authenticate(query, pin,new AuthenticatedLdapEntryContextMapper<SysUserEntity>() { + @Override + public SysUserEntity mapWithContext(DirContext ctx,LdapEntryIdentification ldapEntryIdentification) { + LdapName ldapName = ldapEntryIdentification.getAbsoluteName(); + Attributes attributes; + SysUserEntity user = null; + try { + attributes = ctx.getAttributes(ldapName); + Map<String, String> attrMap = new HashMap<String, String>(); + // 获取用户属性导入 系统 + for (Entry<String, String> entry : defaultMapping.entrySet()) { + String key = entry.getKey(); + String attrKey = StrUtil.isNotBlank(configMapping.get(key)) ? configMapping.get(key) : entry.getValue(); + List<String> attrKeyList = StrUtil.splitTrim(attrKey, "|"); + for (String ak : attrKeyList) { + Object obj = attributes.get(ak) != null ? attributes.get(ak).get() : null; + if (obj != null) { + attrMap.put(key, obj.toString()); + break; + } + } + } + // 赋值 sysuser + user = new SysUserEntity(); + BeanUtil.fillBeanWithMap(attrMap, user, true); + } catch (NamingException e) { + log.debug(e); + } + LdapUtils.closeContext(ctx); + return user; + } + }); + } catch (RuntimeException e) { + log.warn(e,"ldap Authentication failed,base: {}",base); + } + if (entity != null) { + break; + } + } + return entity; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/setup/controller/SetupController.java b/cn-admin/src/main/java/net/geedge/setup/controller/SetupController.java new file mode 100644 index 0000000..80544cc --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/setup/controller/SetupController.java @@ -0,0 +1,209 @@ +package net.geedge.setup.controller; + +import java.io.File; +import java.io.IOException; +import java.sql.SQLException; + +import cn.hutool.core.io.IORuntimeException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import net.geedge.common.smartvalidate.ValidateUtils; +import net.geedge.common.utils.Constant; +import net.geedge.common.utils.R; +import net.geedge.common.utils.RCode; +import net.geedge.common.utils.Tool; +import net.geedge.setup.entity.SetupEntity; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.RuntimeUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.db.Db; +import cn.hutool.db.DbUtil; +import cn.hutool.db.ds.simple.SimpleDataSource; +import cn.hutool.log.Log; +import cn.hutool.setting.dialect.Props; +import redis.clients.jedis.Jedis; + +@RestController +@RequestMapping("/setup") +public class SetupController { + private Log log = Log.get(); + + @Value("${cn.inited:0}") + private int inited; + @Value("${server.tomcat.basedir}") + private String tmpDir; + @Value("${cn.config.path:./config/cn.properties}") + private String nezhaConfigPath; + @Value("${spring.datasource.druid.driver-class-name}") + private String driver; + @Value("${cn.restart.command:systemctl restart nzweb.service}") + private String restartCommand; + @Value("${database.loginTimeout:10}") + private Integer dbLoginTimeouot;//数据库登录超时时间 + @Value("${redis.loginTimeout:10}") + private Integer redisLoginTimeouot;//redis登录超时时间 + /** + * 获取 cn inited 状态 + * @return + */ + @GetMapping("inited") + public R state() { + return R.ok().put("inited", inited); + } + + /** + * 最后完成配置 + * @param setup + * @return + */ + @PostMapping("/config") + public R setup(@RequestBody SetupEntity setup){ + ValidateUtils.is(setup.getDatabase().getHost()).notNull(RCode.SYS_CONFIG_DB_URL_ISNULL) + .and(setup.getDatabase().getUsername()).notNull(RCode.SYS_CONFIG_DB_USERNAME_ISNULL) + .and(setup.getDatabase().getPin()).notNull(RCode.SYS_CONFIG_DB_PASSWORD_ISNULL) + .and(setup.getRedis().getHost()).notNull(RCode.SYS_CONFIG_REDIS_HOST_ISNULL); + R r = doCheckCode(setup.getCode()); + if(r.get("code") != RCode.SUCCESS.getCode()){ + return R.error(RCode.SYS_CONFIG_CODE_INVALID); + } + if(inited == 2) {//已经配置过,不需要再配置 + return R.error(RCode.SYS_CONFIG_HAD_CONFIG); + } + try{ + //配置文件 + boolean absolutePath = Tool.FileUtil.isAbsolutePath(nezhaConfigPath); + File configFile = absolutePath ? Tool.FileUtil.file(nezhaConfigPath) : Tool.FileUtil.file(Tool.WebPathUtil.getRootPath(),nezhaConfigPath); + log.info("nezhaConfigPath:{}",configFile.getAbsolutePath()); + //更改 cn.inited 为 2,下次启动时不再执行 + //cn.properties 配置文件路径:./config/cn.properties + Props prop = null; + if(!configFile.exists()) { + //创建父目录&配置文件 + Tool.FileUtil.mkParentDirs(configFile.getAbsolutePath()); + boolean newFile = configFile.createNewFile(); + log.info("set up config new file {}", newFile); + } + prop = new Props(configFile, Constant.DEFAULT_CHARTSET_NAME); + prop.put("cn.inited", "1"); + prop.put("database.host",setup.getDatabase().getHost()); + prop.put("database.port",Tool.StrUtil.utf8Str(setup.getDatabase().getPort())); + prop.put("database.name",setup.getDatabase().getName()); + prop.put("database.user",setup.getDatabase().getUsername()); + prop.put("database.pin",setup.getDatabase().getPin()); + prop.put("redis.host",setup.getRedis().getHost()); + prop.put("redis.port",Tool.StrUtil.utf8Str(setup.getRedis().getPort())); + prop.put("redis.pin",setup.getRedis().getPin()); + if(Tool.StrUtil.isBlank(prop.getStr("server.port"))) { + prop.put("server.port","8080"); + } + //保存配置文件 + prop.store(configFile.getAbsolutePath()); + + //其它配置保存到临时文件 + File tmpConfigFile = Tool.FileUtil.file(tmpDir, Constant.SETUP_FILE_NAME); + if(!tmpConfigFile.exists()) { + //创建父目录&配置文件 + Tool.FileUtil.mkParentDirs(tmpConfigFile.getAbsolutePath()); + boolean newFile = tmpConfigFile.createNewFile(); + log.info("set up config new file {}", newFile); + } + Tool.FileUtil.writeUtf8String(Tool.JSONUtil.toJsonStr(setup), tmpConfigFile); + //重启nzweb + this.restart(); + return R.ok(); + } catch (IOException e) { + log.error(e); + return R.error(); + } catch (IORuntimeException e) { + log.error(e); + return R.error(); + } + } + @GetMapping("/checkCode") + public R checkCode(String code){ + R r = doCheckCode(code); + return r; + } + + @PostMapping("/checkDb") + public R checkDBConnection(@RequestBody SetupEntity setup){ + R r = doCheckCode(setup.getCode()); + if(r.get("code") != RCode.SUCCESS.getCode()){ + return R.error(RCode.SYS_CONFIG_CODE_INVALID); + } + ValidateUtils.is(setup.getDatabase().getHost()).notNull(RCode.SYS_CONFIG_DB_PARAM_INVALID) + .and(setup.getDatabase().getUsername()).notNull(RCode.SYS_CONFIG_DB_USERNAME_ISNULL) + .and(setup.getDatabase().getPin()).notNull(RCode.SYS_CONFIG_DB_PASSWORD_ISNULL); + try{ + SimpleDataSource ds = new SimpleDataSource(setup.getDatabase().getUrl(), setup.getDatabase().getUsername(), setup.getDatabase().getPin(), driver); + ds.setLoginTimeout(dbLoginTimeouot); + Db db = DbUtil.use(ds); + String result = db.queryString("select 1"); + if(Tool.StrUtil.isNotBlank(result)) { + return R.ok(); + } + return R.error(RCode.SYS_CONFIG_DB_PARAM_INVALID); + }catch (SQLException | RuntimeException e){ + log.error(e); + return R.error(RCode.SYS_CONFIG_DB_PARAM_INVALID); + } + } + + @PostMapping("/checkRedis") + public R checkRedisConnection(@RequestBody SetupEntity setup){ + R r = doCheckCode(setup.getCode()); + if(r.get("code") != RCode.SUCCESS.getCode()){ + return R.error(RCode.SYS_CONFIG_CODE_INVALID); + } + ValidateUtils.is(setup.getRedis().getHost()).notNull(RCode.SYS_CONFIG_REDIS_HOST_ISNULL); + Jedis jedis = null; + try{ + jedis = new Jedis(setup.getRedis().getHost(),setup.getRedis().getPort(),redisLoginTimeouot); + if(!StrUtil.isEmpty(setup.getRedis().getPin())){ + jedis.auth(setup.getRedis().getPin()); + } + + if("pong".equalsIgnoreCase(jedis.ping())){ + return R.ok(); + } + return R.error(RCode.SYS_CONFIG_REDIS_PARAM_INVALID); + }catch (RuntimeException e){ + log.error(e); + if(e.getMessage().indexOf("NOAUTH") != -1){ + return R.error(RCode.SYS_CONFIG_REDIS_PASSWORD_REQUIRED); + }else if(e.getMessage().indexOf("invalid password") != -1){ + return R.error(RCode.SYS_CONFIG_REDIS_PASSWORD_INVALID); + }else{ + return R.error(RCode.SYS_CONFIG_REDIS_PARAM_INVALID); + } + }finally { + IoUtil.close(jedis); + } + } + private R doCheckCode(String code){ + File codeFile = FileUtil.file(this.tmpDir,"cn.auth"); + log.info("cn.auth path: {} ",codeFile.getAbsolutePath()); + if(!FileUtil.exist(codeFile)){ + return R.error(RCode.SYS_CONFIG_CODE_FILE_ISNULL); + } + + String readCode = Tool.FileUtil.readUtf8String(codeFile); + if(StrUtil.isEmpty(readCode) || !readCode.equals(code)){ + return R.error(RCode.SYS_CONFIG_CODE_INVALID); + } + return R.ok(); + } + + public void restart(){ + if (Tool.SystemUtil.getOsInfo().isLinux()){ + RuntimeUtil.exec(restartCommand); + } + } +} diff --git a/cn-admin/src/main/java/net/geedge/setup/entity/DatabaseEntity.java b/cn-admin/src/main/java/net/geedge/setup/entity/DatabaseEntity.java new file mode 100644 index 0000000..a449610 --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/setup/entity/DatabaseEntity.java @@ -0,0 +1,21 @@ +package net.geedge.setup.entity; + +import java.io.Serializable; + +import lombok.Data; + +@Data +public class DatabaseEntity implements Serializable { + + private static final long serialVersionUID = 9168478023996506144L; + private String host; + private Integer port = 3306; + private String name = "cn"; + private String username; + private String pin; + + public String getUrl(){ + return "jdbc:mysql://"+this.getHost()+":"+this.getPort()+"/"+this.getName()+"?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false"; + } + +} diff --git a/cn-admin/src/main/java/net/geedge/setup/entity/RedisEntity.java b/cn-admin/src/main/java/net/geedge/setup/entity/RedisEntity.java new file mode 100644 index 0000000..6fc4a8b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/setup/entity/RedisEntity.java @@ -0,0 +1,16 @@ +package net.geedge.setup.entity; + +import java.io.Serializable; + +import lombok.Data; + +@Data +public class RedisEntity implements Serializable { + /** + * + */ + private static final long serialVersionUID = 482413912244656102L; + private String host; + private Integer port = 6379; + private String pin ; +} diff --git a/cn-admin/src/main/java/net/geedge/setup/entity/SetupEntity.java b/cn-admin/src/main/java/net/geedge/setup/entity/SetupEntity.java new file mode 100644 index 0000000..f042a8a --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/setup/entity/SetupEntity.java @@ -0,0 +1,16 @@ +package net.geedge.setup.entity; + +import java.io.Serializable; + +import lombok.Data; +@Data +public class SetupEntity implements Serializable { + /** + * + */ + private static final long serialVersionUID = 3573525758058342563L; + private RedisEntity redis; + private DatabaseEntity database; + private SystemEntity system; + private String code; +} diff --git a/cn-admin/src/main/java/net/geedge/setup/entity/SystemEntity.java b/cn-admin/src/main/java/net/geedge/setup/entity/SystemEntity.java new file mode 100644 index 0000000..842ed7b --- /dev/null +++ b/cn-admin/src/main/java/net/geedge/setup/entity/SystemEntity.java @@ -0,0 +1,19 @@ +package net.geedge.setup.entity; + +import java.io.Serializable; + +import lombok.Data; + +@Data +public class SystemEntity implements Serializable { + /** + * + */ + private static final long serialVersionUID = -7879602213109898774L; + private String alertPath; + private String alertPrefix; + // prometheus_federation_enabled + private String federationEnabled = "1"; + private String username; + private String pin; +} diff --git a/cn-admin/src/main/resources/application.yml b/cn-admin/src/main/resources/application.yml new file mode 100644 index 0000000..90bf471 --- /dev/null +++ b/cn-admin/src/main/resources/application.yml @@ -0,0 +1,92 @@ +# Tomcat +server: + tomcat: + uri-encoding: UTF-8 + max-threads: 1000 + min-spare-threads: 30 + basedir: /opt/cn/tmp +# port: 8088 + +spring: + main: + allow-bean-definition-overriding: true + profiles: + active: prod + autoconfigure: + exclude: # 排除自动装配,自己实现数据库,redis 装配 + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure + - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration + - org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration + - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration + - com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: UTC + servlet: + multipart: + max-file-size: 100MB + max-request-size: 100MB + enabled: true + + flyway: + enabled: true # 是否开启 + encoding: UTF-8 # 编码 + sql-migration-prefix: V # 脚本文件的前缀,默认为V + sql-migration-separator: __ # 双下划线 + baseline-on-migrate: true # 连接数据库中存在表时设置为true + locations: classpath:db # 脚本路径 + clean-disabled: false # flyway 的 clean 命令会删除指定 schema 下的所有 table, 生产务必禁掉。这个默认值是 false 理论上作为默认配置是不科学的 + validate-on-migrate: true # 执行迁移时是否自动调用验证 当你的 版本不符合逻辑 比如 你先执行了 DML 而没有 对应的DDL 会抛出异常 + placeholder-replacement: false # 不做取值替换 默认替换为 ${} ,初始化sql中有sql语句存在freemarker替换,所以禁用此项 + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + driver-class-name: com.mysql.jdbc.Driver + initial-size: 10 + max-active: 100 + min-idle: 10 + max-wait: 60000 + pool-prepared-statements: true + max-pool-prepared-statement-per-connection-size: 20 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 + test-while-idle: true + test-on-borrow: false + test-on-return: false + stat-view-servlet: + enabled: true + url-pattern: /druid/* + filter: + stat: + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: false + wall: + config: + multi-statement-allow: true +logging: + config: classpath:./config/logback-spring.xml + +#mybatis +mybatis-plus: + mapper-locations: classpath*:/mapper/**/*.xml + #实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: net.geedge.modules.*.entity + global-config: + #数据库相关配置 + db-config: + #主键类型 AUTO:"数据库ID自增", INPUT:"用户输入ID", ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID"; + id-type: AUTO + #字段策略 IGNORED:"忽略判断",NOT_NULL:"非 NULL 判断"),NOT_EMPTY:"非空判断" + field-strategy: NOT_NULL + #驼峰下划线转换 + column-underline: true + logic-delete-value: 1 + logic-not-delete-value: 0 + banner: false + #原生配置 + configuration: + map-underscore-to-camel-case: true + cache-enabled: false + call-setters-on-nulls: true + jdbc-type-for-null: 'null'
\ No newline at end of file diff --git a/cn-admin/src/main/resources/banner.txt b/cn-admin/src/main/resources/banner.txt new file mode 100644 index 0000000..5bd4566 --- /dev/null +++ b/cn-admin/src/main/resources/banner.txt @@ -0,0 +1,9 @@ + _____ _ _ _ _ + / ____| | | | \ | | | | +| | _ _| |__ ___ _ __ | \| | __ _ _ __ _ __ __ _| |_ ___ _ __ +| | | | | | '_ \ / _ \ '__| | . ` |/ _` | '__| '__/ _` | __/ _ \| '__| +| |___| |_| | |_) | __/ | | |\ | (_| | | | | | (_| | || (_) | | + \_____\__, |_.__/ \___|_| |_| \_|\__,_|_| |_| \__,_|\__\___/|_| + __/ | + |___/ + diff --git a/cn-admin/src/main/resources/config/cn.properties b/cn-admin/src/main/resources/config/cn.properties new file mode 100644 index 0000000..712e1c5 --- /dev/null +++ b/cn-admin/src/main/resources/config/cn.properties @@ -0,0 +1,13 @@ +#Sat May 08 06:23:37 UTC 2021 +server.port=8090 +cn.inited=2 +database.name=cn-test +database.host=192.168.40.42 +database.port=3306 +database.user=root +database.pin=111111 +redis.host=192.168.40.41 +redis.port=6379 +redis.database=11 +redis.pin= + diff --git a/cn-admin/src/main/resources/config/logback-spring.xml b/cn-admin/src/main/resources/config/logback-spring.xml new file mode 100644 index 0000000..9e6966e --- /dev/null +++ b/cn-admin/src/main/resources/config/logback-spring.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + <include resource="org/springframework/boot/logging/logback/base.xml" /> + <logger name="org.springframework.web" level="info" /> + <logger name="org.springboot.sample" level="info" /> + <logger name="org.apache" level="info" /> + <logger name="org.springframework" level="info" /> + <logger name="druid.sql" level="info" /> + <logger name="com.springboot" level="debug" /> + + <property name="log.path" value="./logs/" /> + <!-- 输出格式 --> + <property name="out.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n" /> + <!-- 活动文件的大小 --> + <property name="max.file.size" value="100MB"/> + <!-- 保留的归档文件的最大数量 --> + <property name="max.history" value="30"/> + <!-- 控制所有归档日志文件的总大小 --> + <property name="total.size.cap" value="15GB"/> + + <!-- 2.2 level为 INFO 日志,时间滚动输出 --> + <appender name="LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <!-- 正在记录的日志文档的路径及文档名 --> + <file>${log.path}/cn-web.log</file> + <!--日志文档输出格式 --> + <encoder> + <pattern>${out.pattern}</pattern> + <charset>UTF-8</charset> + </encoder> + <!-- 日志记录器的滚动策略,按日期,按大小记录 --> + <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> + <fileNamePattern>${log.path}/cn-web-%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <maxFileSize>${max.file.size}</maxFileSize> + <maxHistory>${max.history}</maxHistory> + <totalSizeCap>${total.size.cap}</totalSizeCap> + </rollingPolicy> + </appender> + + <!-- 2.1 level为 ERROR 日志,时间滚动输出 --> + <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <!-- 正在记录的日志文档的路径及文档名 --> + <file>${log.path}/cn-web-error.log</file> + <!--日志文档输出格式 --> + <encoder> + <pattern>${out.pattern}</pattern> + <charset>UTF-8</charset> + </encoder> + <!-- 日志记录器的滚动策略,按日期,按大小记录 --> + <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> + <fileNamePattern>${log.path}/cn-web-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <maxFileSize>${max.file.size}</maxFileSize> + <maxHistory>${max.history}</maxHistory> + <totalSizeCap>${total.size.cap}</totalSizeCap> + </rollingPolicy> + <!-- 此日志文档只记录debug级别的 --> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>error</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <root level="INFO"> + <appender-ref ref="LOG_FILE" /> + <appender-ref ref="ERROR_FILE" /> + </root> + +</configuration> diff --git a/cn-admin/src/main/resources/db/V21.07__init db.sql b/cn-admin/src/main/resources/db/V21.07__init db.sql new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cn-admin/src/main/resources/db/V21.07__init db.sql diff --git a/cn-admin/src/main/resources/license/license.key b/cn-admin/src/main/resources/license/license.key new file mode 100644 index 0000000..23ced89 --- /dev/null +++ b/cn-admin/src/main/resources/license/license.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC53duIKC0ZH15H +k7Rd9y2cj05HDtMguzq9fOlmyEUxzegVq9G2Pc+A3HpmyQLt+k5G4SR1tyoZEG4B ++qQ7bJjLtmhUeNH4w/bKFR5YvfUPXSOcZ2awNWJpL2wcOEM41k5KjEoLUlUwdQ8+ +OUb0mNPZyWm0PZthgOuQIqUUiFOTnT9pI7cOqXHjE+f1lV4Upfje0Czo5ONYduQ8 +OCsnSq7sxzkB+nDndi/j1n2ehZjWjO4ryY02NWGN9KjK+VdYqtFj7ZY0qF+6aWLM +XNuKwpOwke62vFxWuqoQEnz8XrnczUUlFeFlEa/Rcb+TjuJ0c8WZg+A26f3rL7vQ +hutTuJybAgMBAAECggEAfTBvo1/cMGWubOuRuxC3yhHEGZxknFE/mU2/L5mI8ajM +v3wBPoyXbSYT05Nkw8GqY5dVpWv/kO4+Cls1r0jQCbYMw4i1dKcZXLeovwEDRJvp +VnlW8yyh4lMssD09GdVO2mtvm/ySoJbX84NExY8Cclh1OA+ezqe1Alozcob4NB26 +J2u6XpgpY+PLlhduPI7235Klab8ESlYU2WHcB2SQnA9Xwq46X5jJbaUwEys3o4V6 +MDm9WPC00muFHVUzceUouHnX/x4ACFboF2uxMaSI887W3zL+XJQ+ao2Wdnn77O1V +EP55ZCncFF1SegHasGDfFJKcsJv96QWh9WTJOK9doQKBgQDeU83BHe+1sh1NvJS/ +jQ85Ao2m1dsv7/8RR8kLAte263+cgFpCmQjXu6RSBty+yQq9SOxmA7xdpUnzykG+ +HGJVPjwABUqgACpaK+T+1gTe2ZJB5ALikME3iKbUAMBQy7tmUGHVqb1CVWwzIxUE +JZ+EnxAbTXkQOflulrOVdbuu0wKBgQDWBGD7HJD/8Li2rO2GiBGtn65yMQe9iaaD +s9LtGY3jzsFL+Y8IE8mtcQKvlhAitEWBzVM4mmwJlfbnMrH0/P7xtFt2PGo+9Egl +4J+G46746Xcm1/rHu3Nem+d8AHnlB+BL8KvGB7OVeez9IHnvFxlLNjkqAEaFEGJN +ZNd2CLcOGQKBgCrbKqlUNPXoTJ/Ef0PhVBLgPB/xz1uRPrC9DrLxrFVVVfb8Auod +h8fWItmw+vJH3KsaGH+drry6dOPqk/uqiwX1hilW28i133QcS/sXlD7E392Vrzyv +PJ+Q1t+8+VVZwFj7m7BNFO9pef7tf0qaWgJ9iuRIbdLD6iH4KMvhsvkDAoGBAIjo +HDIHQCq6Dy+sx/W7rbNn5uxduRniqIavzkqmgkIszTKQ3pLINceh95njYUcSEzTJ +6GbZQiuPp3aW04hpH533RlsIot7K3ix82RAtLo1ErFhI6cBDhbYL/bUxiMielTl/ +KCNyYctJR/VVhSsRl7ipY0AfFP2iUYA49iwnvxJhAoGAC7GDt9uty3ecRkRg1ctR +S26QVObFvrn2/+6bD8xCz3H0djk8vRc43iQhUQ1sp9T3wZnedNx4s/k1q95lzCme +P4Ewkf3X0S9KrfxST7bXvZ4ScLJrzHNUQEK2BoQXl/gysocuVbOqZlBvohAnHwm/ +GV5WC8M+ssr9EKvLdfhdzCE= +-----END PRIVATE KEY----- diff --git a/cn-admin/src/main/resources/license/license.pem b/cn-admin/src/main/resources/license/license.pem new file mode 100644 index 0000000..70bc88c --- /dev/null +++ b/cn-admin/src/main/resources/license/license.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDmTCCAoGgAwIBAgIJAPix3ELHg4o0MA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV +BAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlqaW5nMRgwFgYD +VQQKDA9HZWVkZ2UgTmV0d29ya3MxFjAUBgNVBAMMDUxpY2Vuc2UtTkVaSEEwHhcN +MjEwNDE1MDQzNTU3WhcNMzEwNDEzMDQzNTU3WjBjMQswCQYDVQQGEwJDTjEQMA4G +A1UECAwHQmVpamluZzEQMA4GA1UEBwwHQmVpamluZzEYMBYGA1UECgwPR2VlZGdl +IE5ldHdvcmtzMRYwFAYDVQQDDA1MaWNlbnNlLU5FWkhBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAud3biCgtGR9eR5O0XfctnI9ORw7TILs6vXzpZshF +Mc3oFavRtj3PgNx6ZskC7fpORuEkdbcqGRBuAfqkO2yYy7ZoVHjR+MP2yhUeWL31 +D10jnGdmsDViaS9sHDhDONZOSoxKC1JVMHUPPjlG9JjT2clptD2bYYDrkCKlFIhT +k50/aSO3Dqlx4xPn9ZVeFKX43tAs6OTjWHbkPDgrJ0qu7Mc5Afpw53Yv49Z9noWY +1ozuK8mNNjVhjfSoyvlXWKrRY+2WNKhfumlizFzbisKTsJHutrxcVrqqEBJ8/F65 +3M1FJRXhZRGv0XG/k47idHPFmYPgNun96y+70IbrU7icmwIDAQABo1AwTjAdBgNV +HQ4EFgQUVt1hbTgMVIfe2A/5m9aFuKSR/7EwHwYDVR0jBBgwFoAUVt1hbTgMVIfe +2A/5m9aFuKSR/7EwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAoZKy +alwHrszTZ/48yfDxOVFmBeI6CnBBl/7r7zldXPY5kHSUavhUVuJKKVoMvDPmfqOe +zo0nSLn8m8RPZ1R6fCMrsRAwBVoB16vOwkSGYh9ajB0F3VqwDQQI0HmpNP7uBPYQ +XGD6ZNCiqCIt0ng8u1GMP/oWHEWi7fjaf/Nnsu9CYw+wMhpH0hyamawP8S+RHvMD +37AH+bEOVZmmV07JYgzLHAuYUGT2NxpdjUMFch8AJqYTEdGsr2e68SR6zCAOse8W +hyMjbcNOaTn5edAEc+1HqV+5slQO7KHBy1PoOwduIoF8veGQq2eOmpIL38mEC2oO +UNegrzOTCmUxUI2zRQ== +-----END CERTIFICATE----- diff --git a/cn-admin/src/main/resources/mapper/sys/LinkDao.xml b/cn-admin/src/main/resources/mapper/sys/LinkDao.xml new file mode 100644 index 0000000..d025cf7 --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/LinkDao.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="net.geedge.modules.sys.dao.LinkDao"> + + <resultMap type="net.geedge.modules.sys.entity.Link" id="link"> + <result property="id" column="id"/> + <result property="name" column="name"/> + <result property="createBy" column="create_by"/> + <result property="url" column="url"/> + <result property="weight" column="weight"/> + <result property="buildIn" column="build_in"/> + + <association columnPrefix="u_" property="creator" javaType="net.geedge.modules.sys.entity.SysUserEntity"> + <result column="id" property="id"/> + <result column="name" property="name"/> + </association> + + </resultMap> + + <select id="queryList" resultMap="link"> + select + l.id AS id, + l.`name` AS name, + l.create_by AS create_by, + l.url AS url, + l.weight AS weight, + l.build_in AS build_in, + u.id AS u_id, + u.name AS u_name + from link l left join sys_user u on l.create_by=u.id + where 1=1 + <if test="params.id != null and params.id != ''"> + AND l.id = #{params.id} + </if> + + <if test="params.name != null and params.name != ''"> + AND l.name = #{params.name} + </if> + + <if test="params.createBy != null and params.createBy != ''"> + AND l.create_by = #{params.createBy} + </if> + order by l.weight + </select> + +</mapper>
\ No newline at end of file diff --git a/cn-admin/src/main/resources/mapper/sys/SysApiKey.xml b/cn-admin/src/main/resources/mapper/sys/SysApiKey.xml new file mode 100644 index 0000000..c044463 --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysApiKey.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="net.geedge.modules.sys.dao.SysApiKeyDao"> + + <resultMap type="net.geedge.modules.sys.entity.SysApiKey" id="sysApiKey"> + <result property="id" column="id"/> + <result property="name" column="name"/> + <result property="createBy" column="create_by"/> + <result property="token" column="token"/> + <result property="roleId" column="role_id"/> + <result property="createAt" column="create_at"/> + <result property="expireAt" column="expire_at"/> + + <association columnPrefix="u_" property="createUser" javaType="net.geedge.modules.sys.entity.SysUserEntity"> + <result column="id" property="id"/> + <result column="name" property="name"/> + </association> + + <association columnPrefix="r_" property="role" javaType="net.geedge.modules.sys.entity.SysRoleEntity"> + <result column="id" property="id"/> + <result column="name" property="name"/> + </association> + + </resultMap> + + <select id="queryList" resultMap="sysApiKey"> + select sak.*, + su.id as u_id, + su.name as u_name, + sr.id as r_id, + sr.name as r_name + from sys_api_key sak left join sys_user su on sak.create_by = su.id + left join sys_role sr on sak.role_id = sr.id + where 1=1 + <if test="params.ids != null"> + and sak.id in + <foreach item="id" collection="params.ids" separator="," open="(" close=")" index=""> + #{id} + </foreach> + </if> + <if test="params.name !=null and params.name != ''"> + and sak.name like CONCAT('%', #{params.name}, '%') + </if> + </select> + +</mapper>
\ No newline at end of file diff --git a/cn-admin/src/main/resources/mapper/sys/SysConfDao.xml b/cn-admin/src/main/resources/mapper/sys/SysConfDao.xml new file mode 100644 index 0000000..aea39f5 --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysConfDao.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="net.geedge.modules.sys.dao.SysConfDao"> + <delete id="clearData" parameterType="string"> + ${sql} + </delete> +</mapper>
\ No newline at end of file diff --git a/cn-admin/src/main/resources/mapper/sys/SysConfigDao.xml b/cn-admin/src/main/resources/mapper/sys/SysConfigDao.xml new file mode 100644 index 0000000..2bb212c --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysConfigDao.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="net.geedge.modules.sys.dao.SysConfigDao"> + + <!-- 根据key,更新value --> + <update id="updateValueByKey" parameterType="map"> + update sys_config set param_value = #{paramValue} where param_key = #{paramKey} + </update> + + <!-- 根据key,查询value --> + <select id="queryByKey" parameterType="string" resultType="net.geedge.modules.sys.entity.SysConfigEntity"> + select * from sys_config where param_key = #{paramKey} + </select> + + <!-- reset清空表数据信息 --> + <delete id="clearData" parameterType="string"> + ${sql} + </delete> + +</mapper> diff --git a/cn-admin/src/main/resources/mapper/sys/SysDictDao.xml b/cn-admin/src/main/resources/mapper/sys/SysDictDao.xml new file mode 100644 index 0000000..a53ad68 --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysDictDao.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="net.geedge.modules.sys.dao.SysDictDao"> + + <resultMap id="sysDictResultMap" type="net.geedge.modules.sys.entity.SysDictEntity"> + <result column="id" property="id"></result> + <result column="name" property="name"></result> + <result column="code" property="code"></result> + <result column="value" property="value"></result> + <result column="i18n_code" property="i18nCode"></result> + <result column="order_num" property="orderNum"></result> + <result column="remark" property="remark"></result> + <result column="del_flag" property="delFlag"></result> + <result column="operator" property="operator"></result> + <result column="op_time" property="opTime"></result> + <association property="operatorUser" column="operator" select="queryUserById"></association> + </resultMap> + + + <select id="queryNodeImgList" resultType="sysDictEntity"> + SELECT code,value + FROM sys_dict + <where> + del_flag=0 and type='topo-img' + </where> + </select> + + <select id="querySysDictListWithPage" resultMap="sysDictResultMap"> + select id,name,type,code,value,order_num,remark,operator,op_time + from sys_dict + <where> + del_flag=0 + <if test="params.type != null and params.type != ''"> + and type=#{params.type} + </if> + <if test="params.value != null and params.value != ''"> + and value=#{params.value} + </if> + </where> + order by order_num + </select> + <select id="querySysDictList" resultMap="sysDictResultMap"> + select id,name,type,code,value,order_num,remark,operator,op_time + from sys_dict + <where> + del_flag=0 + <if test="params.type != null and params.type != ''"> + and type=#{params.type} + </if> + <if test="params.value != null and params.value != ''"> + and value=#{params.value} + </if> + </where> + order by order_num + </select> + + <select id="queryUserById" resultType="net.geedge.modules.sys.entity.SysUserEntity"> + select id,username from sys_user where id=#{id} and status=1 + </select> + + <select id="getMaxTypeCode" resultType="Integer"> + select max(code) from sys_dict where type=#{type} + </select> +</mapper>
\ No newline at end of file diff --git a/cn-admin/src/main/resources/mapper/sys/SysI18nDao.xml b/cn-admin/src/main/resources/mapper/sys/SysI18nDao.xml new file mode 100644 index 0000000..cc0617b --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysI18nDao.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="net.geedge.modules.sys.dao.SysI18nDao"> + + <!-- 可根据自己的需求,是否要使用 --> + <resultMap type="net.geedge.modules.sys.entity.SysI18nEntity" id="sysI18nMap"> + <result property="id" column="id"/> + <result property="code" column="code"/> + <result property="lang" column="lang"/> + <result property="value" column="value"/> + <result property="remark" column="remark"/> + <result property="operator" column="operator"/> + <result property="opTime" column="op_time"/> + </resultMap> + + +</mapper>
\ No newline at end of file diff --git a/cn-admin/src/main/resources/mapper/sys/SysLogDao.xml b/cn-admin/src/main/resources/mapper/sys/SysLogDao.xml new file mode 100644 index 0000000..aaf7d7e --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysLogDao.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="net.geedge.modules.sys.dao.SysLogDao"> + + <resultMap type="net.geedge.modules.sys.entity.SysLogEntity" id="sysLogEntity"> + <result property="id" column="id"/> + <result property="userId" column="user_id"/> + <result property="operation" column="operation"/> + <result property="type" column="type"/> + <result property="operaId" column="opera_id"/> + <result property="method" column="method"/> + <result property="params" column="params"/> + <result property="time" column="time"/> + <result property="ip" column="ip"/> + <result property="state" column="state"/> + <result property="response" column="response"/> + <result property="exception" column="exception"/> + <result property="createDate" column="create_date"/> + <result property="username" column="username"/> + + <association property="apiKey" javaType="net.geedge.modules.sys.entity.SysApiKey"> + <id property="id" column="sak_id"/> + <result property="name" column="sak_name"/> + </association> + </resultMap> + + <select id="queryList" resultMap="sysLogEntity"> + SELECT + sl.*, + su.username AS username, + sak.id AS sak_id, + sak.name AS sak_name + FROM + sys_log sl + LEFT JOIN sys_user su ON sl.user_id = su.id + left join sys_api_key sak on sl.api_key_id = sak.id + <where> + <if test="params.operation != null and params.operation != ''"> + AND sl.operation like CONCAT('%', #{params.operation}, '%') + </if> + <if test="params.state != null and params.state != ''"> + AND sl.state = #{params.state} + </if> + <if test="params.type != null and params.type != ''"> + AND sl.type like CONCAT('%', #{params.type}, '%') + </if> + <if test="params.userIds != null and params.userIds.size > 0"> + AND sl.user_id IN + <foreach collection="params.userIds" item="id" index="no" open="(" separator="," close=")"> + #{id} + </foreach> + </if> + <if test="params.name != null and params.name != ''"> + AND (su.name like CONCAT('%', #{params.name}, '%') or su.username like CONCAT('%', #{params.name}, '%')) + </if> + <if test="params.ip != null and params.ip != ''"> + AND sl.ip = #{params.ip} + </if> + <if test="params.operaId != null"> + AND sl.opera_id in + <foreach item="id" collection="params.operaId" separator="," open="(" close=")" index=""> + #{id} + </foreach> + </if> + <if test="params.params != null and params.params != ''"> + AND sl.params = #{params.params} + </if> + <if test="params.response != null and params.response != ''"> + AND sl.response = #{params.response} + </if> + <if test="params.exception != null and params.exception != ''"> + AND sl.exception = #{params.exception} + </if> + </where> + + <if test="params.orderBy == null or params.orderBy == ''"> + ORDER BY sl.create_date DESC + </if> + </select> +</mapper>
\ No newline at end of file diff --git a/cn-admin/src/main/resources/mapper/sys/SysMenuDao.xml b/cn-admin/src/main/resources/mapper/sys/SysMenuDao.xml new file mode 100644 index 0000000..3e01956 --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysMenuDao.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="net.geedge.modules.sys.dao.SysMenuDao"> + + <select id="getRoleMenuList" resultType="net.geedge.modules.sys.entity.SysMenuEntity"> + SELECT + sm.* + FROM + sys_role_menu rm + LEFT JOIN sys_menu sm ON rm.menu_id = sm.id + WHERE + rm.role_id = #{roleId} + </select> +</mapper>
\ No newline at end of file diff --git a/cn-admin/src/main/resources/mapper/sys/SysRoleDao.xml b/cn-admin/src/main/resources/mapper/sys/SysRoleDao.xml new file mode 100644 index 0000000..d374a7f --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysRoleDao.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="net.geedge.modules.sys.dao.SysRoleDao"> + + <select id="getRolesByUesrId" resultType="net.geedge.modules.sys.entity.SysRoleEntity"> + SELECT + sr.* + FROM + sys_user_role sur + LEFT JOIN sys_role sr ON sur.role_id = sr.id + WHERE + sur.user_id = #{userId} + </select> + + <select id="getRolesBySysApiKeyId" resultType="net.geedge.modules.sys.entity.SysRoleEntity"> + select + sr.* + from + sys_api_key sak + left join sys_role sr ON sak.role_id = sr.id + where + sak.id = #{sysApiKeyId} + </select> + +</mapper>
\ No newline at end of file diff --git a/cn-admin/src/main/resources/mapper/sys/SysRoleMenuDao.xml b/cn-admin/src/main/resources/mapper/sys/SysRoleMenuDao.xml new file mode 100644 index 0000000..1ef61df --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysRoleMenuDao.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="net.geedge.modules.sys.dao.SysRoleMenuDao"> + <select id="queryMenuIdList" resultType="java.lang.Integer"> + select menu_id from sys_role_menu where role_id = #{value} + </select> + + <delete id="deleteBatch"> + delete from sys_role_menu where role_id in + <foreach item="roleId" collection="array" open="(" separator="," close=")"> + #{roleId} + </foreach> + </delete> + +</mapper>
\ No newline at end of file diff --git a/cn-admin/src/main/resources/mapper/sys/SysUserDao.xml b/cn-admin/src/main/resources/mapper/sys/SysUserDao.xml new file mode 100644 index 0000000..4731fe1 --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysUserDao.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="net.geedge.modules.sys.dao.SysUserDao"> + + <!-- 查询用户的所有菜单ID --> + <select id="queryAllMenuId" resultType="long"> + select distinct rm.menu_id from sys_user_role ur + LEFT JOIN sys_role_menu rm on ur.role_id = rm.role_id + where ur.id = #{userId} + </select> + + <select id="queryList" resultType="net.geedge.modules.sys.entity.SysUserEntity"> + SELECT + su.id, + su.username, + su.status, + su.email, + su.create_at, + su.source, + su.name, + su.mobile, + su.last_login_time, + su.last_login_ip + FROM + sys_user su + <where> + <if test="params.ids != null"> + su.id in + <foreach item="id" collection="params.ids" separator="," open="(" close=")" index=""> + #{id} + </foreach> + </if> + + <if test="params.name != null and params.name != ''"> + AND (su.username like CONCAT('%', #{params.name}, '%') or su.name like CONCAT('%', #{params.name}, '%')) + </if> + </where> + </select> + + <select id="getUserListByRoleId" resultType="net.geedge.modules.sys.entity.SysUserEntity"> + SELECT + su.* + FROM + sys_user_role sur + LEFT JOIN sys_user su ON sur.user_id = su.id + WHERE + sur.role_id = #{roleId} + </select> + +</mapper>
\ No newline at end of file diff --git a/cn-admin/src/main/resources/mapper/sys/SysUserRoleDao.xml b/cn-admin/src/main/resources/mapper/sys/SysUserRoleDao.xml new file mode 100644 index 0000000..ff74cad --- /dev/null +++ b/cn-admin/src/main/resources/mapper/sys/SysUserRoleDao.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="net.geedge.modules.sys.dao.SysUserRoleDao"> + + <select id="queryRoleIdList" resultType="java.lang.Integer"> + select role_id from sys_user_role where user_id = #{value} + </select> + + <delete id="deleteBatch"> + delete from sys_user_role where role_id in + <foreach item="roleId" collection="array" open="(" separator="," close=")"> + #{roleId} + </foreach> + </delete> +</mapper>
\ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ecf1c73 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,6 @@ +version: '2' +services: + nz-admin: + image: cn/admin + ports: + - "8080:8080" @@ -0,0 +1,267 @@ +<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"> + <modelVersion>4.0.0</modelVersion> + <groupId>net.geedge</groupId> + <artifactId>cn-web</artifactId> + <version>2.0</version> + <packaging>pom</packaging> + + <name>cn-web</name> + + <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>2.1.3.RELEASE</version> + </parent> + + <modules> + <module>cn-admin</module> + </modules> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <java.version>1.8</java.version> + <junit.version>4.12</junit.version> + <jedis.version>2.9.0</jedis.version> + <druid.version>1.1.13</druid.version> + <mybatisplus.version>3.0.7.1</mybatisplus.version> + <mysql.version>5.1.38</mysql.version> + <mssql.version>4.0</mssql.version> + <oracle.version>11.2.0.3</oracle.version> + <commons.lang.version>2.6</commons.lang.version> + <commons.fileupload.version>1.3.1</commons.fileupload.version> + <commons.collections.version>3.2.2</commons.collections.version> + <commons.beanutils.version>1.9.3</commons.beanutils.version> + <commons.io.version>2.5</commons.io.version> + <commons.codec.version>1.10</commons.codec.version> + <fastjson.version>1.2.45</fastjson.version> + <joda.time.version>2.9.9</joda.time.version> + <lombok.version>1.18.4</lombok.version> + <swagger.version>2.7.0</swagger.version> + <mibble.version>2.9.3</mibble.version> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </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</groupId> + <artifactId>spring-context-support</artifactId> + </dependency> +<!-- <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-redis</artifactId> + </dependency> --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-configuration-processor</artifactId> + <optional>true</optional> + </dependency> + <dependency> + <groupId>redis.clients</groupId> + <artifactId>jedis</artifactId> + <version>${jedis.version}</version> + </dependency> + <!-- mysql驱动 --> + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + <version>${mysql.version}</version> + </dependency> + <!-- oracle驱动 --> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>ojdbc6</artifactId> + <version>${oracle.version}</version> + </dependency> + <!-- mssql驱动 --> + <dependency> + <groupId>com.microsoft.sqlserver</groupId> + <artifactId>sqljdbc4</artifactId> + <version>${mssql.version}</version> + </dependency> + <!-- postgresql驱动 --> + <dependency> + <groupId>org.postgresql</groupId> + <artifactId>postgresql</artifactId> + </dependency> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>druid-spring-boot-starter</artifactId> + <version>${druid.version}</version> + </dependency> + <dependency> + <groupId>com.baomidou</groupId> + <artifactId>mybatis-plus-boot-starter</artifactId> + <version>${mybatisplus.version}</version> + <exclusions> + <exclusion> + <groupId>com.baomidou</groupId> + <artifactId>mybatis-plus-generator</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>fastjson</artifactId> + <version>${fastjson.version}</version> + </dependency> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>${commons.lang.version}</version> + </dependency> + <dependency> + <groupId>commons-fileupload</groupId> + <artifactId>commons-fileupload</artifactId> + <version>${commons.fileupload.version}</version> + </dependency> + <dependency> + <groupId>commons-collections</groupId> + <artifactId>commons-collections</artifactId> + <version>${commons.collections.version}</version> + </dependency> + <dependency> + <groupId>commons-beanutils</groupId> + <artifactId>commons-beanutils</artifactId> + <version>${commons.beanutils.version}</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>${commons.io.version}</version> + </dependency> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>${commons.codec.version}</version> + </dependency> + <dependency> + <groupId>joda-time</groupId> + <artifactId>joda-time</artifactId> + <version>${joda.time.version}</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger2</artifactId> + <version>${swagger.version}</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>${swagger.version}</version> + </dependency> + + <!-- https://mvnrepository.com/artifact/net.percederberg.mibble/mibble-mibs --> + <dependency> + <groupId>net.percederberg.mibble</groupId> + <artifactId>mibble-mibs</artifactId> + <version>${mibble.version}</version> + </dependency> + + <!-- https://mvnrepository.com/artifact/net.percederberg.mibble/mibble --> + <dependency> + <groupId>net.percederberg.mibble</groupId> + <artifactId>mibble</artifactId> + <version>${mibble.version}</version> + </dependency> + <dependency> + <groupId>cn.hutool</groupId> + <artifactId>hutool-all</artifactId> + <version>5.5.2</version> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk15to18</artifactId> + <version>1.68</version> + </dependency> + <dependency> + <groupId>com.github.oshi</groupId> + <artifactId>oshi-core</artifactId> + <version>5.7.0</version> + </dependency> + </dependencies> + + + <!-- 阿里云maven仓库 --> + <repositories> + <!-- 配置私服地址 --> + <repository> + <id>nexus</id> + <name>Team Nexus Repository</name> + <url>http://192.168.40.125:8099/content/groups/public/</url> + </repository> + <repository> + <id>public</id> + <name>aliyun nexus</name> + <url>http://maven.aliyun.com/nexus/content/groups/public/</url> + <releases> + <enabled>true</enabled> + </releases> + </repository> + + <!--opennum仓库 --> + <repository> + <id>opennms</id> + <name>opennms</name> + <url>https://repo.opennms.org/maven2/</url> + </repository> + + <!-- 设置 jitpack.io 仓库 --> + <repository> + <id>jitpack.io</id> + <url>https://jitpack.io</url> + </repository> + + </repositories> + + <pluginRepositories> + <pluginRepository> + <id>nexus</id> + <name>Team Nexus Repository</name> + <url>http://192.168.40.125:8099/content/groups/public/</url> + </pluginRepository> + <pluginRepository> + <id>public</id> + <name>aliyun nexus</name> + <url>http://maven.aliyun.com/nexus/content/groups/public/</url> + <releases> + <enabled>true</enabled> + </releases> + <snapshots> + <enabled>false</enabled> + </snapshots> + </pluginRepository> + + <!-- 设置 jitpack.io 插件仓库 --> + <pluginRepository> + <id>jitpack.io</id> + <url>https://jitpack.io</url> + + </pluginRepository> + </pluginRepositories> +</project> |
