summaryrefslogtreecommitdiff
path: root/UI source code/dns-dev-2.0/dns-system/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'UI source code/dns-dev-2.0/dns-system/src/main/java/com')
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/AppRun.java64
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/ConfigurerAdapter.java88
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusConfig.java236
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusPluginsConfig.java36
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/WebSocketConfig.java33
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskExecutePool.java62
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskProperties.java58
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/TheadFactoryName.java63
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/ThreadPoolExecutorUtil.java39
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/controller/DnsController.java48
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DnsType.java24
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DohAttribute.java66
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ForwardDns.java24
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpCert.java51
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpInformation.java75
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/NonstandardDns.java28
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Result.java71
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ScanResult.java75
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Vulnerability.java24
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDo53Dao.java76
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDohDao.java93
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsTypeDao.java20
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/ForwardDnsDao.java20
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpCertDao.java32
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpInformationDao.java27
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/NonstandardDnsDao.java15
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/VulnerabilityDao.java20
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsService.java19
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsTypeService.java13
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/ScanResultService.java13
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsQueryEnum.java108
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsServiceImpl.java631
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsTypeServiceImpl.java15
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/ScanResultServiceImpl.java66
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/ConfigBeanConfiguration.java43
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/SpringSecurityConfig.java192
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCode.java61
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCodeEnum.java43
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginProperties.java135
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/SecurityProperties.java72
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/AuthorizationController.java146
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/OnlineController.java68
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAccessDeniedHandler.java37
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAuthenticationEntryPoint.java39
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenConfigurer.java43
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenFilter.java109
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenProvider.java123
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/OnlineUserService.java192
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheClean.java53
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheManager.java110
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserDetailsServiceImpl.java159
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/AuthUserDto.java39
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/JwtUserDto.java79
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/OnlineUserDto.java73
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DeptController.java117
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictController.java99
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictDetailController.java99
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/JobController.java94
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/LimitController.java47
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MenuController.java147
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MonitorController.java45
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/RoleController.java154
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/UserController.java196
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dept.java86
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dict.java54
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/DictDetail.java56
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Job.java73
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Menu.java110
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Role.java99
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/User.java125
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuMetaVo.java35
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuVo.java47
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/UserPassVo.java31
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DeptRepository.java69
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictDetailRepository.java36
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictRepository.java43
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/JobRepository.java42
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/MenuRepository.java85
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/RoleRepository.java80
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/UserRepository.java130
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DataService.java34
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DeptService.java124
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictDetailService.java63
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictService.java75
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/JobService.java88
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MenuService.java125
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MonitorService.java31
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/RoleService.java136
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/UserService.java114
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptDto.java78
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptQueryCriteria.java46
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptSmallDto.java31
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailDto.java40
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailQueryCriteria.java33
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDto.java39
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictQueryCriteria.java30
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictSmallDto.java31
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobDto.java46
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobQueryCriteria.java40
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobSmallDto.java33
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuDto.java91
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuQueryCriteria.java41
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleDto.java60
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleQueryCriteria.java36
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleSmallDto.java32
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserDto.java64
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserQueryCriteria.java46
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DataServiceImpl.java91
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DeptServiceImpl.java284
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictDetailServiceImpl.java96
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictServiceImpl.java122
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/JobServiceImpl.java126
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MenuServiceImpl.java356
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MonitorServiceImpl.java186
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/RoleServiceImpl.java227
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/UserServiceImpl.java255
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptMapper.java30
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptSmallMapper.java31
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictDetailMapper.java31
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictMapper.java31
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictSmallMapper.java31
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobMapper.java30
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobSmallMapper.java31
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/MenuMapper.java30
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleMapper.java28
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleSmallMapper.java31
-rw-r--r--UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/UserMapper.java27
127 files changed, 10029 insertions, 0 deletions
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/AppRun.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/AppRun.java
new file mode 100644
index 0000000..521f939
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/AppRun.java
@@ -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 添加文件路径,方便 kill,kill `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;
+ }
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/ConfigurerAdapter.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/ConfigurerAdapter.java
new file mode 100644
index 0000000..b2bcf86
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/ConfigurerAdapter.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusConfig.java
new file mode 100644
index 0000000..87e8cbf
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusConfig.java
@@ -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());
+ }
+ }
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusPluginsConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusPluginsConfig.java
new file mode 100644
index 0000000..cc9739c
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusPluginsConfig.java
@@ -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();
+ }
+
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/WebSocketConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/WebSocketConfig.java
new file mode 100644
index 0000000..906021c
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/WebSocketConfig.java
@@ -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();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskExecutePool.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskExecutePool.java
new file mode 100644
index 0000000..44abd3d
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskExecutePool.java
@@ -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());
+ };
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskProperties.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskProperties.java
new file mode 100644
index 0000000..012a127
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskProperties.java
@@ -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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/TheadFactoryName.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/TheadFactoryName.java
new file mode 100644
index 0000000..b06a723
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/TheadFactoryName.java
@@ -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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/ThreadPoolExecutorUtil.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/ThreadPoolExecutorUtil.java
new file mode 100644
index 0000000..db542cf
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/ThreadPoolExecutorUtil.java
@@ -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()
+ );
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/controller/DnsController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/controller/DnsController.java
new file mode 100644
index 0000000..581a46b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/controller/DnsController.java
@@ -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());
+ }
+
+
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DnsType.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DnsType.java
new file mode 100644
index 0000000..983c2ee
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DnsType.java
@@ -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;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DohAttribute.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DohAttribute.java
new file mode 100644
index 0000000..5a772e2
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DohAttribute.java
@@ -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;
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ForwardDns.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ForwardDns.java
new file mode 100644
index 0000000..5823a34
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ForwardDns.java
@@ -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;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpCert.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpCert.java
new file mode 100644
index 0000000..a7f88af
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpCert.java
@@ -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;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpInformation.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpInformation.java
new file mode 100644
index 0000000..1c61eb5
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpInformation.java
@@ -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;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/NonstandardDns.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/NonstandardDns.java
new file mode 100644
index 0000000..11badef
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/NonstandardDns.java
@@ -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;
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Result.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Result.java
new file mode 100644
index 0000000..6047df6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Result.java
@@ -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;
+
+ //(预留)ipv4,ipv6,dnssec,tcp,udp等
+ 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;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ScanResult.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ScanResult.java
new file mode 100644
index 0000000..8d479dc
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ScanResult.java
@@ -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;
+ //(预留)ipv4,ipv6,dnssec,tcp,udp等
+ 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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Vulnerability.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Vulnerability.java
new file mode 100644
index 0000000..b31ba3e
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Vulnerability.java
@@ -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;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDo53Dao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDo53Dao.java
new file mode 100644
index 0000000..0d1eee5
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDo53Dao.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDohDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDohDao.java
new file mode 100644
index 0000000..29018e6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDohDao.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsTypeDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsTypeDao.java
new file mode 100644
index 0000000..e5193e6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsTypeDao.java
@@ -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> {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/ForwardDnsDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/ForwardDnsDao.java
new file mode 100644
index 0000000..2986981
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/ForwardDnsDao.java
@@ -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> {
+
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpCertDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpCertDao.java
new file mode 100644
index 0000000..01939f6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpCertDao.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpInformationDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpInformationDao.java
new file mode 100644
index 0000000..2ed80e3
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpInformationDao.java
@@ -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);
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/NonstandardDnsDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/NonstandardDnsDao.java
new file mode 100644
index 0000000..7c050ef
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/NonstandardDnsDao.java
@@ -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> {
+
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/VulnerabilityDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/VulnerabilityDao.java
new file mode 100644
index 0000000..5d1c06f
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/VulnerabilityDao.java
@@ -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> {
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsService.java
new file mode 100644
index 0000000..3aad1ca
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsService.java
@@ -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();
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsTypeService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsTypeService.java
new file mode 100644
index 0000000..f9cb1c6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsTypeService.java
@@ -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> {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/ScanResultService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/ScanResultService.java
new file mode 100644
index 0000000..3dcd9dd
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/ScanResultService.java
@@ -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);
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsQueryEnum.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsQueryEnum.java
new file mode 100644
index 0000000..089a514
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsQueryEnum.java
@@ -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;
+ }
+
+}
+
+
+
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsServiceImpl.java
new file mode 100644
index 0000000..09cab1a
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsServiceImpl.java
@@ -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,host,rounds查询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和do53(scan_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和do53(scan_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);
+ }
+
+}
+
+
+
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsTypeServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsTypeServiceImpl.java
new file mode 100644
index 0000000..8bd6d89
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsTypeServiceImpl.java
@@ -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 {
+
+}
+
+
+
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/ScanResultServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/ScanResultServiceImpl.java
new file mode 100644
index 0000000..5b832c9
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/ScanResultServiceImpl.java
@@ -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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/ConfigBeanConfiguration.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/ConfigBeanConfiguration.java
new file mode 100644
index 0000000..1c01c10
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/ConfigBeanConfiguration.java
@@ -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();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/SpringSecurityConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/SpringSecurityConfig.java
new file mode 100644
index 0000000..aa9fddf
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/SpringSecurityConfig.java
@@ -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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCode.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCode.java
new file mode 100644
index 0000000..02fbc23
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCode.java
@@ -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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCodeEnum.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCodeEnum.java
new file mode 100644
index 0000000..d9fe369
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCodeEnum.java
@@ -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
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginProperties.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginProperties.java
new file mode 100644
index 0000000..f4b6754
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginProperties.java
@@ -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();
+ }
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/SecurityProperties.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/SecurityProperties.java
new file mode 100644
index 0000000..f341003
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/SecurityProperties.java
@@ -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 + " ";
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/AuthorizationController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/AuthorizationController.java
new file mode 100644
index 0000000..7e2148b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/AuthorizationController.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/OnlineController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/OnlineController.java
new file mode 100644
index 0000000..c4962a3
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/OnlineController.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAccessDeniedHandler.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAccessDeniedHandler.java
new file mode 100644
index 0000000..c0b6f86
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAccessDeniedHandler.java
@@ -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());
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAuthenticationEntryPoint.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAuthenticationEntryPoint.java
new file mode 100644
index 0000000..9fa256e
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAuthenticationEntryPoint.java
@@ -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());
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenConfigurer.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenConfigurer.java
new file mode 100644
index 0000000..2a1ad1c
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenConfigurer.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenFilter.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenFilter.java
new file mode 100644
index 0000000..dc1369e
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenFilter.java
@@ -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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenProvider.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenProvider.java
new file mode 100644
index 0000000..dfe2134
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenProvider.java
@@ -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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/OnlineUserService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/OnlineUserService.java
new file mode 100644
index 0000000..9cfda04
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/OnlineUserService.java
@@ -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);
+ }
+ }
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheClean.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheClean.java
new file mode 100644
index 0000000..aa1ef9c
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheClean.java
@@ -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();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheManager.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheManager.java
new file mode 100644
index 0000000..9c1f60b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheManager.java
@@ -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;
+ }
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserDetailsServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..8d368f2
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserDetailsServiceImpl.java
@@ -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());
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/AuthUserDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/AuthUserDto.java
new file mode 100644
index 0000000..983d690
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/AuthUserDto.java
@@ -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 = "";
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/JwtUserDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/JwtUserDto.java
new file mode 100644
index 0000000..20e1bc6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/JwtUserDto.java
@@ -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();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/OnlineUserDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/OnlineUserDto.java
new file mode 100644
index 0000000..77ba3bc
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/OnlineUserDto.java
@@ -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;
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DeptController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DeptController.java
new file mode 100644
index 0000000..0bef112
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DeptController.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictController.java
new file mode 100644
index 0000000..8f4dec7
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictController.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictDetailController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictDetailController.java
new file mode 100644
index 0000000..e3c5891
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictDetailController.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/JobController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/JobController.java
new file mode 100644
index 0000000..6106f0d
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/JobController.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/LimitController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/LimitController.java
new file mode 100644
index 0000000..636ec91
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/LimitController.java
@@ -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();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MenuController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MenuController.java
new file mode 100644
index 0000000..26a2f1a
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MenuController.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MonitorController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MonitorController.java
new file mode 100644
index 0000000..bb7bf02
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MonitorController.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/RoleController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/RoleController.java
new file mode 100644
index 0000000..8f4fae8
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/RoleController.java
@@ -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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/UserController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/UserController.java
new file mode 100644
index 0000000..393a878
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/UserController.java
@@ -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("角色权限不足");
+ }
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dept.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dept.java
new file mode 100644
index 0000000..4ef6ac1
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dept.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dict.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dict.java
new file mode 100644
index 0000000..de65392
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dict.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/DictDetail.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/DictDetail.java
new file mode 100644
index 0000000..538743e
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/DictDetail.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Job.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Job.java
new file mode 100644
index 0000000..f3f47b3
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Job.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Menu.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Menu.java
new file mode 100644
index 0000000..0989055
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Menu.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Role.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Role.java
new file mode 100644
index 0000000..b600f46
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Role.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/User.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/User.java
new file mode 100644
index 0000000..fcbba83
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/User.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuMetaVo.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuMetaVo.java
new file mode 100644
index 0000000..68944cc
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuMetaVo.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuVo.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuVo.java
new file mode 100644
index 0000000..71c6161
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuVo.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/UserPassVo.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/UserPassVo.java
new file mode 100644
index 0000000..66869b2
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/UserPassVo.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DeptRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DeptRepository.java
new file mode 100644
index 0000000..5952659
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DeptRepository.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictDetailRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictDetailRepository.java
new file mode 100644
index 0000000..315be98
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictDetailRepository.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictRepository.java
new file mode 100644
index 0000000..c2d1a49
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictRepository.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/JobRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/JobRepository.java
new file mode 100644
index 0000000..d804309
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/JobRepository.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/MenuRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/MenuRepository.java
new file mode 100644
index 0000000..ac1e524
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/MenuRepository.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/RoleRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/RoleRepository.java
new file mode 100644
index 0000000..dd6e48b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/RoleRepository.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/UserRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/UserRepository.java
new file mode 100644
index 0000000..620b247
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/UserRepository.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DataService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DataService.java
new file mode 100644
index 0000000..de01bd9
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DataService.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DeptService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DeptService.java
new file mode 100644
index 0000000..24f6138
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DeptService.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictDetailService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictDetailService.java
new file mode 100644
index 0000000..57e5a7f
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictDetailService.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictService.java
new file mode 100644
index 0000000..8cf7e9c
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictService.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/JobService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/JobService.java
new file mode 100644
index 0000000..2fc99b6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/JobService.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MenuService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MenuService.java
new file mode 100644
index 0000000..4706705
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MenuService.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MonitorService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MonitorService.java
new file mode 100644
index 0000000..d9f87f9
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MonitorService.java
@@ -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();
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/RoleService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/RoleService.java
new file mode 100644
index 0000000..5fa13ca
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/RoleService.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/UserService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/UserService.java
new file mode 100644
index 0000000..10fba88
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/UserService.java
@@ -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);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptDto.java
new file mode 100644
index 0000000..02ec1ea
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptDto.java
@@ -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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptQueryCriteria.java
new file mode 100644
index 0000000..8f8c56b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptQueryCriteria.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptSmallDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptSmallDto.java
new file mode 100644
index 0000000..503762b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptSmallDto.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailDto.java
new file mode 100644
index 0000000..58e826b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailDto.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailQueryCriteria.java
new file mode 100644
index 0000000..2f12c80
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailQueryCriteria.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDto.java
new file mode 100644
index 0000000..72f704e
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDto.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictQueryCriteria.java
new file mode 100644
index 0000000..3a5da52
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictQueryCriteria.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictSmallDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictSmallDto.java
new file mode 100644
index 0000000..a0ed61f
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictSmallDto.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobDto.java
new file mode 100644
index 0000000..502176b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobDto.java
@@ -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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobQueryCriteria.java
new file mode 100644
index 0000000..215d721
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobQueryCriteria.java
@@ -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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobSmallDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobSmallDto.java
new file mode 100644
index 0000000..af9f8a6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobSmallDto.java
@@ -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 lombok.NoArgsConstructor;
+import java.io.Serializable;
+
+/**
+*
+* 2019-6-10 16:32:18
+*/
+@Data
+@NoArgsConstructor
+public class JobSmallDto implements Serializable {
+
+ private Long id;
+
+ private String name;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuDto.java
new file mode 100644
index 0000000..8500654
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuDto.java
@@ -0,0 +1,91 @@
+/*
+ * 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;
+import java.util.Objects;
+
+/**
+ *
+ * 2018-12-17
+ */
+@Getter
+@Setter
+public class MenuDto extends BaseDTO implements Serializable {
+
+ private Long id;
+
+ private List<MenuDto> children;
+
+ private Integer type;
+
+ private String permission;
+
+ private String title;
+
+ private Integer menuSort;
+
+ private String path;
+
+ private String component;
+
+ private Long pid;
+
+ private Integer subCount;
+
+ private Boolean iFrame;
+
+ private Boolean cache;
+
+ private Boolean hidden;
+
+ private String componentName;
+
+ private String icon;
+
+ public Boolean getHasChildren() {
+ return subCount > 0;
+ }
+
+ public Boolean getLeaf() {
+ return subCount <= 0;
+ }
+
+ public String getLabel() {
+ return title;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MenuDto menuDto = (MenuDto) o;
+ return Objects.equals(id, menuDto.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuQueryCriteria.java
new file mode 100644
index 0000000..1d03860
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuQueryCriteria.java
@@ -0,0 +1,41 @@
+/*
+ * 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;
+import java.sql.Timestamp;
+import java.util.List;
+
+/**
+ *
+ * 公共查询类
+ */
+@Data
+public class MenuQueryCriteria {
+
+ @Query(blurry = "title,component,permission")
+ private String blurry;
+
+ @Query(type = Query.Type.BETWEEN)
+ private List<Timestamp> createTime;
+
+ @Query(type = Query.Type.IS_NULL, propName = "pid")
+ private Boolean pidIsNull;
+
+ @Query
+ private Long pid;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleDto.java
new file mode 100644
index 0000000..1373b7f
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleDto.java
@@ -0,0 +1,60 @@
+/*
+ * 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.Objects;
+import java.util.Set;
+
+
+@Getter
+@Setter
+public class RoleDto extends BaseDTO implements Serializable {
+
+ private Long id;
+
+ private Set<MenuDto> menus;
+
+ private Set<DeptDto> depts;
+
+ private String name;
+
+ private String dataScope;
+
+ private Integer level;
+
+ private String description;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ RoleDto roleDto = (RoleDto) o;
+ return Objects.equals(id, roleDto.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleQueryCriteria.java
new file mode 100644
index 0000000..afe3a4e
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleQueryCriteria.java
@@ -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.service.dto;
+
+import lombok.Data;
+import com.example.annotation.Query;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+/**
+ *
+ * 公共查询类
+ */
+@Data
+public class RoleQueryCriteria {
+
+ @Query(blurry = "name,description")
+ private String blurry;
+
+ @Query(type = Query.Type.BETWEEN)
+ private List<Timestamp> createTime;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleSmallDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleSmallDto.java
new file mode 100644
index 0000000..5c7f184
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleSmallDto.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+
+@Data
+public class RoleSmallDto implements Serializable {
+
+ private Long id;
+
+ private String name;
+
+ private Integer level;
+
+ private String dataScope;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserDto.java
new file mode 100644
index 0000000..a1ecd96
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserDto.java
@@ -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.modules.system.service.dto;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Getter;
+import lombok.Setter;
+import com.example.base.BaseDTO;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Set;
+
+
+@Getter
+@Setter
+public class UserDto extends BaseDTO implements Serializable {
+
+ private Long id;
+
+ private Set<RoleSmallDto> roles;
+
+ private Set<JobSmallDto> jobs;
+
+ private DeptSmallDto dept;
+
+ private Long deptId;
+
+ private String username;
+
+ private String nickName;
+
+ private String email;
+
+ private String phone;
+
+ private String gender;
+
+ private String avatarName;
+
+ private String avatarPath;
+
+ @JSONField(serialize = false)
+ private String password;
+
+ private Boolean enabled;
+
+ @JSONField(serialize = false)
+ private Boolean isAdmin = false;
+
+ private Date pwdResetTime;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserQueryCriteria.java
new file mode 100644
index 0000000..1f862cf
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserQueryCriteria.java
@@ -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.Query;
+import java.io.Serializable;
+import java.sql.Timestamp;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+@Data
+public class UserQueryCriteria implements Serializable {
+
+ @Query
+ private Long id;
+
+ @Query(propName = "id", type = Query.Type.IN, joinName = "dept")
+ private Set<Long> deptIds = new HashSet<>();
+
+ @Query(blurry = "email,username,nickName")
+ private String blurry;
+
+ @Query
+ private Boolean enabled;
+
+ private Long deptId;
+
+ @Query(type = Query.Type.BETWEEN)
+ private List<Timestamp> createTime;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DataServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DataServiceImpl.java
new file mode 100644
index 0000000..e31f26b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DataServiceImpl.java
@@ -0,0 +1,91 @@
+/*
+ * 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.impl;
+
+import com.example.modules.system.domain.Dept;
+import com.example.modules.system.service.DataService;
+import com.example.modules.system.service.DeptService;
+import lombok.RequiredArgsConstructor;
+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.utils.enums.DataScopeEnum;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import java.util.*;
+
+/**
+ *
+ * @website https://el-admin.vip
+ * @description 数据权限服务实现
+ * 2020-05-07
+ **/
+@Service
+@RequiredArgsConstructor
+@CacheConfig(cacheNames = "data")
+public class DataServiceImpl implements DataService {
+
+ private final RoleService roleService;
+ private final DeptService deptService;
+
+ /**
+ * 用户角色改变时需清理缓存
+ * @param user /
+ * @return /
+ */
+ @Override
+ @Cacheable(key = "'user:' + #p0.id")
+ public List<Long> getDeptIds(UserDto user) {
+ // 用于存储部门id
+ Set<Long> deptIds = new HashSet<>();
+ // 查询用户角色
+ List<RoleSmallDto> roleSet = roleService.findByUsersId(user.getId());
+ // 获取对应的部门ID
+ for (RoleSmallDto role : roleSet) {
+ DataScopeEnum dataScopeEnum = DataScopeEnum.find(role.getDataScope());
+ switch (Objects.requireNonNull(dataScopeEnum)) {
+ case THIS_LEVEL:
+ deptIds.add(user.getDept().getId());
+ break;
+ case CUSTOMIZE:
+ deptIds.addAll(getCustomize(deptIds, role));
+ break;
+ default:
+ return new ArrayList<>(deptIds);
+ }
+ }
+ return new ArrayList<>(deptIds);
+ }
+
+ /**
+ * 获取自定义的数据权限
+ * @param deptIds 部门ID
+ * @param role 角色
+ * @return 数据权限ID
+ */
+ public Set<Long> getCustomize(Set<Long> deptIds, RoleSmallDto role){
+ Set<Dept> depts = deptService.findByRoleId(role.getId());
+ for (Dept dept : depts) {
+ deptIds.add(dept.getId());
+ List<Dept> deptChildren = deptService.findByPid(dept.getId());
+ if (deptChildren != null && deptChildren.size() != 0) {
+ deptIds.addAll(deptService.getDeptChildren(deptChildren));
+ }
+ }
+ return deptIds;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DeptServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DeptServiceImpl.java
new file mode 100644
index 0000000..e777319
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DeptServiceImpl.java
@@ -0,0 +1,284 @@
+/*
+ * 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.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.example.modules.system.domain.Dept;
+import com.example.modules.system.domain.User;
+import com.example.modules.system.repository.DeptRepository;
+import com.example.modules.system.repository.RoleRepository;
+import com.example.modules.system.service.DeptService;
+import com.example.modules.system.service.dto.DeptDto;
+import com.example.modules.system.service.dto.DeptQueryCriteria;
+import com.example.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.example.exception.BadRequestException;
+import com.example.modules.system.repository.UserRepository;
+import com.example.utils.*;
+import com.example.modules.system.service.mapstruct.DeptMapper;
+import com.example.utils.enums.DataScopeEnum;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+*
+* 2019-03-25
+*/
+@Service
+@RequiredArgsConstructor
+@CacheConfig(cacheNames = "dept")
+public class DeptServiceImpl implements DeptService {
+
+ private final DeptRepository deptRepository;
+ private final DeptMapper deptMapper;
+ private final UserRepository userRepository;
+ private final RedisUtils redisUtils;
+ private final RoleRepository roleRepository;
+
+ @Override
+ public List<DeptDto> queryAll(DeptQueryCriteria criteria, Boolean isQuery) throws Exception {
+ Sort sort = Sort.by(Sort.Direction.ASC, "deptSort");
+ String dataScopeType = SecurityUtils.getDataScopeType();
+ if (isQuery) {
+ if(dataScopeType.equals(DataScopeEnum.ALL.getValue())){
+ criteria.setPidIsNull(true);
+ }
+ List<Field> fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>());
+ List<String> fieldNames = new ArrayList<String>(){{ add("pidIsNull");add("enabled");}};
+ for (Field field : fields) {
+ //设置对象的访问权限,保证对private的属性的访问
+ field.setAccessible(true);
+ Object val = field.get(criteria);
+ if(fieldNames.contains(field.getName())){
+ continue;
+ }
+ if (ObjectUtil.isNotNull(val)) {
+ criteria.setPidIsNull(null);
+ break;
+ }
+ }
+ }
+ List<DeptDto> list = deptMapper.toDto(deptRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort));
+ // 如果为空,就代表为自定义权限或者本级权限,就需要去重,不理解可以注释掉,看查询结果
+ if(StringUtils.isBlank(dataScopeType)){
+ return deduplication(list);
+ }
+ return list;
+ }
+
+ @Override
+ @Cacheable(key = "'id:' + #p0")
+ public DeptDto findById(Long id) {
+ Dept dept = deptRepository.findById(id).orElseGet(Dept::new);
+ ValidationUtil.isNull(dept.getId(),"Dept","id",id);
+ return deptMapper.toDto(dept);
+ }
+
+ @Override
+ public List<Dept> findByPid(long pid) {
+ return deptRepository.findByPid(pid);
+ }
+
+ @Override
+ public Set<Dept> findByRoleId(Long id) {
+ return deptRepository.findByRoleId(id);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void create(Dept resources) {
+ deptRepository.save(resources);
+ // 计算子节点数目
+ resources.setSubCount(0);
+ // 清理缓存
+ updateSubCnt(resources.getPid());
+ // 清理自定义角色权限的datascope缓存
+ delCaches(resources.getPid());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void update(Dept resources) {
+ // 旧的部门
+ Long oldPid = findById(resources.getId()).getPid();
+ Long newPid = resources.getPid();
+ if(resources.getPid() != null && resources.getId().equals(resources.getPid())) {
+ throw new BadRequestException("上级不能为自己");
+ }
+ Dept dept = deptRepository.findById(resources.getId()).orElseGet(Dept::new);
+ ValidationUtil.isNull( dept.getId(),"Dept","id",resources.getId());
+ resources.setId(dept.getId());
+ deptRepository.save(resources);
+ // 更新父节点中子节点数目
+ updateSubCnt(oldPid);
+ updateSubCnt(newPid);
+ // 清理缓存
+ delCaches(resources.getId());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void delete(Set<DeptDto> deptDtos) {
+ for (DeptDto deptDto : deptDtos) {
+ // 清理缓存
+ delCaches(deptDto.getId());
+ deptRepository.deleteById(deptDto.getId());
+ updateSubCnt(deptDto.getPid());
+ }
+ }
+
+ @Override
+ public void download(List<DeptDto> deptDtos, HttpServletResponse response) throws IOException {
+ List<Map<String, Object>> list = new ArrayList<>();
+ for (DeptDto deptDTO : deptDtos) {
+ Map<String,Object> map = new LinkedHashMap<>();
+ map.put("部门名称", deptDTO.getName());
+ map.put("部门状态", deptDTO.getEnabled() ? "启用" : "停用");
+ map.put("创建日期", deptDTO.getCreateTime());
+ list.add(map);
+ }
+ FileUtil.downloadExcel(list, response);
+ }
+
+ @Override
+ public Set<DeptDto> getDeleteDepts(List<Dept> menuList, Set<DeptDto> deptDtos) {
+ for (Dept dept : menuList) {
+ deptDtos.add(deptMapper.toDto(dept));
+ List<Dept> depts = deptRepository.findByPid(dept.getId());
+ if(depts!=null && depts.size()!=0){
+ getDeleteDepts(depts, deptDtos);
+ }
+ }
+ return deptDtos;
+ }
+
+ @Override
+ public List<Long> getDeptChildren(List<Dept> deptList) {
+ List<Long> list = new ArrayList<>();
+ deptList.forEach(dept -> {
+ if (dept!=null && dept.getEnabled()) {
+ List<Dept> depts = deptRepository.findByPid(dept.getId());
+ if (depts.size() != 0) {
+ list.addAll(getDeptChildren(depts));
+ }
+ list.add(dept.getId());
+ }
+ }
+ );
+ return list;
+ }
+
+ @Override
+ public List<DeptDto> getSuperior(DeptDto deptDto, List<Dept> depts) {
+ if(deptDto.getPid() == null){
+ depts.addAll(deptRepository.findByPidIsNull());
+ return deptMapper.toDto(depts);
+ }
+ depts.addAll(deptRepository.findByPid(deptDto.getPid()));
+ return getSuperior(findById(deptDto.getPid()), depts);
+ }
+
+ @Override
+ public Object buildTree(List<DeptDto> deptDtos) {
+ Set<DeptDto> trees = new LinkedHashSet<>();
+ Set<DeptDto> depts= new LinkedHashSet<>();
+ List<String> deptNames = deptDtos.stream().map(DeptDto::getName).collect(Collectors.toList());
+ boolean isChild;
+ for (DeptDto deptDTO : deptDtos) {
+ isChild = false;
+ if (deptDTO.getPid() == null) {
+ trees.add(deptDTO);
+ }
+ for (DeptDto it : deptDtos) {
+ if (it.getPid() != null && deptDTO.getId().equals(it.getPid())) {
+ isChild = true;
+ if (deptDTO.getChildren() == null) {
+ deptDTO.setChildren(new ArrayList<>());
+ }
+ deptDTO.getChildren().add(it);
+ }
+ }
+ if(isChild) {
+ depts.add(deptDTO);
+ } else if(deptDTO.getPid() != null && !deptNames.contains(findById(deptDTO.getPid()).getName())) {
+ depts.add(deptDTO);
+ }
+ }
+
+ if (CollectionUtil.isEmpty(trees)) {
+ trees = depts;
+ }
+ Map<String,Object> map = new HashMap<>(2);
+ map.put("totalElements",deptDtos.size());
+ map.put("content",CollectionUtil.isEmpty(trees)? deptDtos :trees);
+ return map;
+ }
+
+ @Override
+ public void verification(Set<DeptDto> deptDtos) {
+ Set<Long> deptIds = deptDtos.stream().map(DeptDto::getId).collect(Collectors.toSet());
+ if(userRepository.countByDepts(deptIds) > 0){
+ throw new BadRequestException("所选部门存在用户关联,请解除后再试!");
+ }
+ if(roleRepository.countByDepts(deptIds) > 0){
+ throw new BadRequestException("所选部门存在角色关联,请解除后再试!");
+ }
+ }
+
+ private void updateSubCnt(Long deptId){
+ if(deptId != null){
+ int count = deptRepository.countByPid(deptId);
+ deptRepository.updateSubCntById(count, deptId);
+ }
+ }
+
+ private List<DeptDto> deduplication(List<DeptDto> list) {
+ List<DeptDto> deptDtos = new ArrayList<>();
+ for (DeptDto deptDto : list) {
+ boolean flag = true;
+ for (DeptDto dto : list) {
+ if (dto.getId().equals(deptDto.getPid())) {
+ flag = false;
+ break;
+ }
+ }
+ if (flag){
+ deptDtos.add(deptDto);
+ }
+ }
+ return deptDtos;
+ }
+
+ /**
+ * 清理缓存
+ * @param id /
+ */
+ public void delCaches(Long id){
+ List<User> users = userRepository.findByRoleDeptId(id);
+ // 删除数据权限
+ redisUtils.delByKeys(CacheKey.DATA_USER, users.stream().map(User::getId).collect(Collectors.toSet()));
+ redisUtils.del(CacheKey.DEPT_ID + id);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictDetailServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictDetailServiceImpl.java
new file mode 100644
index 0000000..672a31a
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictDetailServiceImpl.java
@@ -0,0 +1,96 @@
+/*
+ * 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.impl;
+
+import com.example.modules.system.domain.Dict;
+import com.example.modules.system.domain.DictDetail;
+import com.example.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.example.modules.system.repository.DictRepository;
+import com.example.modules.system.service.dto.DictDetailQueryCriteria;
+import com.example.utils.*;
+import com.example.modules.system.repository.DictDetailRepository;
+import com.example.modules.system.service.DictDetailService;
+import com.example.modules.system.service.dto.DictDetailDto;
+import com.example.modules.system.service.mapstruct.DictDetailMapper;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import java.util.List;
+import java.util.Map;
+
+/**
+*
+* 2019-04-10
+*/
+@Service
+@RequiredArgsConstructor
+@CacheConfig(cacheNames = "dict")
+public class DictDetailServiceImpl implements DictDetailService {
+
+ private final DictRepository dictRepository;
+ private final DictDetailRepository dictDetailRepository;
+ private final DictDetailMapper dictDetailMapper;
+ private final RedisUtils redisUtils;
+
+ @Override
+ public Map<String,Object> queryAll(DictDetailQueryCriteria criteria, Pageable pageable) {
+ Page<DictDetail> page = dictDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
+ return PageUtil.toPage(page.map(dictDetailMapper::toDto));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void create(DictDetail resources) {
+ dictDetailRepository.save(resources);
+ // 清理缓存
+ delCaches(resources);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void update(DictDetail resources) {
+ DictDetail dictDetail = dictDetailRepository.findById(resources.getId()).orElseGet(DictDetail::new);
+ ValidationUtil.isNull( dictDetail.getId(),"DictDetail","id",resources.getId());
+ resources.setId(dictDetail.getId());
+ dictDetailRepository.save(resources);
+ // 清理缓存
+ delCaches(resources);
+ }
+
+ @Override
+ @Cacheable(key = "'name:' + #p0")
+ public List<DictDetailDto> getDictByName(String name) {
+ return dictDetailMapper.toDto(dictDetailRepository.findByDictName(name));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void delete(Long id) {
+ DictDetail dictDetail = dictDetailRepository.findById(id).orElseGet(DictDetail::new);
+ // 清理缓存
+ delCaches(dictDetail);
+ dictDetailRepository.deleteById(id);
+ }
+
+ public void delCaches(DictDetail dictDetail){
+ Dict dict = dictRepository.findById(dictDetail.getDict().getId()).orElseGet(Dict::new);
+ redisUtils.del(CacheKey.DICT_NAME + dict.getName());
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictServiceImpl.java
new file mode 100644
index 0000000..79cd9e3
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictServiceImpl.java
@@ -0,0 +1,122 @@
+/*
+ * 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.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.example.modules.system.domain.Dict;
+import com.example.modules.system.service.dto.DictDto;
+import com.example.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.example.modules.system.service.dto.DictDetailDto;
+import com.example.modules.system.service.dto.DictQueryCriteria;
+import com.example.utils.*;
+import com.example.modules.system.repository.DictRepository;
+import com.example.modules.system.service.DictService;
+import com.example.modules.system.service.mapstruct.DictMapper;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.*;
+
+/**
+*
+* 2019-04-10
+*/
+@Service
+@RequiredArgsConstructor
+@CacheConfig(cacheNames = "dict")
+public class DictServiceImpl implements DictService {
+
+ private final DictRepository dictRepository;
+ private final DictMapper dictMapper;
+ private final RedisUtils redisUtils;
+
+ @Override
+ public Map<String, Object> queryAll(DictQueryCriteria dict, Pageable pageable){
+ Page<Dict> page = dictRepository.findAll((root, query, cb) -> QueryHelp.getPredicate(root, dict, cb), pageable);
+ return PageUtil.toPage(page.map(dictMapper::toDto));
+ }
+
+ @Override
+ public List<DictDto> queryAll(DictQueryCriteria dict) {
+ List<Dict> list = dictRepository.findAll((root, query, cb) -> QueryHelp.getPredicate(root, dict, cb));
+ return dictMapper.toDto(list);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void create(Dict resources) {
+ dictRepository.save(resources);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void update(Dict resources) {
+ // 清理缓存
+ delCaches(resources);
+ Dict dict = dictRepository.findById(resources.getId()).orElseGet(Dict::new);
+ ValidationUtil.isNull( dict.getId(),"Dict","id",resources.getId());
+ dict.setName(resources.getName());
+ dict.setDescription(resources.getDescription());
+ dictRepository.save(dict);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void delete(Set<Long> ids) {
+ // 清理缓存
+ List<Dict> dicts = dictRepository.findByIdIn(ids);
+ for (Dict dict : dicts) {
+ delCaches(dict);
+ }
+ dictRepository.deleteByIdIn(ids);
+ }
+
+ @Override
+ public void download(List<DictDto> dictDtos, HttpServletResponse response) throws IOException {
+ List<Map<String, Object>> list = new ArrayList<>();
+ for (DictDto dictDTO : dictDtos) {
+ if(CollectionUtil.isNotEmpty(dictDTO.getDictDetails())){
+ for (DictDetailDto dictDetail : dictDTO.getDictDetails()) {
+ Map<String,Object> map = new LinkedHashMap<>();
+ map.put("字典名称", dictDTO.getName());
+ map.put("字典描述", dictDTO.getDescription());
+ map.put("字典标签", dictDetail.getLabel());
+ map.put("字典值", dictDetail.getValue());
+ map.put("创建日期", dictDetail.getCreateTime());
+ list.add(map);
+ }
+ } else {
+ Map<String,Object> map = new LinkedHashMap<>();
+ map.put("字典名称", dictDTO.getName());
+ map.put("字典描述", dictDTO.getDescription());
+ map.put("字典标签", null);
+ map.put("字典值", null);
+ map.put("创建日期", dictDTO.getCreateTime());
+ list.add(map);
+ }
+ }
+ FileUtil.downloadExcel(list, response);
+ }
+
+ public void delCaches(Dict dict){
+ redisUtils.del(CacheKey.DICT_NAME + dict.getName());
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/JobServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/JobServiceImpl.java
new file mode 100644
index 0000000..73c93c5
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/JobServiceImpl.java
@@ -0,0 +1,126 @@
+/*
+ * 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.impl;
+
+import com.example.modules.system.domain.Job;
+import com.example.modules.system.service.JobService;
+import com.example.modules.system.service.dto.JobDto;
+import com.example.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.example.exception.BadRequestException;
+import com.example.exception.EntityExistException;
+import com.example.modules.system.repository.UserRepository;
+import com.example.modules.system.service.dto.JobQueryCriteria;
+import com.example.utils.*;
+import com.example.modules.system.repository.JobRepository;
+import com.example.modules.system.service.mapstruct.JobMapper;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.*;
+
+/**
+*
+* 2019-03-29
+*/
+@Service
+@RequiredArgsConstructor
+@CacheConfig(cacheNames = "job")
+public class JobServiceImpl implements JobService {
+
+ private final JobRepository jobRepository;
+ private final JobMapper jobMapper;
+ private final RedisUtils redisUtils;
+ private final UserRepository userRepository;
+
+ @Override
+ public Map<String,Object> queryAll(JobQueryCriteria criteria, Pageable pageable) {
+ Page<Job> page = jobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
+ return PageUtil.toPage(page.map(jobMapper::toDto).getContent(),page.getTotalElements());
+ }
+
+ @Override
+ public List<JobDto> queryAll(JobQueryCriteria criteria) {
+ List<Job> list = jobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
+ return jobMapper.toDto(list);
+ }
+
+ @Override
+ @Cacheable(key = "'id:' + #p0")
+ public JobDto findById(Long id) {
+ Job job = jobRepository.findById(id).orElseGet(Job::new);
+ ValidationUtil.isNull(job.getId(),"Job","id",id);
+ return jobMapper.toDto(job);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void create(Job resources) {
+ Job job = jobRepository.findByName(resources.getName());
+ if(job != null){
+ throw new EntityExistException(Job.class,"name",resources.getName());
+ }
+ jobRepository.save(resources);
+ }
+
+ @Override
+ @CacheEvict(key = "'id:' + #p0.id")
+ @Transactional(rollbackFor = Exception.class)
+ public void update(Job resources) {
+ Job job = jobRepository.findById(resources.getId()).orElseGet(Job::new);
+ Job old = jobRepository.findByName(resources.getName());
+ if(old != null && !old.getId().equals(resources.getId())){
+ throw new EntityExistException(Job.class,"name",resources.getName());
+ }
+ ValidationUtil.isNull( job.getId(),"Job","id",resources.getId());
+ resources.setId(job.getId());
+ jobRepository.save(resources);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void delete(Set<Long> ids) {
+ jobRepository.deleteAllByIdIn(ids);
+ // 删除缓存
+ redisUtils.delByKeys(CacheKey.JOB_ID, ids);
+ }
+
+ @Override
+ public void download(List<JobDto> jobDtos, HttpServletResponse response) throws IOException {
+ List<Map<String, Object>> list = new ArrayList<>();
+ for (JobDto jobDTO : jobDtos) {
+ Map<String,Object> map = new LinkedHashMap<>();
+ map.put("岗位名称", jobDTO.getName());
+ map.put("岗位状态", jobDTO.getEnabled() ? "启用" : "停用");
+ map.put("创建日期", jobDTO.getCreateTime());
+ list.add(map);
+ }
+ FileUtil.downloadExcel(list, response);
+ }
+
+ @Override
+ public void verification(Set<Long> ids) {
+ if(userRepository.countByJobs(ids) > 0){
+ throw new BadRequestException("所选的岗位中存在用户关联,请解除关联再试!");
+ }
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MenuServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MenuServiceImpl.java
new file mode 100644
index 0000000..ceacddb
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MenuServiceImpl.java
@@ -0,0 +1,356 @@
+/*
+ * 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.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.example.modules.system.domain.Menu;
+import com.example.modules.system.domain.Role;
+import com.example.modules.system.domain.User;
+import com.example.modules.system.domain.vo.MenuMetaVo;
+import com.example.modules.system.domain.vo.MenuVo;
+import com.example.modules.system.repository.MenuRepository;
+import com.example.modules.system.service.MenuService;
+import com.example.modules.system.service.RoleService;
+import com.example.modules.system.service.dto.MenuDto;
+import com.example.modules.system.service.dto.MenuQueryCriteria;
+import com.example.modules.system.service.dto.RoleSmallDto;
+import com.example.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.example.exception.BadRequestException;
+import com.example.exception.EntityExistException;
+import com.example.modules.system.repository.UserRepository;
+import com.example.modules.system.service.mapstruct.MenuMapper;
+import com.example.utils.*;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ *
+ */
+@Service
+@RequiredArgsConstructor
+@CacheConfig(cacheNames = "menu")
+public class MenuServiceImpl implements MenuService {
+
+ private final MenuRepository menuRepository;
+ private final UserRepository userRepository;
+ private final MenuMapper menuMapper;
+ private final RoleService roleService;
+ private final RedisUtils redisUtils;
+
+ @Override
+ public List<MenuDto> queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception {
+ Sort sort = Sort.by(Sort.Direction.ASC, "menuSort");
+ if(Boolean.TRUE.equals(isQuery)){
+ criteria.setPidIsNull(true);
+ List<Field> fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>());
+ for (Field field : fields) {
+ //设置对象的访问权限,保证对private的属性的访问
+ field.setAccessible(true);
+ Object val = field.get(criteria);
+ if("pidIsNull".equals(field.getName())){
+ continue;
+ }
+ if (ObjectUtil.isNotNull(val)) {
+ criteria.setPidIsNull(null);
+ break;
+ }
+ }
+ }
+ return menuMapper.toDto(menuRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort));
+ }
+
+ @Override
+ @Cacheable(key = "'id:' + #p0")
+ public MenuDto findById(long id) {
+ Menu menu = menuRepository.findById(id).orElseGet(Menu::new);
+ ValidationUtil.isNull(menu.getId(),"Menu","id",id);
+ return menuMapper.toDto(menu);
+ }
+
+ /**
+ * 用户角色改变时需清理缓存
+ * @param currentUserId /
+ * @return /
+ */
+ @Override
+ @Cacheable(key = "'user:' + #p0")
+ public List<MenuDto> findByUser(Long currentUserId) {
+ List<RoleSmallDto> roles = roleService.findByUsersId(currentUserId);
+ Set<Long> roleIds = roles.stream().map(RoleSmallDto::getId).collect(Collectors.toSet());
+ LinkedHashSet<Menu> menus = menuRepository.findByRoleIdsAndTypeNot(roleIds, 2);
+ return menus.stream().map(menuMapper::toDto).collect(Collectors.toList());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void create(Menu resources) {
+ if(menuRepository.findByTitle(resources.getTitle()) != null){
+ throw new EntityExistException(Menu.class,"title",resources.getTitle());
+ }
+ if(StringUtils.isNotBlank(resources.getComponentName())){
+ if(menuRepository.findByComponentName(resources.getComponentName()) != null){
+ throw new EntityExistException(Menu.class,"componentName",resources.getComponentName());
+ }
+ }
+ if(resources.getPid().equals(0L)){
+ resources.setPid(null);
+ }
+ if(resources.getIFrame()){
+ String http = "http://", https = "https://";
+ if (!(resources.getPath().toLowerCase().startsWith(http)||resources.getPath().toLowerCase().startsWith(https))) {
+ throw new BadRequestException("外链必须以http://或者https://开头");
+ }
+ }
+ menuRepository.save(resources);
+ // 计算子节点数目
+ resources.setSubCount(0);
+ // 更新父节点菜单数目
+ updateSubCnt(resources.getPid());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void update(Menu resources) {
+ if(resources.getId().equals(resources.getPid())) {
+ throw new BadRequestException("上级不能为自己");
+ }
+ Menu menu = menuRepository.findById(resources.getId()).orElseGet(Menu::new);
+ ValidationUtil.isNull(menu.getId(),"Permission","id",resources.getId());
+
+ if(resources.getIFrame()){
+ String http = "http://", https = "https://";
+ if (!(resources.getPath().toLowerCase().startsWith(http)||resources.getPath().toLowerCase().startsWith(https))) {
+ throw new BadRequestException("外链必须以http://或者https://开头");
+ }
+ }
+ Menu menu1 = menuRepository.findByTitle(resources.getTitle());
+
+ if(menu1 != null && !menu1.getId().equals(menu.getId())){
+ throw new EntityExistException(Menu.class,"title",resources.getTitle());
+ }
+
+ if(resources.getPid().equals(0L)){
+ resources.setPid(null);
+ }
+
+ // 记录的父节点ID
+ Long oldPid = menu.getPid();
+ Long newPid = resources.getPid();
+
+ if(StringUtils.isNotBlank(resources.getComponentName())){
+ menu1 = menuRepository.findByComponentName(resources.getComponentName());
+ if(menu1 != null && !menu1.getId().equals(menu.getId())){
+ throw new EntityExistException(Menu.class,"componentName",resources.getComponentName());
+ }
+ }
+ menu.setTitle(resources.getTitle());
+ menu.setComponent(resources.getComponent());
+ menu.setPath(resources.getPath());
+ menu.setIcon(resources.getIcon());
+ menu.setIFrame(resources.getIFrame());
+ menu.setPid(resources.getPid());
+ menu.setMenuSort(resources.getMenuSort());
+ menu.setCache(resources.getCache());
+ menu.setHidden(resources.getHidden());
+ menu.setComponentName(resources.getComponentName());
+ menu.setPermission(resources.getPermission());
+ menu.setType(resources.getType());
+ menuRepository.save(menu);
+ // 计算父级菜单节点数目
+ updateSubCnt(oldPid);
+ updateSubCnt(newPid);
+ // 清理缓存
+ delCaches(resources.getId());
+ }
+
+ @Override
+ public Set<Menu> getChildMenus(List<Menu> menuList, Set<Menu> menuSet) {
+ for (Menu menu : menuList) {
+ menuSet.add(menu);
+ List<Menu> menus = menuRepository.findByPid(menu.getId());
+ if(menus!=null && menus.size()!=0){
+ getChildMenus(menus, menuSet);
+ }
+ }
+ return menuSet;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void delete(Set<Menu> menuSet) {
+ for (Menu menu : menuSet) {
+ // 清理缓存
+ delCaches(menu.getId());
+ roleService.untiedMenu(menu.getId());
+ menuRepository.deleteById(menu.getId());
+ updateSubCnt(menu.getPid());
+ }
+ }
+
+ @Override
+ public List<MenuDto> getMenus(Long pid) {
+ List<Menu> menus;
+ if(pid != null && !pid.equals(0L)){
+ menus = menuRepository.findByPid(pid);
+ } else {
+ menus = menuRepository.findByPidIsNull();
+ }
+ return menuMapper.toDto(menus);
+ }
+
+ @Override
+ public List<MenuDto> getSuperior(MenuDto menuDto, List<Menu> menus) {
+ if(menuDto.getPid() == null){
+ menus.addAll(menuRepository.findByPidIsNull());
+ return menuMapper.toDto(menus);
+ }
+ menus.addAll(menuRepository.findByPid(menuDto.getPid()));
+ return getSuperior(findById(menuDto.getPid()), menus);
+ }
+
+ @Override
+ public List<MenuDto> buildTree(List<MenuDto> menuDtos) {
+ List<MenuDto> trees = new ArrayList<>();
+ Set<Long> ids = new HashSet<>();
+ for (MenuDto menuDTO : menuDtos) {
+ if (menuDTO.getPid() == null) {
+ trees.add(menuDTO);
+ }
+ for (MenuDto it : menuDtos) {
+ if (menuDTO.getId().equals(it.getPid())) {
+ if (menuDTO.getChildren() == null) {
+ menuDTO.setChildren(new ArrayList<>());
+ }
+ menuDTO.getChildren().add(it);
+ ids.add(it.getId());
+ }
+ }
+ }
+ if(trees.size() == 0){
+ trees = menuDtos.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList());
+ }
+ return trees;
+ }
+
+ @Override
+ public List<MenuVo> buildMenus(List<MenuDto> menuDtos) {
+ List<MenuVo> list = new LinkedList<>();
+ menuDtos.forEach(menuDTO -> {
+ if (menuDTO!=null){
+ List<MenuDto> menuDtoList = menuDTO.getChildren();
+ MenuVo menuVo = new MenuVo();
+ menuVo.setName(ObjectUtil.isNotEmpty(menuDTO.getComponentName()) ? menuDTO.getComponentName() : menuDTO.getTitle());
+ // 一级目录需要加斜杠,不然会报警告
+ menuVo.setPath(menuDTO.getPid() == null ? "/" + menuDTO.getPath() :menuDTO.getPath());
+ menuVo.setHidden(menuDTO.getHidden());
+ // 如果不是外链
+ if(!menuDTO.getIFrame()){
+ if(menuDTO.getPid() == null){
+ menuVo.setComponent(StringUtils.isEmpty(menuDTO.getComponent())?"Layout":menuDTO.getComponent());
+ // 如果不是一级菜单,并且菜单类型为目录,则代表是多级菜单
+ }else if(menuDTO.getType() == 0){
+ menuVo.setComponent(StringUtils.isEmpty(menuDTO.getComponent())?"ParentView":menuDTO.getComponent());
+ }else if(StringUtils.isNoneBlank(menuDTO.getComponent())){
+ menuVo.setComponent(menuDTO.getComponent());
+ }
+ }
+ menuVo.setMeta(new MenuMetaVo(menuDTO.getTitle(),menuDTO.getIcon(),!menuDTO.getCache()));
+ if(CollectionUtil.isNotEmpty(menuDtoList)){
+ menuVo.setAlwaysShow(true);
+ menuVo.setRedirect("noredirect");
+ menuVo.setChildren(buildMenus(menuDtoList));
+ // 处理是一级菜单并且没有子菜单的情况
+ } else if(menuDTO.getPid() == null){
+ MenuVo menuVo1 = new MenuVo();
+ menuVo1.setMeta(menuVo.getMeta());
+ // 非外链
+ if(!menuDTO.getIFrame()){
+ menuVo1.setPath("index");
+ menuVo1.setName(menuVo.getName());
+ menuVo1.setComponent(menuVo.getComponent());
+ } else {
+ menuVo1.setPath(menuDTO.getPath());
+ }
+ menuVo.setName(null);
+ menuVo.setMeta(null);
+ menuVo.setComponent("Layout");
+ List<MenuVo> list1 = new ArrayList<>();
+ list1.add(menuVo1);
+ menuVo.setChildren(list1);
+ }
+ list.add(menuVo);
+ }
+ }
+ );
+ return list;
+ }
+
+ @Override
+ public Menu findOne(Long id) {
+ Menu menu = menuRepository.findById(id).orElseGet(Menu::new);
+ ValidationUtil.isNull(menu.getId(),"Menu","id",id);
+ return menu;
+ }
+
+ @Override
+ public void download(List<MenuDto> menuDtos, HttpServletResponse response) throws IOException {
+ List<Map<String, Object>> list = new ArrayList<>();
+ for (MenuDto menuDTO : menuDtos) {
+ Map<String,Object> map = new LinkedHashMap<>();
+ map.put("菜单标题", menuDTO.getTitle());
+ map.put("菜单类型", menuDTO.getType() == null ? "目录" : menuDTO.getType() == 1 ? "菜单" : "按钮");
+ map.put("权限标识", menuDTO.getPermission());
+ map.put("外链菜单", menuDTO.getIFrame() ? "是" : "否");
+ map.put("菜单可见", menuDTO.getHidden() ? "否" : "是");
+ map.put("是否缓存", menuDTO.getCache() ? "是" : "否");
+ map.put("创建日期", menuDTO.getCreateTime());
+ list.add(map);
+ }
+ FileUtil.downloadExcel(list, response);
+ }
+
+ private void updateSubCnt(Long menuId){
+ if(menuId != null){
+ int count = menuRepository.countByPid(menuId);
+ menuRepository.updateSubCntById(count, menuId);
+ }
+ }
+
+ /**
+ * 清理缓存
+ * @param id 菜单ID
+ */
+ public void delCaches(Long id){
+ List<User> users = userRepository.findByMenuId(id);
+ redisUtils.del(CacheKey.MENU_ID + id);
+ redisUtils.delByKeys(CacheKey.MENU_USER, users.stream().map(User::getId).collect(Collectors.toSet()));
+ // 清除 Role 缓存
+ List<Role> roles = roleService.findInMenuId(new ArrayList<Long>(){{
+ add(id);
+ }});
+ redisUtils.delByKeys(CacheKey.ROLE_ID, roles.stream().map(Role::getId).collect(Collectors.toSet()));
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MonitorServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MonitorServiceImpl.java
new file mode 100644
index 0000000..c279293
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MonitorServiceImpl.java
@@ -0,0 +1,186 @@
+/*
+ * 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.impl;
+
+import cn.hutool.core.date.BetweenFormater;
+import cn.hutool.core.date.DateUtil;
+import com.example.modules.system.service.MonitorService;
+import com.example.utils.ElAdminConstant;
+import com.example.utils.FileUtil;
+import com.example.utils.StringUtils;
+import org.springframework.stereotype.Service;
+import oshi.SystemInfo;
+import oshi.hardware.*;
+import oshi.software.os.FileSystem;
+import oshi.software.os.OSFileStore;
+import oshi.software.os.OperatingSystem;
+import oshi.util.FormatUtil;
+import oshi.util.Util;
+import java.lang.management.ManagementFactory;
+import java.text.DecimalFormat;
+import java.util.*;
+
+/**
+*
+* 2020-05-02
+*/
+@Service
+public class MonitorServiceImpl implements MonitorService {
+
+ private final DecimalFormat df = new DecimalFormat("0.00");
+
+ @Override
+ public Map<String,Object> getServers(){
+ Map<String, Object> resultMap = new LinkedHashMap<>(8);
+ try {
+ SystemInfo si = new SystemInfo();
+ OperatingSystem os = si.getOperatingSystem();
+ HardwareAbstractionLayer hal = si.getHardware();
+ // 系统信息
+ resultMap.put("sys", getSystemInfo(os));
+ // cpu 信息
+ resultMap.put("cpu", getCpuInfo(hal.getProcessor()));
+ // 内存信息
+ resultMap.put("memory", getMemoryInfo(hal.getMemory()));
+ // 交换区信息
+ resultMap.put("swap", getSwapInfo(hal.getMemory()));
+ // 磁盘
+ resultMap.put("disk", getDiskInfo(os));
+ resultMap.put("time", DateUtil.format(new Date(), "HH:mm:ss"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return resultMap;
+ }
+
+ /**
+ * 获取磁盘信息
+ * @return /
+ */
+ private Map<String,Object> getDiskInfo(OperatingSystem os) {
+ Map<String,Object> diskInfo = new LinkedHashMap<>();
+ FileSystem fileSystem = os.getFileSystem();
+ List<OSFileStore> fsArray = fileSystem.getFileStores();
+ String osName = System.getProperty("os.name");
+ long available = 0, total = 0;
+ for (OSFileStore fs : fsArray){
+ // windows 需要将所有磁盘分区累加,linux 和 mac 直接累加会出现磁盘重复的问题,待修复
+ if(osName.toLowerCase().startsWith(ElAdminConstant.WIN)) {
+ available += fs.getUsableSpace();
+ total += fs.getTotalSpace();
+ } else {
+ available = fs.getUsableSpace();
+ total = fs.getTotalSpace();
+ break;
+ }
+ }
+ long used = total - available;
+ diskInfo.put("total", total > 0 ? FileUtil.getSize(total) : "?");
+ diskInfo.put("available", FileUtil.getSize(available));
+ diskInfo.put("used", FileUtil.getSize(used));
+ if(total != 0){
+ diskInfo.put("usageRate", df.format(used/(double)total * 100));
+ } else {
+ diskInfo.put("usageRate", 0);
+ }
+ return diskInfo;
+ }
+
+ /**
+ * 获取交换区信息
+ * @param memory /
+ * @return /
+ */
+ private Map<String,Object> getSwapInfo(GlobalMemory memory) {
+ Map<String,Object> swapInfo = new LinkedHashMap<>();
+ VirtualMemory virtualMemory = memory.getVirtualMemory();
+ long total = virtualMemory.getSwapTotal();
+ long used = virtualMemory.getSwapUsed();
+ swapInfo.put("total", FormatUtil.formatBytes(total));
+ swapInfo.put("used", FormatUtil.formatBytes(used));
+ swapInfo.put("available", FormatUtil.formatBytes(total - used));
+ if(used == 0){
+ swapInfo.put("usageRate", 0);
+ } else {
+ swapInfo.put("usageRate", df.format(used/(double)total * 100));
+ }
+ return swapInfo;
+ }
+
+ /**
+ * 获取内存信息
+ * @param memory /
+ * @return /
+ */
+ private Map<String,Object> getMemoryInfo(GlobalMemory memory) {
+ Map<String,Object> memoryInfo = new LinkedHashMap<>();
+ memoryInfo.put("total", FormatUtil.formatBytes(memory.getTotal()));
+ memoryInfo.put("available", FormatUtil.formatBytes(memory.getAvailable()));
+ memoryInfo.put("used", FormatUtil.formatBytes(memory.getTotal() - memory.getAvailable()));
+ memoryInfo.put("usageRate", df.format((memory.getTotal() - memory.getAvailable())/(double)memory.getTotal() * 100));
+ return memoryInfo;
+ }
+
+ /**
+ * 获取Cpu相关信息
+ * @param processor /
+ * @return /
+ */
+ private Map<String,Object> getCpuInfo(CentralProcessor processor) {
+ Map<String,Object> cpuInfo = new LinkedHashMap<>();
+ cpuInfo.put("name", processor.getProcessorIdentifier().getName());
+ cpuInfo.put("package", processor.getPhysicalPackageCount() + "个物理CPU");
+ cpuInfo.put("core", processor.getPhysicalProcessorCount() + "个物理核心");
+ cpuInfo.put("coreNumber", processor.getPhysicalProcessorCount());
+ cpuInfo.put("logic", processor.getLogicalProcessorCount() + "个逻辑CPU");
+ // CPU信息
+ long[] prevTicks = processor.getSystemCpuLoadTicks();
+ // 等待1秒...
+ Util.sleep(1000);
+ long[] ticks = processor.getSystemCpuLoadTicks();
+ long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
+ long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
+ long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
+ long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
+ long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
+ long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
+ long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
+ long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
+ long totalCpu = user + nice + sys + idle + iowait + irq + softirq + steal;
+ cpuInfo.put("used", df.format(100d * user / totalCpu + 100d * sys / totalCpu));
+ cpuInfo.put("idle", df.format(100d * idle / totalCpu));
+ return cpuInfo;
+ }
+
+ /**
+ * 获取系统相关信息,系统、运行天数、系统IP
+ * @param os /
+ * @return /
+ */
+ private Map<String,Object> getSystemInfo(OperatingSystem os){
+ Map<String,Object> systemInfo = new LinkedHashMap<>();
+ // jvm 运行时间
+ long time = ManagementFactory.getRuntimeMXBean().getStartTime();
+ Date date = new Date(time);
+ // 计算项目运行时间
+ String formatBetween = DateUtil.formatBetween(date, new Date(),BetweenFormater.Level.HOUR);
+ // 系统信息
+ systemInfo.put("os", os.toString());
+ systemInfo.put("day", formatBetween);
+ systemInfo.put("ip", StringUtils.getLocalIp());
+ return systemInfo;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/RoleServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/RoleServiceImpl.java
new file mode 100644
index 0000000..4a54a8c
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/RoleServiceImpl.java
@@ -0,0 +1,227 @@
+/*
+ * 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.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.example.modules.system.domain.Menu;
+import com.example.modules.system.domain.Role;
+import com.example.modules.system.domain.User;
+import com.example.modules.system.service.dto.RoleDto;
+import com.example.modules.system.service.dto.RoleQueryCriteria;
+import com.example.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.example.exception.BadRequestException;
+import com.example.modules.security.service.UserCacheClean;
+import com.example.exception.EntityExistException;
+import com.example.modules.system.repository.RoleRepository;
+import com.example.modules.system.repository.UserRepository;
+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.mapstruct.RoleMapper;
+import com.example.modules.system.service.mapstruct.RoleSmallMapper;
+import com.example.utils.*;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * 2018-12-03
+ */
+@Service
+@RequiredArgsConstructor
+@CacheConfig(cacheNames = "role")
+public class RoleServiceImpl implements RoleService {
+
+ private final RoleRepository roleRepository;
+ private final RoleMapper roleMapper;
+ private final RoleSmallMapper roleSmallMapper;
+ private final RedisUtils redisUtils;
+ private final UserRepository userRepository;
+ private final UserCacheClean userCacheClean;
+
+ @Override
+ public List<RoleDto> queryAll() {
+ Sort sort = Sort.by(Sort.Direction.ASC, "level");
+ return roleMapper.toDto(roleRepository.findAll(sort));
+ }
+
+ @Override
+ public List<RoleDto> queryAll(RoleQueryCriteria criteria) {
+ return roleMapper.toDto(roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
+ }
+
+ @Override
+ public Object queryAll(RoleQueryCriteria criteria, Pageable pageable) {
+ Page<Role> page = roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
+ return PageUtil.toPage(page.map(roleMapper::toDto));
+ }
+
+ @Override
+ @Cacheable(key = "'id:' + #p0")
+ @Transactional(rollbackFor = Exception.class)
+ public RoleDto findById(long id) {
+ Role role = roleRepository.findById(id).orElseGet(Role::new);
+ ValidationUtil.isNull(role.getId(), "Role", "id", id);
+ return roleMapper.toDto(role);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void create(Role resources) {
+ if (roleRepository.findByName(resources.getName()) != null) {
+ throw new EntityExistException(Role.class, "username", resources.getName());
+ }
+ roleRepository.save(resources);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void update(Role resources) {
+ Role role = roleRepository.findById(resources.getId()).orElseGet(Role::new);
+ ValidationUtil.isNull(role.getId(), "Role", "id", resources.getId());
+
+ Role role1 = roleRepository.findByName(resources.getName());
+
+ if (role1 != null && !role1.getId().equals(role.getId())) {
+ throw new EntityExistException(Role.class, "username", resources.getName());
+ }
+ role.setName(resources.getName());
+ role.setDescription(resources.getDescription());
+ role.setDataScope(resources.getDataScope());
+ role.setDepts(resources.getDepts());
+ role.setLevel(resources.getLevel());
+ roleRepository.save(role);
+ // 更新相关缓存
+ delCaches(role.getId(), null);
+ }
+
+ @Override
+ public void updateMenu(Role resources, RoleDto roleDTO) {
+ Role role = roleMapper.toEntity(roleDTO);
+ List<User> users = userRepository.findByRoleId(role.getId());
+ // 更新菜单
+ role.setMenus(resources.getMenus());
+ delCaches(resources.getId(), users);
+ roleRepository.save(role);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void untiedMenu(Long menuId) {
+ // 更新菜单
+ roleRepository.untiedMenu(menuId);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void delete(Set<Long> ids) {
+ for (Long id : ids) {
+ // 更新相关缓存
+ delCaches(id, null);
+ }
+ roleRepository.deleteAllByIdIn(ids);
+ }
+
+ @Override
+ public List<RoleSmallDto> findByUsersId(Long id) {
+ return roleSmallMapper.toDto(new ArrayList<>(roleRepository.findByUserId(id)));
+ }
+
+ @Override
+ public Integer findByRoles(Set<Role> roles) {
+ if (roles.size() == 0) {
+ return Integer.MAX_VALUE;
+ }
+ Set<RoleDto> roleDtos = new HashSet<>();
+ for (Role role : roles) {
+ roleDtos.add(findById(role.getId()));
+ }
+ return Collections.min(roleDtos.stream().map(RoleDto::getLevel).collect(Collectors.toList()));
+ }
+
+ @Override
+ @Cacheable(key = "'auth:' + #p0.id")
+ public List<GrantedAuthority> mapToGrantedAuthorities(UserDto user) {
+ Set<String> permissions = new HashSet<>();
+ // 如果是管理员直接返回
+ if (user.getIsAdmin()) {
+ permissions.add("admin");
+ return permissions.stream().map(SimpleGrantedAuthority::new)
+ .collect(Collectors.toList());
+ }
+ Set<Role> roles = roleRepository.findByUserId(user.getId());
+ permissions = roles.stream().flatMap(role -> role.getMenus().stream())
+ .filter(menu -> StringUtils.isNotBlank(menu.getPermission()))
+ .map(Menu::getPermission).collect(Collectors.toSet());
+ return permissions.stream().map(SimpleGrantedAuthority::new)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void download(List<RoleDto> roles, HttpServletResponse response) throws IOException {
+ List<Map<String, Object>> list = new ArrayList<>();
+ for (RoleDto role : roles) {
+ Map<String, Object> map = new LinkedHashMap<>();
+ map.put("角色名称", role.getName());
+ map.put("角色级别", role.getLevel());
+ map.put("描述", role.getDescription());
+ map.put("创建日期", role.getCreateTime());
+ list.add(map);
+ }
+ FileUtil.downloadExcel(list, response);
+ }
+
+ @Override
+ public void verification(Set<Long> ids) {
+ if (userRepository.countByRoles(ids) > 0) {
+ throw new BadRequestException("所选角色存在用户关联,请解除关联再试!");
+ }
+ }
+
+ @Override
+ public List<Role> findInMenuId(List<Long> menuIds) {
+ return roleRepository.findInMenuId(menuIds);
+ }
+
+ /**
+ * 清理缓存
+ * @param id /
+ */
+ public void delCaches(Long id, List<User> users) {
+ users = CollectionUtil.isEmpty(users) ? userRepository.findByRoleId(id) : users;
+ if (CollectionUtil.isNotEmpty(users)) {
+ users.forEach(item -> userCacheClean.cleanUserCache(item.getUsername()));
+ Set<Long> userIds = users.stream().map(User::getId).collect(Collectors.toSet());
+ redisUtils.delByKeys(CacheKey.DATA_USER, userIds);
+ redisUtils.delByKeys(CacheKey.MENU_USER, userIds);
+ redisUtils.delByKeys(CacheKey.ROLE_AUTH, userIds);
+ }
+ redisUtils.del(CacheKey.ROLE_ID + id);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/UserServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..6b86b77
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/UserServiceImpl.java
@@ -0,0 +1,255 @@
+/*
+ * 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.impl;
+
+import com.example.modules.system.domain.User;
+import com.example.modules.system.service.UserService;
+import com.example.modules.system.service.dto.JobSmallDto;
+import com.example.modules.system.service.dto.UserQueryCriteria;
+import com.example.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.example.config.FileProperties;
+import com.example.exception.BadRequestException;
+import com.example.modules.security.service.OnlineUserService;
+import com.example.modules.security.service.UserCacheClean;
+import com.example.exception.EntityExistException;
+import com.example.exception.EntityNotFoundException;
+import com.example.modules.system.repository.UserRepository;
+import com.example.modules.system.service.dto.RoleSmallDto;
+import com.example.modules.system.service.dto.UserDto;
+import com.example.modules.system.service.mapstruct.UserMapper;
+import com.example.utils.*;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.constraints.NotBlank;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+@Service
+@RequiredArgsConstructor
+@CacheConfig(cacheNames = "user")
+public class UserServiceImpl implements UserService {
+
+ private final UserRepository userRepository;
+ private final UserMapper userMapper;
+ private final FileProperties properties;
+ private final RedisUtils redisUtils;
+ private final UserCacheClean userCacheClean;
+ private final OnlineUserService onlineUserService;
+
+ @Override
+ public Object queryAll(UserQueryCriteria criteria, Pageable pageable) {
+ Page<User> page = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
+ return PageUtil.toPage(page.map(userMapper::toDto));
+ }
+
+ @Override
+ public List<UserDto> queryAll(UserQueryCriteria criteria) {
+ List<User> users = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder));
+ return userMapper.toDto(users);
+ }
+
+ @Override
+ @Cacheable(key = "'id:' + #p0")
+ @Transactional(rollbackFor = Exception.class)
+ public UserDto findById(long id) {
+ User user = userRepository.findById(id).orElseGet(User::new);
+ ValidationUtil.isNull(user.getId(), "User", "id", id);
+ return userMapper.toDto(user);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void create(User resources) {
+ if (userRepository.findByUsername(resources.getUsername()) != null) {
+ throw new EntityExistException(User.class, "username", resources.getUsername());
+ }
+ if (userRepository.findByEmail(resources.getEmail()) != null) {
+ throw new EntityExistException(User.class, "email", resources.getEmail());
+ }
+ if (userRepository.findByPhone(resources.getPhone()) != null) {
+ throw new EntityExistException(User.class, "phone", resources.getPhone());
+ }
+ userRepository.save(resources);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void update(User resources) throws Exception {
+ User user = userRepository.findById(resources.getId()).orElseGet(User::new);
+ ValidationUtil.isNull(user.getId(), "User", "id", resources.getId());
+ User user1 = userRepository.findByUsername(resources.getUsername());
+ User user2 = userRepository.findByEmail(resources.getEmail());
+ User user3 = userRepository.findByPhone(resources.getPhone());
+ if (user1 != null && !user.getId().equals(user1.getId())) {
+ throw new EntityExistException(User.class, "username", resources.getUsername());
+ }
+ if (user2 != null && !user.getId().equals(user2.getId())) {
+ throw new EntityExistException(User.class, "email", resources.getEmail());
+ }
+ if (user3 != null && !user.getId().equals(user3.getId())) {
+ throw new EntityExistException(User.class, "phone", resources.getPhone());
+ }
+ // 如果用户的角色改变
+ if (!resources.getRoles().equals(user.getRoles())) {
+ redisUtils.del(CacheKey.DATA_USER + resources.getId());
+ redisUtils.del(CacheKey.MENU_USER + resources.getId());
+ redisUtils.del(CacheKey.ROLE_AUTH + resources.getId());
+ }
+ // 如果用户被禁用,则清除用户登录信息
+ if(!resources.getEnabled()){
+ onlineUserService.kickOutForUsername(resources.getUsername());
+ }
+ user.setUsername(resources.getUsername());
+ user.setEmail(resources.getEmail());
+ user.setEnabled(resources.getEnabled());
+ user.setRoles(resources.getRoles());
+ user.setDept(resources.getDept());
+ user.setJobs(resources.getJobs());
+ user.setPhone(resources.getPhone());
+ user.setNickName(resources.getNickName());
+ user.setGender(resources.getGender());
+ userRepository.save(user);
+ // 清除缓存
+ delCaches(user.getId(), user.getUsername());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateCenter(User resources) {
+ User user = userRepository.findById(resources.getId()).orElseGet(User::new);
+ User user1 = userRepository.findByPhone(resources.getPhone());
+ if (user1 != null && !user.getId().equals(user1.getId())) {
+ throw new EntityExistException(User.class, "phone", resources.getPhone());
+ }
+ user.setNickName(resources.getNickName());
+ user.setPhone(resources.getPhone());
+ user.setGender(resources.getGender());
+ userRepository.save(user);
+ // 清理缓存
+ delCaches(user.getId(), user.getUsername());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void delete(Set<Long> ids) {
+ for (Long id : ids) {
+ // 清理缓存
+ UserDto user = findById(id);
+ delCaches(user.getId(), user.getUsername());
+ }
+ userRepository.deleteAllByIdIn(ids);
+ }
+
+ @Override
+ public UserDto findByName(String userName) {
+ User user = userRepository.findByUsername(userName);
+ if (user == null) {
+ throw new EntityNotFoundException(User.class, "name", userName);
+ } else {
+ return userMapper.toDto(user);
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updatePass(String username, String pass) {
+ userRepository.updatePass(username, pass, new Date());
+ flushCache(username);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Map<String, String> updateAvatar(MultipartFile multipartFile) {
+ // 文件大小验证
+ FileUtil.checkSize(properties.getAvatarMaxSize(), multipartFile.getSize());
+ // 验证文件上传的格式
+ String image = "gif jpg png jpeg";
+ String fileType = FileUtil.getExtensionName(multipartFile.getOriginalFilename());
+ if(fileType != null && !image.contains(fileType)){
+ throw new BadRequestException("文件格式错误!, 仅支持 " + image +" 格式");
+ }
+ User user = userRepository.findByUsername(SecurityUtils.getCurrentUsername());
+ String oldPath = user.getAvatarPath();
+ File file = FileUtil.upload(multipartFile, properties.getPath().getAvatar());
+ user.setAvatarPath(Objects.requireNonNull(file).getPath());
+ user.setAvatarName(file.getName());
+ userRepository.save(user);
+ if (StringUtils.isNotBlank(oldPath)) {
+ FileUtil.del(oldPath);
+ }
+ @NotBlank String username = user.getUsername();
+ flushCache(username);
+ return new HashMap<String, String>(1) {{
+ put("avatar", file.getName());
+ }};
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateEmail(String username, String email) {
+ userRepository.updateEmail(username, email);
+ flushCache(username);
+ }
+
+ @Override
+ public void download(List<UserDto> queryAll, HttpServletResponse response) throws IOException {
+ List<Map<String, Object>> list = new ArrayList<>();
+ for (UserDto userDTO : queryAll) {
+ List<String> roles = userDTO.getRoles().stream().map(RoleSmallDto::getName).collect(Collectors.toList());
+ Map<String, Object> map = new LinkedHashMap<>();
+ map.put("用户名", userDTO.getUsername());
+ map.put("角色", roles);
+ map.put("部门", userDTO.getDept().getName());
+ map.put("岗位", userDTO.getJobs().stream().map(JobSmallDto::getName).collect(Collectors.toList()));
+ map.put("邮箱", userDTO.getEmail());
+ map.put("状态", userDTO.getEnabled() ? "启用" : "禁用");
+ map.put("手机号码", userDTO.getPhone());
+ map.put("修改密码的时间", userDTO.getPwdResetTime());
+ map.put("创建日期", userDTO.getCreateTime());
+ list.add(map);
+ }
+ FileUtil.downloadExcel(list, response);
+ }
+
+ /**
+ * 清理缓存
+ *
+ * @param id /
+ */
+ public void delCaches(Long id, String username) {
+ redisUtils.del(CacheKey.USER_ID + id);
+ flushCache(username);
+ }
+
+ /**
+ * 清理 登陆时 用户缓存信息
+ *
+ * @param username /
+ */
+ private void flushCache(String username) {
+ userCacheClean.cleanUserCache(username);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptMapper.java
new file mode 100644
index 0000000..25de23f
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptMapper.java
@@ -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.mapstruct;
+
+import com.example.modules.system.domain.Dept;
+import com.example.modules.system.service.dto.DeptDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+*
+* 2019-03-25
+*/
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface DeptMapper extends BaseMapper<DeptDto, Dept> {
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptSmallMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptSmallMapper.java
new file mode 100644
index 0000000..01b7c65
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptSmallMapper.java
@@ -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.mapstruct;
+
+import com.example.modules.system.domain.Dept;
+import com.example.modules.system.service.dto.DeptSmallDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+*
+* 2019-03-25
+*/
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface DeptSmallMapper extends BaseMapper<DeptSmallDto, Dept> {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictDetailMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictDetailMapper.java
new file mode 100644
index 0000000..42ad48c
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictDetailMapper.java
@@ -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.mapstruct;
+
+import com.example.modules.system.domain.DictDetail;
+import com.example.modules.system.service.dto.DictDetailDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+*
+* 2019-04-10
+*/
+@Mapper(componentModel = "spring", uses = {DictSmallMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface DictDetailMapper extends BaseMapper<DictDetailDto, DictDetail> {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictMapper.java
new file mode 100644
index 0000000..24b763e
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictMapper.java
@@ -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.mapstruct;
+
+import com.example.modules.system.domain.Dict;
+import com.example.modules.system.service.dto.DictDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+*
+* 2019-04-10
+*/
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface DictMapper extends BaseMapper<DictDto, Dict> {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictSmallMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictSmallMapper.java
new file mode 100644
index 0000000..8f05535
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictSmallMapper.java
@@ -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.mapstruct;
+
+import com.example.modules.system.domain.Dict;
+import com.example.modules.system.service.dto.DictSmallDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+*
+* 2019-04-10
+*/
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface DictSmallMapper extends BaseMapper<DictSmallDto, Dict> {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobMapper.java
new file mode 100644
index 0000000..90be895
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobMapper.java
@@ -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.mapstruct;
+
+import com.example.modules.system.domain.Job;
+import com.example.modules.system.service.dto.JobDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+*
+* 2019-03-29
+*/
+@Mapper(componentModel = "spring",uses = {DeptMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface JobMapper extends BaseMapper<JobDto, Job> {
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobSmallMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobSmallMapper.java
new file mode 100644
index 0000000..9a36c91
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobSmallMapper.java
@@ -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.mapstruct;
+
+import com.example.modules.system.domain.Job;
+import com.example.modules.system.service.dto.JobSmallDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+*
+* 2019-03-29
+*/
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface JobSmallMapper extends BaseMapper<JobSmallDto, Job> {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/MenuMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/MenuMapper.java
new file mode 100644
index 0000000..867cbf2
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/MenuMapper.java
@@ -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.mapstruct;
+
+import com.example.modules.system.domain.Menu;
+import com.example.modules.system.service.dto.MenuDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ *
+ * 2018-12-17
+ */
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface MenuMapper extends BaseMapper<MenuDto, Menu> {
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleMapper.java
new file mode 100644
index 0000000..929b14b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleMapper.java
@@ -0,0 +1,28 @@
+/*
+ * 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.mapstruct;
+
+import com.example.modules.system.domain.Role;
+import com.example.modules.system.service.dto.RoleDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+
+@Mapper(componentModel = "spring", uses = {MenuMapper.class, DeptMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface RoleMapper extends BaseMapper<RoleDto, Role> {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleSmallMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleSmallMapper.java
new file mode 100644
index 0000000..4d4ecff
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleSmallMapper.java
@@ -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.mapstruct;
+
+import com.example.modules.system.domain.Role;
+import com.example.modules.system.service.dto.RoleSmallDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ *
+ * 2019-5-23
+ */
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface RoleSmallMapper extends BaseMapper<RoleSmallDto, Role> {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/UserMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/UserMapper.java
new file mode 100644
index 0000000..68a45dd
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/UserMapper.java
@@ -0,0 +1,27 @@
+/*
+ * 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.mapstruct;
+
+import com.example.modules.system.domain.User;
+import com.example.modules.system.service.dto.UserDto;
+import com.example.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+
+@Mapper(componentModel = "spring",uses = {RoleMapper.class, DeptMapper.class, JobMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface UserMapper extends BaseMapper<UserDto, User> {
+}