diff --git a/bocloud.sms.booter/pom.xml b/bocloud.sms.booter/pom.xml new file mode 100644 index 0000000..ca19a22 --- /dev/null +++ b/bocloud.sms.booter/pom.xml @@ -0,0 +1,228 @@ + + + + bocloud.sms + com.bocloud + 6.5.0-LTS-SZ + + 4.0.0 + bocloud.sms.booter + ${bocloud.booter.version} + + + jakarta.platform + jakarta.jakartaee-api + 10.0.0 + provided + + + jakarta.servlet + jakarta.servlet-api + provided + + + org.slf4j + slf4j-api + 2.0.7 + + + + org.springframework.boot + spring-boot-starter-web + + + org.hibernate.validator + hibernate-validator + + + commons-logging + commons-logging + + + org.slf4j + slf4j-api + + + + + + com.bocloud + bocloud.sms.service + + + commons-logging + commons-logging + + + + + com.bocloud + bocloud.boot.common + + + commons-logging + commons-logging + + + org.slf4j + slf4j-api + + + + + com.bocloud + bocloud.cmp.core + ${bocloud.core.version} + + + com.freedom + megatron.microservice + + + org.springframework.boot + spring-boot-starter-websocket + + + org.springframework + spring-websocket + + + org.springframework + spring-messaging + + + jakarta.websocket + jakarta.websocket-api + 2.1.1 + + + org.apache.logging.log4j + log4j-core + 2.23.1 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + true + 21 + 21 + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + com.bocloud.sms.booter.Application + true + false + libs/ + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.6.1 + + + + copy-dependencies + + + jar + jar + runtime + ${project.build.directory}/libs + + + + + + + + + + + + + + + + + + + + + + + + + + + bocloud.booter.tomcat + + 6.5.0-LTS-SZ + + + + org.springframework.boot + spring-boot-starter-web + + + org.hibernate.validator + hibernate-validator + + + + + + + bocloud.booter.tongweb + + 6.5.0-LTS-SZ-TONGWEB + + + + com.tongweb + tongweb-embed + 7.0.E.2 + + + com.tongweb.springboot + tongweb-spring-boot-starter + 2.x.0.RELEASE + + + com.tongweb.springboot + tongweb-spring-boot-websocket + 2.x.0.RELEASE + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + org.hibernate.validator + hibernate-validator + + + + + + + \ No newline at end of file diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/Application.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/Application.java new file mode 100644 index 0000000..0646dda --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/Application.java @@ -0,0 +1,20 @@ +package com.bocloud.sms.booter; + +import org.springframework.amqp.rabbit.annotation.EnableRabbit; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * @author dmw + */ +@EnableRabbit +@EnableScheduling +@SpringBootApplication +@ComponentScan(value = {"com.bocloud", "com.megatron"}) +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/AccountCache.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/AccountCache.java new file mode 100644 index 0000000..08b0a9a --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/AccountCache.java @@ -0,0 +1,222 @@ +package com.bocloud.sms.booter.config; + +import java.util.List; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; + +import com.bocloud.sms.entity.ApiToken; +import com.bocloud.sms.entity.Role; +import com.bocloud.sms.entity.Tenant; +import com.bocloud.sms.entity.User; +import com.bocloud.sms.entity.UserGroup; +import com.bocloud.sms.repository.ApiTokenRepository; +import com.bocloud.sms.repository.RoleRepository; +import com.bocloud.sms.repository.TenantRepository; +import com.bocloud.sms.repository.UserGroupRepository; +import com.bocloud.sms.repository.UserRepository; +import com.megatron.common.model.RequestContext; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author tyl + * @since 2020/3/25 周三 14:06 + */ +@Component +@Slf4j +public class AccountCache implements InitializingBean { + + private final StringRedisTemplate redisTemplate; + private final TenantRepository tenantRepository; + private final UserRepository userRepository; + private final RoleRepository roleRepository; + private final UserGroupRepository userGroupRepository; + private final ApiTokenRepository apiTokenRepository; + private final ThreadPoolTaskExecutor taskExecutor; + + public AccountCache(StringRedisTemplate redisTemplate, TenantRepository tenantRepository, + UserRepository userRepository, RoleRepository roleRepository, UserGroupRepository userGroupRepository, + ApiTokenRepository apiTokenRepository, ThreadPoolTaskExecutor taskExecutor) { + this.redisTemplate = redisTemplate; + this.tenantRepository = tenantRepository; + this.userRepository = userRepository; + this.roleRepository = roleRepository; + this.userGroupRepository = userGroupRepository; + this.apiTokenRepository = apiTokenRepository; + this.taskExecutor = taskExecutor; + } + + public void putAccountCache(RequestContext.Catalog catalog, Long id, String account) { + String key = catalog.name() + "_" + id; + this.redisTemplate.opsForValue().set(key, account); + } + + public void putNameCache(RequestContext.Catalog catalog, Long id, String name) { + String key = catalog.name() + "_Name_" + id; + this.redisTemplate.opsForValue().set(key, name); + } + + public void putRoleCache(Long id, String name) { + this.redisTemplate.opsForValue().set("Role_Name_" + id, name); + } + + public void putUserGroupCache(Long id, String name) { + this.redisTemplate.opsForValue().set("Group_Name_" + id, name); + } + + public void putApiTokenCache(String token, String apis) { + this.redisTemplate.opsForValue().set("Api_Token_" + token, apis); + } + + /** + * 获取缓存中用户账号 + * + * @param id + * 用户id + * @return + */ + public String getUserAccount(Long id) { + return redisTemplate.opsForValue().get(RequestContext.Catalog.User.name() + "_" + id); + } + + /** + * 获取缓存中用户名称 + * + * @param id + * 用户id + * @return + */ + public String getUserName(Long id) { + return redisTemplate.opsForValue().get(RequestContext.Catalog.User.name() + "_Name_" + id); + } + + /** + * 获取缓存中租户账号 + * + * @param id + * 租户id + * @return + */ + public String getTenantAccount(Long id) { + return redisTemplate.opsForValue().get(RequestContext.Catalog.Tenant.name() + "_" + id); + } + + /** + * 获取缓存中租户名称 + * + * @param id + * 租户id + * @return + */ + public String getTenantName(Long id) { + return redisTemplate.opsForValue().get(RequestContext.Catalog.Tenant.name() + "_Name_" + id); + } + + /** + * 获取缓存中角色名称 + * + * @param id + * 租户id + * @return + */ + public String getRoleName(Long id) { + return redisTemplate.opsForValue().get("Role_Name_" + id); + } + + /** + * 获取缓存中用户组名称 + * + * @param id + * 租户id + * @return + */ + public String getUserGroupName(Long id) { + return redisTemplate.opsForValue().get("Group_Name_" + id); + } + + public String getApiToken(String api) { + return redisTemplate.opsForValue().get("Api_Token_" + api); + } + + @Override + public void afterPropertiesSet() { + taskExecutor.execute(this::addTenantCache); + taskExecutor.execute(this::addUserCache); + taskExecutor.execute(this::addRoleCache); + taskExecutor.execute(this::addUserGroupCache); + taskExecutor.execute(this::addApiTokenCache); + } + + public void addTenantCache() { + try { + List tenants = tenantRepository.listAll(); + // 缓存租户账号和租户名 + for (Tenant tenant : tenants) { + if (!tenant.getDeleted()) { + putAccountCache(RequestContext.Catalog.Tenant, tenant.getId(), tenant.getAccount()); + } + putNameCache(RequestContext.Catalog.Tenant, tenant.getId(), tenant.getName()); + } + } catch (Exception e) { + log.error("put tenant cache error,", e); + } + } + + public void addUserCache() { + try { + List users = userRepository.listAll(); + // 缓存用户账号和用户名 + for (User user : users) { + if (!user.getDeleted()) { + putAccountCache(RequestContext.Catalog.User, user.getId(), user.getAccount()); + } + putNameCache(RequestContext.Catalog.User, user.getId(), user.getName()); + } + } catch (Exception e) { + log.error("put user cache error,", e); + } + } + + public void addRoleCache() { + try { + List roles = roleRepository.list(); + // 缓存角色名 + for (Role role : roles) { + putRoleCache(role.getId(), role.getName()); + } + } catch (Exception e) { + log.error("put role cache error,", e); + } + } + + public void addUserGroupCache() { + try { + List groups = userGroupRepository.list(); + // 缓存角色名 + for (UserGroup group : groups) { + putUserGroupCache(group.getId(), group.getName()); + } + } catch (Exception e) { + log.error("put user group cache error,", e); + } + } + + public void addApiTokenCache() { + try { + List tokens = apiTokenRepository.listAll(); + // 缓存角色名 + for (ApiToken token : tokens) { + if (!token.getEnabled()) { + continue; + } + putApiTokenCache(token.getToken(), token.getApis()); + } + } catch (Exception e) { + log.error("put api token cache error,", e); + } + } + +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/DictCache.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/DictCache.java new file mode 100644 index 0000000..8d3c7e6 --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/DictCache.java @@ -0,0 +1,63 @@ +package com.bocloud.sms.booter.config; + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; + +import com.alibaba.fastjson.JSONObject; +import com.bocloud.sms.entity.Dictionary; +import com.bocloud.sms.interfaces.DictService; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author tyl + * @since 2020/3/25 周三 14:06 + */ +@Component +@Slf4j +public class DictCache implements InitializingBean { + + private final StringRedisTemplate redisTemplate; + private final DictService dictService; + private final ThreadPoolTaskExecutor taskExecutor; + + public DictCache(StringRedisTemplate redisTemplate, DictService dictService, ThreadPoolTaskExecutor taskExecutor) { + this.redisTemplate = redisTemplate; + this.dictService = dictService; + this.taskExecutor = taskExecutor; + } + + public void putCache(String code, String value) { + String key = Dictionary.class.getSimpleName() + "_" + code; + this.redisTemplate.opsForValue().set(key, value); + } + + @Override + public void afterPropertiesSet() { + taskExecutor.execute(this::addOsNamesCache); + taskExecutor.execute(this::addDataCenterCache); + } + + public void addOsNamesCache() { + try { + List list = dictService.getAllOsName(); + putCache("OS_CATEGORY_TASK", JSONObject.toJSONString(list)); + } catch (Exception e) { + log.error("put os name cache error,", e); + } + } + + public void addDataCenterCache() { + try { + Map map = dictService.getAllDataCenter(); + putCache("DATA_CENTER", JSONObject.toJSONString(map)); + } catch (Exception e) { + log.error("put data center cache error,", e); + } + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/RabbitMQConfiguration.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/RabbitMQConfiguration.java new file mode 100644 index 0000000..f1bc059 --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/RabbitMQConfiguration.java @@ -0,0 +1,155 @@ +package com.bocloud.sms.booter.config; + +import com.bocloud.cmp.boot.model.BoCloudExchange; +import com.bocloud.cmp.core.encrypt.AbstractEncryptHandler; +import com.bocloud.sms.booter.listener.BocloudMessageListener; +import com.megatron.common.utils.IDFactory; +import com.megatron.common.utils.MapTools; +import com.megatron.framework.core.CurrentService; +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitAdmin; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +import java.util.Map; + +/** + * rabbitmq配置类 + * + * @author wangyu + * @version 1.0 + * @since 2018年3月30日 + */ +@Configuration +public class RabbitMQConfiguration { + + private final ConnectionFactory connectionFactory; + private final Map arguments = MapTools.simpleMap("x-ha-policy", "all"); + + public RabbitMQConfiguration(ConnectionFactory connectionFactory) { + this.connectionFactory = connectionFactory; + } + + /** + * 声明主题交换机 + * + * @return 交换机 + */ + @Bean + public TopicExchange topicExchange() { + return new TopicExchange(BoCloudExchange.Default.TOPIC.getExchange(), true, true); + } + + /** + * 声明默认交换机 + * + * @return 交换机 + */ + @Bean + public DirectExchange defaultExchange() { + return new DirectExchange(BoCloudExchange.Default.DIRECT.getExchange(), true, true); + } + + @Bean + public Binding bindingMessageQueue(CurrentService service) { + return BindingBuilder.bind(declareMessageQueue(service)).to(topicExchange()).with("bocloud.message.queue.#"); + } + + @Bean + public MessageConverter messageConverter() { + return new Jackson2JsonMessageConverter(); + } + + @Bean + public Queue declareMessageQueue(CurrentService service) { + return new Queue("bocloud.message.queue.sms." + service.getToken(), true, false, true, arguments); + } + + /** + * 声明审计日志队列 + * + * @return 队列 + */ + @Bean + public Queue declareLogQueue() { + return new Queue("bocloud.log.queue", true, false, false, arguments); + } + + /** + * 声明通知消息队列 + * + * @return 队列 + */ + @Bean + public Queue declareNoticeQueue() { + return new Queue("event.notice.queue", true, false, false, arguments); + } + + @Bean + public Binding bindingNoticeQueue() { + return BindingBuilder.bind(declareNoticeQueue()).to(defaultExchange()).withQueueName(); + } + + @Bean + public Binding bindingLogQueue() { + return BindingBuilder.bind(declareLogQueue()).to(defaultExchange()).withQueueName(); + } + + @Bean + @ConditionalOnBean(AbstractEncryptHandler.class) + public Queue declareLicenseInstallQueue() { + return new Queue("license.install.queue." + IDFactory.instance().uuid(), true, false, true, arguments); + } + + @Bean + @ConditionalOnBean(AbstractEncryptHandler.class) + public Binding bindLicenseInstallQueue() { + return BindingBuilder.bind(declareLicenseInstallQueue()).to(defaultExchange()).with("license.install.queue"); + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public RabbitTemplate amqpTemplate() { + RabbitTemplate amqpTemplate = new RabbitTemplate(connectionFactory); + amqpTemplate.setMessageConverter(messageConverter()); + return amqpTemplate; + } + + @Bean + public RabbitAdmin rabbitAdmin() { + return new RabbitAdmin(amqpTemplate()); + } + + @Bean + public SimpleMessageListenerContainer autoMessageListener(CurrentService service, BocloudMessageListener bocloudMessageListener) { + SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); + container.setQueues(declareMessageQueue(service)); + // 设置确认模式自动确认 + container.setAcknowledgeMode(AcknowledgeMode.AUTO); + container.setMessageListener(bocloudMessageListener); + container.setAmqpAdmin(rabbitAdmin()); + container.setAutoStartup(true); + return container; + } + + @Bean + @ConditionalOnBean(AbstractEncryptHandler.class) + public SimpleMessageListenerContainer licenseInstallListener(AbstractEncryptHandler encryptHandler) { + SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); + // 设置确认模式自动确认 + container.setQueues(declareLicenseInstallQueue()); + container.setAcknowledgeMode(AcknowledgeMode.AUTO); + container.setMessageListener(encryptHandler); + container.setAmqpAdmin(rabbitAdmin()); + container.setAutoStartup(true); + return container; + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/SwaggerConfiguration.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/SwaggerConfiguration.java new file mode 100644 index 0000000..b9b8420 --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/SwaggerConfiguration.java @@ -0,0 +1,45 @@ +package com.bocloud.sms.booter.config; + +import cn.hutool.core.util.RandomUtil; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springdoc.core.customizers.GlobalOpenApiCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author dmw + */ +@Configuration +public class SwaggerConfiguration { + @Bean + public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() { + return openApi -> { + if (openApi.getTags() != null) { + openApi.getTags().forEach(tag -> { + Map map = new HashMap<>(); + map.put("x-order", RandomUtil.randomInt(0, 100)); + tag.setExtensions(map); + }); + } + if (openApi.getPaths() != null) { + openApi.addExtension("x-production", "BeyondCMP"); + openApi.getPaths().addExtension("x-sign", RandomUtil.randomInt(1, 100)); + } + }; + } + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info().title("系统管理服务API接口文档") + .version("6.5.0-LTS") + .description("系统管理服务API接口文档") + .termsOfService("https://www.bocloud.com") + .license(new License().name("Apache 2.0").url("https://www.bocloud.com"))); + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/WebInterceptorConfiguration.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/WebInterceptorConfiguration.java new file mode 100644 index 0000000..1c5d035 --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/WebInterceptorConfiguration.java @@ -0,0 +1,108 @@ +package com.bocloud.sms.booter.config; + +import com.bocloud.cmp.boot.config.PagerArgumentResolver; +import com.bocloud.cmp.boot.interceptor.AccessInterceptor; +import com.bocloud.cmp.boot.interceptor.LogInterceptor; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.megatron.framework.core.InterceptorBridge; +import com.megatron.framework.core.config.InterceptorConfiguration; +import com.megatron.framework.core.domain.InterceptorEntity; +import lombok.extern.slf4j.Slf4j; +import org.reflections.Reflections; +import org.reflections.scanners.Scanner; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.http.converter.ByteArrayHttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.stereotype.Component; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; + +import java.nio.charset.Charset; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * 拦截器配置类 + * + * @author wangyu + * @version 1.0 + * @since 2018年3月30日 + */ +@Slf4j +@Component +public class WebInterceptorConfiguration implements InterceptorConfiguration { + + private static final String[] ACCESS_EXCLUDES = new String[]{"/*/*.css", + "/*/*.js", "/*/*.png", "/*/*.jpg", "/*/*.jpeg", "/*.html", "/*/*.html", "/swagger-resources/**", + "/favicon.ico", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/v1/log/**", "/v1/logo", "/v1/configs", "/v1/*/login", + "/v1/logview", "/v1/logzip", "/status/**", "/v1/tokens", "/v1/config/captcha/install", "/v1/status/sid", + "/v1/config/license/install", "/v1/config/status/", "/v1/status/sids", "/status", "/status/db", + "/error", "/v1/*/info", "/v1/*/status", "/v1/config/**", "/v1/status/**", "/v1/config/license", + "/v3/api-docs/**", "/v1/autologin", "/v1/single/login"}; + private static final String[] LOG_EXCLUDES = new String[]{"/*/*.css", + "/*/*.js", "/*/*.png", "/*/*.jpg", "/*/*.jpeg", "/*.html", "/*/*.html", "/swagger-resources/**", "/favicon.ico", + "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/error", "/v3/api-docs/**"}; + private static final String[] INCLUDES = new String[]{"/**"}; + private final LogInterceptor logInterceptor; + private final AccessInterceptor accessInterceptor; + + @Autowired + public WebInterceptorConfiguration(AccessInterceptor accessInterceptor, LogInterceptor logInterceptor) { + this.logInterceptor = logInterceptor; + this.accessInterceptor = accessInterceptor; + } + + @Override + public InterceptorBridge buildBridge() { + log.info("start to build interceptor bridge ..."); + InterceptorEntity accessEntity = InterceptorEntity.builder().interceptor(accessInterceptor).includes(INCLUDES).excludes(ACCESS_EXCLUDES).order(0).build(); + InterceptorEntity auditLogEntity = InterceptorEntity.builder().interceptor(logInterceptor).includes(INCLUDES).excludes(LOG_EXCLUDES).order(1).build(); + + List interceptors = new ArrayList<>(); + interceptors.add(accessEntity); + interceptors.add(auditLogEntity); + + List resolvers = new ArrayList<>(); + resolvers.add(new PagerArgumentResolver()); + + List> converters = new ArrayList<>(); + converters.add(this.byteConverter()); + converters.add(this.jsonConverter()); + + InterceptorBridge bridge = new InterceptorBridge(); + bridge.setInterceptors(interceptors); + bridge.setResolvers(resolvers); + bridge.setMessageConverters(converters); + + log.info("build interceptor bridge success!!!"); + return bridge; + } + + private HttpMessageConverter byteConverter() { + return new ByteArrayHttpMessageConverter(); + } + + private HttpMessageConverter jsonConverter() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, true); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + Reflections reflections = new Reflections("com", new Scanner[0]); + Set> classSet = reflections.getTypesAnnotatedWith(JsonTypeName.class); + objectMapper.registerSubtypes(classSet); + objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); + + MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); + jackson2HttpMessageConverter.setDefaultCharset(Charset.defaultCharset()); + jackson2HttpMessageConverter.setObjectMapper(objectMapper); + jackson2HttpMessageConverter.setPrettyPrint(true); + jackson2HttpMessageConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON)); + return jackson2HttpMessageConverter; + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/WebSocketConfiguration.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/WebSocketConfiguration.java new file mode 100644 index 0000000..d13073e --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/WebSocketConfiguration.java @@ -0,0 +1,71 @@ +package com.bocloud.sms.booter.config; + +import com.bocloud.sms.booter.websocket.logview.LogViewHandler; +import com.bocloud.sms.booter.websocket.message.MessageHandler; +import com.bocloud.sms.booter.websocket.message.MessageInterceptor; +import com.bocloud.sms.booter.websocket.upload.UploadServiceHandler; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; +import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean; +import org.springframework.web.socket.server.support.DefaultHandshakeHandler; + +/** + * 拦截器配置类 + * + * @author tyl + * @version 1.0 + * @since 2021年3月25日 + */ +@Configuration +@EnableWebSocket +@RequiredArgsConstructor +public class WebSocketConfiguration implements WebSocketConfigurer { + + private final MessageInterceptor messageInterceptor; + private final MessageHandler messageHandler; + private final LogViewHandler logViewHandler; + private final UploadServiceHandler uploadServiceHandler; + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } + + @Bean + public DefaultHandshakeHandler handshakeHandler() { + return new DefaultHandshakeHandler(); + } + + @Bean + public ServletServerContainerFactoryBean createWebSocketContainer() { + ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); + container.setMaxTextMessageBufferSize(10240); + container.setMaxBinaryMessageBufferSize(5 * 1024 * 1024); + return container; + } + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + // 注册普通消息服务 + registry.addHandler(messageHandler, "/messageService").addInterceptors(messageInterceptor) + .setHandshakeHandler(handshakeHandler()).setAllowedOrigins("*"); + registry.addHandler(messageHandler, "/sockjs/messageService").addInterceptors(messageInterceptor) + .setHandshakeHandler(handshakeHandler()).setAllowedOrigins("*").withSockJS(); + // 注册日志查看消息服务 + registry.addHandler(logViewHandler, "/logViewService").addInterceptors(messageInterceptor) + .setHandshakeHandler(handshakeHandler()).setAllowedOrigins("*"); + registry.addHandler(logViewHandler, "/sockjs/logViewService").addInterceptors(messageInterceptor) + .setHandshakeHandler(handshakeHandler()).setAllowedOrigins("*").withSockJS(); + // 普通文件上传消息服务 + registry.addHandler(this.uploadServiceHandler, "/uploadService").addInterceptors(messageInterceptor) + .setHandshakeHandler(handshakeHandler()).setAllowedOrigins("*"); + registry.addHandler(this.uploadServiceHandler, "/sockjs/uploadService") + .addInterceptors(this.messageInterceptor).setHandshakeHandler(handshakeHandler()).setAllowedOrigins("*") + .withSockJS(); + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/WhiteApiCache.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/WhiteApiCache.java new file mode 100644 index 0000000..7c55615 --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/config/WhiteApiCache.java @@ -0,0 +1,39 @@ +package com.bocloud.sms.booter.config; + +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * api权限白名单设置 + * + * @author tyl + * @since 2021/3/9 18:10 + */ +@Component +public class WhiteApiCache implements InitializingBean { + private final StringRedisTemplate redisTemplate; + private final ThreadPoolTaskExecutor taskExecutor; + + public WhiteApiCache(StringRedisTemplate redisTemplate, ThreadPoolTaskExecutor taskExecutor) { + this.redisTemplate = redisTemplate; + this.taskExecutor = taskExecutor; + } + + + @Override + public void afterPropertiesSet() { + taskExecutor.execute(() -> { + //设置白名单 + List whiteList = Lists.newArrayList("^GET:/v1/users/permissions$", + "^GET:/v1/login/detail$", "^GET:/v1/messages$", "^GET:/v1/token$", + "^POST:/v1/users/logout$", "^POST:/v1/tenants/logout$", "^GET:/v1/config/license$", "^GET:/v1/roles/ids$"); + redisTemplate.opsForValue().set("permission_white", JSONObject.toJSONString(whiteList)); + }); + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/AdmissionController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/AdmissionController.java new file mode 100644 index 0000000..2239f2d --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/AdmissionController.java @@ -0,0 +1,107 @@ +package com.bocloud.sms.booter.controller; + +import com.bocloud.sms.entity.Admission; +import com.bocloud.sms.interfaces.AdmissionService; +import com.bocloud.sms.model.AdmissionModel; +import com.bocloud.sms.service.utils.AdmissionUtil; +import com.megatron.common.model.*; +import com.megatron.common.utils.Common; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * ip访问限制控制器 + * + * @author wangyu + * @version 4.2.1-SNAPSHOT + * @since 2019/11/12 + */ +@RestController +@RequestMapping("/v1/admissions") +@Tag(name = "IP限制管理") +public class AdmissionController { + + private final AdmissionService admissionService; + private final AdmissionUtil admissionUtil; + + public AdmissionController(AdmissionService admissionService, AdmissionUtil admissionUtil) { + this.admissionService = admissionService; + this.admissionUtil = admissionUtil; + } + + /** + * 获取IP访问限制列表 + * + * @param pager 分页参数 + * @return 分页数据 + */ + @Operation(summary = "查询IP访问限制列表") + @GetMapping + public GeneralResult> list(Pager pager) { + return admissionService.list(pager); + } + + /** + * 添加IP访问限制 + * + * @param admissionModel ip和类型 + * @return 是否添加成功 + */ + @Operation(summary = "创建IP访问限制") + @PostMapping + public Result create(@RequestBody AdmissionModel admissionModel, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + Assert.notNull(admissionModel, "请求参数不能为空"); + Result result = admissionService.create(admissionModel, requestContext); + if (result.isSuccess()) { + admissionUtil.refresh(); + } + return result; + } + + /** + * 删除IP访问限制 + * + * @param id 被删除的id + * @return 是否删除成功 + */ + @Operation(summary = "删除IP访问限制") + @DeleteMapping("/{id}") + public Result remove(@PathVariable(value = Common.ID) Long id) { + Result result = admissionService.remove(id); + if (result.isSuccess()) { + admissionUtil.refresh(); + } + return result; + } + + /** + * 查看IP访问限制详情 + * + * @param id 被查看的数据id + * @return id访问限制 + */ + @Operation(summary = "查看IP访问限制") + @GetMapping("/{id}") + public GeneralResult detail(@PathVariable(value = Common.ID) Long id) { + return admissionService.detail(id); + } + + /** + * 批量删除IP访问限制 + * + * @param ids 被删除的id列表 + * @return 删除结果 + */ + @Operation(summary = "批量删除IP访问限制") + @DeleteMapping + public Result batchRemove(@RequestBody List ids) { + return admissionService.batchRemove(ids); + } + +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/ApiTokenController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/ApiTokenController.java new file mode 100644 index 0000000..49c8ebe --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/ApiTokenController.java @@ -0,0 +1,85 @@ +package com.bocloud.sms.booter.controller; + +import com.bocloud.sms.entity.ApiToken; +import com.bocloud.sms.interfaces.ApiTokenService; +import com.megatron.common.model.GeneralResult; +import com.megatron.common.model.GridBean; +import com.megatron.common.model.Pager; +import com.megatron.common.model.RequestContext; +import com.megatron.common.utils.Common; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +/** + * api token访问限制控制器 + */ +@RestController +@RequestMapping("/v1/api/tokens") +@Tag(name = "API Token管理") +public class ApiTokenController { + + @Autowired + private ApiTokenService apiTokenService; + + @GetMapping("/check/{token}") + @Operation(summary = "查看API Token") + public GeneralResult detail(@PathVariable(value = Common.TOKEN) String token) { + return apiTokenService.get(token); + } + + /** + * 创建Token + * + * @param token + * @param context + * @return + */ + @PostMapping + @Operation(summary = "创建 ApiToken") + public GeneralResult create(@RequestBody ApiToken token, @Value(Common.REQ_CONTEXT) RequestContext context) { + return apiTokenService.create(token, context); + } + + /** + * 查询Api token列表 + * + * @param pager + * @param context + * @return + */ + @GetMapping + @Operation(summary = "查看API Token列表") + public GeneralResult> list(Pager pager, @Value(Common.REQ_CONTEXT) RequestContext context) { + return apiTokenService.list(pager, context); + } + + /** + * 修改Api token + * + * @param token + * @param context + * @return + */ + @PutMapping + @Operation(summary = "修改API Token") + public GeneralResult modify(@RequestBody ApiToken token, @Value(Common.REQ_CONTEXT) RequestContext context) { + return apiTokenService.modify(token, context); + } + + /** + * 移除Api Token + * + * @param id + * @param context + * @return + */ + @DeleteMapping("/{id}") + @Operation(summary = "移除Api Token") + public GeneralResult remove(@PathVariable(value = Common.ID) Long id, @Value(Common.REQ_CONTEXT) RequestContext context) { + return apiTokenService.remove(id, context); + } + +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/AutoLoginController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/AutoLoginController.java new file mode 100644 index 0000000..d100f38 --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/AutoLoginController.java @@ -0,0 +1,29 @@ +package com.bocloud.sms.booter.controller; + +import com.bocloud.sms.interfaces.AutoLoginService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.view.RedirectView; + +@RestController +@RequestMapping("/v1/autologin") +@Tag(name = "自动登录") +public class AutoLoginController { + + @Autowired + private AutoLoginService autoLoginService; + + @GetMapping() + @Operation(summary = "查看API Token") + public RedirectView autoLogin( + @RequestHeader(value = "x-forwarded-host", required = false) String host, + HttpServletRequest request) { + return autoLoginService.autoLogin(host, request); + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/BusinessController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/BusinessController.java new file mode 100644 index 0000000..a90d42b --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/BusinessController.java @@ -0,0 +1,221 @@ +package com.bocloud.sms.booter.controller; + +import com.bocloud.sms.entity.Business; +import com.bocloud.sms.entity.Project; +import com.bocloud.sms.interfaces.BusinessService; +import com.bocloud.sms.model.BusinessModel; +import com.megatron.common.model.*; +import com.megatron.common.utils.Common; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; + +import java.io.OutputStream; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * @author tyl + * @time 2020/6/3 周三 15:29 + */ +@RestController +@RequestMapping("/v1/bizs") +@Tag(name = "业务管理") +@Slf4j +public class BusinessController { + + private final BusinessService businessService; + + public BusinessController(BusinessService businessService) { + this.businessService = businessService; + } + + /** + * 查看业务列表 + * + * @param pager 分页参数 + * @return 分页查询数据 + */ + @Operation(summary = "查看业务列表") + @GetMapping + public GeneralResult> list(Pager pager, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return businessService.list(pager, requestContext); + } + + /** + * 添加业务 + * + * @param businessModel 要添加的业务 + * @param requestContext 请求上下文 + * @return 是否添加成功 + */ + @Operation(summary = "添加业务") + @PostMapping + public Result create(@RequestBody BusinessModel businessModel, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return businessService.create(businessModel, requestContext); + } + + /** + * 修改业务 + * + * @param id 被修改的业务id + * @param businessModel 修改的数据 + * @param requestContext 请求上下文 + * @return 修改结果 + */ + @Operation(summary = "修改业务") + @PutMapping("/{id}") + public Result modify(@PathVariable(value = Common.ID) Long id, + @RequestBody BusinessModel businessModel, @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return businessService.modify(id, businessModel, requestContext); + } + + /** + * 删除业务 + * + * @param id 被删除的业务id + * @param requestContext 请求上下文 + * @return 删除结果 + */ + @Operation(summary = "删除业务") + @DeleteMapping("/{id}") + public Result remove(@PathVariable(value = Common.ID) Long id, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return businessService.remove(id, requestContext); + } + + /** + * 批量删除业务 + * + * @param ids 被删除的业务id列表 + * @param requestContext 请求上下文 + * @return 删除结果 + */ + @Operation(summary = "批量删除业务") + @DeleteMapping + public Result batchRemove(@RequestBody List ids, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return businessService.batchRemove(ids, requestContext); + } + + /** + * 查看业务明细 + * + * @param id 被查看的业务id + * @return 业务实体类 + */ + @Operation(summary = "查看业务明细") + @GetMapping("/{id}") + public GeneralResult detail(@PathVariable(value = Common.ID) Long id) { + return businessService.detail(id); + } + + /** + * 查看业务下项目 + * + * @param id 业务id + * @return 项目列表 + */ + @Operation(summary = "查看业务下项目") + @GetMapping("/{id}/projects") + public GeneralResult> projects( + @PathVariable(value = Common.ID) Long id) { + return businessService.listBusinessProject(id); + } + + /** + * 配置业务项目 + * + * @param id 业务id + * @param projectIds 项目id列表 + * @return 配置结果 + */ + @Operation(summary = "配置业务项目") + @PatchMapping("/{id}") + public Result businessAction(@PathVariable(value = Common.ID) Long id, + @RequestBody List projectIds) { + return businessService.businessAction(id, projectIds); + } + + /** + * 导出业务列表 + * + * @param pager 分页参数 + * @param requestContext 上下文 + */ + @Deprecated + @Operation(summary = "导出项目列表") + @RequestMapping(value = "/export", method = {RequestMethod.GET}) + public void export(Pager pager, + @Value(Common.REQ_CONTEXT) RequestContext requestContext, HttpServletRequest request, + HttpServletResponse response) { + List paramList = pager.getParams(); + try { + XSSFWorkbook workbook = businessService.export(paramList, requestContext); + // 下载表格到浏览器 + response.setCharacterEncoding("utf-8"); + response.setContentType("application/octet-stream"); + String fileName = "业务统计数据" + System.currentTimeMillis() + ".xlsx"; + final String userAgent = request.getHeader("user-agent").toLowerCase(); + if (userAgent.contains("trident") || userAgent.contains("edge")) { + fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8); + } else { + fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); + } + response.setHeader("Content-Disposition", "attachment;fileName=" + fileName); + OutputStream os = response.getOutputStream(); + workbook.write(os); + os.flush(); + os.close(); + } catch (Exception e) { + log.error("export project error,", e); + } + } + + /** + * 下载业务列表模板 + * + * @param response 浏览器响应 + */ + @Operation(summary = "下载业务列表模板") + @RequestMapping(value = "/import/template", method = {RequestMethod.GET}) + public void importTemp(HttpServletResponse response) { + businessService.importTemp(response); + } + + /** + * 导入业务列表 + * + * @param requestContext 请求上下文 + * @param request 请求参数 + * @return 导入结果 + */ + @Operation(summary = "导入业务列表") + @PostMapping(value = "/import") + public Result importData(@Value(Common.REQ_CONTEXT) RequestContext requestContext, HttpServletRequest request) { + MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; + List fileList = multipartRequest.getFiles("file"); + if (fileList.isEmpty()) { + return new Result(false, "文件错误"); + } + MultipartFile multipartFile = fileList.get(0); + String originalFilename = multipartFile.getOriginalFilename(); + // 判断文件名 + if (originalFilename == null || !(originalFilename.endsWith(".xls") || originalFilename.endsWith(".xlsx"))) { + return new Result(false, "文件错误"); + } + return businessService.importData(multipartFile, requestContext); + } + +} + diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/ConfigController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/ConfigController.java new file mode 100644 index 0000000..c52e65f --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/ConfigController.java @@ -0,0 +1,167 @@ +package com.bocloud.sms.booter.controller; + +import com.alibaba.fastjson.JSONObject; +import com.bocloud.cmp.boot.model.BoCloudExchange; +import com.bocloud.sms.model.LicenseMask; +import com.megatron.common.http.HttpClient; +import com.megatron.common.model.GeneralResult; +import com.megatron.common.model.License; +import com.megatron.common.model.Result; +import com.megatron.common.utils.Common; +import com.megatron.framework.core.CurrentService; +import com.megatron.framework.license.LicenseDaemon; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +/** + * 服务节点信息 + * + * @author weiwei + */ +@Slf4j +@RestController +@RequestMapping("/v1") +@Tag(name = "服务节点信息管理") +public class ConfigController { + + private static final String LICENSE_SUCCESS = "证书激活成功"; + private static final String LICENSE_FAILED = "证书激活失败"; + private final LicenseDaemon licenseDaemon; + @Value("${service.host:127.0.0.1}") + private String host; + @Value("${server.port:18088}") + private String port; + @Autowired + private AmqpTemplate amqpTemplate; + + public ConfigController(CurrentService currentService) { + this.licenseDaemon = LicenseDaemon.instance(currentService); + } + + + /** + * 查询云管license信息 + * + * @return license信息 + */ + @Operation(summary = "查询云管license信息") + @GetMapping("/config/license") + public GeneralResult license() { + License license = licenseDaemon.content(); + return new GeneralResult<>(true, license, "查询成功"); + } + + /** + * 系统状态信息 + * + * @param value 系统url + * @return 系统状态信息 + */ + @Operation(summary = "系统状态信息") + @GetMapping("/config/status") + public GeneralResult status(@RequestParam(value = Common.VALUE) String value) { + HttpClient client = new HttpClient(); + String message = client.get(value).getMessage(); + return JSONObject.parseObject(message, GeneralResult.class); + } + + /** + * 安装证书 + * + * @param file 证书文件 + * @return 安装结果 + */ + @Operation(summary = "安装证书") + @PostMapping("/config/license/install") + public Result licenseInstall(@RequestParam("file") MultipartFile file) { + if (file.isEmpty()) { + return new Result(false, "证书为空!"); + } + Result result; + try { + result = licenseDaemon.verify(file.getBytes()); + if (result.isFailed()) { + log.error("证书校验失败"); + return new Result(false, LICENSE_FAILED); + } + result = licenseDaemon.install(file.getBytes()); + if (result.isSuccess()) { + return new Result(true, LICENSE_SUCCESS); + } + return new Result(false, LICENSE_FAILED); + } catch (IOException e) { + log.error("证书激活异常:", e); + return new Result(false, LICENSE_FAILED); + } + } + + /** + * 安装license验证码 + * + * @param licenseMask license验证码 + * @return 安装结果 + */ + @Operation(summary = "安装license验证码") + @PostMapping("/config/captcha/install") + public Result captchaInstall(@RequestBody LicenseMask licenseMask) { + try { + GeneralResult GeneralResult = licenseDaemon.decode(licenseMask.getLicenseMask()); + if (GeneralResult.isFailed()) { + log.error("证书激活码格式有误,激活失败!"); + return new Result(false, LICENSE_FAILED); + } + Result result = licenseDaemon.verify(GeneralResult.getData()); + if (result.isFailed()) { + log.error("证书格式不正确!"); + return new Result(false, LICENSE_FAILED); + } + result = licenseDaemon.install(GeneralResult.getData()); + if (result.isFailed()) { + log.error("证书安装失败"); + return new Result(false, LICENSE_FAILED); + } + amqpTemplate.convertAndSend(BoCloudExchange.Default.DIRECT.getExchange(), + "license.install.queue", LICENSE_SUCCESS); + return new Result(true, LICENSE_SUCCESS); + } catch (Exception e) { + log.error("证书激活异常!", e); + return new Result(false, LICENSE_FAILED); + } + } + + /** + * 系统sid信息 + * + * @return sid信息 + */ + @Operation(summary = "系统状态信息") + @GetMapping("/status/sid") + public GeneralResult getSid() { + HttpClient client = new HttpClient(); + String url = "http://" + host + ":" + port + "/status/sid"; + String message = client.get(url).getMessage(); + return JSONObject.parseObject(message, GeneralResult.class); + } + + /** + * 系统sid信息 + * + * @return sid信息列表 + */ + @Operation(summary = "系统状态信息") + @GetMapping("/status/sids") + public GeneralResult getSids() { + HttpClient client = new HttpClient(); + String url = "http://" + host + ":" + port + "/status/sids"; + String message = client.get(url).getMessage(); + return JSONObject.parseObject(message, GeneralResult.class); + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/DepartmentController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/DepartmentController.java new file mode 100644 index 0000000..353d23d --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/DepartmentController.java @@ -0,0 +1,117 @@ +package com.bocloud.sms.booter.controller; + +import com.bocloud.sms.entity.Department; +import com.bocloud.sms.entity.User; +import com.bocloud.sms.interfaces.DepartmentService; +import com.bocloud.sms.model.DepartmentModel; +import com.megatron.common.model.GeneralResult; +import com.megatron.common.model.RequestContext; +import com.megatron.common.model.Result; +import com.megatron.common.utils.Common; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 组织管理控制器 + * + * @author tyl + * @since 2021/03/25 + */ +@RestController +@RequestMapping("/v1/departments") +@Tag(name = "组织管理") +public class DepartmentController { + + private final DepartmentService departmentService; + + public DepartmentController(DepartmentService departmentService) { + this.departmentService = departmentService; + } + + /** + * 查询组织机构 + * + * @param parentId 父组织id + * @param requestContext 上下文 + * @return 组织机构列表 + */ + @GetMapping + @Operation(summary = "组织机构列表显示") + public GeneralResult> list(@RequestParam(value = Common.PARENTID) Long parentId, @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return departmentService.list(parentId, requestContext); + } + + /** + * 查询组织机构下的管理员 + * + * @param id 组织id + * @param requestContext 上下文 + * @return 管理员信息 + */ + @GetMapping("/{id}/managers") + @Operation(summary = "查询组织机构下的管理员") + public GeneralResult> listDeptManager(@PathVariable(value = Common.ID) Long id, RequestContext requestContext) { + return departmentService.listDeptManager(id, requestContext); + } + + /** + * 创建组织机构 + * + * @param department 组织 + * @param requestContext 上下文 + * @return 创建结果 + */ + @Operation(summary = "创建组织机构") + @PostMapping + public Result create(@RequestBody DepartmentModel department, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return departmentService.create(department, requestContext); + } + + /** + * 修改组织机构 + * + * @param id 组织id + * @param department 组织 + * @param requestContext 上下文 + * @return 修改结果 + */ + @Operation(summary = "修改组织机构") + @PutMapping("/{id}") + public Result modify(@PathVariable(value = Common.ID) Long id, + @RequestBody DepartmentModel department, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return departmentService.modify(id, department, requestContext); + } + + /** + * 删除组织机构 + * + * @param id 组织id + * @param requestContext 上下文 + * @return 删除结果 + */ + @Operation(summary = "删除组织机构") + @DeleteMapping("/{id}") + public Result remove(@PathVariable(value = Common.ID) Long id, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return departmentService.remove(id, requestContext); + } + + /** + * 查询组织机构详情 + * + * @param id 组织id + * @return 组织 + */ + @Operation(summary = "组织机构详情") + @GetMapping("/{id}") + public GeneralResult detail(@PathVariable(value = Common.ID) Long id) { + return departmentService.detail(id); + } + +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/DictController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/DictController.java new file mode 100644 index 0000000..0a57cdf --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/DictController.java @@ -0,0 +1,106 @@ +package com.bocloud.sms.booter.controller; + +import com.bocloud.sms.entity.Dictionary; +import com.bocloud.sms.interfaces.DictService; +import com.bocloud.sms.model.DictionaryBean; +import com.megatron.common.model.GeneralResult; +import com.megatron.common.model.Result; +import com.megatron.common.utils.Common; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 字典信息控制器 + * + * @author dmw + */ +@RestController +@RequestMapping("/v1/dictionaries") +@Tag(name = "字典信息管理") +public class DictController { + private final DictService dictService; + + public DictController(DictService dictService) { + this.dictService = dictService; + } + + @Operation(summary = "查询字典树列表") + @GetMapping + public GeneralResult> list(@RequestParam(value = "pid", required = false) Long pid) { + return dictService.list(pid); + } + + @Operation(summary = "根据id查询字典") + @GetMapping("/{id}") + public GeneralResult detail(@PathVariable(value = "id") Long id) { + return dictService.detail(id); + } + + /** + * 根据字典值获取子节点列表 + * + * @param value 字典值 + * @return 子节点列表 + */ + @Operation(summary = "查询系统字典子信息") + @GetMapping("/children") + public GeneralResult> children(@RequestParam(value = Common.VALUE, required = false) String value, + @RequestParam(value = "pid", required = false) Long pid) { + return dictService.listChild(value, pid); + } + + /** + * 查询字典树 + * + * @param value 字典值 + * @return 字典树 + */ + @Operation(summary = "查询字典树") + @GetMapping("/children/tree") + public GeneralResult> childTree(@RequestParam(value = Common.VALUE, required = false) String value) { + return dictService.childTree(value); + } + + /** + * 创建 + * + * @param dictionary 字典数据 + * @return 创建结果 + */ + @Operation(summary = "新增字典") + @PostMapping + public GeneralResult create(@RequestBody Dictionary dictionary) { + return dictService.create(dictionary); + } + + /** + * 删除字典 + * + * @param id 字典id + * @return 删除结果 + */ + @Operation(summary = "删除字典") + @DeleteMapping("/{id}") + public Result remove(@PathVariable(value = Common.ID) Long id) { + return dictService.remove(id); + } + + /** + * 修改字典 + * + * @param id 字典id + * @param bean 字典 + * @return 修改结果 + */ + @Operation(summary = "修改字典") + @PutMapping("/{id}") + public GeneralResult modify(@PathVariable(value = Common.ID) Long id, + @RequestBody DictionaryBean bean) { + bean.setId(id); + return dictService.modify(bean); + } + +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/DispatchController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/DispatchController.java new file mode 100644 index 0000000..9fbbb91 --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/DispatchController.java @@ -0,0 +1,96 @@ +package com.bocloud.sms.booter.controller; + +import com.auth0.jwt.interfaces.Claim; +import com.bocloud.sms.entity.SystemConfig; +import com.bocloud.sms.repository.SystemConfigRepository; +import com.megatron.common.utils.Common; +import com.megatron.common.utils.Tokens; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.util.Objects; +import java.util.Optional; + +/** + * @author tyl + * {@code @time} 2020/4/24 周五 20:02 + */ +@Slf4j +@Controller +@RequestMapping +@Tag(name = "跳转控制") +public class DispatchController { + + private final SystemConfigRepository configRepository; + private final StringRedisTemplate redisTemplate; + + + public DispatchController(SystemConfigRepository systemConfigService, StringRedisTemplate redisTemplate) { + this.configRepository = systemConfigService; + this.redisTemplate = redisTemplate; + } + + /** + * 单点登录跳转接口 + * + * @param request 浏览器请求 + * @param response 浏览器响应 + * @throws Exception 出现的异常 + */ + + @RequestMapping("/v1/redirect") + @Operation(summary = "单点登录跳转") + public void redirect(HttpServletRequest request, HttpServletResponse response) throws Exception { + //获取登录地址 + String target = request.getParameter("target"); + String redirectParameter = request.getParameter("redirect"); + SystemConfig config; + if (target == null || "Manager".equals(target)) { + config = configRepository.queryByCode("ManagerAddress"); + } else { + config = configRepository.queryByCode("TenantAddress"); + } + String loginAddress = config.getValue(); + log.info("#######debuge########the request url is {}", request.getRequestURL() + "?" + request.getQueryString()); + log.info("#######debuge########the redirect url is {}", redirectParameter); + String redirect = Optional.ofNullable(redirectParameter).orElse(loginAddress + "/#/"); + String token = request.getParameter("token"); + log.info("#######debuge########the redirect token is {}", token); + Claim claim = Tokens.parse(token); + if (!Objects.isNull(claim)) { + String catalog = claim.asMap().get("catalog").toString(); + long uuid = Long.parseLong(claim.asMap().get(Common.UUID).toString()); + String tokenKey = Common.TOKEN + "_" + catalog + "_" + uuid; + boolean checkResult = check(token, tokenKey); + if (checkResult) { + HttpSession session = request.getSession(); + session.setAttribute("redirect", redirect); + session.setAttribute(Common.TOKEN, token); + response.sendRedirect(loginAddress + "/#/sso"); + } else { + String replace = redirect.replace("#", "%23"); + response.sendRedirect(loginAddress + "/#/login?redirect=" + replace); + } + } else { + String replace = redirect.replace("#", "%23"); + response.sendRedirect(loginAddress + "/#/login?redirect=" + replace); + } + } + + private boolean check(String token, String tokenKey) { + String newTokenCache = (String) this.redisTemplate.opsForHash().get(tokenKey + "_n", Common.TOKEN); + String oldTokenCache = this.redisTemplate.opsForValue().get(tokenKey + "_o"); + if (token.equals(newTokenCache)) { + return true; + } else { + return token.equals(oldTokenCache); + } + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/EnvironmentController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/EnvironmentController.java new file mode 100644 index 0000000..fac6d92 --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/EnvironmentController.java @@ -0,0 +1,99 @@ +package com.bocloud.sms.booter.controller; + +import com.bocloud.sms.entity.Environment; +import com.bocloud.sms.interfaces.EnvironmentService; +import com.megatron.common.model.GeneralResult; +import com.megatron.common.model.GridBean; +import com.megatron.common.model.Pager; +import com.megatron.common.model.RequestContext; +import com.megatron.common.utils.Common; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +/** + * 环境实体类Controller + * + * @author wangshuai + * @version 4.1.0-SNAPSHOT + * @since 2018/12/24 + */ +@RestController +@RequestMapping("/v1/environments") +@Tag(name = "所属环境") +public class EnvironmentController { + private final EnvironmentService environmentService; + + public EnvironmentController(EnvironmentService environmentService) { + this.environmentService = environmentService; + } + + /** + * 查看环境列表 + * + * @param pager 分页参数 + * @return 环境列表 + */ + @Operation(summary = "获取所属环境列表") + @GetMapping + public GeneralResult> list(Pager pager, @Value(Common.REQ_CONTEXT) RequestContext context) { + return environmentService.list(pager, context); + } + + /** + * 添加环境 + * + * @param environment 环境 + * @param context 上下文 + * @return 添加结果 + */ + @Operation(summary = "添加所属环境") + @PostMapping + public GeneralResult create(@RequestBody Environment environment, + @Value(Common.REQ_CONTEXT) RequestContext context) { + return environmentService.create(environment, context); + } + + /** + * 修改环境 + * + * @param id 环境id + * @param environment 环境 + * @param context 上下文 + * @return 修改结果 + */ + @Operation(summary = "修改所属环境") + @PutMapping("/{id}") + public GeneralResult modify(@PathVariable(value = Common.ID) Long id, @RequestBody Environment environment, + @Value(Common.REQ_CONTEXT) RequestContext context) { + environment.setId(id); + return environmentService.modify(environment, context); + } + + /** + * 删除环境 + * + * @param id 环境id + * @param context 上下文 + * @return 删除结果 + */ + @Operation(summary = "删除所属环境") + @DeleteMapping("/{id}") + public GeneralResult remove(@PathVariable(value = Common.ID) Long id, + @Value(Common.REQ_CONTEXT) RequestContext context) { + return environmentService.remove(id, context); + } + + /** + * 查看环境明细 + * + * @param id 环境id + * @return 环境 + */ + @Operation(summary = "查看所属环境详情") + @GetMapping("/{id}") + public GeneralResult detail(@PathVariable(value = Common.ID) Long id) { + return environmentService.detail(id); + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/GlobalManConfigController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/GlobalManConfigController.java new file mode 100644 index 0000000..d214a76 --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/GlobalManConfigController.java @@ -0,0 +1,66 @@ +package com.bocloud.sms.booter.controller; + +import com.bocloud.sms.entity.GlobalManConfig; +import com.bocloud.sms.interfaces.GlobalManConfigService; +import com.megatron.common.model.*; +import com.megatron.common.utils.Common; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +/** + * @author wpj + * @since 2022/9/8 + */ +@RestController +@RequestMapping("/v1/global/config") +@Slf4j +@Tag(name = "全局运维配置") +public class GlobalManConfigController { + + private final GlobalManConfigService globalManConfigService; + + public GlobalManConfigController(GlobalManConfigService globalManConfigService) { + this.globalManConfigService = globalManConfigService; + } + + + @Operation(summary = "查询周期时间列表") + @GetMapping + public GeneralResult> list(Pager pager, @Value(Common.REQ_CONTEXT) RequestContext context) { + return globalManConfigService.list(pager, context); + } + + + @Operation(summary = "创建禁止周期时间") + @PostMapping + public Result create(@RequestBody GlobalManConfig globalManConfig, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return globalManConfigService.create(globalManConfig, requestContext); + } + + @Operation(summary = "修改禁止周期时间") + @PutMapping("/{id}") + public Result modify(@RequestBody GlobalManConfig globalManConfig, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return globalManConfigService.modify(globalManConfig, requestContext); + } + + + @Operation(summary = "删除禁止周期时间") + @DeleteMapping("/{id}") + public Result remove(@PathVariable(value = Common.ID) Long id, + @Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return globalManConfigService.remove(id, requestContext); + } + + + @Operation(summary = "查询当前全局配置是否被禁止") + @GetMapping("/isAllow") + public Result isAllow(@Value(Common.REQ_CONTEXT) RequestContext requestContext) { + return globalManConfigService.allow(requestContext); + } + +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/IconController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/IconController.java new file mode 100644 index 0000000..c01952e --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/IconController.java @@ -0,0 +1,66 @@ +package com.bocloud.sms.booter.controller; + +import com.bocloud.sms.entity.Icon; +import com.bocloud.sms.interfaces.IconService; +import com.megatron.common.model.GeneralResult; +import com.megatron.common.model.GridBean; +import com.megatron.common.model.Pager; +import com.megatron.common.model.RequestContext; +import com.megatron.common.utils.Common; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +/** + * 图标controller层 + * + * @author 胡立伟 + * @Version 1.0 + * @since 2020年4月7日 + */ +@RestController +@RequestMapping("/v1/icon") +@Tag(name = "图标管理") +public class IconController { + @Autowired + private IconService iconService; + + /** + * 图标列表查询 + * + * @return 图标列表 + */ + @GetMapping + @Operation(summary = "图标列表查询") + public GeneralResult> list(Pager pager, @Value(Common.REQ_CONTEXT) RequestContext context) { + return iconService.list(pager, context); + } + + /** + * 上传图标 + * + * @param files 图标文件 + * @param context 上下文 + * @return 上传结果 + */ + @PostMapping() + @Operation(summary = "上传图标") + public GeneralResult upload(MultipartFile[] files, String category, @Value(Common.REQ_CONTEXT) RequestContext context) { + return iconService.create(files, category, context); + } + + /** + * 删除图标 + * + * @param id 图标id + * @return 删除结果 + */ + @DeleteMapping(value = "/{id}") + @Operation(summary = "删除图标") + public GeneralResult remove(@PathVariable(value = Common.ID) Long id) { + return iconService.remove(id); + } +} diff --git a/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/LabelController.java b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/LabelController.java new file mode 100644 index 0000000..ae3e1e9 --- /dev/null +++ b/bocloud.sms.booter/src/main/java/com/bocloud/sms/booter/controller/LabelController.java @@ -0,0 +1,88 @@ +package com.bocloud.sms.booter.controller; + +import com.bocloud.sms.entity.Label; +import com.bocloud.sms.interfaces.LabelService; +import com.megatron.common.model.*; +import com.megatron.common.utils.Common; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +/** + * @author zhangdi + * @since 2018/7/2 + */ +@RestController +@RequestMapping("/v1/tags") +@Tag(name = "标签管理") +public class LabelController { + + private final LabelService labelService; + + public LabelController(LabelService labelService) { + this.labelService = labelService; + } + + /** + * 获取标签列表 + * + * @param pager 分页参数 + * @return 标签列表 + */ + @Operation(summary = "获取命名规则列表") + @GetMapping + public GeneralResult> list(Pager pager, @Value(Common.REQ_CONTEXT) RequestContext context) { + return labelService.list(pager, context); + } + + /** + * 添加标签 + * + * @param label 标签 + * @return 添加结果 + */ + @Operation(summary = "添加标签") + @PostMapping + public GeneralResult