upload UI source code

This commit is contained in:
unknown
2022-06-24 17:11:23 +08:00
parent 8165dfcc7b
commit 8565e1bb59
537 changed files with 47199 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dns</artifactId>
<groupId>com.example</groupId>
<version>2.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dns-system</artifactId>
<name>dns-system</name>
<properties>
<jjwt.version>0.11.1</jjwt.version>
<!-- oshi监控需要指定jna版本, 问题详见 https://github.com/oshi/oshi/issues/1040 -->
<jna.version>5.8.0</jna.version>
</properties>
<dependencies>
<!-- tools 模块包含了 common 和 logging 模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>dns-common</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>dns-logging</artifactId>
<version>2.6</version>
</dependency>
<!-- Spring boot websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
</dependency>
<!-- quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<!-- linux的管理 -->
<dependency>
<groupId>ch.ethz.ganymed</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>build210</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>5.7.1</version>
</dependency>
</dependencies>
<!-- 打包 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- 跳过单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example;
import com.example.utils.SpringContextHolder;
import io.swagger.annotations.Api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.ApplicationPidFileWriter;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.bind.annotation.RestController;
/**
* 开启审计功能 -> @EnableJpaAuditing
*
* 2018/11/15 9:20:19
*/
@EnableAsync
@RestController
@Api(hidden = true)
@SpringBootApplication
@EnableTransactionManagement
@EnableJpaAuditing(auditorAwareRef = "auditorAware")
public class AppRun {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(AppRun.class);
// 监控应用的PID启动时可指定PID路径--spring.pid.file=/home/dns/app.pid
// 或者在 application.yml 添加文件路径,方便 killkill `cat /home/dns/app.pid`
springApplication.addListeners(new ApplicationPidFileWriter());
springApplication.run(args);
}
@Bean
public SpringContextHolder springContextHolder() {
return new SpringContextHolder();
}
@Bean
public ServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory fa = new TomcatServletWebServerFactory();
fa.addConnectorCustomizers(connector -> connector.setProperty("relaxedQueryChars", "[]{}"));
return fa;
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
* WebMvcConfigurer
*
*
* 2018-11-30
*/
@Configuration
@EnableWebMvc
public class ConfigurerAdapter implements WebMvcConfigurer {
/** 文件配置 */
private final FileProperties properties;
public ConfigurerAdapter(FileProperties properties) {
this.properties = properties;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
FileProperties.ElPath path = properties.getPath();
String avatarUtl = "file:" + path.getAvatar().replace("\\","/");
String pathUtl = "file:" + path.getPath().replace("\\","/");
registry.addResourceHandler("/avatar/**").addResourceLocations(avatarUtl).setCachePeriod(0);
registry.addResourceHandler("/file/**").addResourceLocations(pathUtl).setCachePeriod(0);
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0);
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 使用 fastjson 序列化,会导致 @JsonIgnore 失效,可以使用 @JSONField(serialize = false) 替换
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
List<MediaType> supportMediaTypeList = new ArrayList<>();
supportMediaTypeList.add(MediaType.APPLICATION_JSON);
FastJsonConfig config = new FastJsonConfig();
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
converter.setFastJsonConfig(config);
converter.setSupportedMediaTypes(supportMediaTypeList);
converter.setDefaultCharset(StandardCharsets.UTF_8);
converters.add(converter);
}
}

View File

@@ -0,0 +1,236 @@
package com.example.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
@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());
}
}
}

View File

@@ -0,0 +1,36 @@
package com.example.config;
import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* mybatis-plus 插件配置
*/
@Configuration
public class MybatisPlusPluginsConfig {
private static final Log logger = Log.get();
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @author ZhangHouYing
* 2019-08-24 15:44
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.config.thread;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 异步任务线程池装配类
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
* 2019年10月31日15:06:18
*/
@Slf4j
@Configuration
public class AsyncTaskExecutePool implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(AsyncTaskProperties.corePoolSize);
//最大线程数
executor.setMaxPoolSize(AsyncTaskProperties.maxPoolSize);
//队列容量
executor.setQueueCapacity(AsyncTaskProperties.queueCapacity);
//活跃时间
executor.setKeepAliveSeconds(AsyncTaskProperties.keepAliveSeconds);
//线程名字前缀
executor.setThreadNamePrefix("el-async-");
// setRejectedExecutionHandler当pool已经达到max size的时候如何处理新任务
// CallerRunsPolicy不在新线程中执行任务而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (throwable, method, objects) -> {
log.error("===="+throwable.getMessage()+"====", throwable);
log.error("exception method:"+method.getName());
};
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.config.thread;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* 线程池配置属性类
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
* 2019年10月31日14:58:18
*/
@Data
@Component
public class AsyncTaskProperties {
public static int corePoolSize;
public static int maxPoolSize;
public static int keepAliveSeconds;
public static int queueCapacity;
@Value("${task.pool.core-pool-size}")
public void setCorePoolSize(int corePoolSize) {
AsyncTaskProperties.corePoolSize = corePoolSize;
}
@Value("${task.pool.max-pool-size}")
public void setMaxPoolSize(int maxPoolSize) {
AsyncTaskProperties.maxPoolSize = maxPoolSize;
}
@Value("${task.pool.keep-alive-seconds}")
public void setKeepAliveSeconds(int keepAliveSeconds) {
AsyncTaskProperties.keepAliveSeconds = keepAliveSeconds;
}
@Value("${task.pool.queue-capacity}")
public void setQueueCapacity(int queueCapacity) {
AsyncTaskProperties.queueCapacity = queueCapacity;
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.config.thread;
import org.springframework.stereotype.Component;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 自定义线程名称
*
* 2019年10月31日17:49:55
*/
@Component
public class TheadFactoryName implements ThreadFactory {
private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public TheadFactoryName() {
this("el-pool");
}
private TheadFactoryName(String name){
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
//此时namePrefix就是 name + 第几个用这个工厂创建线程池的
this.namePrefix = name +
POOL_NUMBER.getAndIncrement();
}
@Override
public Thread newThread(Runnable r) {
//此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程
Thread t = new Thread(group, r,
namePrefix + "-thread-"+threadNumber.getAndIncrement(),
0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.config.thread;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 用于获取自定义线程池
*
* 2019年10月31日18:16:47
*/
public class ThreadPoolExecutorUtil {
public static ThreadPoolExecutor getPoll(){
return new ThreadPoolExecutor(
AsyncTaskProperties.corePoolSize,
AsyncTaskProperties.maxPoolSize,
AsyncTaskProperties.keepAliveSeconds,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(AsyncTaskProperties.queueCapacity),
new TheadFactoryName()
);
}
}

View File

@@ -0,0 +1,48 @@
package com.example.modules.dns.controller;
import com.example.modules.dns.service.DnsService;
import com.example.utils.page.PageUtils;
import com.example.utils.page.R;
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.text.DecimalFormat;
import java.util.Map;
@RestController
@RequestMapping("/dns")
public class DnsController {
@Autowired
private DnsService dnsService;
@GetMapping
public R queryPage(@RequestParam Map<String, Object> params) {
long startTime = System.currentTimeMillis();
PageUtils page =dnsService.queryPage(params);
long endTime = System.currentTimeMillis();
DecimalFormat df = new DecimalFormat("0.000");
String totalTime = df.format((float) (endTime - startTime) / 1000);
page.setTotalTime(Double.parseDouble(totalTime));
return R.ok(page);
}
//区域数据统计
@GetMapping("/dataCount")
public R dataCount(@RequestParam Map<String, Object> params) {
return R.ok(dnsService.dataCount(params));
}
//区域数据统计
@GetMapping("/mapData")
public R mapData() {
return R.ok(dnsService.mapData());
}
}

View File

@@ -0,0 +1,24 @@
package com.example.modules.dns.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
@Data
@TableName("dns_type")
public class DnsType implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private String ip;
private String type;
private int epoch;
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.dns.domain;
import com.baomidou.mybatisplus.annotation.IdType;
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;
import java.util.List;
@Data
@TableName("doh_attribute")
public class DohAttribute implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private String ip;
private Integer port;
private String host;
private String path;
private String method;
private Integer connectType;
private Integer statusCode;
private String repHeader;
private String repBody;
private Date timestamp;
private String component;
private int rounds;
@TableField(exist = false)
private List<String> pathList;
@TableField(exist = false)
private List<String> componentList;
@TableField(exist = false)
private List<IpCert> ipCert;
@TableField(exist = false)
private List<IpInformation> ipInformation;
@TableField(exist = false)
private List<List<Vulnerability>> vulnerability;
@TableField(exist = false)
private List<String> tags;
}

View File

@@ -0,0 +1,24 @@
package com.example.modules.dns.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
@Data
@TableName("forward_dns")
public class ForwardDns implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private String forwarder;
private String upstream;
private int epoch;
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.dns.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.example.modules.system.domain.Dept;
import com.example.modules.system.domain.Job;
import com.example.modules.system.domain.Role;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.Set;
/**
* 2018-11-22
*/
@Data
@TableName("ip_cert")
public class IpCert implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private String ip;
private String port;
private String certificate;
private String ca;
private Date timestamp;
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.dns.domain;
import com.baomidou.mybatisplus.annotation.IdType;
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;
import java.util.List;
/**
*
* 2018-11-22
*/
@Data
@TableName("ip_information")
public class IpInformation implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private String ip;
private String country;
private String province;
private String city;
private String district;
private String provider;
private String isp;
private Integer asnumber;
private Date timestamp;
private String zipcode;
private String timezone;
@TableField(exist = false)
private List<IpCert> ipCert;
@TableField(exist = false)
private List<NonstandardDns> nonstandardDns;
@TableField(exist = false)
private DnsType dnsType;
@TableField(exist = false)
private List<DohAttribute> dohAttribute;
@TableField(exist = false)
private List<ForwardDns> forwardDns;
@TableField(exist = false)
private ScanResult scanResult;
@TableField(exist = false)
private Integer dnsTypeValue;
}

View File

@@ -0,0 +1,28 @@
package com.example.modules.dns.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
*
* 直接响DNS表
*/
@Data
@TableName("nonstandard_dns")
public class NonstandardDns implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private String ip;
private String record;
private int epoch;
}

View File

@@ -0,0 +1,71 @@
package com.example.modules.dns.domain;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@Data
public class Result implements Serializable {
private Long id;
private String ip;
private String protocolType;
private String ipType;
private Integer port;
private String host;
private String path;
private String method;
private Integer connectType;
private Integer statusCode;
private String repHeader;
private String repBody;
private Date timestamp;
private String component;
private Integer flags;
private Integer opcode;
private Integer qr;
//权威标志位
private Integer aa;
//递归标志位
private Integer ra;
private Integer rcode;
private String queryName;
private String queryResponse;
//预留ipv4ipv6dnssectcpudp等
private Integer scanType;
private Date time;
private Integer epoch;
private Integer rounds;
private Integer dnsType;
private String uuid;
private List<String> pathList;
private List<String> componentList;
private List<IpCert> ipCert;
private List<Vulnerability> vulnerability;
private List<String> tags;
private IpInformation ipInformation;
private List<? extends Object> banner;
private List<? extends Object> httpContent;
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.dns.domain;
import com.baomidou.mybatisplus.annotation.IdType;
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;
import java.util.List;
/**
* 2018-11-22
*/
@Data
@TableName("scan_result")
public class ScanResult implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private String ip;
private Integer flags;
private Integer opcode;
private Integer qr;
//权威标志位
private Integer aa;
//递归标志位
private Integer ra;
private Integer rcode;
private String queryName;
private String queryResponse;
private String component;
private int epoch;
private List<String> componentList;
//预留ipv4ipv6dnssectcpudp等
private Integer scanType;
private Date time;
@TableField(exist = false)
private IpInformation IpInformation;
@TableField(exist = false)
private List<IpInformation> forwarderBanner;
@TableField(exist = false)
private Integer dnsType;
@TableField(exist = false)
private List<NonstandardDns> nonstandardBanner;
@TableField(exist = false)
private List<String> tags;
}

View File

@@ -0,0 +1,24 @@
package com.example.modules.dns.domain;
import com.baomidou.mybatisplus.annotation.IdType;
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("vulnerability")
public class Vulnerability implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private String component;
private String vulnerability;
private Date timestamp;
}

View File

@@ -0,0 +1,76 @@
package com.example.modules.dns.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.modules.dns.domain.Result;
import com.example.modules.dns.domain.ScanResult;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Mapper
@Repository
public interface DnsDo53Dao extends BaseMapper<ScanResult> {
List<Result> queryDo53Page(IPage page, @Param("params") Map<String, Object> params);
int do53IpCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> do53ServiceCategoryCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> do53ProvinceCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> do53ProviderCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> do53ComponentCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> do53VulnerabilityCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> do53CountryCount();
List<Map<String, Object>> do53CountryMapCount();
List<Map<String, Object>> do53WorldMapCount();
List<Map<String, Object>> do53ChinaMapCount();
int pageCount(@Param("params") Map<String, Object> params);
List<Result> queryOpenRdns(@Param("params")Map<String, Object> params);
int getCountByDnsType(@Param("dnsType")Integer dnsType,@Param("params") Map<String, Object> params);
int getIndependentIpNum(@Param("dnsType")Integer dnsType, @Param("params")Map<String, Object> params);
List<Result> selectScanResultByUnion(IPage page, @Param("params") Map<String, Object> params);
Integer selectScanResultCountByUnion(@Param("params") Map<String, Object> params);
List<Map<String, Object>> getDohAndDo53SrvCategoryCount(@Param("params") Map<String, Object> params);
/**
* 根据dnsType和其他参数统计ip省份分布
* @param dnsType
* @param params
* @return
*/
List<Map<String, Object>> getDo53ProvinceCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map<String, Object> params);
/**
* 根据dnsType和其他参数统计ip运营商分布
* @param dnsType
* @param params
* @return
*/
List<Map<String, Object>> getDo53ProviderCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map<String, Object> params);
List<Map<String, Object>> getDo53ComponentCountByDnsType(@Param("dnsType") Integer dnsType, Map<String, Object> params);
Integer getDo53SrvCategoryCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map<String, Object> params);
List<Map<String, Object>> getDo53VulnerabCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map<String, Object> params);
}

View File

@@ -0,0 +1,93 @@
package com.example.modules.dns.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.modules.dns.domain.DohAttribute;
import com.example.modules.dns.domain.IpInformation;
import com.example.modules.dns.domain.Result;
import com.example.modules.dns.domain.ScanResult;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Mapper
@Repository
public interface DnsDohDao extends BaseMapper<DohAttribute> {
List<Result> queryDohPage(IPage page, @Param("params") Map<String, Object> params);
//省份数据统计
List<Map<String, Object>> dohProvinceCount(@Param("params") Map<String, Object> params);
int dohIpCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> dohPortCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> dohAndDo53ProvinceCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> dohProviderCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> dohAndDo53ProviderCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> dohComponentCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> dohAndDo53ComponentCount(@Param("params") Map<String, Object> params);
Map<String, Object> dohServiceCategoryCount(@Param("params") Map<String, Object> params);
int dohResultTotalCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> dohVulnerabilityCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> dohAndDo53VulnerabilityCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> dohCountryCount();
List<Map<String, Object>> dohChinaMapCount();
List<Result> getDohRepBody(String ip, Integer port, String host, Integer rounds);
List<Result> selectDohInfoByUnion(@Param("params") Map<String, Object> params);
Integer selectDohCountByUnion(@Param("params") Map<String, Object> params);
/**
* 查询 doh 和 do53 交集下的port ip数量
* @param params
* @return
*/
List<Map<String, Object>> countDohPortUnion(@Param("params") Map<String, Object> params);
/**
* 统计 doh和do53公共ip的省份分布
* @param params
* @return
*/
List<Map<String, Object>> getDohAndDo53ProvinceCount(@Param("params") Map<String, Object> params);
/**
* 统计 doh和do53公共ip的运营商分布
* @param params
* @return
*/
List<Map<String, Object>> getDohAndDo53ProviderCount(@Param("params") Map<String, Object> params);
/**
* 统计 doh和do53公共ip的组件分布
* @param params
* @return
*/
List<Map<String, Object>> getDohAndDo53ComponentCount(@Param("params") Map<String, Object> params);
/**
* 统计 doh 和 do53公共ip 服务类别统计
* @param params
* @return
*/
Map<String, Object> getDohServiceCategoryCount(@Param("params") Map<String, Object> params);
List<Map<String, Object>> getDohAndDo53VulnerabilityCount(@Param("params") Map<String, Object> params);
}

View File

@@ -0,0 +1,20 @@
package com.example.modules.dns.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.modules.dns.domain.DnsType;
import com.example.modules.dns.domain.DohAttribute;
import com.example.modules.dns.domain.IpCert;
import com.example.modules.dns.domain.ScanResult;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Mapper
@Repository
public interface DnsTypeDao extends BaseMapper<DnsType> {
}

View File

@@ -0,0 +1,20 @@
package com.example.modules.dns.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.modules.dns.domain.ForwardDns;
import com.example.modules.dns.domain.ScanResult;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Mapper
@Repository
public interface ForwardDnsDao extends BaseMapper<ForwardDns> {
}

View File

@@ -0,0 +1,32 @@
package com.example.modules.dns.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.modules.dns.domain.DohAttribute;
import com.example.modules.dns.domain.IpCert;
import com.example.modules.dns.domain.ScanResult;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Mapper
@Repository
public interface IpCertDao extends BaseMapper<IpCert> {
List<DohAttribute> queryDohPage(IPage page, @Param("params") Map<String, Object> params);
// 国家数据统计
List<Map<String, Object>> countryCount();
//省份数据统计
List<Map<String, Object>> provinceCount();
// 城市数据统计
List<Map<String, Object>> cityCount();
List<ScanResult> queryDo53Page(IPage page, @Param("params") Map<String, Object> params);
}

View File

@@ -0,0 +1,27 @@
package com.example.modules.dns.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.modules.dns.domain.IpInformation;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Mapper
@Repository
public interface IpInformationDao extends BaseMapper<IpInformation> {
List<IpInformation> queryIpPage(IPage page, @Param("params") Map<String, Object> params);
/**
* 根据 forward_dns中的 forwarder查询ip信息
* @param ip
* @return
*/
List<IpInformation> getIpInfoByFwd(@Param("ip")String ip,@Param("epoch")Integer epoch);
}

View File

@@ -0,0 +1,15 @@
package com.example.modules.dns.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.modules.dns.domain.ForwardDns;
import com.example.modules.dns.domain.NonstandardDns;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface NonstandardDnsDao extends BaseMapper<NonstandardDns> {
}

View File

@@ -0,0 +1,20 @@
package com.example.modules.dns.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.modules.dns.domain.DohAttribute;
import com.example.modules.dns.domain.ScanResult;
import com.example.modules.dns.domain.Vulnerability;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Mapper
@Repository
public interface VulnerabilityDao extends BaseMapper<Vulnerability> {
}

View File

@@ -0,0 +1,19 @@
package com.example.modules.dns.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.modules.dns.domain.DohAttribute;
import com.example.modules.dns.domain.IpInformation;
import com.example.utils.page.PageUtils;
import java.util.List;
import java.util.Map;
public interface DnsService extends IService<DohAttribute> {
PageUtils queryPage(Map<String, Object> params);
Map<String, Object> dataCount(Map<String, Object> params);
Map<String, List<Map<String, Object>>> mapData();
}

View File

@@ -0,0 +1,13 @@
package com.example.modules.dns.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.modules.dns.domain.DnsType;
import com.example.modules.dns.domain.DohAttribute;
import com.example.utils.page.PageUtils;
import java.util.List;
import java.util.Map;
public interface DnsTypeService extends IService<DnsType> {
}

View File

@@ -0,0 +1,13 @@
package com.example.modules.dns.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.modules.dns.domain.ScanResult;
import java.util.Map;
public interface ScanResultService extends IService<ScanResult> {
Map<String, Object> queryDo53DataCountByDnsType(Map<String,Object> params,Integer dnsType);
}

View File

@@ -0,0 +1,108 @@
package com.example.modules.dns.service.impl;
import com.example.utils.Constant;
import com.example.utils.ElAdminConstant;
import java.util.List;
/**
* @author Lihe
* @version 1
* @description 查询分类
* @date 2022/6/22
*/
public enum DnsQueryEnum {
OPEN_RDNS(Constant.OPENRDNSTAG, ElAdminConstant.openRdnsLabels, "openRdns", 1),
FORWARDER(Constant.FORWARDERTAG, ElAdminConstant.forwarderLabels, "forwarder", 2),
FWD_RDNS(Constant.FWDRDNSTAG, ElAdminConstant.fwdRdnsLabels, "fwdRdns", 3),
EGRESS_DNS(Constant.EGRESSRDNSTAG, ElAdminConstant.egressDnsLabels, "egressDns", 4),
NON_STANDARD(Constant.NONSTANDARDTAG, ElAdminConstant.nonstandardLabels, "nonstandard", 5),
DNS(Constant.DNSTAG, ElAdminConstant.dnsLabels, "queryDnsInfo", 0),
DOH(Constant.DOH, ElAdminConstant.dohLabels, "queryDohInfo", 0),
DO53(Constant.DO53, ElAdminConstant.do53Labels, "queryDo53Info", 0),
DOH_AND_DO53("dohAndDo53", null, "queryDohAndDo53Info", 0),
IP(Constant.IP, null, "queryPageByIp", 0),
;
private final String service;
private final List<String> labels;
private final String methodName;
private final Integer dnsType;
public static DnsQueryEnum getQueryInfo(String serviceName) {
for (DnsQueryEnum value : DnsQueryEnum.values()) {
if (value.getService().equals(serviceName)) {
return value;
}
}
return null;
}
public String getMethodName() {
return methodName;
}
public String getService() {
return service;
}
public List<String> getLabels() {
return labels;
}
public Integer getDnsType() {
return dnsType;
}
DnsQueryEnum(String service, List<String> labels, String methodName, Integer dnsType) {
this.service = service;
this.labels = labels;
this.methodName = methodName;
this.dnsType = dnsType;
}
public static List<String> getLabels(String key) {
for (DnsQueryEnum value : DnsQueryEnum.values()) {
if (value.getService().equals(key)) {
return value.getLabels();
}
}
return null;
}
public static Integer getDnsType(String key) {
for (DnsQueryEnum value : DnsQueryEnum.values()) {
if (value.getService().equals(key)) {
return value.getDnsType();
}
}
return null;
}
public static String getDnsType(Integer type) {
for (DnsQueryEnum value : DnsQueryEnum.values()) {
if (value.getDnsType().equals(type)) {
return value.getService();
}
}
return null;
}
}

View File

@@ -0,0 +1,631 @@
package com.example.modules.dns.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.modules.dns.domain.*;
import com.example.modules.dns.mapper.*;
import com.example.modules.dns.service.DnsService;
import com.example.modules.dns.service.ScanResultService;
import com.example.utils.Constant;
import com.example.utils.page.PageUtils;
import com.example.utils.page.Query;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class DnsServiceImpl extends ServiceImpl<DnsDohDao, DohAttribute> implements DnsService {
@Autowired
private DnsDohDao dnsDohDao;
@Autowired
private DnsDo53Dao dnsDo53Dao;
@Autowired
private IpCertDao ipCertDao;
@Autowired
private IpInformationDao ipInformationDao;
@Autowired
private NonstandardDnsDao nonstandardDnsDao;
@Autowired
private ScanResultService scanResultService;
/**
* 添加新service查询逻辑时
* 1. 在本类中实现该service的查询逻辑
* 2. DnsQueryEnum 添加该查询逻辑的枚举包括serviceName,方法名标签和dnsType可根据需要设置
* and 查询逻辑需要单独实现
* @param params
* @return
*/
@Override
public PageUtils queryPage(Map<String, Object> params) {
String service = (String) params.get(Constant.SERVICE);
String port = (String) params.get(Constant.PORT);
String ip = (String) params.get(Constant.IP);
IPage page = new Query(IpInformation.class).getPage(params);
params.put("n", (page.getCurrent() - 1) * page.getSize()); //用作doh查询的分页
params.put("m", page.getSize()); //用作doh查询的分页
if(StringUtils.isBlank(service) && StringUtils.isBlank(ip) && StringUtils.isBlank(port)){
return new PageUtils(page);
}
if(StringUtils.isNotBlank(port)){
if(Constant.PORT53.equals(port)){
service = Constant.DO53;
}else if(Constant.PORT443.equals(port) || Constant.PORT8443.equals(port)){
service = Constant.DOH;
}
}
if(StringUtils.isBlank(port) && StringUtils.isBlank(service) && StringUtils.isNotBlank(ip)){
service = Constant.IP;
}
if(StringUtils.isNotBlank(service)) {
if(service.toLowerCase().contains("and")){
return queryDohAndDo53Info(page,params);
}else {
// DnsQueryEnum 枚举类获取service对应的方法名并通过反射调用
DnsQueryEnum serviceEnum = DnsQueryEnum.getQueryInfo(service.toLowerCase());
Class<? extends DnsServiceImpl> aClass = this.getClass();
try {
Method method = aClass.getDeclaredMethod(serviceEnum.getMethodName(), IPage.class, Map.class);
return (PageUtils) method.invoke(this, page, params);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return new PageUtils(page);
}
@Override
public Map<String, Object> dataCount(Map<String, Object> params) {
String service = (String) params.get(Constant.SERVICE);
String port = (String) params.get(Constant.PORT);
String ip = (String) params.get(Constant.IP);
Map<String, Object> resultMap = new HashMap(8);
if(StringUtils.isBlank(service) && StringUtils.isBlank(ip) && StringUtils.isBlank(port)){
return resultMap;
}
List<Map<String, Object>> portList = new ArrayList<>();
List<Map<String, Object>> regionList ;
List<Map<String, Object>> providerList ;
List<Map<String, Object>> componentList ;
List<Map<String, Object>> serviceCategoryList = new ArrayList<>();
List<Map<String, Object>> do53serviceCategoryList ;
List<Map<String, Object>> vulnerabilityCountList ;
if (Constant.DOH.equals(service) || Constant.PORT8443.equals(port) || Constant.PORT443.equals(port)) {
//端口
portList = dnsDohDao.dohPortCount(params);
//地域
regionList = dnsDohDao.dohProvinceCount(params);
//运营商
providerList = dnsDohDao.dohProviderCount(params);
//服务组件
componentList = dnsDohDao.dohComponentCount(params);
//服务类别
Map<String, Object> map = dnsDohDao.dohServiceCategoryCount(params);
map.put("key", Constant.DOHTAG);
serviceCategoryList.add(map);
//漏洞威胁
vulnerabilityCountList = dnsDohDao.dohVulnerabilityCount(params);
} else if (Constant.DO53.equals(service) || Constant.PORT53.equals(port)) {
//端口
Map<String, Object> portMap = new HashMap<>();
int do53PortCount = dnsDo53Dao.do53IpCount(params);
portMap.put("port", Constant.PORT53);
portMap.put("count", do53PortCount);
portList.add(portMap);
//地域
regionList = dnsDo53Dao.do53ProvinceCount(params);
//运营商
providerList = dnsDo53Dao.do53ProviderCount(params);
//服务组件
componentList = dnsDo53Dao.do53ComponentCount(params);
//服务类别
do53serviceCategoryList = dnsDo53Dao.do53ServiceCategoryCount(params);
serviceCategoryList = transformDo53serviceCategory(do53serviceCategoryList);
//漏洞威胁
vulnerabilityCountList = dnsDo53Dao.do53VulnerabilityCount(params);
}else if ("dns".equalsIgnoreCase(service) || StringUtils.isNotBlank(ip)) {
//端口
portList = dnsDohDao.dohPortCount(params);
Map<String, Object> portMap = new HashMap<>();
Integer do53PortCount = dnsDo53Dao.do53IpCount(params);
portMap.put("port", Constant.PORT53);
portMap.put("count", do53PortCount);
portList.add(portMap);
//地域
regionList = dnsDohDao.dohAndDo53ProvinceCount(params);
//运营商
providerList = dnsDohDao.dohAndDo53ProviderCount(params);
//服务组件
componentList = dnsDohDao.dohAndDo53ComponentCount(params);
//服务类别
do53serviceCategoryList = dnsDo53Dao.do53ServiceCategoryCount(params);
serviceCategoryList = transformDo53serviceCategory(do53serviceCategoryList);
Map<String, Object> map = dnsDohDao.dohServiceCategoryCount(params);
map.put("key", Constant.DOHTAG);
serviceCategoryList.add(map);
//漏洞威胁
vulnerabilityCountList = dnsDohDao.dohAndDo53VulnerabilityCount(params);
}else if(service.toLowerCase().contains("and")){
// 目前只有 doh AND do53其余条件未实现
//端口
portList = dnsDohDao.countDohPortUnion(params);
//地域
regionList = dnsDohDao.getDohAndDo53ProvinceCount(params);
//运营商
providerList = dnsDohDao.getDohAndDo53ProviderCount(params);
//服务组件
componentList = dnsDohDao.getDohAndDo53ComponentCount(params);
//服务类别
do53serviceCategoryList = dnsDo53Dao.getDohAndDo53SrvCategoryCount(params);
serviceCategoryList = transformDo53serviceCategory(do53serviceCategoryList);
Map<String, Object> map = dnsDohDao.getDohServiceCategoryCount(params);
map.put("key", Constant.DOHTAG);
map.put("count", dnsDo53Dao.selectScanResultCountByUnion(params));
serviceCategoryList.add(map);
//漏洞威胁
vulnerabilityCountList = dnsDohDao.getDohAndDo53VulnerabilityCount(params);
}else{
// dn53下5种 dns_type 统计
return scanResultService.queryDo53DataCountByDnsType(params,DnsQueryEnum.getDnsType(service));
}
resultMap.put("portList", portList);
resultMap.put("regionList", regionList);
resultMap.put("providerList", providerList);
resultMap.put("componentList", componentList);
resultMap.put("serviceCategoryList", serviceCategoryList);
resultMap.put("vulnerabilityCountList", vulnerabilityCountList);
return resultMap;
}
@Override
public Map<String, List<Map<String, Object>>> mapData() {
Map<String, List<Map<String, Object>>> resultMap = new HashMap<>();
List<Map<String, Object>> dohChinaMapList ;
List<Map<String, Object>> dohWorldMapDataList ;
List<Map<String, Object>> do53CountryMapCountList ;
List<Map<String, Object>> do53OpenRdnsList = new ArrayList<>();
List<Map<String, Object>> do53ForwarderList = new ArrayList<>();
List<Map<String, Object>> do53FwdRdnsList = new ArrayList<>();
List<Map<String, Object>> do53EgressDnsList = new ArrayList<>();
List<Map<String, Object>> do53NonstandardList = new ArrayList<>();
List<Map<String, Object>> do53WorldMapList ;
List<Map<String, Object>> do53ChinaMapList ;
dohChinaMapList = dnsDohDao.dohChinaMapCount();
dohWorldMapDataList = dnsDohDao.dohCountryCount();
do53WorldMapList = dnsDo53Dao.do53WorldMapCount();
do53ChinaMapList = dnsDo53Dao.do53ChinaMapCount();
do53CountryMapCountList = dnsDo53Dao.do53CountryMapCount();
for (Map<String, Object> map : do53CountryMapCountList) {
if (Constant.OPENRDNS == map.get("type")) {
do53OpenRdnsList.add(map);
} else if (Constant.FORWARDER == map.get("type")) {
do53ForwarderList.add(map);
} else if (Constant.FWDRDNS == map.get("type")) {
do53FwdRdnsList.add(map);
} else if (Constant.EGRESSRDNS == map.get("type")) {
do53EgressDnsList.add(map);
} else if (Constant.NONSTANDARD == map.get("type")) {
do53NonstandardList.add(map);
}
}
resultMap.put("dohChinaMapList", dohChinaMapList);
resultMap.put("dohWorldMapDataList", dohWorldMapDataList);
resultMap.put("do53WorldMapDataList", do53WorldMapList);
resultMap.put("do53ChinaMapList", do53ChinaMapList);
resultMap.put("do53OpenRdnsList", do53OpenRdnsList);
resultMap.put("do53ForwarderList", do53ForwarderList);
resultMap.put("do53FwdRdnsList", do53FwdRdnsList);
resultMap.put("do53EgressDnsList", do53EgressDnsList);
resultMap.put("do53NonstandardList", do53NonstandardList);
return resultMap;
}
public List<Map<String, Object>> transformDo53serviceCategory(List<Map<String, Object>> do53serviceCategoryList) {
List<Map<String, Object>> serviceCategoryList = new ArrayList<>();
long do53Count = 0;
for (Map<String, Object> map : do53serviceCategoryList) {
Map<String, Object> do53ServiceMap = new HashMap<>();
long count = (long) map.get("count");
int dnsType = (int) map.get("type");
if (Constant.FORWARDER == dnsType) { //2
do53ServiceMap.put("key", Constant.FORWARDERTAG);
do53ServiceMap.put("count", count);
} else if (Constant.FWDRDNS == dnsType) {//3
do53ServiceMap.put("key", Constant.FWDRDNSTAG);
do53ServiceMap.put("count", count);
} else if (Constant.EGRESSRDNS == dnsType) { //4
do53ServiceMap.put("key", Constant.EGRESSRDNSTAG);
do53ServiceMap.put("count", count);
} else if (Constant.NONSTANDARD == dnsType) { //5
do53ServiceMap.put("key", Constant.NONSTANDARDTAG);
do53ServiceMap.put("count", count);
} else if (Constant.OPENRDNS == dnsType) { //1
do53ServiceMap.put("key", Constant.OPENRDNSTAG);
do53ServiceMap.put("count", count);
}
do53Count += count;
serviceCategoryList.add(do53ServiceMap);
}
HashMap<String, Object> do53Map = new HashMap<>();
do53Map.put("key", Constant.DO53TAG);
do53Map.put("count", do53Count);
serviceCategoryList.add(do53Map);
return serviceCategoryList;
}
/**
* 设置doh属性
* @param dohAttributes
*/
public void setDohData(List<Result> dohAttributes) {
for (Result dohAttribute : dohAttributes) {
String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
dohAttribute.setUuid(uuid);
String dohIp = dohAttribute.getIp();
Integer port = dohAttribute.getPort();
String component = dohAttribute.getComponent();
String path = dohAttribute.getPath();
dohAttribute.setProtocolType(Constant.PROTOC_TCP);
dohAttribute.setIpType(getIpType(dohIp));
if (component != null)
dohAttribute.setComponentList(new ArrayList<>(Arrays.stream(component.split(",")).collect(Collectors.toSet())));
if (path != null)
dohAttribute.setPathList(new ArrayList<>(Arrays.stream(path.split(",")).collect(Collectors.toSet())));
ArrayList<String> tagList = new ArrayList<>(); //添加服务类别标签
tagList.add(Constant.DOHTAG);
List<Object> banner = new ArrayList<>();
List<Object> httpHeader = new ArrayList<>();
// 根据ip,port,hostrounds查询doh_attribute rep_body repHeader信息
List<Result> repList = this.baseMapper.getDohRepBody(dohIp, port, dohAttribute.getHost(), dohAttribute.getRounds());
for (int i = 0; i < repList.size(); i++) {
Result result = repList.get(i);
if (StringUtils.isNotBlank(result.getRepBody())) {
banner.add(result.getRepBody());
}
if (StringUtils.isNotBlank(result.getRepHeader())) {
httpHeader.add(result.getRepHeader());
}
}
dohAttribute.setBanner(banner);
dohAttribute.setHttpContent(httpHeader);
//根据ip和端口查询证书库获取证书数据
List<IpCert> ipCertList = ipCertDao.selectList(new LambdaQueryWrapper<IpCert>().eq(IpCert::getIp, dohIp).eq(IpCert::getPort, port));
dohAttribute.setIpCert(ipCertList);
dohAttribute.setTags(tagList);
}
}
/**
* 设置do53标签根据dnsType设置banner
* type = 1 banner list.get(0)为rep
* type = 2,3 banner中的 list.get(0)为 query_rep,列表其余数据为ip信息
* type = 5 banner list.get(0)为rep其余为NonstandardDns列表
* @param scanResultList
*/
public void setdo53Data(List<Result> scanResultList) {
for (Result scanResult : scanResultList) {
String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
scanResult.setUuid(uuid);
String do53Ip = scanResult.getIp();
Integer epoch = scanResult.getEpoch();
Integer dnsType = scanResult.getDnsType();
ArrayList<String> tagList = new ArrayList<>(); //添加服务类别标签
tagList.add(Constant.DO53TAG);
scanResult.setIpType(getIpType(do53Ip));
scanResult.setProtocolType(getProtocolType(scanResult.getScanType()));
List<Object> bannerList = new ArrayList<>();
if (Constant.FORWARDER.equals(dnsType) || Constant.FWDRDNS.equals(dnsType)) { //2、3
if (Constant.FWDRDNS.equals(dnsType)) { //3
tagList.add(Constant.FORWARDERTAG);
} else {
tagList.add(Constant.FWDRDNSTAG);
}
bannerList.add(scanResult.getQueryResponse());
List<IpInformation> forwardDnsList = ipInformationDao.getIpInfoByFwd(do53Ip, epoch);
bannerList.addAll(forwardDnsList);
} else if (Constant.EGRESSRDNS.equals(dnsType)) { //4
tagList.add(Constant.EGRESSRDNSTAG);
} else if (Constant.NONSTANDARD.equals(dnsType)) { //5
bannerList.add(scanResult.getQueryResponse());
tagList.add(Constant.NONSTANDARDTAG);
List<NonstandardDns> nonstandardDnsList = nonstandardDnsDao.selectList(new LambdaQueryWrapper<NonstandardDns>().eq(NonstandardDns::getIp, do53Ip).eq(NonstandardDns::getEpoch, epoch));
bannerList.addAll((List<JSONObject>) JSONObject.toJSON(nonstandardDnsList));
} else if (Constant.OPENRDNS.equals(dnsType)) { //1
tagList.add(Constant.OPENRDNSTAG);
if(StringUtils.isNotBlank(scanResult.getQueryResponse())){
bannerList.add(scanResult.getQueryResponse());
}
}
scanResult.setBanner(bannerList);
scanResult.setTags(tagList);
}
}
/**
* @param dataList 目标list
* @param pageSize 当前页大小
* @param currentPage 当前页
* @return 返回当前页的数据集
* @deprecated 对list进行分页
*/
public List<Result> getPage(List<Result> dataList, int pageSize, int currentPage) {
List<Result> currentPageList = new ArrayList<>();
if (!dataList.isEmpty()) {
int currIdx = (currentPage > 1 ? (currentPage - 1) * pageSize : 0);
for (int i = 0; i < pageSize && i < dataList.size() - currIdx; i++) {
Result data = dataList.get(currIdx + i);
currentPageList.add(data);
}
}
return currentPageList;
}
/**
* 查询dns信息dnh和do53scan_result结果并集
*
* @param page
* @param params
* @return
*/
private PageUtils queryDnsInfo(IPage page, Map<String, Object> params) {
Map<String, Object> indepentIpMap = new HashMap<>(4);
int resultTotal = 0;
long pageSize = page.getSize();
params.put("n", 0); //用作doh查询的分页偏移量
params.put("m", page.getCurrent() * page.getSize()); //用作查询的分页大小
// 查询doh信息
//同一轮次相同ip合并path和component漏洞信息
List<Result> dohAttributes = dnsDohDao.queryDohPage(null, params);
setDohData(dohAttributes);
int dohResultTotal = dnsDohDao.dohResultTotalCount(params);
indepentIpMap.put("dns-doh", dnsDohDao.dohIpCount(params));
// 查询do53信息
List<Result> scanResultList = dnsDo53Dao.queryDo53Page(null, params);
setdo53Data(scanResultList);
indepentIpMap.put("dns-do53", dnsDo53Dao.do53IpCount(params));
int do53ResultTotal = dnsDo53Dao.pageCount(params);
List<Result> resultList = new ArrayList<>();
resultList.addAll(dohAttributes);
resultList.addAll(scanResultList);
List<Result> collect = resultList.stream().sorted(Comparator.comparing(Result::getTimestamp).reversed()).collect(Collectors.toList());
page.setTotal(do53ResultTotal + dohResultTotal);
page.setRecords(getPage(collect, (int) pageSize, (int) page.getCurrent()));
return buildResult(page,indepentIpMap,(do53ResultTotal + dohResultTotal));
}
/**
* 查询 do53信息
* @param page
* @param params
* @return
*/
private PageUtils queryDo53Info(IPage page, Map<String, Object> params){
// 根据 service=dns-do53 port为53查询 scan_result表 参数ip,port
List<Result> scanResultList = dnsDo53Dao.queryDo53Page(null, params);
setdo53Data(scanResultList);
int independentIpNum = dnsDo53Dao.do53IpCount(params);
int resultTotal = dnsDo53Dao.pageCount(params);
page.setRecords(scanResultList);
return buildResult(page,independentIpNum,resultTotal);
}
/**
* 查询doh信息
* @param page
* @param params
* @return
*/
private PageUtils queryDohInfo(IPage page, Map<String, Object> params){
// 根据 service=dns-do53 port为53查询 scan_result表 参数ip,port
List<Result> scanResultList = dnsDohDao.queryDohPage(null, params);
setDohData(scanResultList);
int independentIpNum = dnsDohDao.dohIpCount(params);
int resultTotal = dnsDohDao.dohResultTotalCount(params);
page.setRecords(scanResultList);
return buildResult(page,independentIpNum,resultTotal);
}
/**
* 只根据ip查询
* @param page
* @param params
* @return
*/
private PageUtils queryPageByIp(IPage page, Map<String, Object> params){
// 只根据ip查询
int independentIpNum = 0;
params.put("n", 0); //用作doh查询的分页
params.put("m", page.getCurrent() * page.getSize()); //用作doh查询的分页
long pageSize = page.getSize();
List<Result> dohAttributesList = dnsDohDao.queryDohPage(null, params);
setDohData(dohAttributesList);
List<Result> scanResultList = dnsDo53Dao.queryDo53Page(null, params);
setdo53Data(scanResultList);
List<Result> resultList = new ArrayList<>();
resultList.addAll(dohAttributesList);
resultList.addAll(scanResultList);
int resultTotal = resultList.size();
List<Result> collect = resultList.stream().sorted(Comparator.comparing(Result::getTimestamp).reversed()).collect(Collectors.toList());
if (!collect.isEmpty()) {
independentIpNum = 1;
}
page.setTotal(collect.size());
page.setRecords(getPage(collect, (int) pageSize, (int) page.getCurrent()));
return buildResult(page,independentIpNum,resultTotal);
}
/**
* 查询 dnh和do53scan_result结果交集 service = dns-doh AND dns-do53
*
* @param page
* @param params
* @return
*/
private PageUtils queryDohAndDo53Info(IPage page, Map<String, Object> params) {
params.put("offset", 0); //用作doh查询的分页偏移量
params.put("limit", page.getCurrent() * page.getSize()); //用作查询的分页大小
Map<String, Object> indepentIpMap = new HashMap<>(4);
// 查询doh信息
List<Result> dohAttributes = dnsDohDao.selectDohInfoByUnion(params);
Integer dohCount = dnsDohDao.selectDohCountByUnion(params);
setDohData(dohAttributes);
// 查询do53(scan_result)信息
List<Result> do53Infos = dnsDo53Dao.selectScanResultByUnion(null,params);
Integer do53Count = dnsDo53Dao.selectScanResultCountByUnion(params);
setdo53Data(do53Infos);
do53Infos.addAll(dohAttributes);
page.setTotal(dohCount + do53Count);
page.setRecords(getPage(do53Infos, (int) page.getSize(), (int) page.getCurrent()));
indepentIpMap.put("dns-doh",do53Count);
indepentIpMap.put("dns-do53",do53Count);
return buildResult(page,indepentIpMap,(dohCount + do53Count));
}
private String getIpType(String ip){
if(ip.contains(Constant.POINT)){
return Constant.IP_IPV4;
}
return Constant.IP_IPV6;
}
private String getProtocolType(Integer scanType){
// dnsType 为2为udp,1或者空为tcp
if(scanType == null || scanType < 2){
return Constant.PROTOC_TCP;
}
return Constant.PROTOC_UDP;
}
private PageUtils buildResult(IPage page,Object independentIpNum,Integer resultTotal ){
PageUtils pageUtils = new PageUtils(page);
// 添加独立IP个数
pageUtils.setIndependentIpNum(independentIpNum);
pageUtils.setResultTotal(resultTotal);
return pageUtils;
}
private PageUtils openRdns(IPage page, Map<String, Object> params) {
List<Result> results = dnsDo53Dao.queryOpenRdns(params);
int totalCount = dnsDo53Dao.getCountByDnsType(Constant.OPENRDNS, params);
setDo53Label(results, Constant.OPENRDNSTAG);
page.setRecords(results);
// 添加独立IP个数
Integer independentIpNum = dnsDo53Dao.getIndependentIpNum(Constant.OPENRDNS, params);
return buildResult(page,independentIpNum,totalCount);
}
private PageUtils forwarder(IPage page, Map<String, Object> params) {
int totalCount = dnsDo53Dao.getCountByDnsType(Constant.FORWARDER, params);
List<Result> results = dnsDo53Dao.queryOpenRdns(params);
for (Result result : results) {
List<IpInformation> ipInfos = ipInformationDao.getIpInfoByFwd(result.getIp(),null);
result.setBanner(ipInfos);
result.setProtocolType(getProtocolType(result.getScanType()));
result.setIpType(getIpType(result.getIp()));
addLabels(result, Constant.FORWARDERTAG);
}
page.setRecords(results);
// 添加独立IP个数
Integer independentIpNum = dnsDo53Dao.getIndependentIpNum(Constant.FORWARDER, params);
return buildResult(page,independentIpNum,totalCount);
}
private PageUtils fwdRdns(IPage page, Map<String, Object> params) {
int totalCount = dnsDo53Dao.getCountByDnsType(Constant.FWDRDNS, params);
List<Result> results = dnsDo53Dao.queryOpenRdns(params);
for (Result result : results) {
List<IpInformation> ipInfos = ipInformationDao.getIpInfoByFwd(result.getIp(),null);
result.setBanner(ipInfos);
result.setProtocolType(getProtocolType(result.getScanType()));
result.setIpType(getIpType(result.getIp()));
addLabels(result, Constant.FWDRDNSTAG);
}
page.setRecords(results);
// 添加独立IP个数
Integer independentIpNum = dnsDo53Dao.getIndependentIpNum(Constant.FWDRDNS, params);
return buildResult(page,independentIpNum,totalCount);
}
private PageUtils egressDns(IPage page, Map<String, Object> params) {
int totalCount = dnsDo53Dao.getCountByDnsType(Constant.EGRESSRDNS, params);
List<Result> results = dnsDo53Dao.queryOpenRdns(params);
setDo53Label(results, Constant.EGRESSRDNSTAG);
page.setRecords(results);
// 添加独立IP个数
Integer independentIpNum = dnsDo53Dao.getIndependentIpNum(Constant.EGRESSRDNS, params);
return buildResult(page,independentIpNum,totalCount);
}
private PageUtils nonstandard(IPage page, Map<String, Object> params) {
int totalCount = dnsDo53Dao.getCountByDnsType(Constant.NONSTANDARD, params);
List<Result> results = dnsDo53Dao.queryOpenRdns(params);
for (Result result : results) {
List<IpInformation> ipInfos = ipInformationDao.getIpInfoByFwd(result.getIp(),null);
result.setBanner(ipInfos);
result.setProtocolType(getProtocolType(result.getScanType()));
result.setIpType(getIpType(result.getIp()));
addLabels(result, Constant.NONSTANDARDTAG);
}
page.setRecords(results);
// 添加独立IP个数
Integer independentIpNum = dnsDo53Dao.getIndependentIpNum(Constant.NONSTANDARD, params);
return buildResult(page,independentIpNum,totalCount);
}
private void setDo53Label(List<Result> results, String serviceType) {
List<String> labels = DnsQueryEnum.getLabels(serviceType);
for (Result result : results) {
// result.setBanner(result.getQueryResponse());
result.setProtocolType(getProtocolType(result.getScanType()));
result.setIpType(getIpType(result.getIp()));
result.setTags(labels);
}
}
private void addLabels(Result result, String serviceType) {
List<String> labels = DnsQueryEnum.getLabels(serviceType);
result.setTags(labels);
}
}

View File

@@ -0,0 +1,15 @@
package com.example.modules.dns.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.modules.dns.domain.DnsType;
import com.example.modules.dns.mapper.DnsTypeDao;
import com.example.modules.dns.service.DnsTypeService;
import org.springframework.stereotype.Service;
@Service
public class DnsTypeServiceImpl extends ServiceImpl<DnsTypeDao, DnsType> implements DnsTypeService {
}

View File

@@ -0,0 +1,66 @@
package com.example.modules.dns.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.modules.dns.domain.ScanResult;
import com.example.modules.dns.mapper.DnsDo53Dao;
import com.example.modules.dns.service.ScanResultService;
import com.example.utils.Constant;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Lihe
* @version 1
* @description
* @date 2022/6/8
*/
@Service
public class ScanResultServiceImpl extends ServiceImpl<DnsDo53Dao, ScanResult> implements ScanResultService {
@Override
public Map<String, Object> queryDo53DataCountByDnsType(Map<String, Object> params, Integer dnsType) {
Map<String, Object> resultMap = new HashMap(8);
List<Map<String, Object>> portList = new ArrayList<>();
List<Map<String, Object>> serviceCategoryList = new ArrayList<>();
//端口
Map<String, Object> portMap = new HashMap<>();
int count = this.baseMapper.getCountByDnsType(dnsType,params);
portMap.put("port", Constant.PORT53);
portMap.put("count", count);
portList.add(portMap);
resultMap.put("portList", portList);
//地域
resultMap.put("regionList", this.baseMapper.getDo53ProvinceCountByDnsType(dnsType,params));
//运营商
resultMap.put("providerList", this.baseMapper.getDo53ProviderCountByDnsType(dnsType,params));
//服务组件
resultMap.put("componentList", this.baseMapper.getDo53ComponentCountByDnsType(dnsType,params));
//服务类别
Integer serviceCount = this.baseMapper.getDo53SrvCategoryCountByDnsType(dnsType,params);
Map<String,Object> dnsTypeMap = new HashMap<>(2);
dnsTypeMap.put("key",DnsQueryEnum.getDnsType(dnsType));
dnsTypeMap.put("count",serviceCount);
serviceCategoryList.add(dnsTypeMap);
Map<String,Object> do53ServiceMap = new HashMap<>(2);
do53ServiceMap.put("key",Constant.DO53TAG);
do53ServiceMap.put("count",serviceCount);
serviceCategoryList.add(do53ServiceMap);
resultMap.put("serviceCategoryList", serviceCategoryList);
//漏洞威胁
resultMap.put("vulnerabilityCountList", this.baseMapper.getDo53VulnerabCountByDnsType(dnsType,params));
return resultMap;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.config;
import com.example.modules.security.config.bean.LoginProperties;
import com.example.modules.security.config.bean.SecurityProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @apiNote 配置文件转换Pojo类的 统一配置 类
* @author: liaojinlong
* : 2020/6/10 19:04
*/
@Configuration
public class ConfigBeanConfiguration {
@Bean
@ConfigurationProperties(prefix = "login")
public LoginProperties loginProperties() {
return new LoginProperties();
}
@Bean
@ConfigurationProperties(prefix = "jwt")
public SecurityProperties securityProperties() {
return new SecurityProperties();
}
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.config;
import com.example.modules.security.security.JwtAccessDeniedHandler;
import com.example.modules.security.security.JwtAuthenticationEntryPoint;
import com.example.modules.security.security.TokenConfigurer;
import com.example.modules.security.security.TokenProvider;
import lombok.RequiredArgsConstructor;
import com.example.annotation.AnonymousAccess;
import com.example.modules.security.config.bean.SecurityProperties;
import com.example.modules.security.security.*;
import com.example.modules.security.service.OnlineUserService;
import com.example.modules.security.service.UserCacheClean;
import com.example.utils.enums.RequestMethodEnum;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.*;
/**
*
*/
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
private final TokenProvider tokenProvider;
private final CorsFilter corsFilter;
private final JwtAuthenticationEntryPoint authenticationErrorHandler;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
private final ApplicationContext applicationContext;
private final SecurityProperties properties;
private final OnlineUserService onlineUserService;
private final UserCacheClean userCacheClean;
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
// 去除 ROLE_ 前缀
return new GrantedAuthorityDefaults("");
}
@Bean
public PasswordEncoder passwordEncoder() {
// 密码加密方式
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// 搜寻匿名标记 url @AnonymousAccess
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
// 获取匿名标记
Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap);
httpSecurity
// 禁用 CSRF
.csrf().disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
// 授权异常
.exceptionHandling()
.authenticationEntryPoint(authenticationErrorHandler)
.accessDeniedHandler(jwtAccessDeniedHandler)
// 防止iframe 造成跨域
.and()
.headers()
.frameOptions()
.disable()
// 不创建会话
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 静态资源等等
.antMatchers(
HttpMethod.GET,
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/webSocket/**"
).permitAll()
// swagger 文档
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").permitAll()
// 文件
.antMatchers("/avatar/**").permitAll()
.antMatchers("/file/**").permitAll()
// 阿里巴巴 druid
.antMatchers("/druid/**").permitAll()
// 放行OPTIONS请求
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// 自定义匿名访问所有url放行允许匿名和带Token访问细腻化到每个 Request 类型
// GET
.antMatchers(HttpMethod.GET, anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray(new String[0])).permitAll()
// POST
.antMatchers(HttpMethod.POST, anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray(new String[0])).permitAll()
// PUT
.antMatchers(HttpMethod.PUT, anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray(new String[0])).permitAll()
// PATCH
.antMatchers(HttpMethod.PATCH, anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray(new String[0])).permitAll()
// DELETE
.antMatchers(HttpMethod.DELETE, anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray(new String[0])).permitAll()
// 所有类型的接口都放行
.antMatchers(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray(new String[0])).permitAll()
// 所有请求都需要认证
.anyRequest().authenticated()
.and().apply(securityConfigurerAdapter());
}
private TokenConfigurer securityConfigurerAdapter() {
return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheClean);
}
private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) {
Map<String, Set<String>> anonymousUrls = new HashMap<>(8);
Set<String> get = new HashSet<>();
Set<String> post = new HashSet<>();
Set<String> put = new HashSet<>();
Set<String> patch = new HashSet<>();
Set<String> delete = new HashSet<>();
Set<String> all = new HashSet<>();
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = infoEntry.getValue();
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
if (null != anonymousAccess) {
List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods());
RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name());
switch (Objects.requireNonNull(request)) {
case GET:
get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case POST:
post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case PUT:
put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case PATCH:
patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case DELETE:
delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
default:
all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
}
}
}
anonymousUrls.put(RequestMethodEnum.GET.getType(), get);
anonymousUrls.put(RequestMethodEnum.POST.getType(), post);
anonymousUrls.put(RequestMethodEnum.PUT.getType(), put);
anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch);
anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete);
anonymousUrls.put(RequestMethodEnum.ALL.getType(), all);
return anonymousUrls;
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.config.bean;
import lombok.Data;
/**
* 登录验证码配置信息
*
* @author liaojinlong
* 2020/6/10 18:53
*/
@Data
public class LoginCode {
/**
* 验证码配置
*/
private LoginCodeEnum codeType;
/**
* 验证码有效期 分钟
*/
private Long expiration = 2L;
/**
* 验证码内容长度
*/
private int length = 2;
/**
* 验证码宽度
*/
private int width = 111;
/**
* 验证码高度
*/
private int height = 36;
/**
* 验证码字体
*/
private String fontName;
/**
* 字体大小
*/
private int fontSize = 25;
public LoginCodeEnum getCodeType() {
return codeType;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.config.bean;
/**
* 验证码配置枚举
*
* @author: liaojinlong
* : 2020/6/10 17:40
*/
public enum LoginCodeEnum {
/**
* 算数
*/
ARITHMETIC,
/**
* 中文
*/
CHINESE,
/**
* 中文闪图
*/
CHINESE_GIF,
/**
* 闪图
*/
GIF,
SPEC
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version loginCode.length.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-loginCode.length.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.config.bean;
import com.wf.captcha.*;
import com.wf.captcha.base.Captcha;
import lombok.Data;
import com.example.exception.BadConfigurationException;
import com.example.utils.StringUtils;
import java.awt.*;
import java.util.Objects;
/**
* 配置文件读取
*
* @author liaojinlong
* loginCode.length0loginCode.length0/6/10 17:loginCode.length6
*/
@Data
public class LoginProperties {
/**
* 账号单用户 登录
*/
private boolean singleLogin = false;
private LoginCode loginCode;
/**
* 用户登录信息缓存
*/
private boolean cacheEnable;
public boolean isSingleLogin() {
return singleLogin;
}
public boolean isCacheEnable() {
return cacheEnable;
}
/**
* 获取验证码生产类
*
* @return /
*/
public Captcha getCaptcha() {
if (Objects.isNull(loginCode)) {
loginCode = new LoginCode();
if (Objects.isNull(loginCode.getCodeType())) {
loginCode.setCodeType(LoginCodeEnum.ARITHMETIC);
}
}
return switchCaptcha(loginCode);
}
/**
* 依据配置信息生产验证码
*
* @param loginCode 验证码配置信息
* @return /
*/
private Captcha switchCaptcha(LoginCode loginCode) {
Captcha captcha;
synchronized (this) {
switch (loginCode.getCodeType()) {
case ARITHMETIC:
// 算术类型 https://gitee.com/whvse/EasyCaptcha
captcha = new FixedArithmeticCaptcha(loginCode.getWidth(), loginCode.getHeight());
// 几位数运算,默认是两位
captcha.setLen(loginCode.getLength());
break;
case CHINESE:
captcha = new ChineseCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case CHINESE_GIF:
captcha = new ChineseGifCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case GIF:
captcha = new GifCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case SPEC:
captcha = new SpecCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
default:
throw new BadConfigurationException("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
}
}
if(StringUtils.isNotBlank(loginCode.getFontName())){
captcha.setFont(new Font(loginCode.getFontName(), Font.PLAIN, loginCode.getFontSize()));
}
return captcha;
}
static class FixedArithmeticCaptcha extends ArithmeticCaptcha {
public FixedArithmeticCaptcha(int width, int height) {
super(width, height);
}
@Override
protected char[] alphas() {
// 生成随机数字和运算符
int n1 = num(1, 10), n2 = num(1, 10);
int opt = num(3);
// 计算结果
int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt];
// 转换为字符运算符
char optChar = "+-x".charAt(opt);
this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2));
this.chars = String.valueOf(res);
return chars.toCharArray();
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.config.bean;
import lombok.Data;
/**
* Jwt参数配置
*
*
* 2019年11月28日
*/
@Data
public class SecurityProperties {
/**
* Request Headers Authorization
*/
private String header;
/**
* 令牌前缀,最后留个空格 Bearer
*/
private String tokenStartWith;
/**
* 必须使用最少88位的Base64对该令牌进行编码
*/
private String base64Secret;
/**
* 令牌过期时间 此处单位/毫秒
*/
private Long tokenValidityInSeconds;
/**
* 在线用户 key根据 key 查询 redis 中在线用户的数据
*/
private String onlineKey;
/**
* 验证码 key
*/
private String codeKey;
/**
* token 续期检查
*/
private Long detect;
/**
* 续期时间
*/
private Long renew;
public String getTokenStartWith() {
return tokenStartWith + " ";
}
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.rest;
import cn.hutool.core.util.IdUtil;
import com.wf.captcha.base.Captcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.example.annotation.rest.AnonymousDeleteMapping;
import com.example.annotation.rest.AnonymousGetMapping;
import com.example.annotation.rest.AnonymousPostMapping;
import com.example.config.RsaProperties;
import com.example.exception.BadRequestException;
import com.example.modules.security.config.bean.LoginCodeEnum;
import com.example.modules.security.config.bean.LoginProperties;
import com.example.modules.security.config.bean.SecurityProperties;
import com.example.modules.security.security.TokenProvider;
import com.example.modules.security.service.dto.AuthUserDto;
import com.example.modules.security.service.dto.JwtUserDto;
import com.example.modules.security.service.OnlineUserService;
import com.example.utils.RsaUtils;
import com.example.utils.RedisUtils;
import com.example.utils.SecurityUtils;
import com.example.utils.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
*
* 2018-11-23
* 授权、根据token获取用户详细信息
*/
@Slf4j
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
@Api(tags = "系统:系统授权接口")
public class AuthorizationController {
private final SecurityProperties properties;
private final RedisUtils redisUtils;
private final OnlineUserService onlineUserService;
private final TokenProvider tokenProvider;
private final AuthenticationManagerBuilder authenticationManagerBuilder;
@Resource
private LoginProperties loginProperties;
@ApiOperation("登录授权")
@AnonymousPostMapping(value = "/login")
public ResponseEntity<Object> login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception {
// 密码解密
String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword());
//去除验证码功能
/* // 查询验证码
String code = (String) redisUtils.get(authUser.getUuid());
// 清除验证码
redisUtils.del(authUser.getUuid());
if (StringUtils.isBlank(code)) {
throw new BadRequestException("验证码不存在或已过期");
}
if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) {
throw new BadRequestException("验证码错误");
}*/
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(authUser.getUsername(), password);
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
// 生成令牌与第三方系统获取令牌方式
// UserDetails userDetails = userDetailsService.loadUserByUsername(userInfo.getUsername());
// Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
// SecurityContextHolder.getContext().setAuthentication(authentication);
String token = tokenProvider.createToken(authentication);
final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal();
// 保存在线信息
onlineUserService.save(jwtUserDto, token, request);
// 返回 token 与 用户信息
Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
put("token", properties.getTokenStartWith() + token);
put("user", jwtUserDto);
}};
if (loginProperties.isSingleLogin()) {
//踢掉之前已经登录的token
onlineUserService.checkLoginOnUser(authUser.getUsername(), token);
}
return ResponseEntity.ok(authInfo);
}
@ApiOperation("获取用户信息")
@GetMapping(value = "/info")
public ResponseEntity<Object> getUserInfo() {
return ResponseEntity.ok(SecurityUtils.getCurrentUser());
}
@ApiOperation("获取验证码")
@AnonymousGetMapping(value = "/code")
public ResponseEntity<Object> getCode() {
// 获取运算的结果
Captcha captcha = loginProperties.getCaptcha();
String uuid = properties.getCodeKey() + IdUtil.simpleUUID();
//当验证码类型为 arithmetic时且长度 >= 2 时captcha.text()的结果有几率为浮点型
String captchaValue = captcha.text();
if (captcha.getCharType() - 1 == LoginCodeEnum.ARITHMETIC.ordinal() && captchaValue.contains(".")) {
captchaValue = captchaValue.split("\\.")[0];
}
// 保存
redisUtils.set(uuid, captchaValue, loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES);
// 验证码信息
Map<String, Object> imgResult = new HashMap<String, Object>(2) {{
put("img", captcha.toBase64());
put("uuid", uuid);
}};
return ResponseEntity.ok(imgResult);
}
@ApiOperation("退出登录")
@AnonymousDeleteMapping(value = "/logout")
public ResponseEntity<Object> logout(HttpServletRequest request) {
onlineUserService.logout(tokenProvider.getToken(request));
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.example.modules.security.service.OnlineUserService;
import com.example.utils.EncryptUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;
/**
*
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/auth/online")
@Api(tags = "系统:在线用户管理")
public class OnlineController {
private final OnlineUserService onlineUserService;
@ApiOperation("查询在线用户")
@GetMapping
@PreAuthorize("@el.check()")
public ResponseEntity<Object> queryOnlineUser(String filter, Pageable pageable){
return new ResponseEntity<>(onlineUserService.getAll(filter, pageable),HttpStatus.OK);
}
@ApiOperation("导出数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check()")
public void exportOnlineUser(HttpServletResponse response, String filter) throws IOException {
onlineUserService.download(onlineUserService.getAll(filter), response);
}
@ApiOperation("踢出用户")
@DeleteMapping
@PreAuthorize("@el.check()")
public ResponseEntity<Object> deleteOnlineUser(@RequestBody Set<String> keys) throws Exception {
for (String key : keys) {
// 解密Key
key = EncryptUtils.desDecrypt(key);
onlineUserService.kickOut(key);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.security;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
*
*/
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
//当用户在没有授权的情况下访问受保护的REST资源时将调用此方法发送403 Forbidden响应
response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.security;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
*
*/
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
// 当用户尝试访问安全的REST资源而不提供任何凭据时将调用此方法发送401 响应
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage());
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.security;
import com.example.modules.security.config.bean.SecurityProperties;
import com.example.modules.security.service.OnlineUserService;
import com.example.modules.security.service.UserCacheClean;
import lombok.RequiredArgsConstructor;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* @author /
*/
@RequiredArgsConstructor
public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private final TokenProvider tokenProvider;
private final SecurityProperties properties;
private final OnlineUserService onlineUserService;
private final UserCacheClean userCacheClean;
@Override
public void configure(HttpSecurity http) {
TokenFilter customFilter = new TokenFilter(tokenProvider, properties, onlineUserService, userCacheClean);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.security;
import cn.hutool.core.util.StrUtil;
import com.example.modules.security.config.bean.SecurityProperties;
import com.example.modules.security.service.OnlineUserService;
import com.example.modules.security.service.UserCacheClean;
import com.example.modules.security.service.dto.OnlineUserDto;
import io.jsonwebtoken.ExpiredJwtException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;
/**
* @author /
*/
public class TokenFilter extends GenericFilterBean {
private static final Logger log = LoggerFactory.getLogger(TokenFilter.class);
private final TokenProvider tokenProvider;
private final SecurityProperties properties;
private final OnlineUserService onlineUserService;
private final UserCacheClean userCacheClean;
/**
* @param tokenProvider Token
* @param properties JWT
* @param onlineUserService 用户在线
* @param userCacheClean 用户缓存清理工具
*/
public TokenFilter(TokenProvider tokenProvider, SecurityProperties properties, OnlineUserService onlineUserService, UserCacheClean userCacheClean) {
this.properties = properties;
this.onlineUserService = onlineUserService;
this.tokenProvider = tokenProvider;
this.userCacheClean = userCacheClean;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String token = resolveToken(httpServletRequest);
// 对于 Token 为空的不需要去查 Redis
if (StrUtil.isNotBlank(token)) {
OnlineUserDto onlineUserDto = null;
boolean cleanUserCache = false;
try {
onlineUserDto = onlineUserService.getOne(properties.getOnlineKey() + token);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
cleanUserCache = true;
} finally {
if (cleanUserCache || Objects.isNull(onlineUserDto)) {
userCacheClean.cleanUserCache(String.valueOf(tokenProvider.getClaims(token).get(TokenProvider.AUTHORITIES_KEY)));
}
}
if (onlineUserDto != null && StringUtils.hasText(token)) {
Authentication authentication = tokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Token 续期
tokenProvider.checkRenewal(token);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
/**
* 初步检测Token
*
* @param request /
* @return /
*/
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(properties.getHeader());
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) {
// 去掉令牌前缀
return bearerToken.replace(properties.getTokenStartWith(), "");
} else {
log.debug("非法Token{}", bearerToken);
}
return null;
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.security;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.example.modules.security.config.bean.SecurityProperties;
import com.example.utils.RedisUtils;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @author /
*/
@Slf4j
@Component
public class TokenProvider implements InitializingBean {
private final SecurityProperties properties;
private final RedisUtils redisUtils;
public static final String AUTHORITIES_KEY = "user";
private JwtParser jwtParser;
private JwtBuilder jwtBuilder;
public TokenProvider(SecurityProperties properties, RedisUtils redisUtils) {
this.properties = properties;
this.redisUtils = redisUtils;
}
@Override
public void afterPropertiesSet() {
byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret());
Key key = Keys.hmacShaKeyFor(keyBytes);
jwtParser = Jwts.parserBuilder()
.setSigningKey(key)
.build();
jwtBuilder = Jwts.builder()
.signWith(key, SignatureAlgorithm.HS512);
}
/**
* 创建Token 设置永不过期,
* Token 的时间有效性转到Redis 维护
*
* @param authentication /
* @return /
*/
public String createToken(Authentication authentication) {
return jwtBuilder
// 加入ID确保生成的 Token 都不一致
.setId(IdUtil.simpleUUID())
.claim(AUTHORITIES_KEY, authentication.getName())
.setSubject(authentication.getName())
.compact();
}
/**
* 依据Token 获取鉴权信息
*
* @param token /
* @return /
*/
Authentication getAuthentication(String token) {
Claims claims = getClaims(token);
User principal = new User(claims.getSubject(), "******", new ArrayList<>());
return new UsernamePasswordAuthenticationToken(principal, token, new ArrayList<>());
}
public Claims getClaims(String token) {
return jwtParser
.parseClaimsJws(token)
.getBody();
}
/**
* @param token 需要检查的token
*/
public void checkRenewal(String token) {
// 判断是否续期token,计算token的过期时间
long time = redisUtils.getExpire(properties.getOnlineKey() + token) * 1000;
Date expireDate = DateUtil.offset(new Date(), DateField.MILLISECOND, (int) time);
// 判断当前时间与过期时间的时间差
long differ = expireDate.getTime() - System.currentTimeMillis();
// 如果在续期检查的范围内,则续期
if (differ <= properties.getDetect()) {
long renew = time + properties.getRenew();
redisUtils.expire(properties.getOnlineKey() + token, renew, TimeUnit.MILLISECONDS);
}
}
public String getToken(HttpServletRequest request) {
final String requestHeader = request.getHeader(properties.getHeader());
if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) {
return requestHeader.substring(7);
}
return null;
}
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.service;
import com.example.modules.security.config.bean.SecurityProperties;
import com.example.utils.*;
import lombok.extern.slf4j.Slf4j;
import com.example.modules.security.service.dto.JwtUserDto;
import com.example.modules.security.service.dto.OnlineUserDto;
import com.example.utils.*;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
/**
*
* 2019年10月26日21:56:27
*/
@Service
@Slf4j
public class OnlineUserService {
private final SecurityProperties properties;
private final RedisUtils redisUtils;
public OnlineUserService(SecurityProperties properties, RedisUtils redisUtils) {
this.properties = properties;
this.redisUtils = redisUtils;
}
/**
* 保存在线用户信息
* @param jwtUserDto /
* @param token /
* @param request /
*/
public void save(JwtUserDto jwtUserDto, String token, HttpServletRequest request){
String dept = jwtUserDto.getUser().getDept().getName();
String ip = StringUtils.getIp(request);
String browser = StringUtils.getBrowser(request);
String address = StringUtils.getCityInfo(ip);
OnlineUserDto onlineUserDto = null;
try {
onlineUserDto = new OnlineUserDto(jwtUserDto.getUsername(), jwtUserDto.getUser().getNickName(), dept, browser , ip, address, EncryptUtils.desEncrypt(token), new Date());
} catch (Exception e) {
log.error(e.getMessage(),e);
}
redisUtils.set(properties.getOnlineKey() + token, onlineUserDto, properties.getTokenValidityInSeconds()/1000);
}
/**
* 查询全部数据
* @param filter /
* @param pageable /
* @return /
*/
public Map<String,Object> getAll(String filter, Pageable pageable){
List<OnlineUserDto> onlineUserDtos = getAll(filter);
return PageUtil.toPage(
PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(), onlineUserDtos),
onlineUserDtos.size()
);
}
/**
* 查询全部数据,不分页
* @param filter /
* @return /
*/
public List<OnlineUserDto> getAll(String filter){
List<String> keys = redisUtils.scan(properties.getOnlineKey() + "*");
Collections.reverse(keys);
List<OnlineUserDto> onlineUserDtos = new ArrayList<>();
for (String key : keys) {
OnlineUserDto onlineUserDto = (OnlineUserDto) redisUtils.get(key);
if(StringUtils.isNotBlank(filter)){
if(onlineUserDto.toString().contains(filter)){
onlineUserDtos.add(onlineUserDto);
}
} else {
onlineUserDtos.add(onlineUserDto);
}
}
onlineUserDtos.sort((o1, o2) -> o2.getLoginTime().compareTo(o1.getLoginTime()));
return onlineUserDtos;
}
/**
* 踢出用户
* @param key /
*/
public void kickOut(String key){
key = properties.getOnlineKey() + key;
redisUtils.del(key);
}
/**
* 退出登录
* @param token /
*/
public void logout(String token) {
String key = properties.getOnlineKey() + token;
redisUtils.del(key);
}
/**
* 导出
* @param all /
* @param response /
* @throws IOException /
*/
public void download(List<OnlineUserDto> all, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (OnlineUserDto user : all) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("用户名", user.getUserName());
map.put("部门", user.getDept());
map.put("登录IP", user.getIp());
map.put("登录地点", user.getAddress());
map.put("浏览器", user.getBrowser());
map.put("登录日期", user.getLoginTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
/**
* 查询用户
* @param key /
* @return /
*/
public OnlineUserDto getOne(String key) {
return (OnlineUserDto)redisUtils.get(key);
}
/**
* 检测用户是否在之前已经登录,已经登录踢下线
* @param userName 用户名
*/
public void checkLoginOnUser(String userName, String igoreToken){
List<OnlineUserDto> onlineUserDtos = getAll(userName);
if(onlineUserDtos ==null || onlineUserDtos.isEmpty()){
return;
}
for(OnlineUserDto onlineUserDto : onlineUserDtos){
if(onlineUserDto.getUserName().equals(userName)){
try {
String token =EncryptUtils.desDecrypt(onlineUserDto.getKey());
if(StringUtils.isNotBlank(igoreToken)&&!igoreToken.equals(token)){
this.kickOut(token);
}else if(StringUtils.isBlank(igoreToken)){
this.kickOut(token);
}
} catch (Exception e) {
log.error("checkUser is error",e);
}
}
}
}
/**
* 根据用户名强退用户
* @param username /
*/
@Async
public void kickOutForUsername(String username) throws Exception {
List<OnlineUserDto> onlineUsers = getAll(username);
for (OnlineUserDto onlineUser : onlineUsers) {
if (onlineUser.getUserName().equals(username)) {
String token =EncryptUtils.desDecrypt(onlineUser.getKey());
kickOut(token);
}
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.service;
import lombok.AllArgsConstructor;
import com.example.utils.StringUtils;
import org.springframework.stereotype.Component;
/**
* @author: liaojinlong
* : 2020/6/11 18:01
* @apiNote: 用于清理 用户登录信息缓存为防止Spring循环依赖与安全考虑 ,单独构成工具类
*/
@Component
@AllArgsConstructor
public class UserCacheClean {
private final UserCacheManager userCacheManager;
/**
* 清理特定用户缓存信息<br>
* 用户信息变更时
*
* @param userName /
*/
public void cleanUserCache(String userName) {
if (StringUtils.isNotEmpty(userName)) {
userCacheManager.remove(userName);
}
}
/**
* 清理所有用户的缓存信息<br>
* ,如发生角色授权信息变化,可以简便的全部失效缓存
*/
public void cleanAll() {
userCacheManager.clear();
}
}

View File

@@ -0,0 +1,110 @@
package com.example.modules.security.service;
import lombok.extern.slf4j.Slf4j;
import com.example.modules.security.service.dto.JwtUserDto;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 用户缓存
*
* @author TikiWong
* 2022/1/27 8:23
**/
@Slf4j
@Component
public class UserCacheManager {
@Value("${user-cache.min-evictable-size}")
private int minEvictableSize;
@Value("${user-cache.min-evictable-interval}")
private long minEvictableInterval;
@Value("${user-cache.min-idle-time}")
private long minIdleTime;
private final Map<String, Node> cache = new ConcurrentHashMap<>();
private final AtomicBoolean expelLock = new AtomicBoolean(true);
private long nextMinEvictableTime = 0;
public Future<JwtUserDto> putIfAbsent(String username, Future<JwtUserDto> ft) {
Node tryNode = new Node(ft);
Node node = cache.putIfAbsent(username, tryNode);
expel();
return nodeToDate(node);
}
/**
* 缓存回收
* 为避免超过边界后回收热点数据设置了最小生存时间
* 回收时会保留在最小生存时间内的数据
**/
public void expel() {
long now = System.currentTimeMillis();
if (cache.size() < minEvictableSize ||
now < nextMinEvictableTime ||
!expelLock.compareAndSet(true, false)) {
return;
}
long oldestTime = now;
int evictedCount = 0;
try {
Iterator<Map.Entry<String, Node>> iterator = cache.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Node> entry = iterator.next();
long nodeTime = entry.getValue().getTime();
if (nodeTime + minIdleTime < now) {
iterator.remove();
evictedCount++;
}
oldestTime = Math.min(oldestTime, nodeTime);
}
} finally {
this.nextMinEvictableTime = Math.max(now + minEvictableInterval, oldestTime);
expelLock.set(true);
log.info("回收掉【{}】条用户缓存, 剩余缓存数为【{}】,下次可回收时间为【{}】秒后",
evictedCount,
cache.size(),
(this.nextMinEvictableTime - now) / 1000);
}
}
public Future<JwtUserDto> get(String username) {
return nodeToDate(cache.get(username));
}
public void clear() {
cache.clear();
}
public void remove(String username) {
cache.remove(username);
}
private Future<JwtUserDto> nodeToDate(Node node) {
return node == null ? null : node.getData();
}
private static class Node {
private final Future<JwtUserDto> data;
private final long time;
public Node(Future<JwtUserDto> data) {
this.data = data;
this.time = System.currentTimeMillis();
}
public Future<JwtUserDto> getData() {
return data;
}
public long getTime() {
return time;
}
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.service;
import com.example.modules.security.config.bean.LoginProperties;
import com.example.modules.system.service.DataService;
import com.example.modules.system.service.RoleService;
import com.example.modules.system.service.UserService;
import com.example.modules.system.service.dto.UserDto;
import lombok.RequiredArgsConstructor;
import com.example.exception.BadRequestException;
import com.example.exception.EntityNotFoundException;
import com.example.modules.security.service.dto.JwtUserDto;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* 2018-11-22
*/
@RequiredArgsConstructor
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserService userService;
private final RoleService roleService;
private final DataService dataService;
private final LoginProperties loginProperties;
private final UserCacheManager USER_DTO_CACHE;
public void setEnableCache(boolean enableCache) {
this.loginProperties.setCacheEnable(enableCache);
}
public static ExecutorService executor = newThreadPool();
@Override
public JwtUserDto loadUserByUsername(String username) {
JwtUserDto jwtUserDto = null;
Future<JwtUserDto> future = USER_DTO_CACHE.get(username);
if (!loginProperties.isCacheEnable()) {
UserDto user;
try {
user = userService.findByName(username);
} catch (EntityNotFoundException e) {
// SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException
throw new UsernameNotFoundException(username, e);
}
if (user == null) {
throw new UsernameNotFoundException("");
} else {
if (!user.getEnabled()) {
throw new BadRequestException("账号未激活!");
}
jwtUserDto = new JwtUserDto(
user,
dataService.getDeptIds(user),
roleService.mapToGrantedAuthorities(user)
);
}
return jwtUserDto;
}
if (future == null) {
Callable<JwtUserDto> call = () -> getJwtBySearchDb(username);
FutureTask<JwtUserDto> ft = new FutureTask<>(call);
future = USER_DTO_CACHE.putIfAbsent(username, ft);
if (future == null) {
future = ft;
executor.submit(ft);
}
try {
return future.get();
} catch (CancellationException e) {
USER_DTO_CACHE.remove(username);
System.out.println("error" + Thread.currentThread().getName());
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
jwtUserDto = future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e.getMessage());
}
// 检查dataScope是否修改
List<Long> dataScopes = jwtUserDto.getDataScopes();
dataScopes.clear();
dataScopes.addAll(dataService.getDeptIds(jwtUserDto.getUser()));
}
return jwtUserDto;
}
private JwtUserDto getJwtBySearchDb(String username) {
UserDto user;
try {
user = userService.findByName(username);
} catch (EntityNotFoundException e) {
// SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException
throw new UsernameNotFoundException("", e);
}
if (user == null) {
throw new UsernameNotFoundException("");
} else {
if (!user.getEnabled()) {
throw new BadRequestException("账号未激活!");
}
return new JwtUserDto(
user,
dataService.getDeptIds(user),
roleService.mapToGrantedAuthorities(user)
);
}
}
public static ExecutorService newThreadPool() {
ThreadFactory namedThreadFactory = new ThreadFactory() {
final AtomicInteger sequence = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
int seq = this.sequence.getAndIncrement();
thread.setName("future-task-thread" + (seq > 1 ? "-" + seq : ""));
if (!thread.isDaemon()) {
thread.setDaemon(true);
}
return thread;
}
};
return new ThreadPoolExecutor(10, 200,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1024),
namedThreadFactory,
new ThreadPoolExecutor.AbortPolicy());
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.service.dto;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
*
* 2018-11-30
*/
@Getter
@Setter
public class AuthUserDto {
@NotBlank
private String username;
@NotBlank
private String password;
private String code;
private String uuid = "";
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.service.dto;
import com.alibaba.fastjson.annotation.JSONField;
import com.example.modules.system.service.dto.UserDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor
public class JwtUserDto implements UserDetails {
private final UserDto user;
private final List<Long> dataScopes;
@JSONField(serialize = false)
private final List<GrantedAuthority> authorities;
public Set<String> getRoles() {
return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
}
@Override
@JSONField(serialize = false)
public String getPassword() {
return user.getPassword();
}
@Override
@JSONField(serialize = false)
public String getUsername() {
return user.getUsername();
}
@JSONField(serialize = false)
@Override
public boolean isAccountNonExpired() {
return true;
}
@JSONField(serialize = false)
@Override
public boolean isAccountNonLocked() {
return true;
}
@JSONField(serialize = false)
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
@JSONField(serialize = false)
public boolean isEnabled() {
return user.getEnabled();
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.security.service.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* 在线用户
*
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OnlineUserDto {
/**
* 用户名
*/
private String userName;
/**
* 昵称
*/
private String nickName;
/**
* 岗位
*/
private String dept;
/**
* 浏览器
*/
private String browser;
/**
* IP
*/
private String ip;
/**
* 地址
*/
private String address;
/**
* token
*/
private String key;
/**
* 登录时间
*/
private Date loginTime;
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.controller;
import cn.hutool.core.collection.CollectionUtil;
import com.example.modules.system.domain.Dept;
import com.example.modules.system.service.DeptService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.example.annotation.Log;
import com.example.exception.BadRequestException;
import com.example.modules.system.service.dto.DeptDto;
import com.example.modules.system.service.dto.DeptQueryCriteria;
import com.example.utils.PageUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
*
* 2019-03-25
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "系统:部门管理")
@RequestMapping("/api/dept")
public class DeptController {
private final DeptService deptService;
private static final String ENTITY_NAME = "dept";
@ApiOperation("导出部门数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('dept:list')")
public void exportDept(HttpServletResponse response, DeptQueryCriteria criteria) throws Exception {
deptService.download(deptService.queryAll(criteria, false), response);
}
@ApiOperation("查询部门")
@GetMapping
@PreAuthorize("@el.check('user:list','dept:list')")
public ResponseEntity<Object> queryDept(DeptQueryCriteria criteria) throws Exception {
List<DeptDto> deptDtos = deptService.queryAll(criteria, true);
return new ResponseEntity<>(PageUtil.toPage(deptDtos, deptDtos.size()),HttpStatus.OK);
}
@ApiOperation("查询部门:根据ID获取同级与上级数据")
@PostMapping("/superior")
@PreAuthorize("@el.check('user:list','dept:list')")
public ResponseEntity<Object> getDeptSuperior(@RequestBody List<Long> ids) {
Set<DeptDto> deptDtos = new LinkedHashSet<>();
for (Long id : ids) {
DeptDto deptDto = deptService.findById(id);
List<DeptDto> depts = deptService.getSuperior(deptDto, new ArrayList<>());
deptDtos.addAll(depts);
}
return new ResponseEntity<>(deptService.buildTree(new ArrayList<>(deptDtos)),HttpStatus.OK);
}
@Log("新增部门")
@ApiOperation("新增部门")
@PostMapping
@PreAuthorize("@el.check('dept:add')")
public ResponseEntity<Object> createDept(@Validated @RequestBody Dept resources){
if (resources.getId() != null) {
throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
}
deptService.create(resources);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@Log("修改部门")
@ApiOperation("修改部门")
@PutMapping
@PreAuthorize("@el.check('dept:edit')")
public ResponseEntity<Object> updateDept(@Validated(Dept.Update.class) @RequestBody Dept resources){
deptService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@Log("删除部门")
@ApiOperation("删除部门")
@DeleteMapping
@PreAuthorize("@el.check('dept:del')")
public ResponseEntity<Object> deleteDept(@RequestBody Set<Long> ids){
Set<DeptDto> deptDtos = new HashSet<>();
for (Long id : ids) {
List<Dept> deptList = deptService.findByPid(id);
deptDtos.add(deptService.findById(id));
if(CollectionUtil.isNotEmpty(deptList)){
deptDtos = deptService.getDeleteDepts(deptList, deptDtos);
}
}
// 验证是否被角色或用户关联
deptService.verification(deptDtos);
deptService.delete(deptDtos);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.controller;
import com.example.modules.system.domain.Dict;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.example.annotation.Log;
import com.example.exception.BadRequestException;
import com.example.modules.system.service.DictService;
import com.example.modules.system.service.dto.DictQueryCriteria;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;
/**
*
* 2019-04-10
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "系统:字典管理")
@RequestMapping("/api/dict")
public class DictController {
private final DictService dictService;
private static final String ENTITY_NAME = "dict";
@ApiOperation("导出字典数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('dict:list')")
public void exportDict(HttpServletResponse response, DictQueryCriteria criteria) throws IOException {
dictService.download(dictService.queryAll(criteria), response);
}
@ApiOperation("查询字典")
@GetMapping(value = "/all")
@PreAuthorize("@el.check('dict:list')")
public ResponseEntity<Object> queryAllDict(){
return new ResponseEntity<>(dictService.queryAll(new DictQueryCriteria()),HttpStatus.OK);
}
@ApiOperation("查询字典")
@GetMapping
@PreAuthorize("@el.check('dict:list')")
public ResponseEntity<Object> queryDict(DictQueryCriteria resources, Pageable pageable){
return new ResponseEntity<>(dictService.queryAll(resources,pageable),HttpStatus.OK);
}
@Log("新增字典")
@ApiOperation("新增字典")
@PostMapping
@PreAuthorize("@el.check('dict:add')")
public ResponseEntity<Object> createDict(@Validated @RequestBody Dict resources){
if (resources.getId() != null) {
throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
}
dictService.create(resources);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@Log("修改字典")
@ApiOperation("修改字典")
@PutMapping
@PreAuthorize("@el.check('dict:edit')")
public ResponseEntity<Object> updateDict(@Validated(Dict.Update.class) @RequestBody Dict resources){
dictService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@Log("删除字典")
@ApiOperation("删除字典")
@DeleteMapping
@PreAuthorize("@el.check('dict:del')")
public ResponseEntity<Object> deleteDict(@RequestBody Set<Long> ids){
dictService.delete(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.controller;
import com.example.modules.system.domain.DictDetail;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.example.annotation.Log;
import com.example.exception.BadRequestException;
import com.example.modules.system.service.DictDetailService;
import com.example.modules.system.service.dto.DictDetailDto;
import com.example.modules.system.service.dto.DictDetailQueryCriteria;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* 2019-04-10
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "系统:字典详情管理")
@RequestMapping("/api/dictDetail")
public class DictDetailController {
private final DictDetailService dictDetailService;
private static final String ENTITY_NAME = "dictDetail";
@ApiOperation("查询字典详情")
@GetMapping
public ResponseEntity<Object> queryDictDetail(DictDetailQueryCriteria criteria,
@PageableDefault(sort = {"dictSort"}, direction = Sort.Direction.ASC) Pageable pageable){
return new ResponseEntity<>(dictDetailService.queryAll(criteria,pageable),HttpStatus.OK);
}
@ApiOperation("查询多个字典详情")
@GetMapping(value = "/map")
public ResponseEntity<Object> getDictDetailMaps(@RequestParam String dictName){
String[] names = dictName.split("[,]");
Map<String, List<DictDetailDto>> dictMap = new HashMap<>(16);
for (String name : names) {
dictMap.put(name, dictDetailService.getDictByName(name));
}
return new ResponseEntity<>(dictMap, HttpStatus.OK);
}
@Log("新增字典详情")
@ApiOperation("新增字典详情")
@PostMapping
@PreAuthorize("@el.check('dict:add')")
public ResponseEntity<Object> createDictDetail(@Validated @RequestBody DictDetail resources){
if (resources.getId() != null) {
throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
}
dictDetailService.create(resources);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@Log("修改字典详情")
@ApiOperation("修改字典详情")
@PutMapping
@PreAuthorize("@el.check('dict:edit')")
public ResponseEntity<Object> updateDictDetail(@Validated(DictDetail.Update.class) @RequestBody DictDetail resources){
dictDetailService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@Log("删除字典详情")
@ApiOperation("删除字典详情")
@DeleteMapping(value = "/{id}")
@PreAuthorize("@el.check('dict:del')")
public ResponseEntity<Object> deleteDictDetail(@PathVariable Long id){
dictDetailService.delete(id);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.controller;
import com.example.modules.system.domain.Job;
import com.example.modules.system.service.JobService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.example.annotation.Log;
import com.example.exception.BadRequestException;
import com.example.modules.system.service.dto.JobQueryCriteria;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;
/**
*
* 2019-03-29
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "系统:岗位管理")
@RequestMapping("/api/job")
public class JobController {
private final JobService jobService;
private static final String ENTITY_NAME = "job";
@ApiOperation("导出岗位数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('job:list')")
public void exportJob(HttpServletResponse response, JobQueryCriteria criteria) throws IOException {
jobService.download(jobService.queryAll(criteria), response);
}
@ApiOperation("查询岗位")
@GetMapping
@PreAuthorize("@el.check('job:list','user:list')")
public ResponseEntity<Object> queryJob(JobQueryCriteria criteria, Pageable pageable){
return new ResponseEntity<>(jobService.queryAll(criteria, pageable),HttpStatus.OK);
}
@Log("新增岗位")
@ApiOperation("新增岗位")
@PostMapping
@PreAuthorize("@el.check('job:add')")
public ResponseEntity<Object> createJob(@Validated @RequestBody Job resources){
if (resources.getId() != null) {
throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
}
jobService.create(resources);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@Log("修改岗位")
@ApiOperation("修改岗位")
@PutMapping
@PreAuthorize("@el.check('job:edit')")
public ResponseEntity<Object> updateJob(@Validated(Job.Update.class) @RequestBody Job resources){
jobService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@Log("删除岗位")
@ApiOperation("删除岗位")
@DeleteMapping
@PreAuthorize("@el.check('job:del')")
public ResponseEntity<Object> deleteJob(@RequestBody Set<Long> ids){
// 验证是否被用户关联
jobService.verification(ids);
jobService.delete(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import com.example.annotation.Limit;
import com.example.annotation.rest.AnonymousGetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author /
* 接口限流测试类
*/
@RestController
@RequestMapping("/api/limit")
@Api(tags = "系统:限流测试管理")
public class LimitController {
private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger();
/**
* 测试限流注解,下面配置说明该接口 60秒内最多只能访问 10次保存到redis的键名为 limit_test
*/
@AnonymousGetMapping
@ApiOperation("测试")
@Limit(key = "test", period = 60, count = 10, name = "testLimit", prefix = "limit")
public int testLimit() {
return ATOMIC_INTEGER.incrementAndGet();
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.controller;
import cn.hutool.core.collection.CollectionUtil;
import com.example.modules.system.domain.Menu;
import com.example.modules.system.service.MenuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.example.annotation.Log;
import com.example.exception.BadRequestException;
import com.example.modules.system.service.dto.MenuDto;
import com.example.modules.system.service.dto.MenuQueryCriteria;
import com.example.modules.system.service.mapstruct.MenuMapper;
import com.example.utils.PageUtil;
import com.example.utils.SecurityUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
/**
*
* 2018-12-03
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "系统:菜单管理")
@RequestMapping("/api/menus")
public class MenuController {
private final MenuService menuService;
private final MenuMapper menuMapper;
private static final String ENTITY_NAME = "menu";
@ApiOperation("导出菜单数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('menu:list')")
public void exportMenu(HttpServletResponse response, MenuQueryCriteria criteria) throws Exception {
menuService.download(menuService.queryAll(criteria, false), response);
}
@GetMapping(value = "/build")
@ApiOperation("获取前端所需菜单")
public ResponseEntity<Object> buildMenus(){
List<MenuDto> menuDtoList = menuService.findByUser(SecurityUtils.getCurrentUserId());
List<MenuDto> menuDtos = menuService.buildTree(menuDtoList);
return new ResponseEntity<>(menuService.buildMenus(menuDtos),HttpStatus.OK);
}
@ApiOperation("返回全部的菜单")
@GetMapping(value = "/lazy")
@PreAuthorize("@el.check('menu:list','roles:list')")
public ResponseEntity<Object> queryAllMenu(@RequestParam Long pid){
return new ResponseEntity<>(menuService.getMenus(pid),HttpStatus.OK);
}
@ApiOperation("根据菜单ID返回所有子节点ID包含自身ID")
@GetMapping(value = "/child")
@PreAuthorize("@el.check('menu:list','roles:list')")
public ResponseEntity<Object> childMenu(@RequestParam Long id){
Set<Menu> menuSet = new HashSet<>();
List<MenuDto> menuList = menuService.getMenus(id);
menuSet.add(menuService.findOne(id));
menuSet = menuService.getChildMenus(menuMapper.toEntity(menuList), menuSet);
Set<Long> ids = menuSet.stream().map(Menu::getId).collect(Collectors.toSet());
return new ResponseEntity<>(ids,HttpStatus.OK);
}
@GetMapping
@ApiOperation("查询菜单")
@PreAuthorize("@el.check('menu:list')")
public ResponseEntity<Object> queryMenu(MenuQueryCriteria criteria) throws Exception {
List<MenuDto> menuDtoList = menuService.queryAll(criteria, true);
return new ResponseEntity<>(PageUtil.toPage(menuDtoList, menuDtoList.size()),HttpStatus.OK);
}
@ApiOperation("查询菜单:根据ID获取同级与上级数据")
@PostMapping("/superior")
@PreAuthorize("@el.check('menu:list')")
public ResponseEntity<Object> getMenuSuperior(@RequestBody List<Long> ids) {
Set<MenuDto> menuDtos = new LinkedHashSet<>();
if(CollectionUtil.isNotEmpty(ids)){
for (Long id : ids) {
MenuDto menuDto = menuService.findById(id);
menuDtos.addAll(menuService.getSuperior(menuDto, new ArrayList<>()));
}
return new ResponseEntity<>(menuService.buildTree(new ArrayList<>(menuDtos)),HttpStatus.OK);
}
return new ResponseEntity<>(menuService.getMenus(null),HttpStatus.OK);
}
@Log("新增菜单")
@ApiOperation("新增菜单")
@PostMapping
@PreAuthorize("@el.check('menu:add')")
public ResponseEntity<Object> createMenu(@Validated @RequestBody Menu resources){
if (resources.getId() != null) {
throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
}
menuService.create(resources);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@Log("修改菜单")
@ApiOperation("修改菜单")
@PutMapping
@PreAuthorize("@el.check('menu:edit')")
public ResponseEntity<Object> updateMenu(@Validated(Menu.Update.class) @RequestBody Menu resources){
menuService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@Log("删除菜单")
@ApiOperation("删除菜单")
@DeleteMapping
@PreAuthorize("@el.check('menu:del')")
public ResponseEntity<Object> deleteMenu(@RequestBody Set<Long> ids){
Set<Menu> menuSet = new HashSet<>();
for (Long id : ids) {
List<MenuDto> menuList = menuService.getMenus(id);
menuSet.add(menuService.findOne(id));
menuSet = menuService.getChildMenus(menuMapper.toEntity(menuList), menuSet);
}
menuService.delete(menuSet);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.example.modules.system.service.MonitorService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
/**
*
* 2020-05-02
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "系统-服务监控管理")
@RequestMapping("/api/monitor")
public class MonitorController {
private final MonitorService serverService;
@GetMapping
@ApiOperation("查询服务监控")
@PreAuthorize("@el.check('monitor:list')")
public ResponseEntity<Object> queryMonitor(){
return new ResponseEntity<>(serverService.getServers(),HttpStatus.OK);
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.controller;
import cn.hutool.core.lang.Dict;
import com.example.modules.system.domain.Role;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.example.annotation.Log;
import com.example.exception.BadRequestException;
import com.example.modules.system.service.RoleService;
import com.example.modules.system.service.dto.RoleDto;
import com.example.modules.system.service.dto.RoleQueryCriteria;
import com.example.modules.system.service.dto.RoleSmallDto;
import com.example.utils.SecurityUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
*
* 2018-12-03
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "系统:角色管理")
@RequestMapping("/api/roles")
public class RoleController {
private final RoleService roleService;
private static final String ENTITY_NAME = "role";
@ApiOperation("获取单个role")
@GetMapping(value = "/{id}")
@PreAuthorize("@el.check('roles:list')")
public ResponseEntity<Object> findRoleById(@PathVariable Long id){
return new ResponseEntity<>(roleService.findById(id), HttpStatus.OK);
}
@ApiOperation("导出角色数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('role:list')")
public void exportRole(HttpServletResponse response, RoleQueryCriteria criteria) throws IOException {
roleService.download(roleService.queryAll(criteria), response);
}
@ApiOperation("返回全部的角色")
@GetMapping(value = "/all")
@PreAuthorize("@el.check('roles:list','user:add','user:edit')")
public ResponseEntity<Object> queryAllRole(){
return new ResponseEntity<>(roleService.queryAll(),HttpStatus.OK);
}
@ApiOperation("查询角色")
@GetMapping
@PreAuthorize("@el.check('roles:list')")
public ResponseEntity<Object> queryRole(RoleQueryCriteria criteria, Pageable pageable){
return new ResponseEntity<>(roleService.queryAll(criteria,pageable),HttpStatus.OK);
}
@ApiOperation("获取用户级别")
@GetMapping(value = "/level")
public ResponseEntity<Object> getRoleLevel(){
return new ResponseEntity<>(Dict.create().set("level", getLevels(null)),HttpStatus.OK);
}
@Log("新增角色")
@ApiOperation("新增角色")
@PostMapping
@PreAuthorize("@el.check('roles:add')")
public ResponseEntity<Object> createRole(@Validated @RequestBody Role resources){
if (resources.getId() != null) {
throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
}
getLevels(resources.getLevel());
roleService.create(resources);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@Log("修改角色")
@ApiOperation("修改角色")
@PutMapping
@PreAuthorize("@el.check('roles:edit')")
public ResponseEntity<Object> updateRole(@Validated(Role.Update.class) @RequestBody Role resources){
getLevels(resources.getLevel());
roleService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@Log("修改角色菜单")
@ApiOperation("修改角色菜单")
@PutMapping(value = "/menu")
@PreAuthorize("@el.check('roles:edit')")
public ResponseEntity<Object> updateRoleMenu(@RequestBody Role resources){
RoleDto role = roleService.findById(resources.getId());
getLevels(role.getLevel());
roleService.updateMenu(resources,role);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@Log("删除角色")
@ApiOperation("删除角色")
@DeleteMapping
@PreAuthorize("@el.check('roles:del')")
public ResponseEntity<Object> deleteRole(@RequestBody Set<Long> ids){
for (Long id : ids) {
RoleDto role = roleService.findById(id);
getLevels(role.getLevel());
}
// 验证是否被用户关联
roleService.verification(ids);
roleService.delete(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
/**
* 获取用户的角色级别
* @return /
*/
private int getLevels(Integer level){
List<Integer> levels = roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList());
int min = Collections.min(levels);
if(level != null){
if(level < min){
throw new BadRequestException("权限不足,你的角色级别:" + min + ",低于操作的角色级别:" + level);
}
}
return min;
}
}

View File

@@ -0,0 +1,196 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.controller;
import cn.hutool.core.collection.CollectionUtil;
import com.example.modules.system.domain.Dept;
import com.example.modules.system.domain.vo.UserPassVo;
import com.example.modules.system.service.DataService;
import com.example.modules.system.service.DeptService;
import com.example.modules.system.service.UserService;
import com.example.utils.PageUtil;
import com.example.utils.RsaUtils;
import com.example.utils.SecurityUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.example.annotation.Log;
import com.example.config.RsaProperties;
import com.example.modules.system.domain.User;
import com.example.exception.BadRequestException;
import com.example.modules.system.service.RoleService;
import com.example.modules.system.service.dto.RoleSmallDto;
import com.example.modules.system.service.dto.UserDto;
import com.example.modules.system.service.dto.UserQueryCriteria;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
@Api(tags = "系统:用户管理")
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final PasswordEncoder passwordEncoder;
private final UserService userService;
private final DataService dataService;
private final DeptService deptService;
private final RoleService roleService;
@ApiOperation("导出用户数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('user:list')")
public void exportUser(HttpServletResponse response, UserQueryCriteria criteria) throws IOException {
userService.download(userService.queryAll(criteria), response);
}
@ApiOperation("查询用户")
@GetMapping
@PreAuthorize("@el.check('user:list')")
public ResponseEntity<Object> queryUser(UserQueryCriteria criteria, Pageable pageable){
if (!ObjectUtils.isEmpty(criteria.getDeptId())) {
criteria.getDeptIds().add(criteria.getDeptId());
// 先查找是否存在子节点
List<Dept> data = deptService.findByPid(criteria.getDeptId());
// 然后把子节点的ID都加入到集合中
criteria.getDeptIds().addAll(deptService.getDeptChildren(data));
}
// 数据权限
List<Long> dataScopes = dataService.getDeptIds(userService.findByName(SecurityUtils.getCurrentUsername()));
// criteria.getDeptIds() 不为空并且数据权限不为空则取交集
if (!CollectionUtils.isEmpty(criteria.getDeptIds()) && !CollectionUtils.isEmpty(dataScopes)){
// 取交集
criteria.getDeptIds().retainAll(dataScopes);
if(!CollectionUtil.isEmpty(criteria.getDeptIds())){
return new ResponseEntity<>(userService.queryAll(criteria,pageable),HttpStatus.OK);
}
} else {
// 否则取并集
criteria.getDeptIds().addAll(dataScopes);
return new ResponseEntity<>(userService.queryAll(criteria,pageable),HttpStatus.OK);
}
return new ResponseEntity<>(PageUtil.toPage(null,0),HttpStatus.OK);
}
@Log("新增用户")
@ApiOperation("新增用户")
@PostMapping
@PreAuthorize("@el.check('user:add')")
public ResponseEntity<Object> createUser(@Validated @RequestBody User resources){
// checkLevel(resources);
// 默认密码 123456
resources.setPassword(passwordEncoder.encode("123456"));
userService.create(resources);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@Log("修改用户")
@ApiOperation("修改用户")
@PutMapping
@PreAuthorize("@el.check('user:edit')")
public ResponseEntity<Object> updateUser(@Validated(User.Update.class) @RequestBody User resources) throws Exception {
checkLevel(resources);
userService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@Log("修改用户:个人中心")
@ApiOperation("修改用户:个人中心")
@PutMapping(value = "center")
public ResponseEntity<Object> centerUser(@Validated(User.Update.class) @RequestBody User resources){
if(!resources.getId().equals(SecurityUtils.getCurrentUserId())){
throw new BadRequestException("不能修改他人资料");
}
userService.updateCenter(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@Log("删除用户")
@ApiOperation("删除用户")
@DeleteMapping
@PreAuthorize("@el.check('user:del')")
public ResponseEntity<Object> deleteUser(@RequestBody Set<Long> ids){
for (Long id : ids) {
Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
Integer optLevel = Collections.min(roleService.findByUsersId(id).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
if (currentLevel > optLevel) {
throw new BadRequestException("角色权限不足,不能删除:" + userService.findById(id).getUsername());
}
}
userService.delete(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
@ApiOperation("修改密码")
@PostMapping(value = "/updatePass")
public ResponseEntity<Object> updateUserPass(@RequestBody UserPassVo passVo) throws Exception {
String oldPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getOldPass());
String newPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getNewPass());
UserDto user = userService.findByName(SecurityUtils.getCurrentUsername());
if(!passwordEncoder.matches(oldPass, user.getPassword())){
throw new BadRequestException("修改失败,旧密码错误");
}
if(passwordEncoder.matches(newPass, user.getPassword())){
throw new BadRequestException("新密码不能与旧密码相同");
}
userService.updatePass(user.getUsername(),passwordEncoder.encode(newPass));
return new ResponseEntity<>(HttpStatus.OK);
}
@ApiOperation("修改头像")
@PostMapping(value = "/updateAvatar")
public ResponseEntity<Object> updateUserAvatar(@RequestParam MultipartFile avatar){
return new ResponseEntity<>(userService.updateAvatar(avatar), HttpStatus.OK);
}
@Log("修改邮箱")
@ApiOperation("修改邮箱")
@PostMapping(value = "/updateEmail/{code}")
public ResponseEntity<Object> updateUserEmail(@PathVariable String code,@RequestBody User user) throws Exception {
String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,user.getPassword());
UserDto userDto = userService.findByName(SecurityUtils.getCurrentUsername());
if(!passwordEncoder.matches(password, userDto.getPassword())){
throw new BadRequestException("密码错误");
}
userService.updateEmail(userDto.getUsername(),user.getEmail());
return new ResponseEntity<>(HttpStatus.OK);
}
/**
* 如果当前用户的角色级别低于创建用户的角色级别,则抛出权限不足的错误
* @param resources /
*/
private void checkLevel(User resources) {
Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
Integer optLevel = roleService.findByRoles(resources.getRoles());
if (currentLevel > optLevel) {
throw new BadRequestException("角色权限不足");
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.domain;
import com.alibaba.fastjson.annotation.JSONField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import com.example.base.BaseEntity;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Objects;
import java.util.Set;
/**
*
* 2019-03-25
*/
@Entity
@Getter
@Setter
@Table(name="sys_dept")
public class Dept extends BaseEntity implements Serializable {
@Id
@Column(name = "dept_id")
@NotNull(groups = Update.class)
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@JSONField(serialize = false)
@ManyToMany(mappedBy = "depts")
@ApiModelProperty(value = "角色")
private Set<Role> roles;
@ApiModelProperty(value = "排序")
private Integer deptSort;
@NotBlank
@ApiModelProperty(value = "部门名称")
private String name;
@NotNull
@ApiModelProperty(value = "是否启用")
private Boolean enabled;
@ApiModelProperty(value = "上级部门")
private Long pid;
@ApiModelProperty(value = "子节点数目", hidden = true)
private Integer subCount = 0;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Dept dept = (Dept) o;
return Objects.equals(id, dept.id) &&
Objects.equals(name, dept.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import com.example.base.BaseEntity;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;
/**
*
* 2019-04-10
*/
@Entity
@Getter
@Setter
@Table(name="sys_dict")
public class Dict extends BaseEntity implements Serializable {
@Id
@Column(name = "dict_id")
@NotNull(groups = Update.class)
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "dict",cascade={CascadeType.PERSIST,CascadeType.REMOVE})
private List<DictDetail> dictDetails;
@NotBlank
@ApiModelProperty(value = "名称")
private String name;
@ApiModelProperty(value = "描述")
private String description;
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import com.example.base.BaseEntity;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
*
* 2019-04-10
*/
@Entity
@Getter
@Setter
@Table(name="sys_dict_detail")
public class DictDetail extends BaseEntity implements Serializable {
@Id
@Column(name = "detail_id")
@NotNull(groups = Update.class)
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@JoinColumn(name = "dict_id")
@ManyToOne(fetch=FetchType.LAZY)
@ApiModelProperty(value = "字典", hidden = true)
private Dict dict;
@ApiModelProperty(value = "字典标签")
private String label;
@ApiModelProperty(value = "字典值")
private String value;
@ApiModelProperty(value = "排序")
private Integer dictSort = 999;
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import com.example.base.BaseEntity;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Objects;
/**
*
* 2019-03-29
*/
@Entity
@Getter
@Setter
@Table(name="sys_job")
public class Job extends BaseEntity implements Serializable {
@Id
@Column(name = "job_id")
@NotNull(groups = Update.class)
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@ApiModelProperty(value = "岗位名称")
private String name;
@NotNull
@ApiModelProperty(value = "岗位排序")
private Long jobSort;
@NotNull
@ApiModelProperty(value = "是否启用")
private Boolean enabled;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Job job = (Job) o;
return Objects.equals(id, job.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.domain;
import com.alibaba.fastjson.annotation.JSONField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import com.example.base.BaseEntity;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Objects;
import java.util.Set;
/**
*
* 2018-12-17
*/
@Entity
@Getter
@Setter
@Table(name = "sys_menu")
public class Menu extends BaseEntity implements Serializable {
@Id
@Column(name = "menu_id")
@NotNull(groups = {Update.class})
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@JSONField(serialize = false)
@ManyToMany(mappedBy = "menus")
@ApiModelProperty(value = "菜单角色")
private Set<Role> roles;
@ApiModelProperty(value = "菜单标题")
private String title;
@Column(name = "name")
@ApiModelProperty(value = "菜单组件名称")
private String componentName;
@ApiModelProperty(value = "排序")
private Integer menuSort = 999;
@ApiModelProperty(value = "组件路径")
private String component;
@ApiModelProperty(value = "路由地址")
private String path;
@ApiModelProperty(value = "菜单类型,目录、菜单、按钮")
private Integer type;
@ApiModelProperty(value = "权限标识")
private String permission;
@ApiModelProperty(value = "菜单图标")
private String icon;
@Column(columnDefinition = "bit(1) default 0")
@ApiModelProperty(value = "缓存")
private Boolean cache;
@Column(columnDefinition = "bit(1) default 0")
@ApiModelProperty(value = "是否隐藏")
private Boolean hidden;
@ApiModelProperty(value = "上级菜单")
private Long pid;
@ApiModelProperty(value = "子节点数目", hidden = true)
private Integer subCount = 0;
@ApiModelProperty(value = "外链菜单")
private Boolean iFrame;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Menu menu = (Menu) o;
return Objects.equals(id, menu.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.domain;
import com.alibaba.fastjson.annotation.JSONField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import com.example.base.BaseEntity;
import com.example.utils.enums.DataScopeEnum;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Objects;
import java.util.Set;
/**
* 角色
*
* 2018-11-22
*/
@Getter
@Setter
@Entity
@Table(name = "sys_role")
public class Role extends BaseEntity implements Serializable {
@Id
@Column(name = "role_id")
@NotNull(groups = {Update.class})
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ApiModelProperty(value = "ID", hidden = true)
private Long id;
@JSONField(serialize = false)
@ManyToMany(mappedBy = "roles")
@ApiModelProperty(value = "用户", hidden = true)
private Set<User> users;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "sys_roles_menus",
joinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")},
inverseJoinColumns = {@JoinColumn(name = "menu_id",referencedColumnName = "menu_id")})
@ApiModelProperty(value = "菜单", hidden = true)
private Set<Menu> menus;
@ManyToMany
@JoinTable(name = "sys_roles_depts",
joinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")},
inverseJoinColumns = {@JoinColumn(name = "dept_id",referencedColumnName = "dept_id")})
@ApiModelProperty(value = "部门", hidden = true)
private Set<Dept> depts;
@NotBlank
@ApiModelProperty(value = "名称", hidden = true)
private String name;
@ApiModelProperty(value = "数据权限,全部 、 本级 、 自定义")
private String dataScope = DataScopeEnum.THIS_LEVEL.getValue();
@Column(name = "level")
@ApiModelProperty(value = "级别,数值越小,级别越大")
private Integer level = 3;
@ApiModelProperty(value = "描述")
private String description;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Role role = (Role) o;
return Objects.equals(id, role.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import com.example.base.BaseEntity;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
import java.util.Set;
/**
*
* 2018-11-22
*/
@Entity
@Getter
@Setter
@Table(name="sys_user")
public class User extends BaseEntity implements Serializable {
@Id
@Column(name = "user_id")
@NotNull(groups = Update.class)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ApiModelProperty(value = "ID", hidden = true)
private Long id;
@ManyToMany(fetch = FetchType.EAGER)
@ApiModelProperty(value = "用户角色")
@JoinTable(name = "sys_users_roles",
joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")},
inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")})
private Set<Role> roles;
@ManyToMany(fetch = FetchType.EAGER)
@ApiModelProperty(value = "用户岗位")
@JoinTable(name = "sys_users_jobs",
joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")},
inverseJoinColumns = {@JoinColumn(name = "job_id",referencedColumnName = "job_id")})
private Set<Job> jobs;
@OneToOne
@JoinColumn(name = "dept_id")
@ApiModelProperty(value = "用户部门")
private Dept dept;
@NotBlank
@Column(unique = true)
@ApiModelProperty(value = "用户名称")
private String username;
@NotBlank
@ApiModelProperty(value = "用户昵称")
private String nickName;
@Email
@NotBlank
@ApiModelProperty(value = "邮箱")
private String email;
@NotBlank
@ApiModelProperty(value = "电话号码")
private String phone;
@ApiModelProperty(value = "用户性别")
private String gender;
@ApiModelProperty(value = "头像真实名称",hidden = true)
private String avatarName;
@ApiModelProperty(value = "头像存储的路径", hidden = true)
private String avatarPath;
@ApiModelProperty(value = "密码")
private String password;
@NotNull
@ApiModelProperty(value = "是否启用")
private Boolean enabled;
@ApiModelProperty(value = "是否为admin账号", hidden = true)
private Boolean isAdmin = false;
@Column(name = "pwd_reset_time")
@ApiModelProperty(value = "最后修改密码的时间", hidden = true)
private Date pwdResetTime;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User user = (User) o;
return Objects.equals(id, user.id) &&
Objects.equals(username, user.username);
}
@Override
public int hashCode() {
return Objects.hash(id, username);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.domain.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;
/**
*
* 2018-12-20
*/
@Data
@AllArgsConstructor
public class MenuMetaVo implements Serializable {
private String title;
private String icon;
private Boolean noCache;
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.domain.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 构建前端路由时用到
*
* 2018-12-20
*/
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class MenuVo implements Serializable {
private String name;
private String path;
private Boolean hidden;
private String redirect;
private String component;
private Boolean alwaysShow;
private MenuMetaVo meta;
private List<MenuVo> children;
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.domain.vo;
import lombok.Data;
/**
* 修改密码的 Vo 类
*
* 2019年7月11日13:59:49
*/
@Data
public class UserPassVo {
private String oldPass;
private String newPass;
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.repository;
import com.example.modules.system.domain.Dept;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
import java.util.Set;
/**
*
* 2019-03-25
*/
public interface DeptRepository extends JpaRepository<Dept, Long>, JpaSpecificationExecutor<Dept> {
/**
* 根据 PID 查询
* @param id pid
* @return /
*/
List<Dept> findByPid(Long id);
/**
* 获取顶级部门
* @return /
*/
List<Dept> findByPidIsNull();
/**
* 根据角色ID 查询
* @param roleId 角色ID
* @return /
*/
@Query(value = "select d.* from sys_dept d, sys_roles_depts r where " +
"d.dept_id = r.dept_id and r.role_id = ?1", nativeQuery = true)
Set<Dept> findByRoleId(Long roleId);
/**
* 判断是否存在子节点
* @param pid /
* @return /
*/
int countByPid(Long pid);
/**
* 根据ID更新sub_count
* @param count /
* @param id /
*/
@Modifying
@Query(value = " update sys_dept set sub_count = ?1 where dept_id = ?2 ",nativeQuery = true)
void updateSubCntById(Integer count, Long id);
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.repository;
import com.example.modules.system.domain.DictDetail;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
/**
*
* 2019-04-10
*/
public interface DictDetailRepository extends JpaRepository<DictDetail, Long>, JpaSpecificationExecutor<DictDetail> {
/**
* 根据字典名称查询
* @param name /
* @return /
*/
List<DictDetail> findByDictName(String name);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.repository;
import com.example.modules.system.domain.Dict;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
import java.util.Set;
/**
*
* 2019-04-10
*/
public interface DictRepository extends JpaRepository<Dict, Long>, JpaSpecificationExecutor<Dict> {
/**
* 删除
* @param ids /
*/
void deleteByIdIn(Set<Long> ids);
/**
* 查询
* @param ids /
* @return /
*/
List<Dict> findByIdIn(Set<Long> ids);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.repository;
import com.example.modules.system.domain.Job;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.Set;
/**
*
* 2019-03-29
*/
public interface JobRepository extends JpaRepository<Job, Long>, JpaSpecificationExecutor<Job> {
/**
* 根据名称查询
* @param name 名称
* @return /
*/
Job findByName(String name);
/**
* 根据Id删除
* @param ids /
*/
void deleteAllByIdIn(Set<Long> ids);
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.repository;
import com.example.modules.system.domain.Menu;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
*
* 2018-12-17
*/
public interface MenuRepository extends JpaRepository<Menu, Long>, JpaSpecificationExecutor<Menu> {
/**
* 根据菜单标题查询
* @param title 菜单标题
* @return /
*/
Menu findByTitle(String title);
/**
* 根据组件名称查询
* @param name 组件名称
* @return /
*/
Menu findByComponentName(String name);
/**
* 根据菜单的 PID 查询
* @param pid /
* @return /
*/
List<Menu> findByPid(long pid);
/**
* 查询顶级菜单
* @return /
*/
List<Menu> findByPidIsNull();
/**
* 根据角色ID与菜单类型查询菜单
* @param roleIds roleIDs
* @param type 类型
* @return /
*/
@Query(value = "SELECT m.* FROM sys_menu m, sys_roles_menus r WHERE " +
"m.menu_id = r.menu_id AND r.role_id IN ?1 AND type != ?2 order by m.menu_sort asc",nativeQuery = true)
LinkedHashSet<Menu> findByRoleIdsAndTypeNot(Set<Long> roleIds, int type);
/**
* 获取节点数量
* @param id /
* @return /
*/
int countByPid(Long id);
/**
* 更新节点数目
* @param count /
* @param menuId /
*/
@Modifying
@Query(value = " update sys_menu set sub_count = ?1 where menu_id = ?2 ",nativeQuery = true)
void updateSubCntById(int count, Long menuId);
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.repository;
import com.example.modules.system.domain.Role;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
import java.util.Set;
/**
*
* 2018-12-03
*/
public interface RoleRepository extends JpaRepository<Role, Long>, JpaSpecificationExecutor<Role> {
/**
* 根据名称查询
* @param name /
* @return /
*/
Role findByName(String name);
/**
* 删除多个角色
* @param ids /
*/
void deleteAllByIdIn(Set<Long> ids);
/**
* 根据用户ID查询
* @param id 用户ID
* @return /
*/
@Query(value = "SELECT r.* FROM sys_role r, sys_users_roles u WHERE " +
"r.role_id = u.role_id AND u.user_id = ?1",nativeQuery = true)
Set<Role> findByUserId(Long id);
/**
* 解绑角色菜单
* @param id 菜单ID
*/
@Modifying
@Query(value = "delete from sys_roles_menus where menu_id = ?1",nativeQuery = true)
void untiedMenu(Long id);
/**
* 根据部门查询
* @param deptIds /
* @return /
*/
@Query(value = "select count(1) from sys_role r, sys_roles_depts d where " +
"r.role_id = d.role_id and d.dept_id in ?1",nativeQuery = true)
int countByDepts(Set<Long> deptIds);
/**
* 根据菜单Id查询
* @param menuIds /
* @return /
*/
@Query(value = "SELECT r.* FROM sys_role r, sys_roles_menus m WHERE " +
"r.role_id = m.role_id AND m.menu_id in ?1",nativeQuery = true)
List<Role> findInMenuId(List<Long> menuIds);
}

View File

@@ -0,0 +1,130 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.repository;
import com.example.modules.system.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
*
* 2018-11-22
*/
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
/**
* 根据用户名查询
* @param username 用户名
* @return /
*/
User findByUsername(String username);
/**
* 根据邮箱查询
* @param email 邮箱
* @return /
*/
User findByEmail(String email);
/**
* 根据手机号查询
* @param phone 手机号
* @return /
*/
User findByPhone(String phone);
/**
* 修改密码
* @param username 用户名
* @param pass 密码
* @param lastPasswordResetTime /
*/
@Modifying
@Query(value = "update sys_user set password = ?2 , pwd_reset_time = ?3 where username = ?1",nativeQuery = true)
void updatePass(String username, String pass, Date lastPasswordResetTime);
/**
* 修改邮箱
* @param username 用户名
* @param email 邮箱
*/
@Modifying
@Query(value = "update sys_user set email = ?2 where username = ?1",nativeQuery = true)
void updateEmail(String username, String email);
/**
* 根据角色查询用户
* @param roleId /
* @return /
*/
@Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r WHERE" +
" u.user_id = r.user_id AND r.role_id = ?1", nativeQuery = true)
List<User> findByRoleId(Long roleId);
/**
* 根据角色中的部门查询
* @param deptId /
* @return /
*/
@Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r, sys_roles_depts d WHERE " +
"u.user_id = r.user_id AND r.role_id = d.role_id AND d.dept_id = ?1 group by u.user_id", nativeQuery = true)
List<User> findByRoleDeptId(Long deptId);
/**
* 根据菜单查询
* @param id 菜单ID
* @return /
*/
@Query(value = "SELECT u.* FROM sys_user u, sys_users_roles ur, sys_roles_menus rm WHERE\n" +
"u.user_id = ur.user_id AND ur.role_id = rm.role_id AND rm.menu_id = ?1 group by u.user_id", nativeQuery = true)
List<User> findByMenuId(Long id);
/**
* 根据Id删除
* @param ids /
*/
void deleteAllByIdIn(Set<Long> ids);
/**
* 根据岗位查询
* @param ids /
* @return /
*/
@Query(value = "SELECT count(1) FROM sys_user u, sys_users_jobs j WHERE u.user_id = j.user_id AND j.job_id IN ?1", nativeQuery = true)
int countByJobs(Set<Long> ids);
/**
* 根据部门查询
* @param deptIds /
* @return /
*/
@Query(value = "SELECT count(1) FROM sys_user u WHERE u.dept_id IN ?1", nativeQuery = true)
int countByDepts(Set<Long> deptIds);
/**
* 根据角色查询
* @param ids /
* @return /
*/
@Query(value = "SELECT count(1) FROM sys_user u, sys_users_roles r WHERE " +
"u.user_id = r.user_id AND r.role_id in ?1", nativeQuery = true)
int countByRoles(Set<Long> ids);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service;
import com.example.modules.system.service.dto.UserDto;
import java.util.List;
/**
* 数据权限服务类
*
* 2020-05-07
*/
public interface DataService {
/**
* 获取数据权限
* @param user /
* @return /
*/
List<Long> getDeptIds(UserDto user);
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service;
import com.example.modules.system.domain.Dept;
import com.example.modules.system.service.dto.DeptDto;
import com.example.modules.system.service.dto.DeptQueryCriteria;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;
/**
*
* 2019-03-25
*/
public interface DeptService {
/**
* 查询所有数据
* @param criteria 条件
* @param isQuery /
* @throws Exception /
* @return /
*/
List<DeptDto> queryAll(DeptQueryCriteria criteria, Boolean isQuery) throws Exception;
/**
* 根据ID查询
* @param id /
* @return /
*/
DeptDto findById(Long id);
/**
* 创建
* @param resources /
*/
void create(Dept resources);
/**
* 编辑
* @param resources /
*/
void update(Dept resources);
/**
* 删除
* @param deptDtos /
*
*/
void delete(Set<DeptDto> deptDtos);
/**
* 根据PID查询
* @param pid /
* @return /
*/
List<Dept> findByPid(long pid);
/**
* 根据角色ID查询
* @param id /
* @return /
*/
Set<Dept> findByRoleId(Long id);
/**
* 导出数据
* @param queryAll 待导出的数据
* @param response /
* @throws IOException /
*/
void download(List<DeptDto> queryAll, HttpServletResponse response) throws IOException;
/**
* 获取待删除的部门
* @param deptList /
* @param deptDtos /
* @return /
*/
Set<DeptDto> getDeleteDepts(List<Dept> deptList, Set<DeptDto> deptDtos);
/**
* 根据ID获取同级与上级数据
* @param deptDto /
* @param depts /
* @return /
*/
List<DeptDto> getSuperior(DeptDto deptDto, List<Dept> depts);
/**
* 构建树形数据
* @param deptDtos /
* @return /
*/
Object buildTree(List<DeptDto> deptDtos);
/**
* 获取
* @param deptList
* @return
*/
List<Long> getDeptChildren(List<Dept> deptList);
/**
* 验证是否被角色或用户关联
* @param deptDtos /
*/
void verification(Set<DeptDto> deptDtos);
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service;
import com.example.modules.system.domain.DictDetail;
import com.example.modules.system.service.dto.DictDetailDto;
import com.example.modules.system.service.dto.DictDetailQueryCriteria;
import org.springframework.data.domain.Pageable;
import java.util.List;
import java.util.Map;
/**
*
* 2019-04-10
*/
public interface DictDetailService {
/**
* 创建
* @param resources /
*/
void create(DictDetail resources);
/**
* 编辑
* @param resources /
*/
void update(DictDetail resources);
/**
* 删除
* @param id /
*/
void delete(Long id);
/**
* 分页查询
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Map<String,Object> queryAll(DictDetailQueryCriteria criteria, Pageable pageable);
/**
* 根据字典名称获取字典详情
* @param name 字典名称
* @return /
*/
List<DictDetailDto> getDictByName(String name);
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service;
import com.example.modules.system.domain.Dict;
import com.example.modules.system.service.dto.DictDto;
import com.example.modules.system.service.dto.DictQueryCriteria;
import org.springframework.data.domain.Pageable;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* 2019-04-10
*/
public interface DictService {
/**
* 分页查询
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Map<String,Object> queryAll(DictQueryCriteria criteria, Pageable pageable);
/**
* 查询全部数据
* @param dict /
* @return /
*/
List<DictDto> queryAll(DictQueryCriteria dict);
/**
* 创建
* @param resources /
* @return /
*/
void create(Dict resources);
/**
* 编辑
* @param resources /
*/
void update(Dict resources);
/**
* 删除
* @param ids /
*/
void delete(Set<Long> ids);
/**
* 导出数据
* @param queryAll 待导出的数据
* @param response /
* @throws IOException /
*/
void download(List<DictDto> queryAll, HttpServletResponse response) throws IOException;
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service;
import com.example.modules.system.domain.Job;
import com.example.modules.system.service.dto.JobDto;
import com.example.modules.system.service.dto.JobQueryCriteria;
import org.springframework.data.domain.Pageable;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* 2019-03-29
*/
public interface JobService {
/**
* 根据ID查询
* @param id /
* @return /
*/
JobDto findById(Long id);
/**
* 创建
* @param resources /
* @return /
*/
void create(Job resources);
/**
* 编辑
* @param resources /
*/
void update(Job resources);
/**
* 删除
* @param ids /
*/
void delete(Set<Long> ids);
/**
* 分页查询
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Map<String,Object> queryAll(JobQueryCriteria criteria, Pageable pageable);
/**
* 查询全部数据
* @param criteria /
* @return /
*/
List<JobDto> queryAll(JobQueryCriteria criteria);
/**
* 导出数据
* @param queryAll 待导出的数据
* @param response /
* @throws IOException /
*/
void download(List<JobDto> queryAll, HttpServletResponse response) throws IOException;
/**
* 验证是否被用户关联
* @param ids /
*/
void verification(Set<Long> ids);
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service;
import com.example.modules.system.domain.Menu;
import com.example.modules.system.service.dto.MenuDto;
import com.example.modules.system.service.dto.MenuQueryCriteria;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;
/**
*
* 2018-12-17
*/
public interface MenuService {
/**
* 查询全部数据
* @param criteria 条件
* @param isQuery /
* @throws Exception /
* @return /
*/
List<MenuDto> queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception;
/**
* 根据ID查询
* @param id /
* @return /
*/
MenuDto findById(long id);
/**
* 创建
* @param resources /
*/
void create(Menu resources);
/**
* 编辑
* @param resources /
*/
void update(Menu resources);
/**
* 获取所有子节点包含自身ID
* @param menuList /
* @param menuSet /
* @return /
*/
Set<Menu> getChildMenus(List<Menu> menuList, Set<Menu> menuSet);
/**
* 构建菜单树
* @param menuDtos 原始数据
* @return /
*/
List<MenuDto> buildTree(List<MenuDto> menuDtos);
/**
* 构建菜单树
* @param menuDtos /
* @return /
*/
Object buildMenus(List<MenuDto> menuDtos);
/**
* 根据ID查询
* @param id /
* @return /
*/
Menu findOne(Long id);
/**
* 删除
* @param menuSet /
*/
void delete(Set<Menu> menuSet);
/**
* 导出
* @param queryAll 待导出的数据
* @param response /
* @throws IOException /
*/
void download(List<MenuDto> queryAll, HttpServletResponse response) throws IOException;
/**
* 懒加载菜单数据
* @param pid /
* @return /
*/
List<MenuDto> getMenus(Long pid);
/**
* 根据ID获取同级与上级数据
* @param menuDto /
* @param objects /
* @return /
*/
List<MenuDto> getSuperior(MenuDto menuDto, List<Menu> objects);
/**
* 根据当前用户获取菜单
* @param currentUserId /
* @return /
*/
List<MenuDto> findByUser(Long currentUserId);
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service;
import java.util.Map;
/**
*
* 2020-05-02
*/
public interface MonitorService {
/**
* 查询数据分页
* @return Map<String,Object>
*/
Map<String,Object> getServers();
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service;
import com.example.modules.system.domain.Role;
import com.example.modules.system.service.dto.RoleDto;
import com.example.modules.system.service.dto.RoleQueryCriteria;
import com.example.modules.system.service.dto.RoleSmallDto;
import com.example.modules.system.service.dto.UserDto;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.GrantedAuthority;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;
/**
*
* 2018-12-03
*/
public interface RoleService {
/**
* 查询全部数据
* @return /
*/
List<RoleDto> queryAll();
/**
* 根据ID查询
* @param id /
* @return /
*/
RoleDto findById(long id);
/**
* 创建
* @param resources /
*/
void create(Role resources);
/**
* 编辑
* @param resources /
*/
void update(Role resources);
/**
* 删除
* @param ids /
*/
void delete(Set<Long> ids);
/**
* 根据用户ID查询
* @param id 用户ID
* @return /
*/
List<RoleSmallDto> findByUsersId(Long id);
/**
* 根据角色查询角色级别
* @param roles /
* @return /
*/
Integer findByRoles(Set<Role> roles);
/**
* 修改绑定的菜单
* @param resources /
* @param roleDTO /
*/
void updateMenu(Role resources, RoleDto roleDTO);
/**
* 解绑菜单
* @param id /
*/
void untiedMenu(Long id);
/**
* 待条件分页查询
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Object queryAll(RoleQueryCriteria criteria, Pageable pageable);
/**
* 查询全部
* @param criteria 条件
* @return /
*/
List<RoleDto> queryAll(RoleQueryCriteria criteria);
/**
* 导出数据
* @param queryAll 待导出的数据
* @param response /
* @throws IOException /
*/
void download(List<RoleDto> queryAll, HttpServletResponse response) throws IOException;
/**
* 获取用户权限信息
* @param user 用户信息
* @return 权限信息
*/
List<GrantedAuthority> mapToGrantedAuthorities(UserDto user);
/**
* 验证是否被用户关联
* @param ids /
*/
void verification(Set<Long> ids);
/**
* 根据菜单Id查询
* @param menuIds /
* @return /
*/
List<Role> findInMenuId(List<Long> menuIds);
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service;
import com.example.modules.system.domain.User;
import com.example.modules.system.service.dto.UserDto;
import com.example.modules.system.service.dto.UserQueryCriteria;
import org.springframework.data.domain.Pageable;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface UserService {
/**
* 根据ID查询
* @param id ID
* @return /
*/
UserDto findById(long id);
/**
* 新增用户
* @param resources /
*/
void create(User resources);
/**
* 编辑用户
* @param resources /
* @throws Exception /
*/
void update(User resources) throws Exception;
/**
* 删除用户
* @param ids /
*/
void delete(Set<Long> ids);
/**
* 根据用户名查询
* @param userName /
* @return /
*/
UserDto findByName(String userName);
/**
* 修改密码
* @param username 用户名
* @param encryptPassword 密码
*/
void updatePass(String username, String encryptPassword);
/**
* 修改头像
* @param file 文件
* @return /
*/
Map<String, String> updateAvatar(MultipartFile file);
/**
* 修改邮箱
* @param username 用户名
* @param email 邮箱
*/
void updateEmail(String username, String email);
/**
* 查询全部
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Object queryAll(UserQueryCriteria criteria, Pageable pageable);
/**
* 查询全部不分页
* @param criteria 条件
* @return /
*/
List<UserDto> queryAll(UserQueryCriteria criteria);
/**
* 导出数据
* @param queryAll 待导出的数据
* @param response /
* @throws IOException /
*/
void download(List<UserDto> queryAll, HttpServletResponse response) throws IOException;
/**
* 用户自助修改资料
* @param resources /
*/
void updateCenter(User resources);
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
import com.example.base.BaseDTO;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
/**
*
* 2019-03-25
*/
@Getter
@Setter
public class DeptDto extends BaseDTO implements Serializable {
private Long id;
private String name;
private Boolean enabled;
private Integer deptSort;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<DeptDto> children;
private Long pid;
private Integer subCount;
public Boolean getHasChildren() {
return subCount > 0;
}
public Boolean getLeaf() {
return subCount <= 0;
}
public String getLabel() {
return name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DeptDto deptDto = (DeptDto) o;
return Objects.equals(id, deptDto.id) &&
Objects.equals(name, deptDto.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service.dto;
import lombok.Data;
import com.example.annotation.DataPermission;
import com.example.annotation.Query;
import java.sql.Timestamp;
import java.util.List;
/**
*
* 2019-03-25
*/
@Data
@DataPermission(fieldName = "id")
public class DeptQueryCriteria{
@Query(type = Query.Type.INNER_LIKE)
private String name;
@Query
private Boolean enabled;
@Query
private Long pid;
@Query(type = Query.Type.IS_NULL, propName = "pid")
private Boolean pidIsNull;
@Query(type = Query.Type.BETWEEN)
private List<Timestamp> createTime;
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service.dto;
import lombok.Data;
import java.io.Serializable;
/**
*
* 2019-6-10 16:32:18
*/
@Data
public class DeptSmallDto implements Serializable {
private Long id;
private String name;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service.dto;
import lombok.Getter;
import lombok.Setter;
import com.example.base.BaseDTO;
import java.io.Serializable;
/**
*
* 2019-04-10
*/
@Getter
@Setter
public class DictDetailDto extends BaseDTO implements Serializable {
private Long id;
private DictSmallDto dict;
private String label;
private String value;
private Integer dictSort;
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service.dto;
import lombok.Data;
import com.example.annotation.Query;
/**
*
* 2019-04-10
*/
@Data
public class DictDetailQueryCriteria {
@Query(type = Query.Type.INNER_LIKE)
private String label;
@Query(propName = "name",joinName = "dict")
private String dictName;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service.dto;
import lombok.Getter;
import lombok.Setter;
import com.example.base.BaseDTO;
import java.io.Serializable;
import java.util.List;
/**
*
* 2019-04-10
*/
@Getter
@Setter
public class DictDto extends BaseDTO implements Serializable {
private Long id;
private List<DictDetailDto> dictDetails;
private String name;
private String description;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service.dto;
import lombok.Data;
import com.example.annotation.Query;
/**
*
* 公共查询类
*/
@Data
public class DictQueryCriteria {
@Query(blurry = "name,description")
private String blurry;
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service.dto;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
*
* 2019-04-10
*/
@Getter
@Setter
public class DictSmallDto implements Serializable {
private Long id;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service.dto;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import com.example.base.BaseDTO;
import java.io.Serializable;
/**
*
* 2019-03-29
*/
@Getter
@Setter
@NoArgsConstructor
public class JobDto extends BaseDTO implements Serializable {
private Long id;
private Integer jobSort;
private String name;
private Boolean enabled;
public JobDto(String name, Boolean enabled) {
this.name = name;
this.enabled = enabled;
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.modules.system.service.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.example.annotation.Query;
import java.sql.Timestamp;
import java.util.List;
/**
*
* 2019-6-4 14:49:34
*/
@Data
@NoArgsConstructor
public class JobQueryCriteria {
@Query(type = Query.Type.INNER_LIKE)
private String name;
@Query
private Boolean enabled;
@Query(type = Query.Type.BETWEEN)
private List<Timestamp> createTime;
}

Some files were not shown because too many files have changed in this diff Show More