From 764413a6cd967ae437c5ff35a8288d209d2d13fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A2=9C=E8=B6=85?= <7631990@qq.com> Date: Mon, 6 Nov 2023 15:54:50 +0800 Subject: [PATCH] Initial commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 精简 --- .gitignore | 37 + .mvn/wrapper/maven-wrapper.jar | Bin 0 -> 59925 bytes .mvn/wrapper/maven-wrapper.properties | 18 + common/common.iml | 179 +++++ common/pom.xml | 36 + .../advisor/DefaultControllerAdvisor.java | 65 ++ .../imitate/common/annotation/DoSysLog.java | 19 + .../com/imitate/common/bean/ApiResult.java | 61 ++ .../com/imitate/common/bean/BeanFactory.java | 44 ++ .../com/imitate/common/bean/BridgePage.java | 53 ++ .../com/imitate/common/bean/ShellResult.java | 49 ++ .../com/imitate/common/config/DateConfig.java | 146 ++++ .../imitate/common/config/InitListener.java | 36 + .../common/config/RedisListenerConfig.java | 20 + .../imitate/common/config/WebMvcConfig.java | 38 ++ .../common/constant/ApiResultCsts.java | 7 + .../imitate/common/enums/CommonStateEnum.java | 55 ++ .../imitate/common/enums/ErrorCodeEnum.java | 56 ++ .../common/exception/BusinessException.java | 33 + .../com/imitate/common/util/AbstractDO.java | 34 + .../com/imitate/common/util/Base64Util.java | 91 +++ .../com/imitate/common/util/BaseMapper.java | 13 + .../common/util/BasePageCondition.java | 52 ++ .../imitate/common/util/BasicController.java | 34 + .../com/imitate/common/util/DBHelper.java | 43 ++ .../imitate/common/util/FileDownloadUtil.java | 113 ++++ .../imitate/common/util/HttpContextUtils.java | 29 + .../java/com/imitate/common/util/IpUtil.java | 50 ++ .../com/imitate/common/util/JedisUtil.java | 635 ++++++++++++++++++ .../com/imitate/common/util/JsonUtils.java | 49 ++ .../java/com/imitate/common/util/MD5Util.java | 51 ++ .../imitate/common/util/OKHttp3Utils3.java | 313 +++++++++ .../main/java/com/imitate/common/util/R.java | 82 +++ .../com/imitate/common/util/RedisPool.java | 74 ++ .../imitate/common/util/ShellExeCallBack.java | 12 + .../com/imitate/common/util/ShellUtil.java | 179 +++++ .../com/imitate/common/util/SignUtil.java | 140 ++++ .../imitate/common/util/SimpleFileUtils.java | 109 +++ .../common/util/SymmetricCryptoUtil.java | 49 ++ .../main/resources/META-INF/spring.factories | 1 + common/src/main/resources/common.properties | 0 parent/parent.iml | 166 +++++ parent/pom.xml | 275 ++++++++ pom.xml | 19 + web/pom.xml | 30 + .../java/com/imitate/web/WebApplication.java | 16 + .../imitate/web/aspect/ParamsOutAspect.java | 183 +++++ .../java/com/imitate/web/init/Runner.java | 107 +++ .../controller/DataCenterController.java | 190 ++++++ .../controller/DeviceController.java | 266 ++++++++ .../DeviceDistributionController.java | 106 +++ .../controller/DeviceTypeController.java | 189 ++++++ .../controller/LocalManagerController.java | 187 ++++++ .../controller/ProducerController.java | 129 ++++ .../controller/ResourceController.java | 169 +++++ .../controller/SecretKeyController.java | 129 ++++ .../controller/SysDictController.java | 42 ++ .../controller/SysLogController.java | 63 ++ .../simulation/enums/SecretKeyTypeEnum.java | 23 + .../service/DataTerminalService.java | 79 +++ .../service/DeviceDistributionService.java | 88 +++ .../simulation/service/DeviceService.java | 188 ++++++ .../service/DeviceTypeProducerService.java | 16 + .../simulation/service/DeviceTypeService.java | 130 ++++ .../simulation/service/ProducerService.java | 62 ++ .../simulation/service/ResourceService.java | 335 +++++++++ .../simulation/service/SecretKeyService.java | 126 ++++ .../simulation/service/SysDictService.java | 253 +++++++ .../simulation/service/SysLogService.java | 32 + .../web/params/CertificateOpenParam.java | 27 + .../imitate/web/params/DataTerminalParam.java | 25 + .../params/DatabaseTestConnectionParam.java | 29 + .../imitate/web/params/DeviceListParam.java | 23 + .../com/imitate/web/params/DeviceParam.java | 23 + .../imitate/web/params/DeviceTypeParam.java | 27 + .../web/params/DistributionListParam.java | 21 + .../imitate/web/params/DistributionParam.java | 22 + .../com/imitate/web/params/ProducerParam.java | 23 + .../imitate/web/params/ResourceOpenParam.java | 27 + .../imitate/web/params/SecretKeyParam.java | 23 + .../web/persistence/beans/Certificate.java | 93 +++ .../web/persistence/beans/DataTerminal.java | 73 ++ .../imitate/web/persistence/beans/Device.java | 83 +++ .../persistence/beans/DeviceDistribution.java | 92 +++ .../web/persistence/beans/DeviceType.java | 71 ++ .../persistence/beans/DeviceTypeProducer.java | 35 + .../web/persistence/beans/Producer.java | 116 ++++ .../web/persistence/beans/Resource.java | 64 ++ .../web/persistence/beans/SecretKey.java | 58 ++ .../imitate/web/persistence/beans/SysLog.java | 86 +++ .../persistence/mapper/CertificateMapper.java | 21 + .../mapper/DataTerminalMapper.java | 43 ++ .../mapper/DeviceDistributionMapper.java | 37 + .../web/persistence/mapper/DeviceMapper.java | 58 ++ .../persistence/mapper/DeviceTypeMapper.java | 37 + .../mapper/DeviceTypeProducerMapper.java | 26 + .../persistence/mapper/ProducerMapper.java | 21 + .../persistence/mapper/ResourceMapper.java | 17 + .../persistence/mapper/SecretKeyMapper.java | 63 ++ .../web/persistence/mapper/SysLogMapper.java | 20 + .../com/imitate/web/vo/DeviceByTypeVO.java | 16 + .../imitate/web/vo/DeviceManagerInitVO.java | 36 + .../imitate/web/vo/DeviceResourceInitVO.java | 30 + .../imitate/web/vo/DeviceSoftwareInitVO.java | 48 ++ .../java/com/imitate/web/vo/DeviceTypeVO.java | 28 + .../java/com/imitate/web/vo/DeviceVO.java | 38 ++ .../imitate/web/vo/LocalManagerInitVO.java | 47 ++ web/src/main/resources/application.properties | 62 ++ .../resources/mybatis/CerificateMapper.xml | 48 ++ .../resources/mybatis/DataTerminalMapper.xml | 65 ++ .../mybatis/DeviceDistributionMapper.xml | 85 +++ .../main/resources/mybatis/DeviceMapper.xml | 138 ++++ .../resources/mybatis/DeviceTypeMapper.xml | 51 ++ .../mybatis/DeviceTypeProducerMapper.xml | 17 + .../main/resources/mybatis/ProducerMapper.xml | 5 + .../main/resources/mybatis/ResourceMapper.xml | 46 ++ .../resources/mybatis/SecretKeyMapper.xml | 88 +++ .../main/resources/mybatis/SysLogMapper.xml | 40 ++ web/web.iml | 179 +++++ 119 files changed, 9154 insertions(+) create mode 100644 .gitignore create mode 100644 .mvn/wrapper/maven-wrapper.jar create mode 100644 .mvn/wrapper/maven-wrapper.properties create mode 100644 common/common.iml create mode 100644 common/pom.xml create mode 100644 common/src/main/java/com/imitate/common/advisor/DefaultControllerAdvisor.java create mode 100644 common/src/main/java/com/imitate/common/annotation/DoSysLog.java create mode 100644 common/src/main/java/com/imitate/common/bean/ApiResult.java create mode 100644 common/src/main/java/com/imitate/common/bean/BeanFactory.java create mode 100644 common/src/main/java/com/imitate/common/bean/BridgePage.java create mode 100644 common/src/main/java/com/imitate/common/bean/ShellResult.java create mode 100644 common/src/main/java/com/imitate/common/config/DateConfig.java create mode 100644 common/src/main/java/com/imitate/common/config/InitListener.java create mode 100644 common/src/main/java/com/imitate/common/config/RedisListenerConfig.java create mode 100644 common/src/main/java/com/imitate/common/config/WebMvcConfig.java create mode 100644 common/src/main/java/com/imitate/common/constant/ApiResultCsts.java create mode 100644 common/src/main/java/com/imitate/common/enums/CommonStateEnum.java create mode 100644 common/src/main/java/com/imitate/common/enums/ErrorCodeEnum.java create mode 100644 common/src/main/java/com/imitate/common/exception/BusinessException.java create mode 100644 common/src/main/java/com/imitate/common/util/AbstractDO.java create mode 100644 common/src/main/java/com/imitate/common/util/Base64Util.java create mode 100644 common/src/main/java/com/imitate/common/util/BaseMapper.java create mode 100644 common/src/main/java/com/imitate/common/util/BasePageCondition.java create mode 100644 common/src/main/java/com/imitate/common/util/BasicController.java create mode 100644 common/src/main/java/com/imitate/common/util/DBHelper.java create mode 100644 common/src/main/java/com/imitate/common/util/FileDownloadUtil.java create mode 100644 common/src/main/java/com/imitate/common/util/HttpContextUtils.java create mode 100644 common/src/main/java/com/imitate/common/util/IpUtil.java create mode 100644 common/src/main/java/com/imitate/common/util/JedisUtil.java create mode 100644 common/src/main/java/com/imitate/common/util/JsonUtils.java create mode 100644 common/src/main/java/com/imitate/common/util/MD5Util.java create mode 100644 common/src/main/java/com/imitate/common/util/OKHttp3Utils3.java create mode 100644 common/src/main/java/com/imitate/common/util/R.java create mode 100644 common/src/main/java/com/imitate/common/util/RedisPool.java create mode 100644 common/src/main/java/com/imitate/common/util/ShellExeCallBack.java create mode 100644 common/src/main/java/com/imitate/common/util/ShellUtil.java create mode 100644 common/src/main/java/com/imitate/common/util/SignUtil.java create mode 100644 common/src/main/java/com/imitate/common/util/SimpleFileUtils.java create mode 100644 common/src/main/java/com/imitate/common/util/SymmetricCryptoUtil.java create mode 100644 common/src/main/resources/META-INF/spring.factories create mode 100644 common/src/main/resources/common.properties create mode 100644 parent/parent.iml create mode 100644 parent/pom.xml create mode 100644 pom.xml create mode 100644 web/pom.xml create mode 100644 web/src/main/java/com/imitate/web/WebApplication.java create mode 100644 web/src/main/java/com/imitate/web/aspect/ParamsOutAspect.java create mode 100644 web/src/main/java/com/imitate/web/init/Runner.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/controller/DataCenterController.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/controller/DeviceController.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/controller/DeviceDistributionController.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/controller/DeviceTypeController.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/controller/LocalManagerController.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/controller/ProducerController.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/controller/ResourceController.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/controller/SecretKeyController.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/controller/SysDictController.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/controller/SysLogController.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/enums/SecretKeyTypeEnum.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/service/DataTerminalService.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/service/DeviceDistributionService.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/service/DeviceService.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/service/DeviceTypeProducerService.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/service/DeviceTypeService.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/service/ProducerService.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/service/ResourceService.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/service/SecretKeyService.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/service/SysDictService.java create mode 100644 web/src/main/java/com/imitate/web/module/simulation/service/SysLogService.java create mode 100644 web/src/main/java/com/imitate/web/params/CertificateOpenParam.java create mode 100644 web/src/main/java/com/imitate/web/params/DataTerminalParam.java create mode 100644 web/src/main/java/com/imitate/web/params/DatabaseTestConnectionParam.java create mode 100644 web/src/main/java/com/imitate/web/params/DeviceListParam.java create mode 100644 web/src/main/java/com/imitate/web/params/DeviceParam.java create mode 100644 web/src/main/java/com/imitate/web/params/DeviceTypeParam.java create mode 100644 web/src/main/java/com/imitate/web/params/DistributionListParam.java create mode 100644 web/src/main/java/com/imitate/web/params/DistributionParam.java create mode 100644 web/src/main/java/com/imitate/web/params/ProducerParam.java create mode 100644 web/src/main/java/com/imitate/web/params/ResourceOpenParam.java create mode 100644 web/src/main/java/com/imitate/web/params/SecretKeyParam.java create mode 100644 web/src/main/java/com/imitate/web/persistence/beans/Certificate.java create mode 100644 web/src/main/java/com/imitate/web/persistence/beans/DataTerminal.java create mode 100644 web/src/main/java/com/imitate/web/persistence/beans/Device.java create mode 100644 web/src/main/java/com/imitate/web/persistence/beans/DeviceDistribution.java create mode 100644 web/src/main/java/com/imitate/web/persistence/beans/DeviceType.java create mode 100644 web/src/main/java/com/imitate/web/persistence/beans/DeviceTypeProducer.java create mode 100644 web/src/main/java/com/imitate/web/persistence/beans/Producer.java create mode 100644 web/src/main/java/com/imitate/web/persistence/beans/Resource.java create mode 100644 web/src/main/java/com/imitate/web/persistence/beans/SecretKey.java create mode 100644 web/src/main/java/com/imitate/web/persistence/beans/SysLog.java create mode 100644 web/src/main/java/com/imitate/web/persistence/mapper/CertificateMapper.java create mode 100644 web/src/main/java/com/imitate/web/persistence/mapper/DataTerminalMapper.java create mode 100644 web/src/main/java/com/imitate/web/persistence/mapper/DeviceDistributionMapper.java create mode 100644 web/src/main/java/com/imitate/web/persistence/mapper/DeviceMapper.java create mode 100644 web/src/main/java/com/imitate/web/persistence/mapper/DeviceTypeMapper.java create mode 100644 web/src/main/java/com/imitate/web/persistence/mapper/DeviceTypeProducerMapper.java create mode 100644 web/src/main/java/com/imitate/web/persistence/mapper/ProducerMapper.java create mode 100644 web/src/main/java/com/imitate/web/persistence/mapper/ResourceMapper.java create mode 100644 web/src/main/java/com/imitate/web/persistence/mapper/SecretKeyMapper.java create mode 100644 web/src/main/java/com/imitate/web/persistence/mapper/SysLogMapper.java create mode 100644 web/src/main/java/com/imitate/web/vo/DeviceByTypeVO.java create mode 100644 web/src/main/java/com/imitate/web/vo/DeviceManagerInitVO.java create mode 100644 web/src/main/java/com/imitate/web/vo/DeviceResourceInitVO.java create mode 100644 web/src/main/java/com/imitate/web/vo/DeviceSoftwareInitVO.java create mode 100644 web/src/main/java/com/imitate/web/vo/DeviceTypeVO.java create mode 100644 web/src/main/java/com/imitate/web/vo/DeviceVO.java create mode 100644 web/src/main/java/com/imitate/web/vo/LocalManagerInitVO.java create mode 100644 web/src/main/resources/application.properties create mode 100644 web/src/main/resources/mybatis/CerificateMapper.xml create mode 100644 web/src/main/resources/mybatis/DataTerminalMapper.xml create mode 100644 web/src/main/resources/mybatis/DeviceDistributionMapper.xml create mode 100644 web/src/main/resources/mybatis/DeviceMapper.xml create mode 100644 web/src/main/resources/mybatis/DeviceTypeMapper.xml create mode 100644 web/src/main/resources/mybatis/DeviceTypeProducerMapper.xml create mode 100644 web/src/main/resources/mybatis/ProducerMapper.xml create mode 100644 web/src/main/resources/mybatis/ResourceMapper.xml create mode 100644 web/src/main/resources/mybatis/SecretKeyMapper.xml create mode 100644 web/src/main/resources/mybatis/SysLogMapper.xml create mode 100644 web/web.iml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87f6ce4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +logs/ + + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ +*.iml +web/web.iml diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..bf82ff01c6cdae4a1bb754a6e062954d77ac5c11 GIT binary patch literal 59925 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

dy!05UMhSKsK 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 VCNKd3JGtOvEm(5t0lFyE{{i--k}m)N literal 0 HcmV?d00001 diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..ca5ab4b --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/common/common.iml b/common/common.iml new file mode 100644 index 0000000..b691c30 --- /dev/null +++ b/common/common.iml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 0000000..0f9fdbd --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + parent + com.imitate + 0.0.1-SNAPSHOT + ../parent/pom.xml + + + common + 0.0.1-SNAPSHOT + common + common + jar + + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-autoconfigure + + + + + + + + diff --git a/common/src/main/java/com/imitate/common/advisor/DefaultControllerAdvisor.java b/common/src/main/java/com/imitate/common/advisor/DefaultControllerAdvisor.java new file mode 100644 index 0000000..4297282 --- /dev/null +++ b/common/src/main/java/com/imitate/common/advisor/DefaultControllerAdvisor.java @@ -0,0 +1,65 @@ +package com.imitate.common.advisor; + +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.exception.BusinessException; +import com.imitate.common.util.R; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.validation.ConstraintViolationException; + +/** + * @author yanchao + */ +@RestControllerAdvice +public class DefaultControllerAdvisor { + + private static final Logger logger = LoggerFactory.getLogger(DefaultControllerAdvisor.class); + + @ExceptionHandler(Exception.class) + public R processException(Exception e) { + logger.error(e.getMessage(), e); + return R.error(ErrorCodeEnum.EXCEPTION.getValue(), ErrorCodeEnum.EXCEPTION.getDescription()); + } + + @ExceptionHandler(BusinessException.class) + public R processException(BusinessException e) { + logger.error(e.getMessage(), e); + return R.error(e.getErrCode(), e.getMessage()); + } + + @ExceptionHandler(MissingServletRequestParameterException.class) + public R processMissingServletRequestParameterException(MissingServletRequestParameterException e) { + logger.error(e.getMessage(), e); + return R.error(ErrorCodeEnum.MVC_BIND_EXCEPTION.getValue(), ErrorCodeEnum.MVC_BIND_EXCEPTION.getDescription()); + } + + @ExceptionHandler(ConstraintViolationException.class) + public R processConstraintViolationException(ConstraintViolationException e) { + logger.error(e.getMessage(), e); + return R.error(ErrorCodeEnum.INVALID_ARG_EXCEPTION.getValue(), + ErrorCodeEnum.INVALID_ARG_EXCEPTION.getDescription()); + } + + @ExceptionHandler(BindException.class) + public R processBindException(BindException e) { + logger.error(e.getMessage(), e); + return R.error(ErrorCodeEnum.BIND_EXCEPTION.getValue(), ErrorCodeEnum.BIND_EXCEPTION.getDescription()); + } + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + public R processHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) { + logger.error(e.getMessage(), e); + return R.error(ErrorCodeEnum.METHOD_NOT_ALLOWED_EXCEPTION.getValue(), + ErrorCodeEnum.METHOD_NOT_ALLOWED_EXCEPTION.getDescription()); + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/imitate/common/annotation/DoSysLog.java b/common/src/main/java/com/imitate/common/annotation/DoSysLog.java new file mode 100644 index 0000000..aa01581 --- /dev/null +++ b/common/src/main/java/com/imitate/common/annotation/DoSysLog.java @@ -0,0 +1,19 @@ +package com.imitate.common.annotation; + +import java.lang.annotation.*; + +/** + * 日志开启注解 + * + * @author jshixiong + */ +@Inherited +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DoSysLog { + /** + * 是否开启日志 + */ + boolean isLog() default false; +} diff --git a/common/src/main/java/com/imitate/common/bean/ApiResult.java b/common/src/main/java/com/imitate/common/bean/ApiResult.java new file mode 100644 index 0000000..8a95c6e --- /dev/null +++ b/common/src/main/java/com/imitate/common/bean/ApiResult.java @@ -0,0 +1,61 @@ +package com.imitate.common.bean; + + +import com.imitate.common.constant.ApiResultCsts; + +public class ApiResult { + + private int code = ApiResultCsts.CODE_SUCCESS; + private String msg; + + private T data; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public ApiResult() { + } + + public ApiResult(int code, String msg, T data) { + this.code = code; + this.msg = msg; + this.data = data; + } + + public static ApiResult successResult(T data) { + return successResult("success", data); + } + + public static ApiResult successResult(String msg, T data) { + return new ApiResult<>(0, msg, data); + } + + public static ApiResult failResult(int code, String msg, T data) { + return new ApiResult<>(code, msg, data); + } + + public static ApiResult failResult(int code, String msg) { + return new ApiResult<>(code, msg, null); + } +} diff --git a/common/src/main/java/com/imitate/common/bean/BeanFactory.java b/common/src/main/java/com/imitate/common/bean/BeanFactory.java new file mode 100644 index 0000000..532fe6d --- /dev/null +++ b/common/src/main/java/com/imitate/common/bean/BeanFactory.java @@ -0,0 +1,44 @@ + +/** + * 文件名 : BeanFactory.java + * 版权 : <版权/公司名> + * 描述 : <描述> + * @author liliy + * 版本 : <版本> + * 修改时间: 2017年6月13日 + * 修改内容: <修改内容> + */ +package com.imitate.common.bean; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * <一句话功能简述> <功能详细描述> + * + * @author liliy + * @version [版本号,2017年6月13日] + * @see [相关类/方法] + * @since [产品/模块版本] + */ +@Component +public class BeanFactory implements ApplicationContextAware { + private static ApplicationContext ctx = null; + + public static Object getObejct(String name) { + return ctx.getBean(name); + } + + public static T getObejct(Class requiredType) { + return ctx.getBean(requiredType); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + BeanFactory.ctx = applicationContext; + + } + +} diff --git a/common/src/main/java/com/imitate/common/bean/BridgePage.java b/common/src/main/java/com/imitate/common/bean/BridgePage.java new file mode 100644 index 0000000..695f946 --- /dev/null +++ b/common/src/main/java/com/imitate/common/bean/BridgePage.java @@ -0,0 +1,53 @@ +package com.imitate.common.bean; + +import com.github.pagehelper.Page; + +import java.util.List; + +public class BridgePage { + + private List data; + private Integer pageNum; + private Integer pageSize; + private Long total; + + public BridgePage(Page page) { + this.data = page.getResult(); + this.pageNum = page.getPageNum(); + this.pageSize = page.getPageSize(); + this.total = page.getTotal(); + } + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + + public Integer getPageNum() { + return pageNum; + } + + public void setPageNum(Integer pageNum) { + this.pageNum = pageNum; + } + + public Integer getPageSize() { + return pageSize; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public Long getTotal() { + return total; + } + + public void setTotal(Long total) { + this.total = total; + } + +} diff --git a/common/src/main/java/com/imitate/common/bean/ShellResult.java b/common/src/main/java/com/imitate/common/bean/ShellResult.java new file mode 100644 index 0000000..ae81167 --- /dev/null +++ b/common/src/main/java/com/imitate/common/bean/ShellResult.java @@ -0,0 +1,49 @@ +package com.imitate.common.bean; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * shell执行结果 + * + * @author 威少 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ShellResult { + /** + * 退出码 + */ + private Integer exitStatus; + /** + * 实际输出 + */ + private String out; + + public enum ExitStatus { + /** + * 成功 + */ + SUCCESS(0), + /** + * 超时 + */ + TIMEOUT(124), + /** + * 默认失败 + */ + FAIL(-1); + + private int code; + + ExitStatus(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + } +} diff --git a/common/src/main/java/com/imitate/common/config/DateConfig.java b/common/src/main/java/com/imitate/common/config/DateConfig.java new file mode 100644 index 0000000..c8bb60d --- /dev/null +++ b/common/src/main/java/com/imitate/common/config/DateConfig.java @@ -0,0 +1,146 @@ +package com.imitate.common.config; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.converter.Converter; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +@Configuration +public class DateConfig { + + /** 默认日期时间格式 */ + public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + /** 默认日期格式 */ + public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; + /** 默认时间格式 */ + public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; + + /** + * LocalDate转换器,用于转换RequestParam和PathVariable参数 + */ + @Bean + public Converter localDateConverter() { + return new Converter() { + @Override + public LocalDate convert(String source) { + return LocalDate.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)); + } + }; + } + + /** + * LocalDateTime转换器,用于转换RequestParam和PathVariable参数 + */ + @Bean + public Converter localDateTimeConverter() { + return new Converter() { + @Override + public LocalDateTime convert(String source) { + return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)); + } + }; + } + + /** + * LocalTime转换器,用于转换RequestParam和PathVariable参数 + */ + @Bean + public Converter localTimeConverter() { + return new Converter() { + @Override + public LocalTime convert(String source) { + return LocalTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)); + } + }; + } + + /** + * Date转换器,用于转换RequestParam和PathVariable参数 + */ + @Bean + public Converter dateConverter() { + return new Converter() { + @Override + public Date convert(String source) { + SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT); + try { + return format.parse(source); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + }; + } + + /** + * Json序列化和反序列化转换器,用于转换Post请求体中的json以及将我们的对象序列化为返回响应的json + */ + @Bean("objectMapper") + public ObjectMapper objectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE); + + // LocalDateTime系列序列化和反序列化模块,继承自jsr310,我们在这里修改了日期格式 + JavaTimeModule javaTimeModule = new JavaTimeModule(); + javaTimeModule.addSerializer(LocalDateTime.class, + new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); + javaTimeModule.addSerializer(LocalDate.class, + new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))); + javaTimeModule.addSerializer(LocalTime.class, + new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); + javaTimeModule.addDeserializer(LocalDateTime.class, + new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); + javaTimeModule.addDeserializer(LocalDate.class, + new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))); + javaTimeModule.addDeserializer(LocalTime.class, + new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); + + // Date序列化和反序列化 + javaTimeModule.addSerializer(Date.class, new JsonSerializer() { + @Override + public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + SimpleDateFormat formatter = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT); + String formattedDate = formatter.format(date); + jsonGenerator.writeString(formattedDate); + } + }); + javaTimeModule.addDeserializer(Date.class, new JsonDeserializer() { + @Override + public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException, JsonProcessingException { + SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT); + String date = jsonParser.getText(); + try { + return format.parse(date); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + }); + + objectMapper.registerModule(javaTimeModule); + return objectMapper; + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/imitate/common/config/InitListener.java b/common/src/main/java/com/imitate/common/config/InitListener.java new file mode 100644 index 0000000..f35ce6b --- /dev/null +++ b/common/src/main/java/com/imitate/common/config/InitListener.java @@ -0,0 +1,36 @@ +package com.imitate.common.config; + +import com.imitate.common.util.RedisPool; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; +import redis.clients.jedis.Jedis; + +@Component +public class InitListener implements ApplicationListener { + private static final Logger log = LoggerFactory.getLogger(InitListener.class); + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + String active = System.getProperty("spring.profiles.active"); + // 本地不初始化这些信息 + Jedis jedis = null; + try { + if (!StringUtils.equals(active, "local")) { + // 初始化redis + jedis = RedisPool.getJedis(); + } + } catch (Exception e) { + log.error("项目启动失败", e); + if ("jedisPool初始化错误".equals(e.getMessage())) { + Runtime.getRuntime().exit(-1); + } + } finally { + RedisPool.returnResource(jedis); + } + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/imitate/common/config/RedisListenerConfig.java b/common/src/main/java/com/imitate/common/config/RedisListenerConfig.java new file mode 100644 index 0000000..d1dd77d --- /dev/null +++ b/common/src/main/java/com/imitate/common/config/RedisListenerConfig.java @@ -0,0 +1,20 @@ +package com.imitate.common.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; + +@Order(1) +@Configuration +public class RedisListenerConfig { + + @Bean + RedisMessageListenerContainer listenerContainer(RedisConnectionFactory connectionFactory) { + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + container.setConnectionFactory(connectionFactory); + return container; + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/imitate/common/config/WebMvcConfig.java b/common/src/main/java/com/imitate/common/config/WebMvcConfig.java new file mode 100644 index 0000000..b406865 --- /dev/null +++ b/common/src/main/java/com/imitate/common/config/WebMvcConfig.java @@ -0,0 +1,38 @@ +package com.imitate.common.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; + +import java.util.List; + +/** + * + * @author yanchao + */ +@Configuration +@Order(1) +@Slf4j +public class WebMvcConfig extends WebMvcConfigurationSupport { + + + @Override + public void addArgumentResolvers(List resolvers) { + log.debug("【配置argumentResolver】ok"); + } + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedHeaders("Content-Type", "x-requested-with", "X-Custom-Header") + .allowedOriginPatterns("*") + .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS") + .allowCredentials(true) + .maxAge(3600); + } + + +} \ No newline at end of file diff --git a/common/src/main/java/com/imitate/common/constant/ApiResultCsts.java b/common/src/main/java/com/imitate/common/constant/ApiResultCsts.java new file mode 100644 index 0000000..7c11aee --- /dev/null +++ b/common/src/main/java/com/imitate/common/constant/ApiResultCsts.java @@ -0,0 +1,7 @@ +package com.imitate.common.constant; + +public interface ApiResultCsts { + int CODE_SUCCESS = 0; + int CODE_FAIL = -1; + +} diff --git a/common/src/main/java/com/imitate/common/enums/CommonStateEnum.java b/common/src/main/java/com/imitate/common/enums/CommonStateEnum.java new file mode 100644 index 0000000..977f1b0 --- /dev/null +++ b/common/src/main/java/com/imitate/common/enums/CommonStateEnum.java @@ -0,0 +1,55 @@ +package com.imitate.common.enums; + +/** + * 通用状态枚举 0为否定含义,1为肯定含义 + * + * @author 威少 + */ +public enum CommonStateEnum { + /** + * 否定含义 + */ + FALSE(0, false), + /** + * 肯定含义 + */ + TRUE(1, true); + + int value; + + boolean booleanValue; + + CommonStateEnum(int value, boolean booleanValue) { + this.value = value; + this.booleanValue = booleanValue; + } + + public int getValue() { + return value; + } + + public boolean getBooleanValue() { + return booleanValue; + } + + /** + * 从bool值转换 + * + * @param value bool值 + * @return 肯定为1,否定为0 + */ + public static CommonStateEnum fromBoolean(Boolean value) { + return value == null ? FALSE : value ? TRUE : FALSE; + } + + /** + * 从整型值转换 + * + * @param value 整型值 + * @return 肯定为1,否定为0 + */ + public static CommonStateEnum fromInteger(Integer value) { + return value == null || value == FALSE.getValue() ? FALSE : TRUE; + } + +} diff --git a/common/src/main/java/com/imitate/common/enums/ErrorCodeEnum.java b/common/src/main/java/com/imitate/common/enums/ErrorCodeEnum.java new file mode 100644 index 0000000..1d04a4d --- /dev/null +++ b/common/src/main/java/com/imitate/common/enums/ErrorCodeEnum.java @@ -0,0 +1,56 @@ +package com.imitate.common.enums; + +import java.util.Arrays; + +/** + * 全局错误枚举 + * + * @author yanchao + */ +public enum ErrorCodeEnum { + SUCCESS("000000", "成功"), + INVALID_ARG_EXCEPTION("000001", "参数验证异常"), + BIND_EXCEPTION("000007", "参数绑定异常"), + MVC_BIND_EXCEPTION("000014", "请求参数绑定异常"), + METHOD_NOT_ALLOWED_EXCEPTION("000008", "请求方式异常"), + EXCEPTION("999999", "系统异常"), + DATAFLOW_EXCEPTION("000010", "默认数据异常"), + BUSINESS_EXCEPTION("000011", "默认业务异常"), + LOGIN_EXPIRE_TIME("000013", "登录已过期,请重新登录"), + USER_LOGIN_DISABLE("000014", "账号已经锁定,请联系管理员"), + NO_AUTH("000012", "未认证登录状态"), + AFTERMATH_EXP("000013", "评测线程出错,善后处理发生异常"), + GIT_FAIL("000014", "获取git凭证失败: "), + GIT_CREDENTIAL_FAIL("000015", "设置git凭证失败:"), + + CLONE_FAIL("100001", "克隆失败"), + EVALUATION_SHELL_FAIL("100002", "生成评测脚本失败"), + WRITE_FILE_CODE_FAIL("100003", "写代码文件失败"), + UPDATE_VERSION_REPOSITORY_FAIL("100004", "更新版本库失败"), + SYNC_CLUSTER_VERSION_REPOSITORY_FAIL("100005", "远程集群版本库同步失败"), + PUSH_FAIL("100006", "push版本库失败"), + JUPYTER_ADD_OR_COMMIT_FAIL("100007", "Jupyter添加提交失败"), + VERSION_REPOSITORY_NOT_EXIST("10000", "主机名不存在"); + + String value; + String description; + + ErrorCodeEnum(String value, String description) { + this.value = value; + this.description = description; + } + + public String getValue() { + return value; + } + + public String getDescription() { + return description; + } + + public static ErrorCodeEnum getByDescription(String description) { + return Arrays.stream(values()).filter(errorCodeEnum -> errorCodeEnum.getDescription().equals(description)) + .findFirst().orElse(null); + } + +} diff --git a/common/src/main/java/com/imitate/common/exception/BusinessException.java b/common/src/main/java/com/imitate/common/exception/BusinessException.java new file mode 100644 index 0000000..8586585 --- /dev/null +++ b/common/src/main/java/com/imitate/common/exception/BusinessException.java @@ -0,0 +1,33 @@ +package com.imitate.common.exception; + +import com.imitate.common.enums.ErrorCodeEnum; + +/** + * 业务异常 + * + * @author yanchao + */ +public class BusinessException extends RuntimeException { + /** + * 错误码 + */ + private String errCode = ErrorCodeEnum.DATAFLOW_EXCEPTION.getValue(); + + public BusinessException(ErrorCodeEnum errorCodeEnum) { + super(errorCodeEnum.getDescription()); + setErrCode(errorCodeEnum.getValue()); + } + + public BusinessException(String code, String msg) { + super(msg); + setErrCode(code); + } + + public void setErrCode(String errCode) { + this.errCode = errCode; + } + + public String getErrCode() { + return errCode; + } +} diff --git a/common/src/main/java/com/imitate/common/util/AbstractDO.java b/common/src/main/java/com/imitate/common/util/AbstractDO.java new file mode 100644 index 0000000..d8f641e --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/AbstractDO.java @@ -0,0 +1,34 @@ +package com.imitate.common.util; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +/** + * 表网关实体公共字段抽离DO抽象类 + * @author yanchao + */ +@Data +@EqualsAndHashCode(callSuper = false) +public abstract class AbstractDO implements Serializable{ + + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(generator = "JDBC") + private Long id; + + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone = "GMT+8") + private LocalDateTime createTime; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone = "GMT+8") + private LocalDateTime updateTime; +} diff --git a/common/src/main/java/com/imitate/common/util/Base64Util.java b/common/src/main/java/com/imitate/common/util/Base64Util.java new file mode 100644 index 0000000..dba5a06 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/Base64Util.java @@ -0,0 +1,91 @@ +package com.imitate.common.util; + +import org.apache.commons.codec.binary.Base64; +import org.springframework.util.StringUtils; + +import java.nio.charset.StandardCharsets; + +/** + * Created by guange on 23/02/2017. + */ +public final class Base64Util { + + /** + * base64编码 + * + * @param code + * @return + */ + public static String encode(String code) { + byte[] encode = Base64.encodeBase64URLSafe(code.getBytes(StandardCharsets.UTF_8)); + return new String(encode, StandardCharsets.UTF_8); + } + + public static byte[] encodeBytes(byte[] codes) { + return Base64.encodeBase64(codes); + } + + /** + * base64解码 + * + * @param code + * @return + */ + public static String decode(String code) { + byte[] decode = Base64.decodeBase64(code); + return new String(decode, StandardCharsets.UTF_8); + } + + /** + * base64再解码,把原本的非URL safe编码转换为URL safe编码 + * + * @param code + * @return + */ + public static String reencode(String code) { + String str = decode(code).replace("\u0000", ""); + //str = str.replace("\n", "\r\n"); + str = replaceLineFeed(str); + return encode(str); + } + + private static String replaceLineFeed(String str) { + StringBuilder sb = new StringBuilder(); + char[] cs = str.toCharArray(); + int len = cs.length; + for (int i = 0; i < len; i++) { + char c = cs[i]; + if (c == '\n') { + if (i == 0) { + sb.append('\r').append(c); + } else { + char pre = cs[i - 1]; + if (pre == '\r') { + sb.append(c); + } else { + sb.append('\r').append(c); + } + } + } else { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * 正常编码 + * + * @param code + * @return + */ + public static String encodeNoSafe(String code) { + if (StringUtils.isEmpty(code)) { + code = " "; + } + byte[] encode = Base64.encodeBase64(code.getBytes(StandardCharsets.UTF_8)); + return new String(encode, StandardCharsets.UTF_8); + } + + +} diff --git a/common/src/main/java/com/imitate/common/util/BaseMapper.java b/common/src/main/java/com/imitate/common/util/BaseMapper.java new file mode 100644 index 0000000..4b78758 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/BaseMapper.java @@ -0,0 +1,13 @@ +package com.imitate.common.util; + +import com.imitate.common.util.AbstractDO; +import tk.mybatis.mapper.common.Mapper; +import tk.mybatis.mapper.common.MySqlMapper; + +/** + * 通用mapper整合桥梁 + * @author yanchao + */ +public interface BaseMapper extends Mapper, MySqlMapper { + // 特别注意,该接口不能被扫描到,否则会出错 +} diff --git a/common/src/main/java/com/imitate/common/util/BasePageCondition.java b/common/src/main/java/com/imitate/common/util/BasePageCondition.java new file mode 100644 index 0000000..0209876 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/BasePageCondition.java @@ -0,0 +1,52 @@ +package com.imitate.common.util; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; + +/** + * 基础分页视图对象 + * @author yanchao + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class BasePageCondition implements Serializable { + + private static final long serialVersionUID = 1L; + + public final static int DEFAULT_PAGE_SIZE = 10; + + private Integer pageNumber; + private Integer pageSize; + private Integer pageStart; + + private String orderField; + private String orderDirection; + private String keywords; + + public BasePageCondition(){ + this.pageNumber = 1; + this.pageSize = 0; + this.pageStart = 0; + } + + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date startDate; + + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date endDate; + + public int getPageSize() { + return pageSize > 0 ? pageSize : DEFAULT_PAGE_SIZE; + } + + + public int getPageStart() { + return pageNumber > 0 ? (pageNumber - 1) * getPageSize() :0; + } +} diff --git a/common/src/main/java/com/imitate/common/util/BasicController.java b/common/src/main/java/com/imitate/common/util/BasicController.java new file mode 100644 index 0000000..727a27e --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/BasicController.java @@ -0,0 +1,34 @@ +package com.imitate.common.util; + +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.exception.BusinessException; +import com.imitate.common.util.R; +import org.apache.commons.lang3.StringUtils; +import org.springframework.validation.BindingResult; +import org.springframework.validation.ObjectError; + +import java.util.List; + +/** + * @author yanchao + */ +public class BasicController { + public R actionResultWithBindingResult(ErrorCodeEnum errorCodeEnum, BindingResult bindingResult){ + String errMsg = getBindingResultErrors(bindingResult); + if(StringUtils.isBlank(errMsg)){ + return R.error(errorCodeEnum.getDescription()); + } + throw new BusinessException(errorCodeEnum.getValue(),errorCodeEnum.getDescription() + "," + errMsg); + } + public String getBindingResultErrors(BindingResult bindingResult){ + if (null == bindingResult || !bindingResult.hasErrors()) { + return null; + } + StringBuilder errorStrBuilder = new StringBuilder(); + List errorList = bindingResult.getAllErrors(); + for (ObjectError error : errorList) { + errorStrBuilder.append(error.getDefaultMessage()).append(";"); + } + return StringUtils.removeEnd(errorStrBuilder.toString(), ";"); + } +} diff --git a/common/src/main/java/com/imitate/common/util/DBHelper.java b/common/src/main/java/com/imitate/common/util/DBHelper.java new file mode 100644 index 0000000..8b8eb1f --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/DBHelper.java @@ -0,0 +1,43 @@ +package com.imitate.common.util; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.sql.*; + +/** + * 数据源类型,创建Connection连接信息 + * @author yanchao + */ +public class DBHelper { + + private static Logger logger = LogManager.getLogger(); + + /** + * 根据传入的数据源类型,创建Connection连接信息 + * oracle.jdbc.driver.OracleDriver + * com.mysql.jdbc.Driver + * com.microsoft.sqlserver.jdbc.SQLServerDriver + * com.pivotal.jdbc.GreenplumDriver + * org.apache.hadoop.hive.jdbc.HiveDriver + * @return + */ + public static Connection intiConnection(String jdbcdriver,String jdbcurl, String username, String password, boolean autoCommit) { + Connection conn = null; + try { + Class.forName(jdbcdriver); + // 连接数据库 + conn = DriverManager.getConnection(jdbcurl, username, password); + conn.setAutoCommit(autoCommit); + } catch (Exception e) { + // 连接失败 + logger.error("intiConnection test 连接失败",e); + return null; + } + return conn; + } + + + +} + diff --git a/common/src/main/java/com/imitate/common/util/FileDownloadUtil.java b/common/src/main/java/com/imitate/common/util/FileDownloadUtil.java new file mode 100644 index 0000000..36c088b --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/FileDownloadUtil.java @@ -0,0 +1,113 @@ +package com.imitate.common.util; + + +import org.springframework.util.FileCopyUtils; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.URLConnection; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * 文件上传与下载 + * @author yanchao + */ +public class FileDownloadUtil { + + /** + * 下载单文件 + * @param file + * @param response + * @throws IOException + */ + public static void fileDownload(File file, HttpServletResponse response) throws IOException { + if (file.exists()) { + String mimeType = URLConnection.guessContentTypeFromName(file.getName()); + if (mimeType == null) { + mimeType = "application/octet-stream"; + } + response.setContentType(mimeType); + response.setHeader("Content-Disposition", String.format("inline; filename=\"" + file.getName() + "\"")); + response.setContentLength((int) file.length()); + InputStream inputStream = new BufferedInputStream(new FileInputStream(file)); + FileCopyUtils.copy(inputStream, response.getOutputStream()); + } + } + + /** + * 在classpath下创建文件 + * @param resourceDirPath + * @param createFileName + * @throws IOException + */ + public static File createFile(String resourceDirPath,String createFileName) throws IOException { + File tmpFile = new File(resourceDirPath + File.separator + createFileName); + if (tmpFile.exists()) { + tmpFile.delete(); + } + tmpFile.createNewFile(); + return tmpFile; + } + + + /** + * files打成压缩包,多文件打包 + * @param files + * @param zipTmpFile + */ + public static void zipFile(List files, File zipTmpFile) throws IOException { + // 创建文件输出流 + FileOutputStream fous = new FileOutputStream(zipTmpFile); + ZipOutputStream zipOutputStream = new ZipOutputStream(fous); + int size = files.size(); + for (int i = 0; i < size; i++) { + File file = files.get(i); + zipFile(file, zipOutputStream); + } + zipOutputStream.close(); + fous.close(); + } + + /** + * 多文件打包 + * @param inputFile + * @param ouputStream + */ + private static void zipFile(File inputFile, ZipOutputStream ouputStream) { + try { + if (inputFile.exists()) { + if (inputFile.isFile()) { + FileInputStream IN = new FileInputStream(inputFile); + BufferedInputStream bins = new BufferedInputStream(IN, 512); + ZipEntry entry = new ZipEntry(inputFile.getName()); + ouputStream.putNextEntry(entry); + + int nNumber; + byte[] buffer = new byte[512]; + while ((nNumber = bins.read(buffer)) != -1) { + ouputStream.write(buffer, 0, nNumber); + } + + bins.close(); + IN.close(); + } else { + try { + File[] files = inputFile.listFiles(); + for (int i = 0; i < files.length; i++) { + zipFile(files[i], ouputStream); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + + +} diff --git a/common/src/main/java/com/imitate/common/util/HttpContextUtils.java b/common/src/main/java/com/imitate/common/util/HttpContextUtils.java new file mode 100644 index 0000000..f26cc78 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/HttpContextUtils.java @@ -0,0 +1,29 @@ +package com.imitate.common.util; + +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; + +/** + * http上下文 + * @author 悟空 + */ +public class HttpContextUtils { + + public static HttpServletRequest getHttpServletRequest() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + } + + + public static String getDomain(){ + HttpServletRequest request = getHttpServletRequest(); + StringBuffer url = request.getRequestURL(); + return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString(); + } + + public static String getOrigin(){ + HttpServletRequest request = getHttpServletRequest(); + return request.getHeader("Origin"); + } +} diff --git a/common/src/main/java/com/imitate/common/util/IpUtil.java b/common/src/main/java/com/imitate/common/util/IpUtil.java new file mode 100644 index 0000000..a03b8a7 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/IpUtil.java @@ -0,0 +1,50 @@ +package com.imitate.common.util; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; + +/** + * IP地址 + * @author 悟空 + */ +public class IpUtil { + private static Logger logger = LoggerFactory.getLogger(IpUtil.class); + + private static final String UNKNOWN = "unknown"; + + /** + * 获取IP地址 + * + * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 + * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 + */ + public static String getIpAddr(HttpServletRequest request) { + String ip = null; + try { + ip = request.getHeader("x-forwarded-for"); + if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (StringUtils.isEmpty(ip) || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + } catch (Exception e) { + logger.error("IPUtils ERROR ", e); + } + + return ip; + } + +} diff --git a/common/src/main/java/com/imitate/common/util/JedisUtil.java b/common/src/main/java/com/imitate/common/util/JedisUtil.java new file mode 100644 index 0000000..ef0e9de --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/JedisUtil.java @@ -0,0 +1,635 @@ +package com.imitate.common.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.Response; +import redis.clients.jedis.Transaction; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Created by zzx on 17/10/24. + */ +public final class JedisUtil { + private static final Logger log = LoggerFactory.getLogger(JedisUtil.class); + + /** + * 获取符合模式的key + */ + public static Set keys(String pattern) { + Jedis jedis = null; + Set set = null; + try { + jedis = RedisPool.getJedis(); + set = jedis.keys(pattern); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return set; + } + + /** + * 获取zset中元素个数 + */ + public static int zlen(String key) { + Jedis jedis = null; + int len = 0; + try { + jedis = RedisPool.getJedis(); + len = jedis.zcard(key).intValue(); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return len; + } + + /** + * 获取元素在zset中的排名 + */ + public static double zrank(String key, String value) { + Jedis jedis = null; + double rank = Double.MIN_VALUE; + try { + jedis = RedisPool.getJedis(); + if (jedis.zcard(key) == 0) { + return rank; + } + rank = jedis.zrank(key, value); + } catch (Exception e) { + rank = Double.MAX_VALUE; + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return rank; + } + + /** + * 将zset中队首元素弹出,若zset中没有元素,则返回null + */ + public static String zpop(String key) { + Jedis jedis = null; + String element = null; + try { + jedis = RedisPool.getJedis(); + if (jedis.zcard(key) != 0) { + element = jedis.zrange(key, 0, 0).iterator().next(); + jedis.zrem(key, element); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return element; + } + + /** + * 将一个新元素存到zset队尾,如果zset中尚没有元素,zadd(key, 1, value) + */ + public static void zpush(String key, String value) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + if (jedis.zcard(key) == 0) { + jedis.zadd(key, 1, value); + } else { + String lastElement = jedis.zrange(key, -1, -1).iterator().next(); + double lastScore = jedis.zscore(key, lastElement); + jedis.zadd(key, lastScore + 1, value); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * 将zset中指定元素score加1 + * + * 如果zset中不存在该元素,则此操作等同于zadd(key, 1, value) + */ + public static void zup(String key, String value) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.zincrby(key, 1, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * 将zset中指定元素score减1 + * + * 当分数小于1,代表这个元素代表的任务已完成,删除这个元素 + */ + public static void zdown(String key, String value) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.zincrby(key, -1, value); + if (jedis.zscore(key, value) < 1) { + jedis.zrem(key, value); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * 看一个key中某value元素是否存在,若不存在,返回false + */ + public static boolean zhas(String key, String value) { + Jedis jedis = null; + boolean has = true; + try { + jedis = RedisPool.getJedis(); + has = jedis.zscore(key, value) != null; + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return has; + } + + /** + * hash表,set一个键值对 + */ + public static void hset(String key, String field, String value) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.hset(key, field, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * set一个自动过期的键值对 + */ + public static void psetex(String key, String value, Long expireTime) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.psetex(key, expireTime, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * 设置key的值 + * @param key + * @param value + */ + public static void setnx(String key,String value){ + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.setnx(key, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + public static void lock(String key, String value, int second){ + Jedis jedis = RedisPool.getJedis(); + try { + doLock(key,value,second,jedis); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + RedisPool.returnResource(jedis); + } + } + + private static void doLock(String key,String value, long second, Jedis jedis) throws InterruptedException { + if(jedis.get(key) == null) { + + String result = jedis.set(key, value, "NX", "EX", second); + + if ("OK".equals(result)) { + + } else { + Thread.sleep(50); + doLock(key, value, second, jedis); + } + }else{ + Thread.sleep(50); + doLock(key, value, second, jedis); + } + } + + public static boolean unlock(String key, String value){ + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + String result = jedis.get(key); + if(value.equals(result)){ + jedis.del(key); + return true; + } + return false; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } finally { + RedisPool.returnResource(jedis); + } + } + + + + /** + * 是否存在某个key + */ + public static boolean exists(String key) { + Jedis jedis = null; + Boolean exists = Boolean.FALSE; + try { + jedis = RedisPool.getJedis(); + exists = jedis.exists(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return exists; + } + + /** + * hash表,获取一个field的值 + */ + public static String hget(String key, String field) { + Jedis jedis = null; + String value = null; + try { + jedis = RedisPool.getJedis(); + value = jedis.hget(key, field); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return value; + } + + /** + * hash表,获取所有值 + */ + public static Map hgetAll(String key) { + Jedis jedis = null; + Map value = null; + try { + jedis = RedisPool.getJedis(); + value = jedis.hgetAll(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return value; + } + + /** + * hash表,删除一个field + */ + public static void hdel(String key, String field) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.hdel(key, field); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * list,查询list长度 + * @param key + * @return + */ + public static Long llen(String key) { + Jedis jedis = null; + Long value=0L; + try { + jedis = RedisPool.getJedis(); + value=jedis.llen(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return value; + } + + /** + * 获取list中 指定位置的值 + * index从0开始 + * 如果 index 参数的值不在列表的区间范围内(out of range),返回 nil + * @param key + * @param index + * @return + */ + public static String lindex(String key,int index){ + Jedis jedis = RedisPool.getJedis(); + String result = jedis.lindex(key,index); + RedisPool.returnResource(jedis); + return result; + } + + /** + * 清空List数据 + * ltrim 让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除 + * start和end为0时,即清空list + * @param key + * @return + */ + public static String clearList(String key){ + Jedis jedis = RedisPool.getJedis(); + String result = jedis.ltrim(key,0,0); + jedis.lpop(key); + RedisPool.returnResource(jedis); + return result; + } + + + + /** + * list,弹出并返回list的首元素 + * @param timeout 阻塞时间,blpop操作超过此时间未完成返回null + * @param key + * @return + */ + public static String blpop(int timeout,String key) { + Jedis jedis = null; + List value=null; + try { + jedis = RedisPool.getJedis(); + value=jedis.blpop(timeout,key); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return value==null? null:value.get(0); + } + + /** + * list,在list末尾添加元素 + * @param key + * @param value + * @return + */ + public static Long rpush(String key,String value) { + Jedis jedis = null; + Long success=0L; + try { + jedis = RedisPool.getJedis(); + success=jedis.rpush(key,value); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return success; + } + + /** + * list,删除list中对应的元素 + * @param key + * @param count + * @param value + * @return + */ + public static Long lrem(String key,Long count,String value) { + Jedis jedis = null; + Long success=0L; + try { + jedis = RedisPool.getJedis(); + success=jedis.lrem(key,count,value); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return success; + } + + /** + * set集合,向集合添加一个元素 + */ + public static void sadd(String key, String val) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.sadd(key, val); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * set集合,获取所有元素 + */ + public static Set smembers(String key) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + return jedis.smembers(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return new HashSet<>(2); + } + + + /** + * set集合,向集合删除一个元素 + */ + public static void srem(String key, String val) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.srem(key, val); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * String: set + */ + public static void set(String key, String value) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.set(key, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * String: set 带过期时间 + */ + public static void set(String key, String value,long second) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.set(key,value,"nx", "ex", second); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * String: get + */ + public static String get(String key) { + Jedis jedis = null; + String value = null; + try { + jedis = RedisPool.getJedis(); + value = jedis.get(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return value; + } + + /** + * String: delete + */ + public static void del(String key) { + Jedis jedis = null; + try { + jedis = RedisPool.getJedis(); + jedis.del(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + } + + /** + * + * @param key + * @param increment 增量 + * @return + */ + public static Long incrBy(String key, long increment) { + Jedis jedis = null; + Long value = null; + try { + jedis = RedisPool.getJedis(); + value = jedis.incrBy(key, increment); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return value; + } + + + /** + * 更新key时间 + * @param key + * @param increment + * @return + */ + public static Long expire(String key, int increment) { + Jedis jedis = null; + Long value = null; + try { + jedis = RedisPool.getJedis(); + value = jedis.expire(key, increment); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return value; + } + + + /** + * 获取过期时间 如果获取的值为-1 说明此key 没有设置有效期 当值为 -2 时证明过了有效期。 + * @param key + * @return + */ + public static Long ttl(String key) { + Jedis jedis = null; + Long value = null; + try { + jedis = RedisPool.getJedis(); + value = jedis.ttl(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + RedisPool.returnResource(jedis); + } + return value; + } + + public static long incrByExpire(String key, long increment, int seconds) { + Jedis jedis = null; + Transaction multi = null; + Response value = null; + try { + jedis = RedisPool.getJedis(); + multi = jedis.multi(); + value = multi.incrBy(key, increment); + multi.expire(key, seconds); + multi.exec(); + } catch (Exception e) { + log.error(e.getMessage(), e); + if (multi != null) { + multi.discard(); + } + } finally { + RedisPool.returnResource(jedis); + } + return value == null ? 0 : value.get(); + } + +} + diff --git a/common/src/main/java/com/imitate/common/util/JsonUtils.java b/common/src/main/java/com/imitate/common/util/JsonUtils.java new file mode 100644 index 0000000..53dac29 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/JsonUtils.java @@ -0,0 +1,49 @@ +/******************************************************************************* +case_consumer * Copyright (c) 2005, 2014 springside.github.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + *******************************************************************************/ +package com.imitate.common.util; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; + +/** + * + * @author mumu + * + */ +public final class JsonUtils { + + private static ObjectMapper mapper = new ObjectMapper(); + + public static String toJson(Object object) { + + try { + return mapper.writeValueAsString(object); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static T toBean(String content, Class clazz) { + + try { + return mapper.readValue(content, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static T toBean(String content, TypeReference valueTypeRef) { + + try { + return mapper.readValue(content, valueTypeRef); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/common/src/main/java/com/imitate/common/util/MD5Util.java b/common/src/main/java/com/imitate/common/util/MD5Util.java new file mode 100644 index 0000000..4201897 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/MD5Util.java @@ -0,0 +1,51 @@ +package com.imitate.common.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.MessageDigest; + +/** + * MD5 工具 + */ +public final class MD5Util { + private static final Logger log = LoggerFactory.getLogger(MD5Util.class); + + /** + * md5 加密 + * + * @param input + * @return + */ + public static String toMd5(String input) { + try { + MessageDigest md5 = MessageDigest.getInstance("md5"); + md5.update(input.getBytes()); + return byteToString(md5.digest()); + } catch (Exception e) { + log.error("计算container信息md5出错", e); + + } + return null; + } + + /** + * 字节转字符串 + * + * @param byteValue + * @return + */ + private static String byteToString(byte[] byteValue) { + StringBuilder sb = new StringBuilder(); + int len = byteValue.length; + for (int i = 0; i < len; i++) { + byte b = byteValue[i]; + String hex = Integer.toHexString(0xFF & b); + if (hex.length() == 1) { + sb.append("0"); + } + sb.append(hex); + } + return sb.subSequence(8, 24).toString(); + } +} diff --git a/common/src/main/java/com/imitate/common/util/OKHttp3Utils3.java b/common/src/main/java/com/imitate/common/util/OKHttp3Utils3.java new file mode 100644 index 0000000..bfce032 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/OKHttp3Utils3.java @@ -0,0 +1,313 @@ +package com.imitate.common.util; + + +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.core.type.TypeReference; +import com.imitate.common.constant.ApiResultCsts; +import com.imitate.common.bean.ApiResult; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.*; +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +/** + * okhttp3 客户端 + * @author 悟空 + */ +public class OKHttp3Utils3 { + + private static final Logger log = LoggerFactory.getLogger(OKHttp3Utils3.class); + + public static int DEFAULT_TIME_OUT = 10; + + /** + * 全局实例可以保持http1.1 连接复用,线程池复用, 减少tcp的网络连接,关闭, + * 如果每次一个请求,在高并发下,thread增多到1W,close_wait持续增加到6k。 + */ + private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder() + .connectionPool(new ConnectionPool(50, 5, TimeUnit.MINUTES)) + .connectTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS).build(); + + private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + + + + /** + * 不同timeout的连接池 + */ + public static ConcurrentHashMap cacheClients = new ConcurrentHashMap(); + + + public static OkHttpClient getHttpClient(int timeout) { + + if (timeout == 0 || DEFAULT_TIME_OUT == timeout) { + return OK_HTTP_CLIENT; + } else { + OkHttpClient okHttpClient = cacheClients.get(timeout); + if (okHttpClient == null) { + return syncCreateClient(timeout); + } + return okHttpClient; + } + } + + private static synchronized OkHttpClient syncCreateClient(int timeout) { + OkHttpClient okHttpClient; + + okHttpClient = cacheClients.get(timeout); + if (okHttpClient != null) { + return okHttpClient; + } + + okHttpClient = new OkHttpClient.Builder().connectTimeout(timeout, TimeUnit.SECONDS).readTimeout(timeout, TimeUnit.SECONDS).writeTimeout(timeout, TimeUnit.SECONDS).build(); + cacheClients.put(timeout, okHttpClient); + return okHttpClient; + + } + + + /** + * GET请求 + * + * @param url + * @return Optional + */ + public static String get(String url, int timeout){ + try { + Request request = new Request.Builder().url(url) + .build(); + return getHttpClient(timeout).newCall(request).execute().body().string(); + }catch (Exception e){ + } + return null; + } + + + /** + * 带认证的get请求 + */ + public static String get(String url, int timeout,String authorization) { + try { + Request request = new Request.Builder().header("Authorization",authorization).url(url) + .build(); + return getUnsafeOkHttpClient().newCall(request).execute().body().string(); + }catch (Exception e){ + + } + return null; + } + + /** + * 带认证的delete请求 + */ + public static String delete(String url,Map param, int timeout, String authorization){ + try { + FormBody.Builder builder = new FormBody.Builder(); + for(String key : param.keySet()){ + builder.add(key, (String) param.get(key)); + } + RequestBody body = builder.build(); + Request request = new Request.Builder().header("Authorization",authorization).url(url).delete(body) + .build(); + return getUnsafeOkHttpClient().newCall(request).execute().body().string(); + }catch (Exception e){ + + } + return null; + } + + /** + * 带认证的表单类post请求 + */ + public static String sendPost(String url, Map param,String authorization) { + long start = System.currentTimeMillis(); + try { + FormBody.Builder builder = new FormBody.Builder(); + for(String key : param.keySet()){ + builder.add(key, (String) param.get(key)); + } + RequestBody body = builder.build(); + Request okRequest = new Request.Builder() + .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") + .addHeader("Authorization",authorization) + .url(url).post(body).build(); + return getUnsafeOkHttpClient().newCall(okRequest).execute().body().string(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + log.info("request url {} ,total time {} ms", url, (System.currentTimeMillis() - start)); + } + return null; + } + + + + + /** + * post form表单提交 + * @param url + * @param param + * @return + */ + public static ApiResult sendPost(String url, Map param) { + long start = System.currentTimeMillis(); + try { + FormBody.Builder builder = new FormBody.Builder(); + for(String key : param.keySet()){ + builder.add(key, (String) param.get(key)); + } + RequestBody body = builder.build(); + Request okRequest = new Request.Builder().header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8").url(url).post(body).build(); + return getApiResult(getHttpClient(0).newCall(okRequest).execute().body().string()); + } catch (Exception e) { + } finally { + log.info("request url {} ,total time {} ms", url, (System.currentTimeMillis() - start)); + } + return null; + } + + + public static String requestPost(String url, Map param) { + long start = System.currentTimeMillis(); + try { + FormBody.Builder builder = new FormBody.Builder(); + for(String key : param.keySet()){ + builder.add(key, (String) param.get(key)); + } + RequestBody body = builder.build(); + Request okRequest = new Request.Builder().header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8").url(url).post(body).build(); + String s = getUnsafeOkHttpClient().newCall(okRequest).execute().body().string(); + log.info("请求自动登陆接口返回值:{}",s); + return s; + } catch (Exception e) { + e.printStackTrace(); + } finally { + log.info("request url {} ,total time {} ms", url, (System.currentTimeMillis() - start)); + } + return null; + } + + + + + + + /** + * POST请求,参数为json格式。 + * + * @param url + * @param jsonObject + * @return Optional + */ + public static void sendPost(String url, JSONObject jsonObject) { + long start = System.currentTimeMillis(); + try { + RequestBody body = RequestBody.create(JSON, jsonObject.toJSONString()); + Request request = new Request.Builder().header("Content-Type","application/json").url(url).post(body).build(); + Call call = getHttpClient(15000).newCall(request); + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + //异步请求失败之后的回调 + log.error("异步发送请求失败,url:{},json:{}",url,jsonObject.toJSONString()); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + //异步请求成功之后的回调 + log.info("异步发送请求成功,url:{},json:{}",url,jsonObject.toJSONString()); + response.close(); + } + }); + } catch (Exception e) { + throw e; + } finally { + log.info("request url {} ,total time {} ms", url, (System.currentTimeMillis() - start)); + } + } + + + /** + * post json提交 + * @param url + * @param jsonStr + * @return + */ + public static ApiResult sendPost(String url, String jsonStr) { + long start = System.currentTimeMillis(); + try { + RequestBody body = RequestBody.create(JSON, jsonStr); + Request okRequest = new Request.Builder().header("Content-Type","application/json").url(url).post(body).build(); + return getApiResult(getHttpClient(0).newCall(okRequest).execute().body().string()); + } catch (Exception e) { + } finally { + log.info("request url {} ,total time {} ms", url, (System.currentTimeMillis() - start)); + } + return null; + } + + + private static ApiResult getApiResult(String resultStr) { + ApiResult result = new ApiResult<>(); + try { + log.debug("同步发送 POST 请求,返回结果: {}", resultStr); + result = JsonUtils.toBean(resultStr, new TypeReference>() {}); + }catch (Exception e){ + result.setCode(ApiResultCsts.CODE_FAIL); + log.error("同步发送 POST 请求,返回结果异常: {}", e); + } + return result; + } + + + + + /** + * okHttp3添加信任所有证书 + * @return + */ + public static OkHttpClient getUnsafeOkHttpClient() { + try { + final TrustManager[] trustAllCerts =new TrustManager[]{ + new X509TrustManager() { + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) { + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) { + } + + @Override + public java.security.cert.X509Certificate[]getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } + } + }; + final SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + OkHttpClient.Builder builder =new OkHttpClient.Builder(); + builder.sslSocketFactory(sslSocketFactory,(X509TrustManager)trustAllCerts[0]); + builder.hostnameVerifier(new HostnameVerifier() { + // 可以将不需要忽略的域名放入数组,也可为空(忽略所有证书) + String[] arr =new String[]{}; + @Override + public boolean verify(String hostname, SSLSession session) { + return !Arrays.asList(arr).contains(hostname); + } + }); + return builder.build(); + }catch (Exception e) { + throw new RuntimeException(e); + } + } + + +} diff --git a/common/src/main/java/com/imitate/common/util/R.java b/common/src/main/java/com/imitate/common/util/R.java new file mode 100644 index 0000000..af45150 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/R.java @@ -0,0 +1,82 @@ +package com.imitate.common.util; + +import com.alibaba.fastjson.JSONArray; +import com.imitate.common.enums.ErrorCodeEnum; +import org.apache.http.HttpStatus; + +import java.util.HashMap; +import java.util.Map; + +/** + * 前端统一返回数据 + * @author yanchao + */ +public class R extends HashMap { + + + @Override + public Object get(Object key) { + return this.get(key); + } + + public R(){ + put("result","success"); + put("errorCode", ErrorCodeEnum.SUCCESS.getValue()); + put("errorMsg",""); + put("data",new JSONArray()); + } + + public static R error(){ + return error(HttpStatus.SC_INTERNAL_SERVER_ERROR,"未知异常,请联系管理员"); + } + public static R error(String msg){ + return error(HttpStatus.SC_INTERNAL_SERVER_ERROR,msg); + } + public static R error(int code, String msg){ + R r = new R(); + r.put("result","fail"); + r.put("errorCode",code); + r.put("errorMsg",msg); + return r; + } + public static R error(String code, String msg){ + R r = new R(); + r.put("result","fail"); + r.put("errorCode",code); + r.put("errorMsg",msg); + return r; + } + public static R ok(String msg){ + R r = new R(); + r.put("errorMsg",msg); + return r; + } + public static R ok(Map map){ + R r = new R(); + r.putAll(map); + return r; + } + + public static R ok(){ + return new R(); + } + + + @Override + public R put(String key, Object value){ + super.put(key,value); + return this; + } + + public R setData(Object data) { + if(data == null || data == ""){ + put("data",new JSONArray()); + }else{ + JSONArray rst = new JSONArray(); + rst.add(data); + put("data",rst); + } + return this; + } + +} diff --git a/common/src/main/java/com/imitate/common/util/RedisPool.java b/common/src/main/java/com/imitate/common/util/RedisPool.java new file mode 100644 index 0000000..86eec5f --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/RedisPool.java @@ -0,0 +1,74 @@ +package com.imitate.common.util; + +import com.imitate.common.bean.BeanFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; +import redis.clients.jedis.exceptions.JedisException; + +public final class RedisPool { + private static final Logger log = LoggerFactory.getLogger(RedisPool.class); + + // 可用连接实例的最大数目,默认为8; + // 如果赋值为-1,则表示不限制,如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽) + private static Integer MAX_TOTAL = 1024; + // 控制一个pool最多有多少个状态为idle(空闲)的jedis实例,默认值是8 + private static Integer MAX_IDLE = 200; + // 等待可用连接的最大时间,单位是毫秒,默认值为-1,表示永不超时。 + // 如果超过等待时间,则直接抛出JedisConnectionException + private static Integer MAX_WAIT_MILLIS = 10000; + private static Integer TIMEOUT = 10000; + // 在borrow(用)一个jedis实例时,是否提前进行validate(验证)操作; + // 如果为true,则得到的jedis实例均是可用的 + private static Boolean TEST_ON_BORROW = true; + private static JedisPool jedisPool = null; + + private synchronized static void initJedisPool() { + if (jedisPool == null) { + try { + Environment env = BeanFactory.getObejct(Environment.class); + String ADDR = env.getProperty("spring.redis.host"); + int PORT = Integer.parseInt(env.getProperty("spring.redis.port")); + String AUTH = env.getProperty("spring.redis.password"); + + JedisPoolConfig config = new JedisPoolConfig(); + config.setMaxTotal(MAX_TOTAL); + config.setMaxIdle(MAX_IDLE); + config.setMaxWaitMillis(MAX_WAIT_MILLIS); + config.setTestOnBorrow(TEST_ON_BORROW); + log.info("开始reids初始化..."); + jedisPool = "".equals(AUTH) ? new JedisPool(config, ADDR, PORT, TIMEOUT) + : new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH); + log.info("测试jedisPool 信息:{}", jedisPool.getResource().toString()); + } catch (Exception e) { + throw new RuntimeException("jedisPool初始化错误", e); + } + } + } + + /** + * 获取Jedis实例 + * + * @return + */ + public static Jedis getJedis() { + if (jedisPool == null) { + initJedisPool(); + } + return jedisPool.getResource(); + } + + public static void returnResource(final Jedis jedis) { + if (jedis != null) { + // jedis.close()取代jedisPool.returnResource(jedis)方法将3.0版本开始 + try { + jedis.close(); + } catch (JedisException e) { + log.error(e.getMessage(), e); + } + } + } +} \ No newline at end of file diff --git a/common/src/main/java/com/imitate/common/util/ShellExeCallBack.java b/common/src/main/java/com/imitate/common/util/ShellExeCallBack.java new file mode 100644 index 0000000..7fd3611 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/ShellExeCallBack.java @@ -0,0 +1,12 @@ +package com.imitate.common.util; + +public interface ShellExeCallBack { + + /** + * + * @param line + * @param param + * @return 此 CallBack 特殊信息, + */ + boolean processLine(String line, T param); +} diff --git a/common/src/main/java/com/imitate/common/util/ShellUtil.java b/common/src/main/java/com/imitate/common/util/ShellUtil.java new file mode 100644 index 0000000..2b7afa9 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/ShellUtil.java @@ -0,0 +1,179 @@ +package com.imitate.common.util; + +import com.imitate.common.bean.ShellResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +/** + * @author guange + * @date 26/02/2017 + */ +public final class ShellUtil { + + private static final Logger logger = LoggerFactory.getLogger(ShellUtil.class); + + /** + * 执行shell命令并获取输出 + */ + public static String execute(String command) { + return executeAndGetExitStatus(command).getOut(); + } + + /** + * 执行shell命令并获得输出及退出码,失败重试 共尝试retryTimes次 + */ + public static ShellResult executeAndGetExitStatus(String command, int retryTimes) { + ShellResult result = new ShellResult(); + + for (int i = 0; i < retryTimes; i++) { + result = executeAndGetExitStatus(command); + if (result.getExitStatus() != 0) { + logger.info("执行shell错误, 再次执行 command: {}, result: {}, times: {}", command, result, i); + } else { + break; + } + } + + return result; + } + + /** + * 执行命令并获得输出以及退出码 + */ + public static ShellResult executeAndGetExitStatus(String command) { + ShellResult result = new ShellResult(); + + StringBuilder out = new StringBuilder(); + Integer exitStatus = -1; + + ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", command); + pb.redirectErrorStream(true); + try { + Process process = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + out.append(line); + out.append(System.getProperty("line.separator")); + } + exitStatus = process.waitFor(); + + } catch (Exception e) { + logger.error("执行shell出错, command:{}", command, e); + } + + result.setOut(out.toString().trim()); + result.setExitStatus(exitStatus); + logger.debug("execute shell command: {}, out: {}, status: {}", command, out, exitStatus); + + return result; + } + + /** + * 执行命令并获得输出以及退出码 + */ + public static ShellResult executeAndGetExitStatus(String command, ShellExeCallBack callBack, T param) { + ShellResult result = new ShellResult(); + + StringBuilder out = new StringBuilder(); + Integer exitStatus = -1; + + ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", command); + pb.redirectErrorStream(true); + try { + Process process = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + // 分布输出信息固定为一行,若需要处理多行信息从历史commit"评测分布输出多行处理版本提交"找回 + boolean processed = callBack.processLine(line, param); + if (processed) { + continue; + } + + logger.debug("executeAndGetExitStatus line: {}", line); // TODO 此处稳定后去除 + out.append(line); + out.append(System.getProperty("line.separator")); + } + exitStatus = process.waitFor(); + + } catch (Exception e) { + logger.error("执行shell出错, command:{}", command, e); + } + + result.setOut(out.toString().trim()); + result.setExitStatus(exitStatus); + + return result; + } + + + /** + * 执行shell命令 + * @param cmd + * @param callBack + * @param param + * @param + * @return + */ + public static ShellResult executeAndGetErrorStatus(String cmd,ShellExeCallBack callBack, T param) { + ShellResult result = new ShellResult(); + StringBuffer sb = new StringBuffer(); + Integer exitStatus = -1; + try { + Process ps = Runtime.getRuntime().exec(cmd); + + //获取执行正确结果 + BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream())); + String line; + while ((line = br.readLine()) != null) { + // 分布输出信息固定为一行,若需要处理多行信息从历史commit"评测分布输出多行处理版本提交"找回 + boolean processed = callBack.processLine(line, param); + if (processed) { + continue; + } + + sb.append(line).append(System.getProperty("line.separator")); + } + exitStatus = ps.waitFor(); + }catch (Exception e) { + logger.error("执行shell出错, command:{}", cmd, e); + } + result.setOut(sb.toString().trim()); + result.setExitStatus(exitStatus); + return result; + } + + /** + * 执行shell命令 + * @param cmd + * @param + * @return + */ + public static ShellResult executeAndGetErrorStatus(String cmd) { + ShellResult result = new ShellResult(); + StringBuffer sb = new StringBuffer(); + Integer exitStatus = -1; + try { + Process ps = Runtime.getRuntime().exec(cmd); + + //获取执行正确结果 + BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream())); + String line; + while ((line = br.readLine()) != null) { + sb.append(line).append(System.getProperty("line.separator")); + } + exitStatus = ps.waitFor(); + }catch (Exception e) { + logger.error("执行shell出错, command:{}", cmd, e); + } + result.setOut(sb.toString().trim()); + result.setExitStatus(exitStatus); + return result; + } + + +} diff --git a/common/src/main/java/com/imitate/common/util/SignUtil.java b/common/src/main/java/com/imitate/common/util/SignUtil.java new file mode 100644 index 0000000..867c102 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/SignUtil.java @@ -0,0 +1,140 @@ +package com.imitate.common.util; + + +import lombok.extern.slf4j.Slf4j; + +import java.security.MessageDigest; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +/** + * 签名算法工具类 + * @author yanchao + */ +@Slf4j +public class SignUtil { + private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; + + private final static String randomBaseStr = "abcdefghijklmnopqrstuvwxyz0123456789"; + // 自定义,签名私钥的key ,web端提供 + private static String SIGN_KEY = "sk"; + // 自定义,签名私钥的value,需web 端提供 + private static String SIGN_VALUE = "9NMU8ushmFu8SN1EKHOhvo9jmv1qp0"; + private static String CHARSET_NAME = "UTF-8"; + //签名key + private static final String SIGN = "sign"; + + public static String signMap(Map map) { + StringBuilder param = new StringBuilder(); + Iterator> entries = map.entrySet().iterator(); + //TreeMap自动按字母排序 + Map params = new TreeMap<>(); + while (entries.hasNext()) { + Map.Entry entry = entries.next(); + String key = entry.getKey(); + String[] values = entry.getValue(); + if (values == null) { + entries.remove(); + } + if (SIGN.equals(key)) { + continue; + } + params.put(key, values); + } + + Iterator> entries2 = params.entrySet().iterator(); + int i = 0; + while (entries2.hasNext()) { + Map.Entry entry = entries2.next(); + String key = entry.getKey(); + String[] values = entry.getValue(); + if (values.length == 1) { + if(i == 0){ + param.append(key).append("=").append(values[0]); + }else{ + param.append("&").append(key).append("=").append(values[0]); + } + } + i++; + } + //添加私钥 + param.append("&").append(SIGN_KEY).append("=").append(SIGN_VALUE); + log.debug("最终签名认证字符串:{}",param.toString()); + return MD5Encode(param.toString(), CHARSET_NAME); + } + + + public static String signMap(String path, Map map) { + StringBuilder param = new StringBuilder(); + Iterator> entries = map.entrySet().iterator(); + //TreeMap自动按字母排序 + Map params = new TreeMap<>(); + while (entries.hasNext()) { + Map.Entry entry = entries.next(); + String key = entry.getKey(); + String values = String.valueOf(entry.getValue()); + if (values == null) { + entries.remove(); + } + if (SIGN.equals(key)) { + continue; + } + params.put(key, values); + } + + Iterator> entries2 = params.entrySet().iterator(); + int i = 0; + while (entries2.hasNext()) { + Map.Entry entry = entries2.next(); + String key = entry.getKey(); + String values = entry.getValue(); + if (values != null) { + if(i == 0){ + param.append(key).append("=").append(values); + }else{ + param.append("&").append(key).append("=").append(values); + } + } + i++; + } + //添加私钥 + param.append("&").append(SIGN_KEY).append("=").append(SIGN_VALUE); + log.debug("最终签名认证字符串:{}",param.toString()); + return MD5Encode(param.toString(), CHARSET_NAME); + } + + private static String byteArrayToHexString(byte b[]) { + StringBuffer resultSb = new StringBuffer(); + for (int i = 0; i < b.length; i++) + resultSb.append(byteToHexString(b[i])); + + return resultSb.toString(); + } + + private static String byteToHexString(byte b) { + int n = b; + if (n < 0) { + n += 256; + } + int d1 = n / 16; + int d2 = n % 16; + return hexDigits[d1] + hexDigits[d2]; + } + + public static String MD5Encode(String origin, String charsetname) { + String resultString = null; + try { + resultString = new String(origin); + MessageDigest md = MessageDigest.getInstance("MD5"); + if (charsetname == null || "".equals(charsetname)) { + resultString = byteArrayToHexString(md.digest(resultString.getBytes())); + } else { + resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname))); + } + } catch (Exception exception) { + } + assert resultString != null; + return resultString.toUpperCase(); + } +} diff --git a/common/src/main/java/com/imitate/common/util/SimpleFileUtils.java b/common/src/main/java/com/imitate/common/util/SimpleFileUtils.java new file mode 100644 index 0000000..7b872f0 --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/SimpleFileUtils.java @@ -0,0 +1,109 @@ +package com.imitate.common.util; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.io.IOUtils; +import org.springframework.http.MediaType; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * @author jshixiong + */ +public class SimpleFileUtils { + public static MultipartFile getMultipartFile(File file) { + FileItem item = new DiskFileItemFactory().createItem("file" + , MediaType.MULTIPART_FORM_DATA_VALUE + , true + , file.getName()); + try (InputStream input = new FileInputStream(file); + OutputStream os = item.getOutputStream()) { + // 流转移 + IOUtils.copy(input, os); + } catch (Exception e) { + throw new IllegalArgumentException("Invalid file: " + e, e); + } + + return new CommonsMultipartFile(item); + } + + /** + * 读取文件字符串内容 + * @param file 文件 + * @return fileContent + */ + public static String fileToString(MultipartFile file){ + String fileContent = ""; + try { + InputStream inputStream = file.getInputStream(); + fileContent = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + } catch (IOException e) { + e.printStackTrace(); + } + return fileContent; + } + + /** + * 读取文件字符串内容 + * @param file 文件 + * @return fileContent + */ + public static String fileToString(File file){ + String fileContent = ""; + try { + InputStream inputStream = new FileInputStream(file); + fileContent = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + } catch (IOException e) { + e.printStackTrace(); + } + return fileContent; + } + + /** + * 将字符串内容变成文件导出 + * @param response HttpServletResponse + * @param context 内容 + * @param fileName 文件名 + */ + public static void stringToFileExport(HttpServletResponse response, String context, String fileName){ + response.setContentType("text/plain"); + try { + fileName = URLEncoder.encode(fileName, "UTF-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + response.setHeader("Content-Disposition","attachment; filename=" + fileName); + BufferedOutputStream buff = null; + StringBuffer write = new StringBuffer(); + ServletOutputStream outSos = null; + try { + outSos = response.getOutputStream(); + buff = new BufferedOutputStream(outSos); + //把内容写入文件 + write.append(context); + + buff.write(write.toString().getBytes(StandardCharsets.UTF_8)); + buff.flush(); + buff.close(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (buff!=null){ + buff.close(); + } + if (outSos!=null){ + outSos.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/common/src/main/java/com/imitate/common/util/SymmetricCryptoUtil.java b/common/src/main/java/com/imitate/common/util/SymmetricCryptoUtil.java new file mode 100644 index 0000000..80566ed --- /dev/null +++ b/common/src/main/java/com/imitate/common/util/SymmetricCryptoUtil.java @@ -0,0 +1,49 @@ +package com.imitate.common.util; + +import cn.hutool.crypto.Mode; +import cn.hutool.crypto.Padding; +import cn.hutool.crypto.symmetric.AES; + +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; + +/** + * @author yanchao + */ +public class SymmetricCryptoUtil { + /** + * 16字节 + */ + private static final String ENCODE_KEY = "1234567812345678"; + private static final String IV_KEY = "0000000000000000"; + + + public static String encryptFromString(String data, Mode mode, Padding padding) { + AES aes; + if (Mode.CBC == mode) { + aes = new AES(mode, padding, + new SecretKeySpec(ENCODE_KEY.getBytes(), "AES"), + new IvParameterSpec(IV_KEY.getBytes())); + } else { + aes = new AES(mode, padding, + new SecretKeySpec(ENCODE_KEY.getBytes(), "AES")); + } + return aes.encryptBase64(data, StandardCharsets.UTF_8); + } + + public static String decryptFromString(String data, Mode mode, Padding padding) { + AES aes; + if (Mode.CBC == mode) { + aes = new AES(mode, padding, + new SecretKeySpec(ENCODE_KEY.getBytes(), "AES"), + new IvParameterSpec(IV_KEY.getBytes())); + } else { + aes = new AES(mode, padding, + new SecretKeySpec(ENCODE_KEY.getBytes(), "AES")); + } + byte[] decryptDataBase64 = aes.decrypt(data); + return new String(decryptDataBase64, StandardCharsets.UTF_8); + } + +} diff --git a/common/src/main/resources/META-INF/spring.factories b/common/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..abafadb --- /dev/null +++ b/common/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +#Auto Configure \ No newline at end of file diff --git a/common/src/main/resources/common.properties b/common/src/main/resources/common.properties new file mode 100644 index 0000000..e69de29 diff --git a/parent/parent.iml b/parent/parent.iml new file mode 100644 index 0000000..ad687cb --- /dev/null +++ b/parent/parent.iml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/parent/pom.xml b/parent/pom.xml new file mode 100644 index 0000000..2947d1c --- /dev/null +++ b/parent/pom.xml @@ -0,0 +1,275 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.6 + + + com.imitate + parent + 0.0.1-SNAPSHOT + parent + parent + pom + + + + + 1.8 + 1.2.83 + 4.4.5 + 2.0.1.Final + + 2.1.0 + + 1.2.10 + + 1.1.10 + + 5.7.11 + + 2.1.6 + 3.12.0 + 2.9.0 + 2.7 + 3.6 + 1.9 + 5.11.2 + 2.9.0 + 1.9.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-aop + + + + com.spring4all + swagger-spring-boot-starter + ${swagger2.version} + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + org.projectlombok + lombok + + + + com.alibaba + fastjson + ${fastjson.version} + + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + + + + + javax.validation + validation-api + ${javax.validation.version} + + + org.springframework.boot + spring-boot-starter-validation + + + + + com.alibaba + easyexcel + ${esayexcel.version} + + + + cn.hutool + hutool-all + ${hutool.version} + compile + + + + tk.mybatis + mapper-spring-boot-starter + ${mapper.version} + + + + mybatis-spring-boot-starter + org.mybatis.spring.boot + + + log4j-api + org.apache.logging.log4j + + + + + + + mysql + mysql-connector-java + runtime + + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper.version} + + + + + + commons-fileupload + commons-fileupload + 1.3.2 + + + org.apache.commons + commons-lang3 + ${commons-lang3-version} + + + commons-io + commons-io + ${commons-io.version} + + + + com.squareup.okhttp3 + okhttp + 4.9.3 + + + + redis.clients + jedis + ${jedis.version} + + + + com.aliyun + aliyun-java-sdk-core + 4.4.6 + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.imitate.web.WebApplication + execute + + + + + repackage + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + false + true + 1.8 + ${java.version} + ${java.version} + false + UTF8 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + + + + src/main/java + + + **/*.xml + **/*.properties + + false + + + src/main/resources + + **/*.py + **/*.sh + **/*.xml + **/*.properties + + false + + + + + + + imitate-${project.version} + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..a279e7a --- /dev/null +++ b/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + com.imitate + imitsys + 0.0.1-SNAPSHOT + imitsys + imitsys + pom + + + parent + common + web + + + diff --git a/web/pom.xml b/web/pom.xml new file mode 100644 index 0000000..bbb0c5f --- /dev/null +++ b/web/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + + parent + com.imitate + 0.0.1-SNAPSHOT + ../parent/pom.xml + + + web + 0.0.1-SNAPSHOT + web + web + jar + + + + + com.imitate + common + 0.0.1-SNAPSHOT + + + + + + diff --git a/web/src/main/java/com/imitate/web/WebApplication.java b/web/src/main/java/com/imitate/web/WebApplication.java new file mode 100644 index 0000000..054ceea --- /dev/null +++ b/web/src/main/java/com/imitate/web/WebApplication.java @@ -0,0 +1,16 @@ +package com.imitate.web; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScans; +import tk.mybatis.spring.annotation.MapperScan; + +@MapperScan(basePackages = { "com.imitate.web.persistence.mapper" }) +@ComponentScans(value = { @ComponentScan("com.imitate.common") }) +@SpringBootApplication +public class WebApplication { + public static void main(String[] args) { + SpringApplication.run(WebApplication.class, args); + } +} diff --git a/web/src/main/java/com/imitate/web/aspect/ParamsOutAspect.java b/web/src/main/java/com/imitate/web/aspect/ParamsOutAspect.java new file mode 100644 index 0000000..c929fd8 --- /dev/null +++ b/web/src/main/java/com/imitate/web/aspect/ParamsOutAspect.java @@ -0,0 +1,183 @@ +package com.imitate.web.aspect; + +import com.alibaba.fastjson.JSONObject; +import com.imitate.common.annotation.DoSysLog; +import com.imitate.common.util.HttpContextUtils; +import com.imitate.common.util.IpUtil; +import com.imitate.web.persistence.beans.SysLog; +import com.imitate.web.persistence.mapper.SysLogMapper; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.stereotype.Component; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 拦截controller,输出入参、响应内容和响应时间 + * + * @author 威少 + */ +@Component +@Aspect +@Slf4j +public class ParamsOutAspect implements Ordered { + + @Autowired + private SysLogMapper sysLogMapper; + + + @Pointcut("@annotation(com.imitate.common.annotation.DoSysLog)") + public void controllerLogPointCut() { + } + + + @Around("controllerLogPointCut()") + public Object doRecoveryActions(ProceedingJoinPoint joinPoint) throws Throwable { + DoSysLog annotation = AnnotationUtils.getAnnotation( + ((MethodSignature) joinPoint.getSignature()).getMethod(), + DoSysLog.class); + //获取注解传递的参数 + boolean value = annotation.isLog(); + if (!value){ + return joinPoint.proceed(); + } + + SysLog sysLog = new SysLog(); + Instant startTime = Instant.now(); + Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); + RequestMapping methodMapping = method.getAnnotation(RequestMapping.class); + if (methodMapping != null) { + sysLog.setMethodPath(methodMapping.path()[0]); + if (methodMapping.method().length > 0) { + sysLog.setHttpType(methodMapping.method()[0].name()); + } else { + sysLog.setHttpType("GET"); + } + } + + ApiOperation methodApiOperation = method.getAnnotation(ApiOperation.class); + if (methodApiOperation != null) { + sysLog.setOperation(methodApiOperation.value()); + } + + //请求的方法名 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = joinPoint.getSignature().getName(); + sysLog.setMethod(className + "." + methodName + "()"); + + Class clazz = Class.forName(className); + RequestMapping clazzReqMapping = clazz.getAnnotation(RequestMapping.class); + if (clazzReqMapping != null && clazzReqMapping.value().length > 0) { + sysLog.setClassPath(clazzReqMapping.value()[0]); + } + Api clazzApi = clazz.getAnnotation(Api.class); + if (clazzApi != null) { + sysLog.setModuleName(clazzApi.value()); + } + + String[] params = ((MethodSignature) joinPoint.getSignature()).getParameterNames(); + Object[] args = joinPoint.getArgs(); + + //取入参 + Map paramsMap = new HashMap<>(); + if (params != null) { + for (int i = 0; i < params.length; i++) { + if ((!(args[i] instanceof BindingResult) &&!(args[i] instanceof HttpServletRequest) && !(args[i] instanceof HttpServletResponse)) && !(args[i] instanceof MultipartFile) && !(args[i] instanceof MultipartFile[])) { + paramsMap.put(params[i], args[i]); + } + } + } + sysLog.setParams(JSONObject.toJSONString(paramsMap)); + + Object proceed = joinPoint.proceed(); + + //记录耗时 + int cost = Duration.between(startTime, Instant.now()).getNano() / 1000000; + sysLog.setTime(cost); + sysLog.setCreateTime(LocalDateTime.now()); + sysLog.setUpdateTime(LocalDateTime.now()); + //获取request + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + //设置IP地址 + String ip = IpUtil.getIpAddr(request); + if ("0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)) { + sysLog.setIp("localhost"); + } else { + sysLog.setIp(ip); + } + //设置返回结果 + sysLog.setResult(null==proceed?null:proceed.toString()); + +// String remoteHost = request.getRemoteHost(); +// if (!"127.0.0.1".equals(remoteHost) && !"系统健康检测".equals(sysLog.getOperation())) { +// //异步发消息写redis +// +// } + + //主日志数据存储 + sysLogMapper.insertSelective(sysLog); + + return proceed; + } + + /** + * 获取e.printStackTrace() 的具体信息,赋值给String 变量,并返回 + * @param e + * Throwable + * @return e.printStackTrace() 中 的信息 + */ + public static String getStackTraceInfo(Throwable e) { + StringWriter sw = null; + PrintWriter pw = null; + try { + sw = new StringWriter(); + pw = new PrintWriter(sw); + e.printStackTrace(pw);//将出错的栈信息输出到printWriter中 + pw.flush(); + sw.flush(); + return sw.toString(); + } catch (Exception ex) { + return "printStackTrace()转换错误"; + } finally { + if (sw != null) { + try { + sw.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + if (pw != null) { + pw.close(); + } + } + } + + @Override + public int getOrder() { + return 1; + } + +} diff --git a/web/src/main/java/com/imitate/web/init/Runner.java b/web/src/main/java/com/imitate/web/init/Runner.java new file mode 100644 index 0000000..b50cc69 --- /dev/null +++ b/web/src/main/java/com/imitate/web/init/Runner.java @@ -0,0 +1,107 @@ +package com.imitate.web.init; + +import cn.hutool.core.util.XmlUtil; +import com.alibaba.excel.EasyExcel; +import com.imitate.common.util.SimpleFileUtils; +import com.imitate.web.persistence.beans.DeviceType; +import com.imitate.web.persistence.beans.Producer; +import com.imitate.web.persistence.mapper.DeviceTypeMapper; +import com.imitate.web.persistence.mapper.ProducerMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + * @author jshixiong + */ +@Slf4j +@Component +public class Runner{ + + @Autowired + private DeviceTypeMapper deviceTypeMapper; + @Autowired + private ProducerMapper producerMapper; + + @Value("${imitate.init.path}") + private String initPath; + @Value("${imitate.init.xlsx}") + private String initExcelName; + @Value("${imitate.init.xml}") + private String initXmlName; + + @PostConstruct + public void init(){ + log.info("-------init db from excel or xml--------"); + File file = new File(initPath+ File.separator +initExcelName); + if (!file.exists()){ + file = new File(initPath+ File.separator +initXmlName); + if (!file.exists()){ + log.error("-------init db failed : no such file---"+file.getPath()); + }else { + try { + String xmlData = SimpleFileUtils.fileToString(file); + Document document= XmlUtil.parseXml(xmlData); + //获得XML文档根节点 + Element rootElement= XmlUtil.getRootElement(document); + //解析厂商数据 + Element producerInfoElement = XmlUtil.getElement(rootElement, "producer-info"); + List producerElements = XmlUtil.getElements(producerInfoElement, "producer"); + List producerList = new ArrayList<>(); + for (Element producerElement : producerElements){ + Producer producer = new Producer(); + producer.setName(producerElement.getAttribute("name")); + producer.setAddress(producerElement.getAttribute("address")); + producer.setProducerNumber(producerElement.getAttribute("producerNumber")); + producer.setContacts1(producerElement.getAttribute("contacts1")); + producer.setTel1(producerElement.getAttribute("tel1")); + producer.setPhone1(producerElement.getAttribute("phone1")); + producer.setCreateTime(LocalDateTime.now()); + producerList.add(producer); + } + producerMapper.insertList(producerList); + //解析设备类型数据 + Element deviceTypeInfoElement = XmlUtil.getElement(rootElement, "device-type-info"); + List deviceTypeElements = XmlUtil.getElements(deviceTypeInfoElement, "device-type"); + List deviceTypeList = new ArrayList<>(); + for (Element deviceTypeElement : deviceTypeElements){ + DeviceType deviceType = new DeviceType(); + deviceType.setName(deviceTypeElement.getAttribute("name")); + deviceType.setTypeNumber(deviceTypeElement.getAttribute("typeNumber")); + deviceType.setPattern(deviceTypeElement.getAttribute("pattern")); + deviceType.setSecretLevel(deviceTypeElement.getAttribute("secretLevel")); + deviceType.setManagementLevel(deviceTypeElement.getAttribute("managementLevel")); + deviceType.setCreateTime(LocalDateTime.now()); + deviceTypeList.add(deviceType); + } + deviceTypeMapper.insertList(deviceTypeList); + }catch (Exception e){ + log.error("-------init db failed : init error-------"); + } + } + }else { + try{ + List deviceTypeList = EasyExcel.read(file, DeviceType.class,null) + .sheet(5).headRowNumber(2).doReadSync(); + List producerList = EasyExcel.read(file, Producer.class,null) + .sheet(4).headRowNumber(2).doReadSync(); + + deviceTypeMapper.insertList(deviceTypeList); + producerMapper.insertList(producerList); + }catch (Exception e){ + log.error("-------init db failed : init error-------"); + } + } + + } + +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/controller/DataCenterController.java b/web/src/main/java/com/imitate/web/module/simulation/controller/DataCenterController.java new file mode 100644 index 0000000..7a0e1ef --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/controller/DataCenterController.java @@ -0,0 +1,190 @@ +package com.imitate.web.module.simulation.controller; + + +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageInfo; +import com.imitate.common.annotation.DoSysLog; +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.util.BasicController; +import com.imitate.common.util.SimpleFileUtils; +import com.imitate.common.util.R; +import com.imitate.web.module.simulation.service.DataTerminalService; +import com.imitate.web.params.DataTerminalParam; +import com.imitate.web.persistence.beans.DataTerminal; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; + +/** + *

+ * 数据中心控制器 + *

+ * + * @author jshixiong + * @since 2022-07-28 + */ +@Slf4j +@Api(value = "数据中心控制器", hidden = true) +@RestController +@RequestMapping("/dataCenter") +public class DataCenterController extends BasicController { + + @Autowired + private DataTerminalService dataTerminalService; + + /** + * 注册或修改数据中心服务器(有无ID) + * @param dataTerminalParam DataTerminal + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "注册或修改数据中心服务器", httpMethod = "POST") + @RequestMapping(path = "/editOrAdd",method = RequestMethod.POST) + public R editOrAddDataCenter(@RequestBody @Valid DataTerminalParam dataTerminalParam, BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]注册或修改数据中心服务器,param:{}",dataTerminalParam); + dataTerminalParam.setType("1"); + if (dataTerminalService.updateOrAdd(dataTerminalParam.getDataTerminal())>0){ + log.info("[end]注册或修改数据中心服务器"); + return R.ok().setData(dataTerminalParam.getDataTerminal()); + }else { + log.info("[end]注册或修改数据中心服务器,失败"); + return R.error(); + } + } + + /** + * 根据ID删除数据中心服务器 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "删除数据中心服务器", httpMethod = "POST") + @RequestMapping(path = "/delete/{id}",method = RequestMethod.POST) + public R delete(@PathVariable("id") Long id){ + log.info("[start]删除数据中心服务器,id:{}",id); + DataTerminal dataTerminal = dataTerminalService.getById(id); + if (dataTerminalService.deleteById(id)>0){ + log.info("[end]删除数据中心服务器,return:{}",dataTerminal); + return R.ok().setData(dataTerminal); + }else { + log.info("[end]删除数据中心服务器,失败"); + return R.error(); + } + } + + /** + * 通过id获取 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "查看数据中心服务器", httpMethod = "GET") + @RequestMapping(path = "/getById/{id}",method = RequestMethod.GET) + public R getById(@PathVariable(name = "id") Long id){ + log.info("[start]查看数据中心服务器,id:{}",id); + DataTerminal byId = dataTerminalService.getById(id); + log.info("[end]查看数据中心服务器,return:{}",byId); + return R.ok().setData(byId); + } + + /** + * 分页查看数据中心服务器 + * @param param 参数 + * @return R + */ + @ApiOperation(value = "分页查看数据中心服务器", httpMethod = "GET") + @RequestMapping(path = "/page",method = RequestMethod.GET) + public R pageDevice(DataTerminalParam param){ + log.info("[start]分页查看数据中心服务器,param:{}",param); + param.setType("1"); + PageInfo page = dataTerminalService.page(param); + log.info("[end]分页查看数据中心服务器,return:{}",page); + return R.ok().setData(page); + } + + /** + * 导出初装资源 + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "数据中心服务器导出初装资源", httpMethod = "GET") + @RequestMapping(path = "/resourceExport/{id}",method = RequestMethod.GET) + public void resourceExport(@PathVariable("id") Long id,HttpServletResponse response){ + log.info("[start]数据中心服务器导出初装资源,id:{}",id); + String resourceJson = dataTerminalService.resourceExport(id); + SimpleFileUtils.stringToFileExport(response,resourceJson,"数据中心服务器初装资源.txt"); + log.info("[end]数据中心服务器导出初装资源内容,return:{}",resourceJson); + } + + /** + * 开始数据中心服务器开通 + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "开始数据中心服务器开通", httpMethod = "POST") + @RequestMapping(path = "/startOpen",method = RequestMethod.POST) + public R startOpen(){ + log.info("[start]开始数据中心服务器开通"); + log.info("[end]开始数据中心服务器开通"); + return R.ok(); + } + + /** + * 设置宿主机标识 + * @param hostFlag 宿主机标识 + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "数据中心服务器设置宿主机标识", httpMethod = "POST") + @RequestMapping(path = "/setHostFlag",method = RequestMethod.POST) + public R setHostFlag(String hostFlag){ + log.info("[start]数据中心服务器设置宿主机标识"); + log.info("[end]数据中心服务器设置宿主机标识"); + return R.ok().setData(hostFlag); + } + + /** + * 注入初装资源 + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "数据中心服务器注入初装资源", httpMethod = "POST") + @RequestMapping(path = "/resourceImport",method = RequestMethod.POST) + public R resourceImport(@RequestParam("file") MultipartFile file){ + log.info("[start]数据中心服务器注入初装资源"); + String fileContent = SimpleFileUtils.fileToString(file); + DataTerminal dataTerminal; + try { + dataTerminal = JSONObject.parseObject(fileContent, DataTerminal.class); + }catch (Exception e){ + log.info("[end]数据中心服务器注入初装资源,fileContent:{}",fileContent); + return R.error("文件内容错误"); + } + if (!"1".equals(dataTerminal.getType()) || null == dataTerminal.getId() || null == dataTerminalService.getById(dataTerminal.getId())){ + log.info("[end]数据中心服务器注入初装资源,fileContent:{}",fileContent); + return R.error("文件内容错误,error type or id"); + } + dataTerminal = dataTerminalService.openTerminal(dataTerminal); + log.info("[end]数据中心服务器注入初装资源,return:{}",dataTerminal); + return R.ok().setData(dataTerminal); + } + + @ApiOperation(value = "数据中心服务器查询是否开通", httpMethod = "GET") + @RequestMapping(path = "/isOpen",method = RequestMethod.GET) + public R isDataCenterOpen(){ + log.info("[start]数据中心服务器查询是否开通"); + Boolean openFlag = dataTerminalService.isTerminalOpen("1"); + log.info("[end]数据中心服务器查询是否开通,return:{}",openFlag); + return R.ok().setData(openFlag); + } +} + diff --git a/web/src/main/java/com/imitate/web/module/simulation/controller/DeviceController.java b/web/src/main/java/com/imitate/web/module/simulation/controller/DeviceController.java new file mode 100644 index 0000000..0f6ba9d --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/controller/DeviceController.java @@ -0,0 +1,266 @@ +package com.imitate.web.module.simulation.controller; + + +import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageInfo; +import com.imitate.common.annotation.DoSysLog; +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.util.BasicController; +import com.imitate.common.util.R; +import com.imitate.web.params.DeviceParam; +import com.imitate.web.persistence.beans.Device; +import com.imitate.web.module.simulation.service.DeviceService; +import com.imitate.web.params.DeviceListParam; +import com.imitate.web.vo.DeviceByTypeVO; +import com.imitate.web.vo.DeviceVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * 模拟设备表 前端控制器 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Slf4j +@Api(value = "模拟设备控制器", hidden = true) +@RestController +@RequestMapping("/device") +public class DeviceController extends BasicController { + + @Autowired + private DeviceService deviceService; + + /** + * 注册或修改设备(有无ID) + * @param deviceParam Device + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "新增或修改设备", httpMethod = "POST") + @RequestMapping(path = "/editOrAdd",method = RequestMethod.POST) + public R editOrAddDevice(@RequestBody @Valid DeviceParam deviceParam, BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]新增或修改设备,param:{}",deviceParam); + int i = deviceService.updateOrAddDevice(deviceParam.getDevice()); + if (i == -1){ + log.info("[end]新增或修改设备,失败,设备编号重复"); + return R.error("编号重复"); + }else if (i>0){ + log.info("[end]新增或修改设备"); + return R.ok().setData(deviceParam.getDevice()); + }else { + log.info("[end]新增或修改设备,失败"); + return R.error(); + } + } + + /** + * 根据ID删除设备 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "删除设备", httpMethod = "POST") + @RequestMapping(path = "/delete/{id}",method = RequestMethod.POST) + public R deleteDevice(@PathVariable("id") Long id){ + log.info("[start]删除设备,id:{}",id); + Device device = deviceService.getById(id); + if (deviceService.deleteDeviceById(id)>0){ + log.info("[end]删除设备,return:{}",device); + return R.ok().setData(device); + }else { + log.info("[end]删除设备,失败"); + return R.error(); + } + } + + /** + * 批量删除设备 + * @param deviceList 设备列表 + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "批量删除设备", httpMethod = "POST") + @RequestMapping(path = "/deleteByList",method = RequestMethod.POST) + public R deleteByList(@RequestBody List deviceList){ + log.info("[start]批量删除设备,deviceList:{}",deviceList); + if (deviceService.deleteByList(deviceList)>0){ + log.info("[end]批量删除设备"); + return R.ok(); + }else { + log.info("[end]批量删除设备,失败"); + return R.error(); + } + } + + /** + * 通过id获取 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "查看设备", httpMethod = "GET") + @RequestMapping(path = "/getById/{id}",method = RequestMethod.GET) + public R getById(@PathVariable("id") Long id){ + log.info("[start]查看设备,id:{}",id); + Device byId = deviceService.getById(id); + log.info("[end]查看设备,return:{}",byId); + return R.ok().setData(byId); + } + + /** + * 根据类型查询设备列表 + * @return R + */ + @ApiOperation(value = "分类型查看设备列表", httpMethod = "GET") + @RequestMapping(path = "/listByType",method = RequestMethod.GET) + public R listDeviceByType(){ + log.info("[start]分类型查看设备列表"); + List list = deviceService.listDeviceByType(); + log.info("[end]分类型查看设备列表,return:{}",list); + return R.ok().setData(list); + } + + /** + * 查看某类型设备列表 + * @param param 参数 + * @return R + */ + @ApiOperation(value = "查看设备列表", httpMethod = "GET") + @RequestMapping(path = "/list",method = RequestMethod.GET) + public R listDevice(DeviceListParam param){ + log.info("[start]查看设备列表"); + List list = deviceService.list(param); + log.info("[end]查看设备列表,return:{}",list); + return R.ok().setData(list); + } + + /** + * 分页查询设备 + * @param param 参数 + * @return R + */ + @ApiOperation(value = "分页查看设备", httpMethod = "GET") + @RequestMapping(path = "/page",method = RequestMethod.GET) + public R pageDevice(DeviceListParam param){ + log.info("[start]分页查看设备,param:{}",param); + PageInfo page = deviceService.pageDevice(param); + log.info("[end]分页查看设备,return:{}",page); + return R.ok().setData(page); + } + + /** + * 设备初装 + * @param param DeviceListParam + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "设备初装", httpMethod = "POST") + @RequestMapping(path = "/configureDevice",method = RequestMethod.POST) + public R configureDevice(@RequestBody DeviceListParam param){ + log.info("[start]设备初装,param:{}",param); + if (deviceService.configureDevice(param)>0){ + log.info("[end]设备初装"); + return R.ok().setData(param.getDeviceList()); + }else { + log.info("[end]设备初装,失败"); + return R.error(); + } + } + + /** + * excel导入设备 + * @param file excel文件 + * @return R + * @throws IOException IOException + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "批量导入设备", httpMethod = "POST") + @RequestMapping(path = "/import",method = RequestMethod.POST) + public R importList(@RequestParam("file") MultipartFile file) throws IOException { + log.info("[start]批量导入设备"); + List list = EasyExcel.read(file.getInputStream(), DeviceVO.class,null) + .sheet(0).doReadSync(); + List deviceList = deviceService.addExcelList(list); + log.info("[end]批量导入设备"); + return R.ok().setData(deviceList); + } + + /** + * 批量新增设备 + * @param deviceParamList 设备列表 + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "批量新增设备", httpMethod = "POST") + @RequestMapping(path = "/addList",method = RequestMethod.POST) + public R importList(@RequestBody @Valid List deviceParamList, BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]批量新增设备"); + int lc = deviceService.addList(deviceParamList); + if (lc == -1){ + log.info("[end]批量新增设备,失败,有重复设备编号"); + return R.error("有重复设备编号!"); + } + if (lc>0){ + log.info("[end]批量新增设备"); + return R.ok(); + }else { + log.info("[end]批量新增设备,失败"); + return R.error(); + } + } + + /** + * 模板 + * @param response response + * @throws Exception Exception + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "导出设备新增模板", httpMethod = "GET") + @RequestMapping(path = "/model",method = RequestMethod.GET) + public void outModel(HttpServletResponse response) throws Exception { + log.info("[start]导出设备新增模板"); + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + String fileName = URLEncoder.encode("model", "UTF-8"); + response.setHeader("Content-Disposition","attachment;filename="+fileName+".xlsx"); + EasyExcel.write(response.getOutputStream(), DeviceVO.class).head(DeviceVO.class) + .sheet("模板").doWrite(new ArrayList()); + log.info("[end]导出设备新增模板"); + } + + /** + * 获取仿真图默认设备 + * @param u3dType 默认设备类型 1注入器、2开机棒、3授启棒 + */ + @ApiOperation(value = "获取仿真图默认设备", httpMethod = "GET") + @RequestMapping(path = "/u3dDevice/{u3dType}",method = RequestMethod.GET) + public R u3dDevice(@PathVariable("u3dType") Integer u3dType){ + log.info("[start]获取仿真图默认设备,u3dType={}",u3dType); + JSONObject jsonObject = deviceService.u3dDevice(u3dType); + log.info("[end]获取仿真图默认设备,return:{}",jsonObject); + return R.ok().setData(jsonObject); + } +} + diff --git a/web/src/main/java/com/imitate/web/module/simulation/controller/DeviceDistributionController.java b/web/src/main/java/com/imitate/web/module/simulation/controller/DeviceDistributionController.java new file mode 100644 index 0000000..ba03dea --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/controller/DeviceDistributionController.java @@ -0,0 +1,106 @@ +package com.imitate.web.module.simulation.controller; + + +import com.github.pagehelper.PageInfo; +import com.imitate.common.annotation.DoSysLog; +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.util.BasicController; +import com.imitate.common.util.R; +import com.imitate.web.module.simulation.service.DeviceDistributionService; +import com.imitate.web.params.DistributionListParam; +import com.imitate.web.params.DistributionParam; +import com.imitate.web.persistence.beans.DeviceDistribution; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + *

+ * 设备配发/调拨单 前端控制器 + *

+ * + * @author jshixiong + * @since 2022-08-02 + */ +@Slf4j +@Api(value = "设备配发/调拨单控制器", hidden = true) +@RestController +@RequestMapping("/deviceDistribution") +public class DeviceDistributionController extends BasicController { + + @Autowired + private DeviceDistributionService distributionService; + + /** + * 分页查看配发/调拨单 + * @param param DistributionListParam + * @return R + */ + @ApiOperation(value = "分页查看配发/调拨单", httpMethod = "GET") + @RequestMapping(path = "/page",method = RequestMethod.GET) + public R page(DistributionListParam param){ + log.info("[start]分页查看配发/调拨单,param:{}",param); + PageInfo page = distributionService.page(param); + log.info("[end]分页查看配发/调拨单,return:{}",page); + return R.ok().setData(page); + } + + /** + * 新增或修改配发/调拨单 + * @param param DistributionParam + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "新增或修改配发/调拨单", httpMethod = "POST") + @RequestMapping(path = "/editOrAdd",method = RequestMethod.POST) + public R editOrAdd(@RequestBody @Valid DistributionParam param, BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]新增或修改配发/调拨单,param:{}",param); + int lc = distributionService.editOrAdd(param); + if (lc>0){ + log.info("[end]新增或修改配发/调拨单"); + return R.ok().setData(param.getDeviceDistribution()); + }else { + log.info("[end]新增或修改配发/调拨单,失败"); + return R.error(); + } + } + + /** + * 查看配发/调拨单详情 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "查看配发/调拨单详情", httpMethod = "GET") + @RequestMapping(path = "/getById/{id}",method = RequestMethod.GET) + public R getById(@PathVariable("id") Long id){ + log.info("[start]查看配发/调拨单详情,id:{}",id); + DeviceDistribution byId = distributionService.getById(id); + log.info("[end]查看配发/调拨单详情,return:{}",byId); + return R.ok().setData(byId); + } + + /** + * 删除配发/调拨单 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "删除配发/调拨单", httpMethod = "POST") + @RequestMapping(path = "/delete/{id}",method = RequestMethod.POST) + public R deleteById(@PathVariable("id") Long id){ + log.info("[start]删除配发/调拨单,id:{}",id); + DeviceDistribution distribution = distributionService.deleteById(id); + log.info("[end]删除配发/调拨单,return:{}",distribution); + return R.ok().setData(distribution); + } +} + diff --git a/web/src/main/java/com/imitate/web/module/simulation/controller/DeviceTypeController.java b/web/src/main/java/com/imitate/web/module/simulation/controller/DeviceTypeController.java new file mode 100644 index 0000000..e54d933 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/controller/DeviceTypeController.java @@ -0,0 +1,189 @@ +package com.imitate.web.module.simulation.controller; + + +import com.alibaba.excel.EasyExcel; +import com.github.pagehelper.PageInfo; +import com.imitate.common.annotation.DoSysLog; +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.util.BasicController; +import com.imitate.common.util.R; +import com.imitate.web.module.simulation.service.DeviceTypeService; +import com.imitate.web.params.DeviceTypeParam; +import com.imitate.web.persistence.beans.DeviceType; +import com.imitate.web.vo.DeviceTypeVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +/** + *

+ * 设备类型表 前端控制器 + *

+ * + * @author jshixiong + * @since 2022-07-25 + */ +@Slf4j +@Api(value = "设备类型控制器", hidden = true) +@RestController +@RequestMapping("/deviceType") +public class DeviceTypeController extends BasicController { + + @Autowired + private DeviceTypeService deviceTypeService; + + /** + * 通过id获取 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "查看设备类型", httpMethod = "GET") + @RequestMapping(path = "/getById/{id}",method = RequestMethod.GET) + public R getById(@PathVariable("id") Long id){ + log.info("[start]查看设备类型,id:{}",id); + DeviceType byId = deviceTypeService.getById(id); + log.info("[end]查看设备类型,return:{}",byId); + return R.ok().setData(byId); + } + + /** + * 根据ID删除设备 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "删除设备类型", httpMethod = "POST") + @RequestMapping(path = "/delete/{id}",method = RequestMethod.POST) + public R deleteById(@PathVariable("id") Long id){ + log.info("[start]删除设备类型,id:{}",id); + DeviceType deviceType = deviceTypeService.getById(id); + if (deviceTypeService.deleteById(id)>0){ + log.info("[end]删除设备类型,return:{}",deviceType); + return R.ok().setData(deviceType); + }else { + log.info("[end]删除设备类型,失败"); + return R.error(); + } + } + + @DoSysLog(isLog = true) + @ApiOperation(value = "批量删除设备类型", httpMethod = "POST") + @RequestMapping(path = "/deleteByList",method = RequestMethod.POST) + public R deleteByList(@RequestBody List deviceTypeList){ + log.info("[start]批量删除设备类型,params:{}",deviceTypeList); + if (deviceTypeService.deleteByTypeList(deviceTypeList)>0){ + log.info("[end]批量删除设备类型"); + return R.ok(); + }else { + log.info("[end]批量删除设备类型,失败"); + return R.error(); + } + } + + /** + * 注册或修改(有无ID) + * @param deviceTypeParam deviceTypeParam + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "新增或修改设备类型", httpMethod = "POST") + @RequestMapping(path = "/editOrAdd",method = RequestMethod.POST) + public R updateOrAddType(@RequestBody @Valid DeviceTypeParam deviceTypeParam, BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]新增或修改设备类型,param:{}",deviceTypeParam); + int i = deviceTypeService.updateOrAddProducer(deviceTypeParam); + if (i == -1){ + log.info("[end]新增或修改设备类型,代号重复"); + return R.error("代号重复"); + }else if (i>0){ + log.info("[end]新增或修改设备类型"); + return R.ok().setData(deviceTypeParam); + }else { + log.info("[end]新增或修改设备类型,失败"); + return R.error(); + } + } + + /** + * 批量新增设备类型 + * @param typeParamList 设备类型列表 + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "批量新增设备类型", httpMethod = "POST") + @RequestMapping(path = "/addList",method = RequestMethod.POST) + public R addByList(@RequestBody @Valid List typeParamList, BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]批量新增设备类型"); + int lc = deviceTypeService.addByList(typeParamList); + if (lc < typeParamList.size()){ + log.info("[end]批量新增设备类型,部分有重复设备编号"); + return R.ok("部分新增成功,有重复编号!"); + } + if (lc>0){ + log.info("[end]批量新增设备类型"); + return R.ok("新增成功!"); + }else { + log.info("[end]批量新增设备类型,失败"); + return R.error(); + } + } + + /** + * 列表查询 + * @return R + */ + @ApiOperation(value = "查看设备类型列表", httpMethod = "GET") + @RequestMapping(path = "/list",method = RequestMethod.GET) + public R list(){ + log.info("[start]查看设备类型列表"); + List list = deviceTypeService.list(); + log.info("[end]查看设备类型列表,return:{}",list); + return R.ok().setData(list); + } + + /** + * 查看设备类型分页 + * @param param keywords + * @return R + */ + @ApiOperation(value = "查看设备类型分页", httpMethod = "GET") + @RequestMapping(path = "/page",method = RequestMethod.GET) + public R page(DeviceTypeParam param){ + log.info("[start]查看设备类型分页,keywords:{}",param.getKeywords()); + PageInfo page = deviceTypeService.page(param); + log.info("[end]查看设备类型分页,return:{}",page); + return R.ok().setData(page); + } + + /** + * 读取设备类型参数 + * @param file 文件 + * @return R + * @throws IOException IOException + */ + @ApiOperation(value = "读取设备类型参数", httpMethod = "POST") + @RequestMapping(path = "/read",method = RequestMethod.POST) + public R importType(@RequestParam("file") MultipartFile file) throws IOException{ + //TODO:暂时为excel文件导入,后续可能需改成导入xml文件并解析 + log.info("[start]读取设备类型参数"); + List list = EasyExcel.read(file.getInputStream(), DeviceTypeVO.class,null) + .sheet(0).doReadSync(); + log.info("[end]读取设备类型参数,return:{}",list); + return R.ok().setData(list); + } +} + diff --git a/web/src/main/java/com/imitate/web/module/simulation/controller/LocalManagerController.java b/web/src/main/java/com/imitate/web/module/simulation/controller/LocalManagerController.java new file mode 100644 index 0000000..7d8bb92 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/controller/LocalManagerController.java @@ -0,0 +1,187 @@ +package com.imitate.web.module.simulation.controller; + +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageInfo; +import com.imitate.common.annotation.DoSysLog; +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.util.BasicController; +import com.imitate.common.util.R; +import com.imitate.common.util.SimpleFileUtils; +import com.imitate.web.module.simulation.service.DataTerminalService; +import com.imitate.web.params.DataTerminalParam; +import com.imitate.web.persistence.beans.DataTerminal; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; + +/** + * 本地管理终端 控制器 + * + * @author jshixiong + * @since 2022-07-28 + */ +@Slf4j +@Api(value = "本地管理终端控制器", hidden = true) +@RestController +@RequestMapping("/localManager") +public class LocalManagerController extends BasicController { + + @Autowired + private DataTerminalService dataTerminalService; + + /** + * 注册或修改本地管理终端(有无ID) + * @param dataTerminalParam DataTerminal + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "注册或修改本地管理终端", httpMethod = "POST") + @RequestMapping(path = "/editOrAdd",method = RequestMethod.POST) + public R editOrAddDataCenter(@RequestBody @Valid DataTerminalParam dataTerminalParam, BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]注册或修改本地管理终端,param:{}",dataTerminalParam); + dataTerminalParam.setType("2"); + if (dataTerminalService.updateOrAdd(dataTerminalParam.getDataTerminal())>0){ + log.info("[end]注册或修改本地管理终端"); + return R.ok().setData(dataTerminalParam.getDataTerminal()); + }else { + log.info("[end]注册或修改本地管理终端,失败"); + return R.error(); + } + } + + /** + * 根据ID删除本地管理终端 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "删除本地管理终端", httpMethod = "POST") + @RequestMapping(path = "/delete/{id}",method = RequestMethod.POST) + public R delete(@PathVariable("id") Long id){ + log.info("[start]删除本地管理终端,id:{}",id); + DataTerminal dataTerminal = dataTerminalService.getById(id); + if (dataTerminalService.deleteById(id)>0){ + log.info("[end]删除本地管理终端,return:{}",dataTerminal); + return R.ok().setData(dataTerminal); + }else { + log.info("[end]删除本地管理终端,失败"); + return R.error(); + } + } + + /** + * 通过id获取 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "查看本地管理终端", httpMethod = "GET") + @RequestMapping(path = "/getById/{id}",method = RequestMethod.GET) + public R getById(@PathVariable("id") Long id){ + log.info("[start]查看本地管理终端,id:{}",id); + DataTerminal byId = dataTerminalService.getById(id); + log.info("[end]查看本地管理终端,return:{}",byId); + return R.ok().setData(byId); + } + + /** + * 分页查看本地管理终端 + * @param param 参数 + * @return R + */ + @ApiOperation(value = "分页查看本地管理终端", httpMethod = "GET") + @RequestMapping(path = "/page",method = RequestMethod.GET) + public R pageDevice(DataTerminalParam param){ + log.info("[start]分页查看本地管理终端,param:{}",param); + param.setType("2"); + PageInfo page = dataTerminalService.page(param); + log.info("[end]分页查看本地管理终端,return:{}",page); + return R.ok().setData(page); + } + + /** + * 导出初装资源 + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "本地管理终端导出初装资源", httpMethod = "GET") + @RequestMapping(path = "/resourceExport/{id}",method = RequestMethod.GET) + public void resourceExport(@PathVariable("id") Long id,HttpServletResponse response){ + log.info("[start]本地管理终端导出初装资源,id:{}",id); + String resourceJson = dataTerminalService.resourceExport(id); + SimpleFileUtils.stringToFileExport(response,resourceJson,"本地管理终端初装资源.txt"); + log.info("[end]本地管理终端导出初装资源内容,return:{}",resourceJson); + } + + /** + * 开始本地管理终端开通 + * @param terminalType 终端类型 + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "开始本地管理终端开通", httpMethod = "POST") + @RequestMapping(path = "/startOpen",method = RequestMethod.POST) + public R startOpen(String terminalType){ + log.info("[start]开始本地管理终端开通"); + log.info("[end]开始本地管理终端开通"); + return R.ok().setData(terminalType); + } + + /** + * 设置宿主机标识 + * @param hostFlag 宿主机标识 + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "本地管理终端设置宿主机标识", httpMethod = "POST") + @RequestMapping(path = "/setHostFlag",method = RequestMethod.POST) + public R setHostFlag(String hostFlag){ + log.info("[start]本地管理终端设置宿主机标识"); + log.info("[end]本地管理终端设置宿主机标识"); + return R.ok().setData(hostFlag); + } + + /** + * 注入初装资源 + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "本地管理终端注入初装资源", httpMethod = "POST") + @RequestMapping(path = "/resourceImport",method = RequestMethod.POST) + public R resourceImport(@RequestParam("file") MultipartFile file){ + log.info("[start]本地管理终端注入初装资源"); + String fileContent = SimpleFileUtils.fileToString(file); + DataTerminal dataTerminal; + try { + dataTerminal = JSONObject.parseObject(fileContent, DataTerminal.class); + }catch (Exception e){ + log.info("[end]本地管理终端注入初装资源,fileContent:{}",fileContent); + return R.error("文件内容错误"); + } + if (!"2".equals(dataTerminal.getType()) || null == dataTerminal.getId() || null == dataTerminalService.getById(dataTerminal.getId())){ + log.info("[end]本地管理终端注入初装资源,fileContent:{}",fileContent); + return R.error("文件内容错误,error type or id"); + } + dataTerminal = dataTerminalService.openTerminal(dataTerminal); + log.info("[end]本地管理终端注入初装资源,return:{}",dataTerminal); + return R.ok().setData(dataTerminal); + } + + @ApiOperation(value = "本地管理终端查询是否开通", httpMethod = "GET") + @RequestMapping(path = "/isOpen",method = RequestMethod.GET) + public R isLocalManagerOpen(){ + log.info("[start]本地管理终端查询是否开通"); + Boolean openFlag = dataTerminalService.isTerminalOpen("2"); + log.info("[end]本地管理终端查询是否开通,return:{}",openFlag); + return R.ok().setData(openFlag); + } +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/controller/ProducerController.java b/web/src/main/java/com/imitate/web/module/simulation/controller/ProducerController.java new file mode 100644 index 0000000..0214cb8 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/controller/ProducerController.java @@ -0,0 +1,129 @@ +package com.imitate.web.module.simulation.controller; + + +import com.github.pagehelper.PageInfo; +import com.imitate.common.annotation.DoSysLog; +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.util.BasicController; +import com.imitate.common.util.R; +import com.imitate.web.params.ProducerParam; +import com.imitate.web.persistence.beans.Producer; +import com.imitate.web.module.simulation.service.ProducerService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.annotations.Param; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + *

+ * 生产厂商表 前端控制器 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Slf4j +@Api(value = "生产厂商控制器", hidden = true) +@RestController +@RequestMapping("/producer") +public class ProducerController extends BasicController { + + @Autowired + private ProducerService producerService; + + /** + * 通过id获取 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "查看生产厂商", httpMethod = "GET") + @RequestMapping(path = "/getById/{id}",method = RequestMethod.GET) + public R getById(@PathVariable("id") Long id){ + log.info("[start]查看生产厂商,id:{}",id); + Producer byId = producerService.getById(id); + log.info("[end]查看生产厂商,return:{}",byId); + return R.ok().setData(byId); + } + + /** + * 新增或修改厂商(有无ID) + * @param producerParam Producer + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "新增或修改生产厂商", httpMethod = "POST") + @RequestMapping(path = "/editOrAdd",method = RequestMethod.POST) + public R updateOrAddProducer(@RequestBody @Valid ProducerParam producerParam, BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]新增或修改生产厂商,param:{}",producerParam); + if (producerService.updateOrAddProducer(producerParam.getProducer())<=0){ + log.info("[end]新增或修改生产厂商,失败"); + return R.error(); + }else { + log.info("[end]新增或修改生产厂商"); + return R.ok().setData(producerParam); + } + } + + /** + * 根据ID删除 + * @param id ID + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "删除生产厂商", httpMethod = "POST") + @RequestMapping(path = "/delete/{id}",method = RequestMethod.POST) + public R deleteProducer(@PathVariable("id") Long id){ + log.info("[start]删除生产厂商,id:{}",id); + Producer producer = producerService.getById(id); + int flag = producerService.deleteProducerById(id); + if (flag>0){ + log.info("[end]删除生产厂商,return:{}",producer); + return R.ok().setData(producer); + }else if (flag==-1){ + log.info("[end]删除生产厂商,厂商正被设备使用"); + return R.error("厂商正被设备使用!"); + }else { + log.info("[end]删除生产厂商,失败"); + return R.error(); + } + } + + /** + * 列表查询 + * @return R + */ + @ApiOperation(value = "查看厂商列表", httpMethod = "GET") + @RequestMapping(path = "/list",method = RequestMethod.GET) + public R listProducer(){ + log.info("[start]查看厂商列表"); + List list = producerService.listProducer(); + log.info("[end]查看厂商列表,return:{}",list); + return R.ok().setData(list); + } + + /** + * 分页查询 + * @param pageNumber 页数 + * @param pageSize 页大小 + * @return R + */ + @ApiOperation(value = "分页查看厂商", httpMethod = "GET") + @RequestMapping(path = "/page",method = RequestMethod.GET) + public R pageProducer(@Param("pageNum") Integer pageNumber, @Param("pageSize") Integer pageSize){ + log.info("[start]分页查看厂商,pageNumber:{};pageSize:{}",pageNumber,pageSize); + PageInfo page = producerService.pageProducer(pageNumber, pageSize); + log.info("[start]分页查看厂商,return:{}",page); + return R.ok().setData(page); + } +} + diff --git a/web/src/main/java/com/imitate/web/module/simulation/controller/ResourceController.java b/web/src/main/java/com/imitate/web/module/simulation/controller/ResourceController.java new file mode 100644 index 0000000..78d2a20 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/controller/ResourceController.java @@ -0,0 +1,169 @@ +package com.imitate.web.module.simulation.controller; + + + +import com.imitate.common.annotation.DoSysLog; +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.util.BasicController; +import com.imitate.common.util.R; +import com.imitate.web.module.simulation.service.ResourceService; +import com.imitate.web.module.simulation.service.SecretKeyService; +import com.imitate.web.params.CertificateOpenParam; +import com.imitate.web.params.DatabaseTestConnectionParam; +import com.imitate.web.params.ResourceOpenParam; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +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.File; +import java.util.*; + +/** + * 资源管理系统、证书开通 + * @author yanchao + */ +@Slf4j +@Api(value = "资源管理系统开通", hidden = true) +@RestController +@RequestMapping("/resource") +public class ResourceController extends BasicController { + + @Autowired + private ResourceService resourceService; + + @Autowired + private SecretKeyService secretKeyService; + + + + @DoSysLog(isLog = true) + @ApiOperation(value = "点击开通资源管理系统", httpMethod = "POST") + @RequestMapping(path = "/clickOpenResource",method = RequestMethod.POST) + public R clickOpenResource(){ + return R.ok(); + } + + + + @ApiOperation(value = "获取资源管理终端开通状态",httpMethod = "GET") + @RequestMapping(path = "/getResourceStatus",method = RequestMethod.GET) + public R getResourceStatus(){ + log.info("[start]获取资源管理终端开通状态"); + Map resultMap = resourceService.queryResourceStatus(); + log.info("[end]获取资源管理终端开通状态,return:{}",resultMap); + return R.ok().setData(resultMap); + } + + + @DoSysLog(isLog = true) + @ApiOperation(value = "立即开通资源管理系统") + @RequestMapping(path = "/openResourceNow",method = RequestMethod.POST) + public R openResourceNow(@RequestBody @Validated ResourceOpenParam param, BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]立即开通资源管理系统,param:{}",param); + Boolean r = resourceService.open(param); + if(!r){ + return R.error("开通资源管理系统失败,预制资源验证失败!"); + } + //初始化资源 + List fileList = new ArrayList<>(); + fileList.add(ResourceService.BASE_PATH + param.getFile1()); + fileList.add(ResourceService.BASE_PATH + param.getFile2()); + fileList.add(ResourceService.BASE_PATH + param.getFile3()); + fileList.add(ResourceService.BASE_PATH + param.getFile4()); + log.info("初始化密钥资源:fileList:{}",fileList); + String[] msg = secretKeyService.resourceSecretKey(fileList); + log.info("[end]立即开通资源管理系统"); + return R.ok().setData(msg); + } + + + + @DoSysLog(isLog = true) + @ApiOperation(value = "点击开通证书管理系统", httpMethod = "POST") + @RequestMapping(path = "/openCertSystem",method = RequestMethod.POST) + public R openCertSystem(){ + return R.ok(); + } + + + @DoSysLog(isLog = true) + @ApiOperation(value = "立即开通证书管理系统") + @RequestMapping(path = "/openCertNow",method = RequestMethod.POST) + public R openCertNow(@RequestBody @Validated CertificateOpenParam param,BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]立即开通证书管理系统,param:{}",param); + Boolean rst = resourceService.openCert(param); + if(!rst){ + return R.error("开通证书管理系统失败,导入证书验证失败!"); + } + log.info("[end]立即开通证书管理系统"); + return R.ok(); + } + + + @DoSysLog(isLog = true) + @ApiOperation(value = "双证书文件下载") + @RequestMapping(path = "/downloadCertFile",method = RequestMethod.GET) + public void downloadCertFile(HttpServletResponse response){ + resourceService.generateCertDownload(response); + } + + + @DoSysLog(isLog = true) + @ApiOperation(value = "获取颁发机构证书信息") + @RequestMapping(path = "/getCertInfomation",method = RequestMethod.GET) + public R getCertInfomation(){ + List rst = resourceService.getCertInfo(); + if(rst == null || rst.size() == 0){ + return R.error("证书信息校验失败,不合法的证书文件,请下载证书后重试!"); + } + return R.ok().setData(rst); + } + + + @DoSysLog(isLog = true) + @ApiOperation(value = "多文件上传,导入签发机构证书和系统产生的预制资源") + @RequestMapping(path = "/importFiles",method = RequestMethod.POST) + public R importFiles(MultipartFile[] files,@RequestParam(required = false,defaultValue = "/upload") String resourceDir){ + log.info("[start]多文件上传,导入签发机构证书和系统产生的预制资源,param:{}", (Object) files); + List rstList = new ArrayList<>(); + rstList = resourceService.uploadFiles(files,resourceDir); + log.info("[end]多文件上传,导入签发机构证书和系统产生的预制资源,return:{}", rstList); + return R.ok().setData(rstList); + } + + + + @DoSysLog(isLog = true) + @ApiOperation(value = "数据库测试连接") + @RequestMapping(path = "/dbTestConnection",method = RequestMethod.POST) + public R dbTestConnection(@RequestBody @Validated DatabaseTestConnectionParam param,BindingResult bindingResult){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]数据库测试连接,param:{}", param); + Boolean isConn = resourceService.testConnection(param); + Map map = new HashMap<>(); + map.put("isConn",Boolean.TRUE); + if(!isConn){ + map.put("isConn",Boolean.FALSE); + return R.ok().setData(map); + } + log.info("[end]数据库测试连接,return:{}", Boolean.TRUE); + return R.ok().setData(map); + } + + + + +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/controller/SecretKeyController.java b/web/src/main/java/com/imitate/web/module/simulation/controller/SecretKeyController.java new file mode 100644 index 0000000..1351989 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/controller/SecretKeyController.java @@ -0,0 +1,129 @@ +package com.imitate.web.module.simulation.controller; + + +import com.alibaba.fastjson.JSONObject; +import com.aliyuncs.utils.StringUtils; +import com.imitate.common.annotation.DoSysLog; +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.util.BasicController; +import com.imitate.common.util.R; +import com.imitate.common.util.SimpleFileUtils; +import com.imitate.web.module.simulation.enums.SecretKeyTypeEnum; +import com.imitate.web.params.SecretKeyParam; +import com.imitate.web.persistence.beans.SecretKey; +import com.imitate.web.module.simulation.service.SecretKeyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.EnumSet; +import java.util.List; + +/** + *

+ * 密钥存储表 前端控制器 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Slf4j +@Api(value = "密钥存储表控制器", hidden = true) +@RestController +@RequestMapping("/secretKey") +public class SecretKeyController extends BasicController { + + @Autowired + private SecretKeyService secretKeyService; + + /** + * 资源加密 + * @param param SecretKeyParam + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "资源加密", httpMethod = "GET") + @RequestMapping(path = "/encryption",method = RequestMethod.GET) + public void resourceEncryption(SecretKeyParam param, HttpServletResponse response){ + log.info("[start]资源加密,param:{}",param); + String encryption = secretKeyService.resourceEncryption(param); + if (StringUtils.isEmpty(encryption)){ + log.info("[end]资源加密,失败,return:{}",encryption); + } + String fileName = ""; + EnumSet secretSet = EnumSet.allOf(SecretKeyTypeEnum.class); + for (SecretKeyTypeEnum e: secretSet) { + if(e.getValue().equals(param.getType())){ + fileName = e.getDescription() + ".txt"; + } + } + SimpleFileUtils.stringToFileExport(response,encryption, fileName); + log.info("[end]资源加密,return:{}",encryption); + } + + @DoSysLog(isLog = true) + @ApiOperation(value = "加密资源导入", httpMethod = "POST") + @RequestMapping(path = "/resourceImport/{inType}",method = RequestMethod.POST) + public R addKeyList(@RequestParam("file") MultipartFile file,@PathVariable("inType") String inType){ + log.info("[start]加密资源导入"); + String fileToString = SimpleFileUtils.fileToString(file); + SecretKey secretKey = JSONObject.parseObject(fileToString, SecretKey.class); + int i = secretKeyService.addEncryptionKeyList(secretKey, inType); + if (i == -2){ + log.info("[end]加密资源导入,失败,资源文件与类型不匹配"); + return R.error("资源文件与类型不匹配!"); + }else if (i>0){ + log.info("[end]加密资源导入,return:{}",fileToString); + return R.ok().setData(fileToString); + }else { + log.info("[end]加密资源导入,失败,return:{}",fileToString); + return R.error("无对应类型长度/算法:"+fileToString); + } + } + + /** + * 通过类型查各长度密钥的数量 + * @param type 类型 + * @return R + */ + @ApiOperation(value = "查看密钥统计数据", httpMethod = "GET") + @RequestMapping(path = "/statistics",method = RequestMethod.GET) + public R selectStatisticsByType(String type){ + log.info("[start]查看密钥统计数据,param:{}",type); + List list = secretKeyService.selectStatisticsByType(type); + log.info("[start]查看密钥统计数据,return:{}",list); + return R.ok().setData(list); + } + + /** + * 推送密钥 + * @param secretKeyParam SecretKey + * @return R + */ + @DoSysLog(isLog = true) + @ApiOperation(value = "推送密钥", httpMethod = "POST") + @RequestMapping(path = "/pushKey",method = RequestMethod.POST) + public R pushByLengthAndType(@RequestBody @Valid SecretKeyParam secretKeyParam,BindingResult bindingResult ){ + if(bindingResult.hasErrors()){ + return actionResultWithBindingResult(ErrorCodeEnum.BIND_EXCEPTION,bindingResult); + } + log.info("[start]推送密钥,param:{}",secretKeyParam); + if(secretKeyService.pushByLengthAndType(secretKeyParam.getSecretKey())>0){ + log.info("[start]推送密钥"); + return R.ok().setData(secretKeyParam); + }else { + log.info("[start]推送密钥,失败,请检查密钥数量及类型"); + return R.error("请检查密钥数量"); + } + } + + + + +} + diff --git a/web/src/main/java/com/imitate/web/module/simulation/controller/SysDictController.java b/web/src/main/java/com/imitate/web/module/simulation/controller/SysDictController.java new file mode 100644 index 0000000..37dcddd --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/controller/SysDictController.java @@ -0,0 +1,42 @@ +package com.imitate.web.module.simulation.controller; + +import com.imitate.common.util.R; +import com.imitate.web.module.simulation.service.SysDictService; +import com.imitate.web.vo.DeviceManagerInitVO; +import com.imitate.web.vo.DeviceResourceInitVO; +import com.imitate.web.vo.DeviceSoftwareInitVO; +import com.imitate.web.vo.LocalManagerInitVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +/** + * 下拉列表字典值Controller + * + * @author jshixiong + */ +@Slf4j +@Api(value = "下拉列表字典值控制器", hidden = true) +@RestController +@RequestMapping("/sysDict") +public class SysDictController { + @Autowired + private SysDictService sysDictService; + + @ApiOperation(value = "模训系统Dict", httpMethod = "GET") + @RequestMapping(path = "/all",method = RequestMethod.GET) + public R allDict(){ + log.info("[start]获取模训系统Dict"); + List res = sysDictService.getAllDict(); + log.info("[end]获取模训系统Dict"); + return R.ok().setData(res); + } + +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/controller/SysLogController.java b/web/src/main/java/com/imitate/web/module/simulation/controller/SysLogController.java new file mode 100644 index 0000000..32d0a97 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/controller/SysLogController.java @@ -0,0 +1,63 @@ +package com.imitate.web.module.simulation.controller; + + +import com.imitate.common.enums.ErrorCodeEnum; +import com.imitate.common.util.BasicController; +import com.imitate.common.util.R; +import com.imitate.web.module.simulation.service.SysLogService; +import com.imitate.web.persistence.beans.SysLog; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + *

+ * 系统日志表 前端控制器 + *

+ * + * @author jshixiong + * @since 2022-07-28 + */ +@Slf4j +@Api(value = "日志控制器", hidden = true) +@RestController +@RequestMapping("/sysLog") +public class SysLogController extends BasicController { + @Autowired + private SysLogService sysLogService; + + /** + * 根据ID获取日志 + * @param id ID + * @return R + */ + @ApiOperation(value = "根据ID获取日志", httpMethod = "GET") + @RequestMapping(path = "/getById/{id}",method = RequestMethod.GET) + public R getLogById(@PathVariable("id") Long id){ + log.info("[start]根据ID获取日志,id:{}",id); + SysLog byId = sysLogService.getById(id); + log.info("[end]根据ID获取日志,return:{}",byId); + return R.ok().setData(byId); + } + + /** + * 根据操作名获取日志列表 + * @param operation 操作 + * @return R + */ + @ApiOperation(value = "根据操作名获取日志列表", httpMethod = "GET") + @RequestMapping(path = "/listByOperation",method = RequestMethod.GET) + public R listByOperation(@RequestParam("operation") String operation){ + log.info("[start]根据操作名获取日志列表,param:{}",operation); + List list = sysLogService.list(operation); + log.info("[end]根据操作名获取日志列表,return:{}",list); + return R.ok().setData(list); + } +} + diff --git a/web/src/main/java/com/imitate/web/module/simulation/enums/SecretKeyTypeEnum.java b/web/src/main/java/com/imitate/web/module/simulation/enums/SecretKeyTypeEnum.java new file mode 100644 index 0000000..4d8fd48 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/enums/SecretKeyTypeEnum.java @@ -0,0 +1,23 @@ +package com.imitate.web.module.simulation.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 资源类型枚举类 + * @author jshixiong + */ +@AllArgsConstructor +@Getter +public enum SecretKeyTypeEnum { + + PREFORMED_RESOURCE("1","预制资源加密"), + PUBLIC_KEY("2","公钥编制"), + ALGORITHM_PARAMETERS("3","算法参数加密"), + ALGORITHM_LOGIC("4","算法逻辑加密"), + SOFTWARE("5","软件加密"); + + + private String value; + private String description; +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/service/DataTerminalService.java b/web/src/main/java/com/imitate/web/module/simulation/service/DataTerminalService.java new file mode 100644 index 0000000..9d87376 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/service/DataTerminalService.java @@ -0,0 +1,79 @@ +package com.imitate.web.module.simulation.service; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.aliyuncs.utils.StringUtils; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.imitate.common.util.SimpleFileUtils; +import com.imitate.web.params.DataTerminalParam; +import com.imitate.web.persistence.beans.DataTerminal; +import com.imitate.web.persistence.mapper.DataTerminalMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 数据终端表 服务实现类 + *

+ * + * @author jshixiong + * @since 2022-07-28 + */ +@Service +public class DataTerminalService { + + @Autowired + private DataTerminalMapper dataTerminalMapper; + + public DataTerminal getById(Long id){ + return dataTerminalMapper.getById(id); + } + + public int updateOrAdd(DataTerminal dataTerminal){ + LocalDateTime now = LocalDateTime.now(); + if (null == dataTerminal.getId()){ + if(StringUtils.isEmpty(dataTerminal.getName())){ + dataTerminal.setName("终端/服务器"+ DateUtil.format(now,"yyyyMMddHHmmss")); + } + dataTerminal.setCreateTime(now); + return dataTerminalMapper.insertSelective(dataTerminal); + }else { + dataTerminal.setUpdateTime(now); + return dataTerminalMapper.updateByPrimaryKeySelective(dataTerminal); + } + } + + public int deleteById(Long id){ + return dataTerminalMapper.deleteByPrimaryKey(id); + } + + public PageInfo page(DataTerminalParam param){ + PageHelper.startPage(param.getPageNumber(), param.getPageSize()); + List deviceList = dataTerminalMapper.selectAllPro(param.getType()); + PageInfo page = new PageInfo<>(deviceList); + return page; + } + + public String resourceExport(Long id){ + DataTerminal dataTerminal = dataTerminalMapper.getById(id); + return JSONObject.toJSONString(dataTerminal); + } + + public Boolean isTerminalOpen(String type){ + if (null!=dataTerminalMapper.getTerminalOpen(type)){ + return Boolean.TRUE; + } + return Boolean.FALSE; + } + + public DataTerminal openTerminal(DataTerminal dataTerminal){ + dataTerminal.setStatus(Boolean.TRUE); + dataTerminalMapper.updateByPrimaryKeySelective(dataTerminal); + return dataTerminal; + } +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/service/DeviceDistributionService.java b/web/src/main/java/com/imitate/web/module/simulation/service/DeviceDistributionService.java new file mode 100644 index 0000000..5f1c519 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/service/DeviceDistributionService.java @@ -0,0 +1,88 @@ +package com.imitate.web.module.simulation.service; + +import cn.hutool.core.date.DateUtil; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.imitate.web.params.DistributionListParam; +import com.imitate.web.params.DistributionParam; +import com.imitate.web.persistence.beans.Device; +import com.imitate.web.persistence.beans.DeviceDistribution; +import com.imitate.web.persistence.mapper.DeviceDistributionMapper; +import com.imitate.web.persistence.mapper.DeviceMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 设备配发/调拨单 服务实现类 + *

+ * + * @author jshixiong + * @since 2022-08-02 + */ +@Service +public class DeviceDistributionService { + + @Autowired + private DeviceDistributionMapper deviceDistributionMapper; + @Autowired + private DeviceMapper deviceMapper; + + public PageInfo page(DistributionListParam param){ + PageHelper.startPage(param.getPageNumber(), param.getPageSize()); + List list = deviceDistributionMapper.selectAllPro(param); + list.forEach(e->{ + e.setDeviceCount(e.getDeviceList().size()); + }); + return new PageInfo<>(list); + } + + @Transactional(rollbackFor = Exception.class) + public int editOrAdd(DistributionParam param){ + LocalDateTime now = LocalDateTime.now(); + int lc; + if (null == param.getId()){ + param.setBeginTime(now); + param.setCreateTime(now); + param.setEndTime(now.plusDays(30*3)); + param.setStatus("1"); + param.setNumber("CK"+ DateUtil.format(now,"yyyyMMddHHmmss")); + lc = deviceDistributionMapper.insertSelective(param.getDeviceDistribution()); + + param.setDeviceCount(param.getDeviceList().size()); + param.getDeviceList().forEach(e->{ + e.setUpdateTime(now); + e.setDistributionId(param.getId()); + deviceMapper.updateByPrimaryKeySelective(e); + }); + }else { + param.setUpdateTime(now); + lc = deviceDistributionMapper.updateByPrimaryKeySelective(param.getDeviceDistribution()); + deviceMapper.updateDistributionId(param.getId()); + param.getDeviceList().forEach(e->{ + e.setUpdateTime(now); + e.setDistributionId(param.getId()); + deviceMapper.updateByPrimaryKeySelective(e); + }); + } + return lc; + } + + public DeviceDistribution getById(Long id){ + return deviceDistributionMapper.getById(id); + } + + @Transactional(rollbackFor = Exception.class) + public DeviceDistribution deleteById(Long id){ + DeviceDistribution byId = deviceDistributionMapper.getById(id); + //删除配发单 + deviceDistributionMapper.deleteByPrimaryKey(id); + //将配发设备还原,解除配发 + deviceMapper.updateDistributionId(id); + return byId; + } +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/service/DeviceService.java b/web/src/main/java/com/imitate/web/module/simulation/service/DeviceService.java new file mode 100644 index 0000000..9959118 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/service/DeviceService.java @@ -0,0 +1,188 @@ +package com.imitate.web.module.simulation.service; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.aliyuncs.utils.StringUtils; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.imitate.web.params.DeviceParam; +import com.imitate.web.persistence.beans.DeviceType; +import com.imitate.web.persistence.mapper.DeviceTypeMapper; +import com.imitate.web.persistence.mapper.ProducerMapper; +import com.imitate.web.persistence.beans.Device; +import com.imitate.web.persistence.mapper.DeviceMapper; +import com.imitate.web.persistence.beans.Producer; +import com.imitate.web.params.DeviceListParam; +import com.imitate.web.vo.DeviceByTypeVO; +import com.imitate.web.vo.DeviceVO; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import tk.mybatis.mapper.entity.Example; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + *

+ * 模拟设备表 服务实现类 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Service +public class DeviceService{ + + @Autowired + private DeviceMapper deviceMapper; + @Autowired + private ProducerMapper producerMapper; + @Autowired + private DeviceTypeMapper deviceTypeMapper; + + public Device getById(Long id){ + return deviceMapper.getById(id); + } + + public int updateOrAddDevice(Device device){ + LocalDateTime now = LocalDateTime.now(); + + Example example = new Example(Device.class); + example.createCriteria().andEqualTo("deviceId",device.getDeviceId()); + Device oneByExample = deviceMapper.selectOneByExample(example); + + if (null == device.getId()){ + if (null!=oneByExample){ + return -1; + } + if(StringUtils.isEmpty(device.getName())){ + device.setName("设备"+ DateUtil.format(now,"yyyyMMddHHmmss")); + } + device.setAddTime(now); + device.setCreateTime(now); + return deviceMapper.insertSelective(device); + }else { + if (null!=oneByExample && !device.getId().equals(oneByExample.getId())){ + return -1; + } + device.setUpdateTime(now); + return deviceMapper.updateByPrimaryKeySelective(device); + } + } + + public int deleteDeviceById(Long id){ + return deviceMapper.deleteByPrimaryKey(id); + } + + public List listDevice(DeviceListParam param){ + return deviceMapper.selectAllPro(param); + } + + public List listDeviceByType(){ + List deviceList = deviceMapper.selectDeviceByType(); + List deviceByTypeVOList = new ArrayList<>(); + deviceList.forEach(e->{ + DeviceByTypeVO deviceByTypeVO = new DeviceByTypeVO(); + deviceByTypeVO.setType(e.getType()); + deviceByTypeVO.setDeviceList(e.getDeviceList()); + deviceByTypeVOList.add(deviceByTypeVO); + }); + return deviceByTypeVOList; + } + + public List listByType(String type){ + Example example = new Example(Device.class); + example.createCriteria().andEqualTo("type",type); + return deviceMapper.selectByExample(example); + } + + public List list(DeviceListParam param){ + return deviceMapper.selectAllPro(param); + } + + public PageInfo pageDevice(DeviceListParam param){ + PageHelper.startPage(param.getPageNumber(), param.getPageSize()); + List deviceList = deviceMapper.selectAllPro(param); + return new PageInfo<>(deviceList); + } + + public List addExcelList(List deviceVOList){ + if (null==deviceVOList || deviceVOList.size()<=0){ + return null; + } + //将厂商列转为map + List producerList = producerMapper.selectAll(); + Map producerMaps = producerList.stream() + .collect(Collectors.toMap(Producer::getName, Producer::getId, (key1, key2) -> key2)); + //将设备类型转化为map + List typeList = deviceTypeMapper.selectAll(); + Map typeMaps = typeList.stream() + .collect(Collectors.toMap(DeviceType::getName, DeviceType::getId, (key1, key2) -> key2)); + //复制参数 + LocalDateTime now = LocalDateTime.now(); + List deviceList = new ArrayList<>(); + for (DeviceVO vo : deviceVOList) { + //判断是否已存在编号 + Example example = new Example(Device.class); + example.createCriteria().andEqualTo("deviceId",vo.getDeviceId()); + if (null!=deviceMapper.selectOneByExample(example)){ + continue; + } + Device device = new Device(); + BeanUtils.copyProperties(vo,device); + device.setAddTime(now); + device.setCreateTime(now); + device.setType(typeMaps.getOrDefault(vo.getTypeName(),0L)); + device.setProducerId(producerMaps.getOrDefault(vo.getProducerName(),0L)); + deviceList.add(device); + } + deviceMapper.insertList(deviceList); + return deviceList; + } + + public int addList(List deviceParamList){ + List deviceList = deviceParamList.stream().map(DeviceParam::getDevice).collect(Collectors.toList()); + for (DeviceParam e : deviceParamList){ + Example example = new Example(Device.class); + example.createCriteria().andEqualTo("deviceId",e.getDeviceId()); + if (null!=deviceMapper.selectOneByExample(example)){ + return -1; + } + e.setAddTime(LocalDateTime.now()); + e.setStatus("0"); + e.setDistributionId(0L); + }; + return deviceMapper.insertList(deviceList); + } + + @Transactional(rollbackFor = Exception.class) + public int configureDevice(DeviceListParam param){ + List deviceList = param.getDeviceList(); + deviceList.forEach(e-> deviceMapper.updateByPrimaryKeySelective(e)); + return 1; + } + + @Transactional(rollbackFor = Exception.class) + public int deleteByList(List deviceList){ + deviceList.forEach(d-> deviceMapper.deleteByPrimaryKey(d.getId())); + return 1; + } + + public JSONObject u3dDevice(Integer u3dType){ + String res = ""; + //注意id为负数,且id和deviceId不能重复 + if (1 == u3dType){ + res = "{\"list\":[{\"id\":-10,\"name\":\"注入器1\",\"u3dType\":1,\"deviceId\":\"202209071223\"},{\"id\":-11,\"name\":\"注入器2\",\"u3dType\":1,\"deviceId\":\"202209071224\"}]}"; + }else if (2 == u3dType){ + res = "{\"list\":[{\"id\":-20,\"name\":\"开机棒1\",\"u3dType\":2,\"deviceId\":\"202209072223\"},{\"id\":-21,\"name\":\"开机棒2\",\"u3dType\":2,\"deviceId\":\"202209072224\"}]}"; + }else if (3 == u3dType){ + res = "{\"list\":[{\"id\":-30,\"name\":\"授启棒1\",\"u3dType\":3,\"deviceId\":\"202209073223\"},{\"id\":-31,\"name\":\"授启棒2\",\"u3dType\":3,\"deviceId\":\"202209073224\"}]}"; + } + return JSONObject.parseObject(res); + } +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/service/DeviceTypeProducerService.java b/web/src/main/java/com/imitate/web/module/simulation/service/DeviceTypeProducerService.java new file mode 100644 index 0000000..d7ad59f --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/service/DeviceTypeProducerService.java @@ -0,0 +1,16 @@ +package com.imitate.web.module.simulation.service; + +import org.springframework.stereotype.Service; + +/** + *

+ * 服务实现类 + *

+ * + * @author jshixiong + * @since 2022-07-25 + */ +@Service +public class DeviceTypeProducerService { + +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/service/DeviceTypeService.java b/web/src/main/java/com/imitate/web/module/simulation/service/DeviceTypeService.java new file mode 100644 index 0000000..c1532c4 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/service/DeviceTypeService.java @@ -0,0 +1,130 @@ +package com.imitate.web.module.simulation.service; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.imitate.web.persistence.mapper.DeviceTypeMapper; +import com.imitate.web.persistence.mapper.DeviceTypeProducerMapper; +import com.imitate.web.persistence.beans.DeviceType; +import com.imitate.web.persistence.beans.DeviceTypeProducer; +import com.imitate.web.params.DeviceTypeParam; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import tk.mybatis.mapper.entity.Example; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * 设备类型表 服务实现类 + *

+ * + * @author jshixiong + * @since 2022-07-25 + */ +@Service +public class DeviceTypeService { + + @Autowired + private DeviceTypeMapper deviceTypeMapper; + @Autowired + private DeviceTypeProducerMapper typeProducerMapper; + + public DeviceType getById(Long id){ + return deviceTypeMapper.getById(id); + } + + @Transactional(rollbackFor = Exception.class) + public int deleteById(Long id){ + //删除所有 类型-厂商 中间表 + typeProducerMapper.deleteByTypeId(id); + return deviceTypeMapper.deleteByPrimaryKey(id); + } + + @Transactional(rollbackFor = Exception.class) + public int deleteByTypeList(List deviceTypeList){ + deviceTypeList.forEach(deviceType -> { + typeProducerMapper.deleteByTypeId(deviceType.getId()); + deviceTypeMapper.deleteByPrimaryKey(deviceType.getId()); + }); + return 1; + } + + @Transactional(rollbackFor = Exception.class) + public int updateOrAddProducer(DeviceTypeParam deviceTypeParam){ + LocalDateTime now = LocalDateTime.now(); + DeviceType deviceType = new DeviceType(); + BeanUtils.copyProperties(deviceTypeParam,deviceType); + + List typeProducerList = new ArrayList<>(); + + Example example = new Example(DeviceType.class); + example.createCriteria().andEqualTo("typeNumber",deviceTypeParam.getTypeNumber()); + DeviceType oneByExample = deviceTypeMapper.selectOneByExample(example); + + if (deviceTypeParam.getId() == null){ + if (null!=oneByExample){ + return -1; + } + //新增设备类型 + deviceType.setCreateTime(now); + int i = deviceTypeMapper.insertSelective(deviceType); + if (null == deviceTypeParam.getProducerIdList() || i<0){ + return i; + } + //批量新增 设备类型-厂商 中间表 + deviceTypeParam.getProducerIdList().forEach(pid->{ + DeviceTypeProducer deviceTypeProducer = new DeviceTypeProducer(); + deviceTypeProducer.setTypeId(deviceType.getId()); + deviceTypeProducer.setProducerId(pid); + deviceTypeProducer.setCreateTime(now); + typeProducerList.add(deviceTypeProducer); + }); + typeProducerMapper.insertList(typeProducerList); + return i; + }else { + if (null!=oneByExample && !deviceTypeParam.getId().equals(oneByExample.getId())){ + return -1; + } + //先删除所有该设备类型与厂商的中间表,再新增。 + typeProducerMapper.deleteByTypeId(deviceType.getId()); + if (null != deviceTypeParam.getProducerIdList()){ + //批量新增 设备类型-厂商 中间表 + deviceTypeParam.getProducerIdList().forEach(pid->{ + DeviceTypeProducer deviceTypeProducer = new DeviceTypeProducer(); + deviceTypeProducer.setTypeId(deviceType.getId()); + deviceTypeProducer.setProducerId(pid); + deviceTypeProducer.setCreateTime(now); + typeProducerList.add(deviceTypeProducer); + }); + typeProducerMapper.insertList(typeProducerList); + } + + deviceType.setUpdateTime(now); + return deviceTypeMapper.updateByPrimaryKeySelective(deviceType); + } + } + + @Transactional(rollbackFor = Exception.class) + public int addByList(List typeParamList){ + int sum = 0; + for (DeviceTypeParam param : typeParamList){ + int i = updateOrAddProducer(param); + sum+=i; + } + return sum; + } + + public List list(){ + return deviceTypeMapper.selectAll(); + } + + public PageInfo page(DeviceTypeParam param){ + PageHelper.startPage(param.getPageNumber(), param.getPageSize()); + List typeList = deviceTypeMapper.selectByKey(param); + return new PageInfo<>(typeList); + } +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/service/ProducerService.java b/web/src/main/java/com/imitate/web/module/simulation/service/ProducerService.java new file mode 100644 index 0000000..3653eeb --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/service/ProducerService.java @@ -0,0 +1,62 @@ +package com.imitate.web.module.simulation.service; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.imitate.web.persistence.mapper.DeviceMapper; +import com.imitate.web.persistence.beans.Producer; +import com.imitate.web.persistence.mapper.ProducerMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 生产厂商表 服务实现类 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Service +public class ProducerService { + + @Autowired + private ProducerMapper producerMapper; + @Autowired + private DeviceMapper deviceMapper; + + public Producer getById(Long id){ + return producerMapper.selectByPrimaryKey(id); + } + + public int updateOrAddProducer(Producer producer){ + LocalDateTime now = LocalDateTime.now(); + if (producer.getId() == null){ + producer.setCreateTime(now); + return producerMapper.insertSelective(producer); + }else { + producer.setUpdateTime(now); + return producerMapper.updateByPrimaryKey(producer); + } + } + + public int deleteProducerById(Long id){ + if (deviceMapper.selectCountById(id)>0){ + return -1; + } + return producerMapper.deleteByPrimaryKey(id); + } + + public List listProducer(){ + return producerMapper.selectAll(); + } + + public PageInfo pageProducer(Integer pageNum, Integer pageSize){ + PageHelper.startPage(pageNum, pageSize); + List producerList = producerMapper.selectAll(); + PageInfo page = new PageInfo<>(producerList); + return page; + } +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/service/ResourceService.java b/web/src/main/java/com/imitate/web/module/simulation/service/ResourceService.java new file mode 100644 index 0000000..3ceba48 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/service/ResourceService.java @@ -0,0 +1,335 @@ +package com.imitate.web.module.simulation.service; + + +import cn.hutool.core.io.file.FileReader; +import cn.hutool.core.io.file.FileWriter; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.crypto.Mode; +import cn.hutool.crypto.Padding; +import com.imitate.common.util.DBHelper; +import com.imitate.common.util.FileDownloadUtil; +import com.imitate.common.util.SymmetricCryptoUtil; +import com.imitate.web.params.CertificateOpenParam; +import com.imitate.web.params.DatabaseTestConnectionParam; +import com.imitate.web.params.ResourceOpenParam; +import com.imitate.web.persistence.beans.Certificate; +import com.imitate.web.persistence.beans.Resource; +import com.imitate.web.persistence.mapper.CertificateMapper; +import com.imitate.web.persistence.mapper.ResourceMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.sql.Connection; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +/** + * 资源管理系统开通业务 + * @author yanchao + */ +@Service +@Slf4j +public class ResourceService { + + public static final String BASE_PATH = "/data/ww/imitate-system"; + private static final String CERT_PATH1 = BASE_PATH + "/cert/1.req"; + private static final String CERT_PATH2 = BASE_PATH + "/cert/2.req"; + + + + @Autowired + private ResourceMapper resourceMapper; + + @Autowired + private CertificateMapper certificateMapper; + + @Autowired + private ResourceLoader resourceLoader; + + + + + /** + * 获取资源管理终端开通状态 + * @return + */ + public Map queryResourceStatus() { + Map map = new HashMap<>(2); + Resource resource = resourceMapper.selectRecentResource(); + map.put("resource",0); + map.put("cert",0); + if(resource != null && resource.getStatus()){ + map.put("resource",1); + } + + Certificate certificate = certificateMapper.selectRecentCertificate(); + if(certificate != null && certificate.getStatus()){ + map.put("cert",1); + } + return map; + } + + /** + * 立即开通资源管理系统 + * @param param + * @return + */ + @Transactional(rollbackFor = Exception.class) + public Boolean open(ResourceOpenParam param) { + Resource resource = param.getResource(); + //先清空 + resourceMapper.truncateTable(); + int i = resourceMapper.insertSelective(resource); + //TODO: 预制资源检测方法,暂时未实现 + if(i > 0){ + resource.setStatus(Boolean.TRUE); + resourceMapper.updateByPrimaryKeySelective(resource); + return Boolean.TRUE; + } + return Boolean.FALSE; + } + + + /** + * 立即开通证书管理系统 + * @param param + * @return + */ + @Transactional(rollbackFor = Exception.class) + public Boolean openCert(CertificateOpenParam param) { + Certificate certificate = param.getCertificate(); + //先清空 + certificateMapper.truncateTable(); + int i = certificateMapper.insertSelective(certificate); + //双证书校验检测 + if(!verificationCert()){ + log.error("校验证书文件失败!"); + return Boolean.FALSE; + } + + if(i > 0){ + certificate.setStatus(Boolean.TRUE); + certificateMapper.updateByPrimaryKeySelective(certificate); + return Boolean.TRUE; + } + + return Boolean.FALSE; + } + + + /** + * 下载证书文件 + */ + private void downloadCertFiles(HttpServletResponse response) { + List fileList = new ArrayList<>(2); + fileList.add(new File(CERT_PATH1)); + fileList.add(new File(CERT_PATH2)); + downloadCerts(fileList,"cert.zip",response); + } + + /** + * 多证书文件打ZIP包下载 + * @param fileList + * @param response + */ + private void downloadCerts(List fileList,String outZipName, HttpServletResponse response) { + try{ + List files = new ArrayList<>(); + for(File item: fileList){ + if (item.exists()) { + files.add(item); + } + } + //创建压缩文 + File zipTmpFile = FileDownloadUtil.createFile(BASE_PATH,outZipName); + response.reset(); + //证书文件打包 + FileDownloadUtil.zipFile(files, zipTmpFile); + //下载压缩文件 + FileDownloadUtil.fileDownload(zipTmpFile,response); + }catch (IOException e){ + e.printStackTrace(); + } + } + + + /** + * 生成证书内容,并写入文件 + * @return + */ + private void generateCertContent(){ + String t1 = String.format("ECCE%s\n", RandomUtil.randomNumbers(3)); + String v1 = String.format("CN=%sCA,O=一级,C=cn\n",IdUtil.simpleUUID().substring(0,6).toUpperCase(Locale.ROOT)); + String v2 = IdUtil.simpleUUID().substring(0,30).toUpperCase(Locale.ROOT) + "\n"; + String v3 = String.format("CN=%s设备CA,O=一级,O=zoning,C=cn\n",IdUtil.simpleUUID().substring(0,6).toUpperCase(Locale.ROOT)); + String v4 = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "\n"; + String v5 = LocalDateTime.now().plusYears(15).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "\n"; + + String t2 = String.format("ECCE%s\n", RandomUtil.randomNumbers(3)); + String v6 = String.format("CN=%sCA,0=一级,C=cn\n",IdUtil.simpleUUID().substring(0,6).toUpperCase(Locale.ROOT)); + String v7 = IdUtil.simpleUUID().substring(0,31).toUpperCase(Locale.ROOT) + "\n"; + String v8 = String.format("CN=%s设备CA,O=一级,O=zoning,C=cn\n",IdUtil.simpleUUID().substring(0,6).toUpperCase(Locale.ROOT)); + String v9 = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "\n"; + String v10 = LocalDateTime.now().plusYears(10).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "\n"; + + String[] ctx1 = new String[]{t1,v1,v2,v3,v4,v5}; + String[] ctx2 = new String[]{t2,v6,v7,v8,v9,v10}; + + StringBuilder sb1 = new StringBuilder(); + int i; + for(i = 0; i < ctx1.length; i++){ + sb1.append(ctx1[i]); + } + StringBuilder sb2 = new StringBuilder(); + for(i = 0; i < ctx2.length; i++){ + sb2.append(ctx2[i]); + } + + + //加密 + String hex1 = SymmetricCryptoUtil.encryptFromString(sb1.toString(), Mode.CBC, Padding.ZeroPadding); + String hex2 = SymmetricCryptoUtil.encryptFromString(sb2.toString(), Mode.CBC, Padding.ZeroPadding); + + //存储文件 + FileWriter writer = new FileWriter(CERT_PATH1); + writer.write(hex1); + writer = new FileWriter(CERT_PATH2); + writer.write(hex2); + } + + /** + * 生成双证书文件,并打包下载 + * @param response + */ + public void generateCertDownload(HttpServletResponse response) { + //Step1 : 生成证书内容,并写入文件 + generateCertContent(); + //Step2: 打包下载证书文件 + downloadCertFiles(response); + } + + + /** + * 获取证书信息 + * @return + */ + public List getCertInfo() { + List rstList = new ArrayList<>(); + + //step1 : 校验上传文件与源证书文件是否相同 + if(!verificationCert()){ + log.error("校验证书文件失败!"); + return null; + } + + //step2: 若相同则解析源文件证书,并返回 + FileReader fileReader1 = new FileReader(CERT_PATH1); + FileReader fileReader2 = new FileReader(CERT_PATH2); + + String result1 = SymmetricCryptoUtil.decryptFromString(fileReader1.readString(), Mode.CBC, Padding.ZeroPadding); + String result2 = SymmetricCryptoUtil.decryptFromString(fileReader2.readString(), Mode.CBC, Padding.ZeroPadding); + + String[] arr1 = result1.split("\n"); + String[] arr2 = result2.split("\n"); + + int i; + for(i = 0; i < arr1.length; i++){ + rstList.add(arr1[i]); + } + for(i = 0; i < arr2.length; i++){ + rstList.add(arr2[i]); + } + + return rstList; + } + + /** + * 校验上传文件与源证书文件是否相同 + * @return + */ + private boolean verificationCert() { + File file1 = new File(CERT_PATH1); + File file2 = new File(CERT_PATH2); + if(file1.exists() && file2.exists()){ + String filePath1 = BASE_PATH + File.separator + "upload" + File.separator + "1.req"; + String filePath2 = BASE_PATH + File.separator + "upload" + File.separator + "2.req"; + FileReader fileReader1 = new FileReader(filePath1); + FileReader fileReader2 = new FileReader(filePath2); + + FileReader fileReader3 = new FileReader(file1); + FileReader fileReader4 = new FileReader(file2); + + + if(fileReader1.readString().equals(fileReader3.readString()) && fileReader2.readString().equals(fileReader4.readString())){ + return Boolean.TRUE; + } + }else{ + log.error("upload目录不存在上传的证书文件"); + } + + return Boolean.FALSE; + } + + + /** + * 多文件上传 + * @param files + * @return + */ + public List uploadFiles(MultipartFile[] files,String resourceDir) { + List listPath = new ArrayList<>(); + try{ + //获得路径 + String path = BASE_PATH + File.separator + resourceDir; + //创建文件夹 + File fold = new File(path); + while (!fold.exists()){ + fold.mkdirs(); + } + int i = 1; + for (MultipartFile file : files) { + String oldname = file.getOriginalFilename(); + //新文件名 固定写死 文件名从1开始递增 + assert oldname != null; + String rename = String.format("%s%s", i,oldname.substring(oldname.lastIndexOf("."))); + file.transferTo(new File(fold,rename)); + listPath.add(resourceDir + File.separator + rename); + i++; + } + }catch (IOException e){ + e.printStackTrace(); + } + return listPath; + } + + /** + * 测试数据库连接 + * @param param + * @return + */ + public Boolean testConnection(DatabaseTestConnectionParam param) { + Connection conn = null; + String jdbcurl = ""; + if("ORACEL".equals(param.getDbType().toUpperCase(Locale.ROOT))){ + jdbcurl = String.format("jdbc:oracle:thin:@%s:%s:%s",param.getDbIp(),param.getDbPort(),param.getDbName()); + }else if("MYSQL".equals(param.getDbType().toUpperCase(Locale.ROOT))){ + jdbcurl = String.format("jdbc:mysql://%s:%s/%s?useUnicode=true&characterEncoding=utf-8",param.getDbIp(),param.getDbPort(),param.getDbName()); + }else if("SQLSERVER".equals(param.getDbType().toUpperCase(Locale.ROOT))){ + jdbcurl = String.format("jdbc:sqlserver://%s:%s;DatabaseName=%s",param.getDbIp(),param.getDbPort(),param.getDbName()); + }else{ + log.info("不存在的数据库类型,dbType:{}",param.getDbType()); + return Boolean.FALSE; + } + conn = DBHelper.intiConnection(param.getDbDrive(),jdbcurl,param.getDbUser(),param.getDbPasswd(),Boolean.TRUE); + return conn == null ? Boolean.FALSE : Boolean.TRUE; + } +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/service/SecretKeyService.java b/web/src/main/java/com/imitate/web/module/simulation/service/SecretKeyService.java new file mode 100644 index 0000000..f07cb21 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/service/SecretKeyService.java @@ -0,0 +1,126 @@ +package com.imitate.web.module.simulation.service; + +import com.alibaba.fastjson.JSONObject; +import com.aliyuncs.utils.StringUtils; +import com.imitate.common.util.SimpleFileUtils; +import com.imitate.web.params.SecretKeyParam; +import com.imitate.web.persistence.beans.SecretKey; +import com.imitate.web.module.simulation.enums.SecretKeyTypeEnum; +import com.imitate.web.persistence.mapper.SecretKeyMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 密钥存储表 服务实现类 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Service +public class SecretKeyService{ + + @Autowired + private SecretKeyMapper secretKeyMapper; + + public String[] resourceSecretKey(List fileList){ + //删除所有数据 + secretKeyMapper.deleteAll(); + String[] msg = {"","","",""}; + for (int i = 0; i < fileList.size(); i++){ + String f = fileList.get(i); + if (!StringUtils.isEmpty(f)){ + try { + File file = new File(f); + String fileToString = SimpleFileUtils.fileToString(SimpleFileUtils.getMultipartFile(file)); + SecretKey secretKey = JSONObject.parseObject(fileToString, SecretKey.class); + if (addEncryptionKeyList(secretKey,secretKey.getType())<0){ + msg[i] = f+"资源文件"+(i+1)+"内容格式错误!"; + } + }catch (IllegalArgumentException e){ + msg[i] = f+"系统找不到指定的文件"+(i+1)+"!"; + }catch (Exception e){ + msg[i] = f+"资源文件"+(i+1)+"内容格式错误!"; + } + } + } + fileList.forEach(f->{ + + }); + return msg; + } + + public int addEncryptionKeyList(SecretKey secretKey,String inType){ + int lc = -1; + if (!inType.equals(secretKey.getType())){ + return -2; + } + if (SecretKeyTypeEnum.PUBLIC_KEY.getValue().equals(secretKey.getType())){ + //如果是公钥类型,必须有算法类型参数 + if (StringUtils.isEmpty(secretKey.getAlgorithm())){ + return lc; + } + secretKey.setLength(null); + lc = secretKeyMapper.updateByAlgorithmAndType(secretKey); + if (lc<=0){ + secretKey.setCreateTime(LocalDateTime.now()); + lc = secretKeyMapper.insertSelective(secretKey); + } + }else { + //如果是其他类型,必须有长度参数 + if (null == secretKey.getLength()){ + return lc; + } + secretKey.setAlgorithm(null); + lc = secretKeyMapper.updateByLengthAndType(secretKey); + if (lc<=0){ + secretKey.setCreateTime(LocalDateTime.now()); + lc = secretKeyMapper.insertSelective(secretKey); + } + } + return lc; + } + + public List selectStatisticsByType(String type){ + return secretKeyMapper.selectStatisticsByType(type); + } + + public int pushByLengthAndType(SecretKey secretKey){ + if(SecretKeyTypeEnum.PUBLIC_KEY.getValue().equals(secretKey.getType())){ + //如果是公钥类型,必须有算法类型参数 + if (StringUtils.isEmpty(secretKey.getAlgorithm())){ + return -1; + } + secretKey.setLength(null); + }else{ + //如果是其他类型,必须有长度参数 + if (null == secretKey.getLength()){ + return -1; + } + secretKey.setAlgorithm(null); + } + return secretKeyMapper.pushByLengthAndType(secretKey); + } + + public String resourceEncryption(SecretKeyParam param){ + SecretKey secretKey = param.getSecretKey(); + if(SecretKeyTypeEnum.PUBLIC_KEY.getValue().equals(secretKey.getType())){ + //如果是公钥类型,必须有算法类型参数 + if (StringUtils.isEmpty(secretKey.getAlgorithm())){ + return ""; + } + }else{ + //如果是其他类型,必须有长度参数 + if (null == secretKey.getLength()){ + return ""; + } + } + return JSONObject.toJSONString(secretKey); + } + +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/service/SysDictService.java b/web/src/main/java/com/imitate/web/module/simulation/service/SysDictService.java new file mode 100644 index 0000000..01d544b --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/service/SysDictService.java @@ -0,0 +1,253 @@ +package com.imitate.web.module.simulation.service; + +import cn.hutool.core.util.XmlUtil; +import com.alibaba.excel.EasyExcel; +import com.imitate.common.util.SimpleFileUtils; +import com.imitate.web.vo.DeviceManagerInitVO; +import com.imitate.web.vo.DeviceResourceInitVO; +import com.imitate.web.vo.DeviceSoftwareInitVO; +import com.imitate.web.vo.LocalManagerInitVO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author jshixiong + */ +@Service +public class SysDictService { + @Value("${imitate.init.path}") + private String initPath; + @Value("${imitate.init.xlsx}") + private String initExcelName; + @Value("${imitate.init.xml}") + private String initXmlName; + + public List getAllDict(){ + File file = new File(initPath+ File.separator +initExcelName); + if (!file.exists()){ + file = new File(initPath+ File.separator +initXmlName); + if (!file.exists()){ + return null; + }else { + //解析xml + String xmlData = SimpleFileUtils.fileToString(file); + Document document= XmlUtil.parseXml(xmlData); + //获得XML文档根节点 + Element rootElement= XmlUtil.getRootElement(document); + DeviceSoftwareInitVO resList1 = resourceDictXml(rootElement); + DeviceManagerInitVO resList2 = dataDictXml(rootElement); + LocalManagerInitVO resList3 = localManagerDictXml(rootElement); + List res = new ArrayList<>(); + res.add(resList1); + res.add(resList2); + res.add(resList3); + return res; + } + }else { + //解析Excel + DeviceSoftwareInitVO resList1 = resourceDictExcel(file); + DeviceManagerInitVO resList2 = dataDictExcel(file); + LocalManagerInitVO resList3 = localManagerDictExcel(file); +// DeviceResourceInitVO resList4 = configureDeviceExcel(file); + List res = new ArrayList<>(); + res.add(resList1); + res.add(resList2); + res.add(resList3); +// res.add(resList4); + return res; + } + } + + private DeviceSoftwareInitVO resourceDictExcel(File file){ + List list = EasyExcel.read(file, DeviceSoftwareInitVO.class,null) + .sheet(0).headRowNumber(2).doReadSync(); + DeviceSoftwareInitVO resList = new DeviceSoftwareInitVO(); + + //选择单位 + List firstUnitList = list.stream() + .map(DeviceSoftwareInitVO::getFirstUnit) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + //选择保障单位 + List supportUnitList = list.stream() + .map(DeviceSoftwareInitVO::getSupportUnit) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + //选择管理节点 + List managerNodeList = list.stream() + .map(DeviceSoftwareInitVO::getManagerNode) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + //数据库类型 + List dbTypeList = list.stream() + .map(DeviceSoftwareInitVO::getDbType) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + + resList.setDbTypeList(firstUnitList); + resList.setSupportUnitList(supportUnitList); + resList.setManagerNodeList(managerNodeList); + resList.setDbTypeList(dbTypeList); + + return resList; + } + + private DeviceSoftwareInitVO resourceDictXml(Element rootElement){ + Element softwareElement = XmlUtil.getElement(rootElement, "device-manager-software"); + + DeviceSoftwareInitVO resList = new DeviceSoftwareInitVO(true); + NodeList firstUnitNodes = XmlUtil.getElement(softwareElement, "firstUnit").getElementsByTagName("lt"); + for (int i = 0; i list = EasyExcel.read(file, DeviceManagerInitVO.class,null) + .sheet(1).headRowNumber(2).doReadSync(); + DeviceManagerInitVO resList = new DeviceManagerInitVO(); + //密钥长度 + List keyLengthList = list.stream() + .map(DeviceManagerInitVO::getKeyLength) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + //算法类型 + List algorithmList = list.stream() + .map(DeviceManagerInitVO::getAlgorithm) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + + resList.setKeyLengthList(keyLengthList); + resList.setAlgorithmList(algorithmList); + + return resList; + } + + private DeviceManagerInitVO dataDictXml(Element rootElement){ + Element terminalElement = XmlUtil.getElement(rootElement, "device-manager-terminal"); + + DeviceManagerInitVO resList = new DeviceManagerInitVO(true); + NodeList keyLengthNodes = XmlUtil.getElement(terminalElement, "keyLength").getElementsByTagName("lt"); + for (int i = 0; i list = EasyExcel.read(file, LocalManagerInitVO.class,null) + .sheet(2).headRowNumber(2).doReadSync(); + LocalManagerInitVO resList = new LocalManagerInitVO(); + //配发节点 + List distributionNodeList = list.stream() + .map(LocalManagerInitVO::getDistributionNode) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + //配发状态 + List distributionStatusList = list.stream() + .map(LocalManagerInitVO::getDistributionStatus) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + //密钥长度 + List keyLengthList = list.stream() + .map(LocalManagerInitVO::getKeyLength) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + //密钥发送节点 + List keyNodeList = list.stream() + .map(LocalManagerInitVO::getKeyNode) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + + resList.setDistributionNodeList(distributionNodeList); + resList.setDistributionStatusList(distributionStatusList); + resList.setKeyLengthList(keyLengthList); + resList.setKeyNodeList(keyNodeList); + + return resList; + } + + private LocalManagerInitVO localManagerDictXml(Element rootElement){ + Element localElement = XmlUtil.getElement(rootElement, "local-manager-terminal"); + + LocalManagerInitVO resList = new LocalManagerInitVO(true); + NodeList distributionNodeNodes = XmlUtil.getElement(localElement, "distributionNode").getElementsByTagName("lt"); + for (int i = 0; i list = EasyExcel.read(file, DeviceResourceInitVO.class,null) + .sheet(3).headRowNumber(2).doReadSync(); + DeviceResourceInitVO resList = new DeviceResourceInitVO(); + //状态 + List resourceStatusList = list.stream() + .map(DeviceResourceInitVO::getResourceStatus) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + + resList.setResourceStatusList(resourceStatusList); + + return resList; + } + +} diff --git a/web/src/main/java/com/imitate/web/module/simulation/service/SysLogService.java b/web/src/main/java/com/imitate/web/module/simulation/service/SysLogService.java new file mode 100644 index 0000000..3fb0966 --- /dev/null +++ b/web/src/main/java/com/imitate/web/module/simulation/service/SysLogService.java @@ -0,0 +1,32 @@ +package com.imitate.web.module.simulation.service; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.imitate.web.persistence.beans.SysLog; +import com.imitate.web.persistence.mapper.SysLogMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class SysLogService { + + @Autowired + private SysLogMapper sysLogMapper; + + public SysLog getById(Long id){ + return sysLogMapper.selectByPrimaryKey(id); + } + + public List list(String operation){ + return sysLogMapper.selectAllByOperation(operation); + } + + public PageInfo page(Integer pageNum,Integer pageSize){ + PageHelper.startPage(pageNum, pageSize); + List logList = sysLogMapper.selectAll(); + PageInfo page = new PageInfo<>(logList); + return page; + } +} diff --git a/web/src/main/java/com/imitate/web/params/CertificateOpenParam.java b/web/src/main/java/com/imitate/web/params/CertificateOpenParam.java new file mode 100644 index 0000000..3513e73 --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/CertificateOpenParam.java @@ -0,0 +1,27 @@ +package com.imitate.web.params; + +import com.imitate.web.persistence.beans.Certificate; +import lombok.Data; +import lombok.experimental.Delegate; + +import javax.validation.Valid; +import java.io.Serializable; + + + +/** + * 证书管理系统开通 + * @author yanchao + */ +@Data +public class CertificateOpenParam implements Serializable { + + @Valid + @Delegate + private Certificate certificate; + + { + certificate = new Certificate(); + } + +} diff --git a/web/src/main/java/com/imitate/web/params/DataTerminalParam.java b/web/src/main/java/com/imitate/web/params/DataTerminalParam.java new file mode 100644 index 0000000..89f2477 --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/DataTerminalParam.java @@ -0,0 +1,25 @@ +package com.imitate.web.params; + +import com.imitate.common.util.BasePageCondition; +import com.imitate.web.persistence.beans.DataTerminal; +import lombok.Data; +import lombok.experimental.Delegate; + +import javax.validation.Valid; +import java.io.Serializable; + +/** + * @author jshixiong + */ +@Data +public class DataTerminalParam extends BasePageCondition implements Serializable { + + @Valid + @Delegate + private DataTerminal dataTerminal; + + { + dataTerminal = new DataTerminal(); + } + +} diff --git a/web/src/main/java/com/imitate/web/params/DatabaseTestConnectionParam.java b/web/src/main/java/com/imitate/web/params/DatabaseTestConnectionParam.java new file mode 100644 index 0000000..2f35359 --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/DatabaseTestConnectionParam.java @@ -0,0 +1,29 @@ +package com.imitate.web.params; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 测试数据库源 + * @author yanchao + */ +@Data +public class DatabaseTestConnectionParam implements Serializable { + @NotBlank(message = "数据库类型不能为空,类型:MYSQL,ORACLE,SQLSEVER") + private String dbType; + @NotBlank(message = "数据库驱动不能为空") + private String dbDrive; + @NotBlank(message = "数据库ip不能为空") + private String dbIp; + @NotBlank(message = "数据库端口不能为空") + private String dbPort; + @NotBlank(message = "数据库名称不能为空") + private String dbName; + @NotBlank(message = "数据库用户名不能为空") + private String dbUser; + @NotBlank(message = "数据库密码不能为空") + private String dbPasswd; + +} diff --git a/web/src/main/java/com/imitate/web/params/DeviceListParam.java b/web/src/main/java/com/imitate/web/params/DeviceListParam.java new file mode 100644 index 0000000..309c5ba --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/DeviceListParam.java @@ -0,0 +1,23 @@ +package com.imitate.web.params; + +import com.imitate.common.util.BasePageCondition; +import com.imitate.web.persistence.beans.Device; +import lombok.Data; +import lombok.experimental.Delegate; + +import javax.validation.Valid; +import java.io.Serializable; + +/** + * @author jshixiong + */ +@Data +public class DeviceListParam extends BasePageCondition implements Serializable { + + @Delegate + private Device device; + + { + device = new Device(); + } +} diff --git a/web/src/main/java/com/imitate/web/params/DeviceParam.java b/web/src/main/java/com/imitate/web/params/DeviceParam.java new file mode 100644 index 0000000..b6b3c87 --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/DeviceParam.java @@ -0,0 +1,23 @@ +package com.imitate.web.params; + +import com.imitate.web.persistence.beans.Device; +import lombok.Data; +import lombok.experimental.Delegate; + +import javax.validation.Valid; +import java.io.Serializable; + +/** + * @author jshixiong + */ +@Data +public class DeviceParam implements Serializable { + + @Valid + @Delegate + private Device device; + + { + device = new Device(); + } +} diff --git a/web/src/main/java/com/imitate/web/params/DeviceTypeParam.java b/web/src/main/java/com/imitate/web/params/DeviceTypeParam.java new file mode 100644 index 0000000..7206ec8 --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/DeviceTypeParam.java @@ -0,0 +1,27 @@ +package com.imitate.web.params; + +import com.imitate.common.util.BasePageCondition; +import com.imitate.web.persistence.beans.DeviceType; +import lombok.Data; +import lombok.experimental.Delegate; + +import javax.validation.Valid; +import java.io.Serializable; +import java.util.List; + +/** + * @author jshixiong + */ +@Data +public class DeviceTypeParam extends BasePageCondition implements Serializable { + + @Valid + @Delegate + private DeviceType deviceType; + + { + deviceType = new DeviceType(); + } + + private List producerIdList; +} diff --git a/web/src/main/java/com/imitate/web/params/DistributionListParam.java b/web/src/main/java/com/imitate/web/params/DistributionListParam.java new file mode 100644 index 0000000..2328940 --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/DistributionListParam.java @@ -0,0 +1,21 @@ +package com.imitate.web.params; + +import com.imitate.common.util.BasePageCondition; +import com.imitate.web.persistence.beans.DeviceDistribution; +import lombok.Data; +import lombok.experimental.Delegate; + +import java.io.Serializable; + +/** + * @author jshixiong + */ +@Data +public class DistributionListParam extends BasePageCondition implements Serializable { + @Delegate + private DeviceDistribution deviceDistribution; + + { + deviceDistribution = new DeviceDistribution(); + } +} diff --git a/web/src/main/java/com/imitate/web/params/DistributionParam.java b/web/src/main/java/com/imitate/web/params/DistributionParam.java new file mode 100644 index 0000000..2e78a37 --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/DistributionParam.java @@ -0,0 +1,22 @@ +package com.imitate.web.params; + +import com.imitate.web.persistence.beans.DeviceDistribution; +import lombok.Data; +import lombok.experimental.Delegate; + +import javax.validation.Valid; +import java.io.Serializable; + +/** + * @author jshixiong + */ +@Data +public class DistributionParam implements Serializable { + @Valid + @Delegate + private DeviceDistribution deviceDistribution; + + { + deviceDistribution = new DeviceDistribution(); + } +} diff --git a/web/src/main/java/com/imitate/web/params/ProducerParam.java b/web/src/main/java/com/imitate/web/params/ProducerParam.java new file mode 100644 index 0000000..a415ddc --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/ProducerParam.java @@ -0,0 +1,23 @@ +package com.imitate.web.params; + +import com.imitate.web.persistence.beans.Producer; +import lombok.Data; +import lombok.experimental.Delegate; + +import javax.validation.Valid; +import java.io.Serializable; + +/** + * @author jshixiong + */ +@Data +public class ProducerParam implements Serializable { + + @Valid + @Delegate + private Producer producer; + + { + producer = new Producer(); + } +} diff --git a/web/src/main/java/com/imitate/web/params/ResourceOpenParam.java b/web/src/main/java/com/imitate/web/params/ResourceOpenParam.java new file mode 100644 index 0000000..ef2efa9 --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/ResourceOpenParam.java @@ -0,0 +1,27 @@ +package com.imitate.web.params; + + + +import com.imitate.web.persistence.beans.Resource; +import lombok.Data; +import lombok.experimental.Delegate; +import javax.validation.Valid; +import java.io.Serializable; + +/** + * 资源管理系统开通 + * @author yanchao + */ +@Data +public class ResourceOpenParam implements Serializable { + @Valid + @Delegate + private Resource resource; + + { + resource = new Resource(); + } + + + +} diff --git a/web/src/main/java/com/imitate/web/params/SecretKeyParam.java b/web/src/main/java/com/imitate/web/params/SecretKeyParam.java new file mode 100644 index 0000000..4af194e --- /dev/null +++ b/web/src/main/java/com/imitate/web/params/SecretKeyParam.java @@ -0,0 +1,23 @@ +package com.imitate.web.params; + +import com.imitate.web.persistence.beans.SecretKey; +import lombok.Data; +import lombok.experimental.Delegate; + +import javax.validation.Valid; +import java.io.Serializable; + +/** + * @author jshixiong + */ +@Data +public class SecretKeyParam implements Serializable { + + @Valid + @Delegate + private SecretKey secretKey; + + { + secretKey = new SecretKey(); + } +} diff --git a/web/src/main/java/com/imitate/web/persistence/beans/Certificate.java b/web/src/main/java/com/imitate/web/persistence/beans/Certificate.java new file mode 100644 index 0000000..174aaed --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/beans/Certificate.java @@ -0,0 +1,93 @@ +package com.imitate.web.persistence.beans; + +import com.imitate.common.util.AbstractDO; +import lombok.Data; +import lombok.EqualsAndHashCode; +import javax.persistence.Column; +import javax.persistence.Table; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + + +/** + * 证书系统开通 + * @author yanchao + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Table(name = "certificate") +public class Certificate extends AbstractDO { + + @Column(name = "status") + private Boolean status; + + @NotBlank(message = "单位不能为空") + @Column(name = "company") + private String company; + + @NotBlank(message = "数据库类型不能为空") + @Column(name = "db_type") + private String dbType; + + @NotBlank(message = "数据库驱动不能为空") + @Column(name = "db_drive") + private String dbDrive; + + @NotBlank(message = "数据库ip不能为空") + @Column(name = "db_ip") + private String dbIp; + + @NotBlank(message = "数据库端口不能为空") + @Column(name = "db_port") + private String dbPort; + + @NotBlank(message = "数据库名称不能为空") + @Column(name = "db_name") + private String dbName; + + @NotBlank(message = "数据库密码不能为空") + @Column(name = "db_passwd") + private String dbPasswd; + + @Column(name = "db_is_conn") + private Boolean dbIsConn; + + @NotBlank(message = "目标服务器地址不能为空") + @Column(name = "target_ip") + private String targetIp; + + @NotBlank(message = "目标服务器端口不能为空") + @Column(name = "target_port") + private String targetPort; + + @NotBlank(message = "用户dn不能为空") + @Column(name = "target_userdn") + private String targetUserdn; + + @NotBlank(message = "用户口令不能为空") + @Column(name = "target_passwd") + private String targetPasswd; + + @NotBlank(message = "用户证书发布配置文件路径不能为空") + @Column(name = "cert_url") + private String certUrl; + + @NotNull(message = "CRL发布点中的证书数量") + @Column(name = "cert_num") + private Integer certNum; + + @NotNull(message = "CRL发布周期") + @Column(name = "cert_cycle") + private Integer certCycle; + + @NotBlank(message = "导入证书文件1不能为空") + @Column(name = "import_cert_file1") + private String importCertFile1; + + @NotBlank(message = "导入证书文件2不能为空") + @Column(name = "import_cert_file2") + private String importCertFile2; + + + +} diff --git a/web/src/main/java/com/imitate/web/persistence/beans/DataTerminal.java b/web/src/main/java/com/imitate/web/persistence/beans/DataTerminal.java new file mode 100644 index 0000000..77a5d82 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/beans/DataTerminal.java @@ -0,0 +1,73 @@ +package com.imitate.web.persistence.beans; + +import com.imitate.common.util.AbstractDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.persistence.Column; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + *

+ * 数据终端表 + *

+ * + * @author jshixiong + * @since 2022-07-28 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Table(name = "data_terminal") +public class DataTerminal extends AbstractDO { + + /** + * 名称 + */ + @Column(name = "name") + private String name; + + /** + * 类型;1数据中心服务器,2本地管理终端 + */ + @Column(name = "type") + private String type; + + /** + * 编号 + */ + @Column(name = "number") + @NotBlank(message = "编号不能为空") + private String number; + + /** + * 生产厂商ID + */ + @Column(name = "producer_id") + @NotNull(message = "生产厂商ID不能为空") + private Long producerId; + + /** + * 管理标识 + */ + @Column(name = "manager_num") + private String managerNum; + + /** + * 物理标识 + */ + @Column(name = "physics_num") + private String physicsNum; + + /** + * 开通状态 + */ + @Column(name = "status") + private Boolean status; + + @Transient + private Producer producer; + +} diff --git a/web/src/main/java/com/imitate/web/persistence/beans/Device.java b/web/src/main/java/com/imitate/web/persistence/beans/Device.java new file mode 100644 index 0000000..30d749e --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/beans/Device.java @@ -0,0 +1,83 @@ +package com.imitate.web.persistence.beans; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.imitate.common.util.AbstractDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.persistence.Column; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 模拟设备表 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Table(name = "device") +public class Device extends AbstractDO{ + + /** + * 设备编号 + */ + @NotBlank(message = "设备编号不能为空") + @Column(name = "device_id") + private String deviceId; + + /** + * 设备名称 + */ + @Column(name = "name") + private String name; + + /** + * 设备型号 + */ + @NotNull(message = "设备型号不能为空") + @Column(name = "type") + private Long type; + + /** + * 生产厂商id;关联厂商 + */ + @NotNull(message = "生产厂商id不能为空") + @Column(name = "producer_id") + private Long producerId; + + /** + * 资源状态 + */ + @Column(name = "status") + private String status; + + /** + * 配发单ID;默认为0 + */ + @Column(name = "distribution_id") + private Long distributionId; + + /** + * 注册时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone = "GMT+8") + @Column(name = "add_time") + private LocalDateTime addTime; + + @Transient + private Producer producer; + + @Transient + private DeviceType deviceType; + + @Transient + private List deviceList; +} diff --git a/web/src/main/java/com/imitate/web/persistence/beans/DeviceDistribution.java b/web/src/main/java/com/imitate/web/persistence/beans/DeviceDistribution.java new file mode 100644 index 0000000..f5bc4e0 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/beans/DeviceDistribution.java @@ -0,0 +1,92 @@ +package com.imitate.web.persistence.beans; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.imitate.common.util.AbstractDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.persistence.Column; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotBlank; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 设备配发/调拨单 + *

+ * + * @author jshixiong + * @since 2022-08-02 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Table(name = "device_distribution") +public class DeviceDistribution extends AbstractDO { + + /** + * 类型;1配发,2调拨 + */ + @NotBlank(message = "类型不能为空") + @Column(name = "type") + private String type; + + /** + * 状态 + */ + @Column(name = "status") + private String status; + + /** + * 单号 + */ + @Column(name = "number") + private String number; + + /** + * 依据 + */ + @Column(name = "basis") + private String basis; + + /** + * 领用人姓名 + */ + @Column(name = "user_name") + private String userName; + + /** + * 联系电话 + */ + @Column(name = "phone") + private String phone; + + /** + * 发往节点 + */ + @NotBlank(message = "发往节点不能为空") + @Column(name = "send_node") + private String sendNode; + + /** + * 订单开始时间 + */ + @Column(name = "begin_time") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone = "GMT+8") + private LocalDateTime beginTime; + + /** + * 订单结束时间 + */ + @Column(name = "end_time") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone = "GMT+8") + private LocalDateTime endTime; + + @Transient + private List deviceList; + + @Transient + private Integer deviceCount; + +} diff --git a/web/src/main/java/com/imitate/web/persistence/beans/DeviceType.java b/web/src/main/java/com/imitate/web/persistence/beans/DeviceType.java new file mode 100644 index 0000000..a6fa1d1 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/beans/DeviceType.java @@ -0,0 +1,71 @@ +package com.imitate.web.persistence.beans; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.imitate.common.util.AbstractDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.persistence.Column; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotBlank; +import java.util.List; + +/** + *

+ * 设备类型表 + *

+ * + * @author jshixiong + * @since 2022-07-25 + */ +@Data +@ExcelIgnoreUnannotated +@EqualsAndHashCode(callSuper = false) +@Table(name = "device_type") +public class DeviceType extends AbstractDO { + + /** + * 类型名称 + */ + @ExcelProperty(value = "装备名称") + @NotBlank(message = "设备型号名称不能为空") + @Column(name = "name") + private String name; + + /** + * 类型编号 + */ + @ExcelProperty(value = "装备代号") + @NotBlank(message = "设备型号编号不能为空") + @Column(name = "type_number") + private String typeNumber; + + /** + * 工作模式 + */ + @ExcelProperty(value = "工作模式") + @NotBlank(message = "工作模式不能为空") + @Column(name = "pattern") + private String pattern; + + /** + * 密级 + */ + @ExcelProperty(value = "装备密级") + @NotBlank(message = "密级不能为空") + @Column(name = "secret_level") + private String secretLevel; + + /** + * 管理层级 + */ + @ExcelProperty(value = "管理层级") + @NotBlank(message = "管理等级不能为空") + @Column(name = "management_level") + private String managementLevel; + + @Transient + private List producerList; +} diff --git a/web/src/main/java/com/imitate/web/persistence/beans/DeviceTypeProducer.java b/web/src/main/java/com/imitate/web/persistence/beans/DeviceTypeProducer.java new file mode 100644 index 0000000..ecac58d --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/beans/DeviceTypeProducer.java @@ -0,0 +1,35 @@ +package com.imitate.web.persistence.beans; + +import com.imitate.common.util.AbstractDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.persistence.Column; +import javax.persistence.Table; + +/** + *

+ * + *

+ * + * @author jshixiong + * @since 2022-07-25 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Table(name = "device_type_producer") +public class DeviceTypeProducer extends AbstractDO { + + /** + * 设备类型ID + */ + @Column(name = "type_id") + private Long typeId; + + /** + * 生产厂商ID + */ + @Column(name = "producer_id") + private Long producerId; + +} diff --git a/web/src/main/java/com/imitate/web/persistence/beans/Producer.java b/web/src/main/java/com/imitate/web/persistence/beans/Producer.java new file mode 100644 index 0000000..f3903c5 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/beans/Producer.java @@ -0,0 +1,116 @@ +package com.imitate.web.persistence.beans; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.imitate.common.util.AbstractDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.persistence.Column; +import javax.persistence.Table; +import javax.validation.constraints.NotBlank; + +/** + *

+ * 生产厂商表 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Data +@ExcelIgnoreUnannotated +@EqualsAndHashCode(callSuper = false) +@Table(name = "producer") +public class Producer extends AbstractDO { + + /** + * 厂商名称 + */ + @ExcelProperty(value = "厂商全名") + @NotBlank(message = "厂商名称不能为空") + @Column(name = "name") + private String name; + + /** + * 厂商编号 + */ + @ExcelProperty(value = "厂商代号") + @NotBlank(message = "厂商编号不能为空") + @Column(name = "producer_number") + private String producerNumber; + + /** + * 厂商简称 + */ + @Column(name = "simple_name") + private String simpleName; + + /** + * 地址 + */ + @ExcelProperty(value = "厂商地址") + @NotBlank(message = "地址不能为空") + @Column(name = "address") + private String address; + + /** + * 联系人姓名1 + */ + @ExcelProperty(value = "联系人姓名") + @NotBlank(message = "联系人姓名1不能为空") + @Column(name = "contacts1") + private String contacts1; + + /** + * 联系手机1 + */ + @ExcelProperty(value = "联系人手机") + @NotBlank(message = "联系手机1不能为空") + @Column(name = "phone1") + private String phone1; + + /** + * 联系电话1 + */ + @ExcelProperty(value = "联系人电话") + @NotBlank(message = "联系电话1不能为空") + @Column(name = "tel1") + private String tel1; + + /** + * 联系邮箱1 + */ + @Column(name = "email1") + private String email1; + + /** + * 联系人姓名2 + */ + @Column(name = "contacts2") + private String contacts2; + + /** + * 联系手机2 + */ + @Column(name = "phone2") + private String phone2; + + /** + * 联系电话2 + */ + @Column(name = "tel2") + private String tel2; + + /** + * 联系邮箱2 + */ + @Column(name = "email2") + private String email2; + + /** + * 备注 + */ + @Column(name = "remarks") + private String remarks; +} diff --git a/web/src/main/java/com/imitate/web/persistence/beans/Resource.java b/web/src/main/java/com/imitate/web/persistence/beans/Resource.java new file mode 100644 index 0000000..dd6c95a --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/beans/Resource.java @@ -0,0 +1,64 @@ +package com.imitate.web.persistence.beans; + +import com.imitate.common.util.AbstractDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.persistence.Column; +import javax.persistence.Table; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + + +/** + * 资源管理系统开通 + * @author yanchao + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Table(name = "resource") +public class Resource extends AbstractDO { + + @Column(name = "status") + private Boolean status; + @NotBlank(message = "数据库用户名不能为空") + @Column(name = "db_user") + private String dbUser; + @NotBlank(message = "数据库密码不能为空") + @Column(name = "db_passwd") + private String dbPasswd; + @NotBlank(message = "数据库服务器ip地址不能为空") + @Column(name = "db_server_ip") + private String dbServerIp; + @NotNull(message = "type类型不能为空") + @Column(name = "type") + private Byte type; + @NotBlank(message = "数据中心名称不能为空") + @Column(name = "data_name") + private String dataName; + @NotBlank(message = "管理节点名称不能为空") + @Column(name = "node_name") + private String nodeName; + @NotBlank(message = "设备出厂编号不能为空") + @Column(name = "device_no") + private String deviceNo; + @NotBlank(message = "保障单位不能为空") + @Column(name = "support_unit") + private String supportUnit; + @NotBlank(message = "管理节点不能为空") + @Column(name = "manager_node") + private String managerNode; + @NotBlank(message = "导入文件1不能为空") + @Column(name = "file1") + private String file1; + @NotBlank(message = "导入文件2不能为空") + @Column(name = "file2") + private String file2; + @NotBlank(message = "导入文件3不能为空") + @Column(name = "file3") + private String file3; + @NotBlank(message = "导入文件4不能为空") + @Column(name = "file4") + private String file4; + +} diff --git a/web/src/main/java/com/imitate/web/persistence/beans/SecretKey.java b/web/src/main/java/com/imitate/web/persistence/beans/SecretKey.java new file mode 100644 index 0000000..3585664 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/beans/SecretKey.java @@ -0,0 +1,58 @@ +package com.imitate.web.persistence.beans; + +import com.imitate.common.util.AbstractDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.persistence.Column; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + *

+ * 密钥存储表 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Table(name = "secret_key") +public class SecretKey extends AbstractDO { + + /** + * 密钥类型;5种 + */ + @NotBlank(message = "类型ID不能为空") + @Column(name = "type") + private String type; + + /** + * 密钥长度 + */ + @Column(name = "length") + private Integer length; + + /** + * 密钥数量 + */ + @NotNull(message = "密钥数量不可为空") + @Column(name = "count") + private Integer count; + + /** + * 算法类型;1.ECC359;2.ECC281 + */ + @Column(name = "algorithm") + private String algorithm; + + @Transient + private String pushNode; + + @Transient + private List fileNameList; +} diff --git a/web/src/main/java/com/imitate/web/persistence/beans/SysLog.java b/web/src/main/java/com/imitate/web/persistence/beans/SysLog.java new file mode 100644 index 0000000..a5e6531 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/beans/SysLog.java @@ -0,0 +1,86 @@ + +package com.imitate.web.persistence.beans; + +import com.imitate.common.util.AbstractDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.persistence.Column; +import javax.persistence.Table; +import java.time.LocalDateTime; + + +/** + * 系统日志 + * @author 悟空 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Table(name = "sys_log") +public class SysLog extends AbstractDO { + + /** + * 用户操作 + */ + @Column(name = "operation") + private String operation; + + /** + * 模块名称 + */ + @Column(name = "module_name") + private String moduleName; + + /** + * 请求方法 + */ + @Column(name = "method") + private String method; + + /** + * 请求参数 + */ + @Column(name = "params") + private String params; + + /** + * 执行时长(毫秒) + */ + @Column(name = "time") + private Integer time; + + /** + * IP地址 + */ + @Column(name = "ip") + private String ip; + + /** + * 方法路由 + */ + @Column(name = "method_path") + private String methodPath; + + + /** + * 类路由 + */ + @Column(name = "class_path") + private String classPath; + + + /** + * 请求类型 GET或POST + */ + @Column(name = "http_type") + private String httpType; + + + + /** + * 返回结果 + */ + @Column(name = "result") + private String result; + +} diff --git a/web/src/main/java/com/imitate/web/persistence/mapper/CertificateMapper.java b/web/src/main/java/com/imitate/web/persistence/mapper/CertificateMapper.java new file mode 100644 index 0000000..24dc299 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/mapper/CertificateMapper.java @@ -0,0 +1,21 @@ +package com.imitate.web.persistence.mapper; + + +import com.imitate.common.util.BaseMapper; +import com.imitate.web.persistence.beans.Certificate; +import com.imitate.web.persistence.beans.Resource; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +/** + * 证书系统开通 + * @author yanchao + */ +@Mapper +@Repository +public interface CertificateMapper extends BaseMapper { + + Certificate selectRecentCertificate(); + + void truncateTable(); +} diff --git a/web/src/main/java/com/imitate/web/persistence/mapper/DataTerminalMapper.java b/web/src/main/java/com/imitate/web/persistence/mapper/DataTerminalMapper.java new file mode 100644 index 0000000..9cc6660 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/mapper/DataTerminalMapper.java @@ -0,0 +1,43 @@ +package com.imitate.web.persistence.mapper; + +import com.imitate.common.util.BaseMapper; +import com.imitate.web.persistence.beans.DataTerminal; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + *

+ * 数据终端表 Mapper 接口 + *

+ * + * @author jshixiong + * @since 2022-07-28 + */ +@Mapper +@Repository +public interface DataTerminalMapper extends BaseMapper { + + /** + * 根据类型查所有数据终端 + * @param type 类型 + * @return List + */ + List selectAllPro(@Param("type") String type); + + /** + * 通过ID获取数据终端 + * @param id ID + * @return DataTerminal + */ + DataTerminal getById(Long id); + + /** + * 查询已开通的数据终端 + * @param type 数据终端类型 + * @return DataTerminal + */ + DataTerminal getTerminalOpen(@Param("type") String type); +} diff --git a/web/src/main/java/com/imitate/web/persistence/mapper/DeviceDistributionMapper.java b/web/src/main/java/com/imitate/web/persistence/mapper/DeviceDistributionMapper.java new file mode 100644 index 0000000..b785e8f --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/mapper/DeviceDistributionMapper.java @@ -0,0 +1,37 @@ +package com.imitate.web.persistence.mapper; + +import com.imitate.common.util.BaseMapper; +import com.imitate.web.params.DistributionListParam; +import com.imitate.web.persistence.beans.DeviceDistribution; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + *

+ * 设备配发/调拨单 Mapper 接口 + *

+ * + * @author jshixiong + * @since 2022-08-02 + */ +@Mapper +@Repository +public interface DeviceDistributionMapper extends BaseMapper { + + /** + * 条件查询 + * @param param DistributionListParam + * @return List + */ + List selectAllPro(@Param("param") DistributionListParam param); + + /** + * 通过id获取详情 + * @param id ID + * @return DeviceDistribution + */ + DeviceDistribution getById(Long id); +} diff --git a/web/src/main/java/com/imitate/web/persistence/mapper/DeviceMapper.java b/web/src/main/java/com/imitate/web/persistence/mapper/DeviceMapper.java new file mode 100644 index 0000000..637706b --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/mapper/DeviceMapper.java @@ -0,0 +1,58 @@ +package com.imitate.web.persistence.mapper; + + +import com.imitate.common.util.BaseMapper; +import com.imitate.web.persistence.beans.Device; +import com.imitate.web.params.DeviceListParam; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + *

+ * 模拟设备表 Mapper 接口 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Mapper +@Repository +public interface DeviceMapper extends BaseMapper { + + /** + * 查所有设备详情列表 + * @param param 查询条件 + * @return List + */ + List selectAllPro(@Param("param") DeviceListParam param); + + /** + * 根据类型查设备列表 + * @return List + */ + List selectDeviceByType(); + + /** + * id获取设备 + * @param id ID + * @return Device + */ + Device getById(Long id); + + /** + * 查询有多少使用该ID厂商的设备 + * @param producerId 厂商ID + * @return Integer + */ + Integer selectCountById(Long producerId); + + /** + * 还原设备配发状态 + * @param distributionId 配发单ID + * @return int + */ + int updateDistributionId (Long distributionId); +} diff --git a/web/src/main/java/com/imitate/web/persistence/mapper/DeviceTypeMapper.java b/web/src/main/java/com/imitate/web/persistence/mapper/DeviceTypeMapper.java new file mode 100644 index 0000000..348c7b4 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/mapper/DeviceTypeMapper.java @@ -0,0 +1,37 @@ +package com.imitate.web.persistence.mapper; + +import com.imitate.common.util.BaseMapper; +import com.imitate.web.params.DeviceTypeParam; +import com.imitate.web.persistence.beans.DeviceType; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + *

+ * 设备类型表 Mapper 接口 + *

+ * + * @author jshixiong + * @since 2022-07-25 + */ +@Mapper +@Repository +public interface DeviceTypeMapper extends BaseMapper { + + /** + * 根据ID获取类型详情 + * @param id ID + * @return DeviceType + */ + DeviceType getById(Long id); + + /** + * 条件查询列表 + * @param param DeviceTypeParam + * @return List + */ + List selectByKey(@Param("param") DeviceTypeParam param); +} diff --git a/web/src/main/java/com/imitate/web/persistence/mapper/DeviceTypeProducerMapper.java b/web/src/main/java/com/imitate/web/persistence/mapper/DeviceTypeProducerMapper.java new file mode 100644 index 0000000..505e762 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/mapper/DeviceTypeProducerMapper.java @@ -0,0 +1,26 @@ +package com.imitate.web.persistence.mapper; + +import com.imitate.common.util.BaseMapper; +import com.imitate.web.persistence.beans.DeviceTypeProducer; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +/** + *

+ * Mapper 接口 + *

+ * + * @author jshixiong + * @since 2022-07-25 + */ +@Mapper +@Repository +public interface DeviceTypeProducerMapper extends BaseMapper { + + /** + * 根据typeId删除所有相关 类型-厂商表 + * @param id ID + * @return int + */ + int deleteByTypeId(Long id); +} diff --git a/web/src/main/java/com/imitate/web/persistence/mapper/ProducerMapper.java b/web/src/main/java/com/imitate/web/persistence/mapper/ProducerMapper.java new file mode 100644 index 0000000..13b1ac7 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/mapper/ProducerMapper.java @@ -0,0 +1,21 @@ +package com.imitate.web.persistence.mapper; + + +import com.imitate.common.util.BaseMapper; +import com.imitate.web.persistence.beans.Producer; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +/** + *

+ * 生产厂商表 Mapper 接口 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Mapper +@Repository +public interface ProducerMapper extends BaseMapper { + +} diff --git a/web/src/main/java/com/imitate/web/persistence/mapper/ResourceMapper.java b/web/src/main/java/com/imitate/web/persistence/mapper/ResourceMapper.java new file mode 100644 index 0000000..0bfd5a9 --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/mapper/ResourceMapper.java @@ -0,0 +1,17 @@ +package com.imitate.web.persistence.mapper; + + +import com.imitate.common.util.BaseMapper; +import com.imitate.web.persistence.beans.Resource; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Mapper +@Repository +public interface ResourceMapper extends BaseMapper { + + Resource selectRecentResource(); + + + void truncateTable(); +} diff --git a/web/src/main/java/com/imitate/web/persistence/mapper/SecretKeyMapper.java b/web/src/main/java/com/imitate/web/persistence/mapper/SecretKeyMapper.java new file mode 100644 index 0000000..ff8eeff --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/mapper/SecretKeyMapper.java @@ -0,0 +1,63 @@ +package com.imitate.web.persistence.mapper; + + +import com.imitate.common.util.BaseMapper; +import com.imitate.web.persistence.beans.SecretKey; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + *

+ * 密钥存储表 Mapper 接口 + *

+ * + * @author jshixiong + * @since 2022-07-14 + */ +@Mapper +@Repository +public interface SecretKeyMapper extends BaseMapper { + + /** + * 通过长度和类型查询 + * @param secretKey + * @return SecretKey + */ + SecretKey selectByLengthAndType(SecretKey secretKey); + + /** + * 通过长度和类型修改 + * @param secretKey + * @return int + */ + int updateByLengthAndType(SecretKey secretKey); + + /** + * 通过算法和类型修改 + * @param secretKey + * @return int + */ + int updateByAlgorithmAndType(SecretKey secretKey); + + /** + * 通过类型查各长度密钥的数量 + * @param type + * @return List + */ + List selectStatisticsByType(String type); + + /** + * 通过长度和类型推送 + * @param secretKey + * @return int + */ + int pushByLengthAndType(SecretKey secretKey); + + /** + * 删除所有表数据! + * @return int + */ + int deleteAll(); +} diff --git a/web/src/main/java/com/imitate/web/persistence/mapper/SysLogMapper.java b/web/src/main/java/com/imitate/web/persistence/mapper/SysLogMapper.java new file mode 100644 index 0000000..645acad --- /dev/null +++ b/web/src/main/java/com/imitate/web/persistence/mapper/SysLogMapper.java @@ -0,0 +1,20 @@ +package com.imitate.web.persistence.mapper; + +import com.imitate.common.util.BaseMapper; +import com.imitate.web.persistence.beans.SysLog; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Mapper +@Repository +public interface SysLogMapper extends BaseMapper { + /** + * 根据操作名查日志 + * @param operation 操作 + * @return List + */ + List selectAllByOperation(@Param("operation") String operation); +} diff --git a/web/src/main/java/com/imitate/web/vo/DeviceByTypeVO.java b/web/src/main/java/com/imitate/web/vo/DeviceByTypeVO.java new file mode 100644 index 0000000..ac95908 --- /dev/null +++ b/web/src/main/java/com/imitate/web/vo/DeviceByTypeVO.java @@ -0,0 +1,16 @@ +package com.imitate.web.vo; + +import com.imitate.web.persistence.beans.Device; +import lombok.Data; + +import java.util.List; + +/** + * @author jshixiong + */ +@Data +public class DeviceByTypeVO { + private Long type; + + private List deviceList; +} diff --git a/web/src/main/java/com/imitate/web/vo/DeviceManagerInitVO.java b/web/src/main/java/com/imitate/web/vo/DeviceManagerInitVO.java new file mode 100644 index 0000000..040ec71 --- /dev/null +++ b/web/src/main/java/com/imitate/web/vo/DeviceManagerInitVO.java @@ -0,0 +1,36 @@ +package com.imitate.web.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * 设施管理终端初始化资源类 + * @author jshixiong + */ +@Data +@ExcelIgnoreUnannotated +public class DeviceManagerInitVO { + + @ExcelProperty(value = "预制秘钥加密—秘钥长度") + private String keyLength; + + @ExcelProperty(value = "产生公私钥对—算法类型") + private String algorithm; + + private List keyLengthList; + + private List algorithmList; + + public DeviceManagerInitVO() {} + + public DeviceManagerInitVO(boolean isList) { + if (isList){ + this.keyLengthList = new ArrayList<>(); + this.algorithmList = new ArrayList<>(); + } + } +} diff --git a/web/src/main/java/com/imitate/web/vo/DeviceResourceInitVO.java b/web/src/main/java/com/imitate/web/vo/DeviceResourceInitVO.java new file mode 100644 index 0000000..e13bd38 --- /dev/null +++ b/web/src/main/java/com/imitate/web/vo/DeviceResourceInitVO.java @@ -0,0 +1,30 @@ +package com.imitate.web.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * 设备初装初始化资源类 + * @author jshixiong + */ +@Data +@ExcelIgnoreUnannotated +public class DeviceResourceInitVO { + + @ExcelProperty(value = "资源状态") + private String resourceStatus; + + private List resourceStatusList; + + public DeviceResourceInitVO() {} + + public DeviceResourceInitVO(boolean isList) { + if (isList){ + this.resourceStatusList = new ArrayList<>(); + } + } +} diff --git a/web/src/main/java/com/imitate/web/vo/DeviceSoftwareInitVO.java b/web/src/main/java/com/imitate/web/vo/DeviceSoftwareInitVO.java new file mode 100644 index 0000000..2aeee0b --- /dev/null +++ b/web/src/main/java/com/imitate/web/vo/DeviceSoftwareInitVO.java @@ -0,0 +1,48 @@ +package com.imitate.web.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * 设施管理软件初始化资源类 + * @author jshixiong + */ +@Data +@ExcelIgnoreUnannotated +public class DeviceSoftwareInitVO { + + @ExcelProperty(value = "开通设施管理设备证书系统—选择单位") + private String firstUnit; + + @ExcelProperty(value = "总部级—选择保障单位") + private String supportUnit; + + @ExcelProperty(value = "总部级—选择管理节点") + private String managerNode; + + @ExcelProperty(value = "数据库配置—数据库类型") + private String dbType; + + private List firstUnitList; + + private List supportUnitList; + + private List managerNodeList; + + private List dbTypeList; + + public DeviceSoftwareInitVO() {} + + public DeviceSoftwareInitVO(boolean isList) { + if (isList){ + this.firstUnitList = new ArrayList<>(); + this.supportUnitList = new ArrayList<>(); + this.managerNodeList = new ArrayList<>(); + this.dbTypeList = new ArrayList<>(); + } + } +} diff --git a/web/src/main/java/com/imitate/web/vo/DeviceTypeVO.java b/web/src/main/java/com/imitate/web/vo/DeviceTypeVO.java new file mode 100644 index 0000000..52f2e5e --- /dev/null +++ b/web/src/main/java/com/imitate/web/vo/DeviceTypeVO.java @@ -0,0 +1,28 @@ +package com.imitate.web.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +/** + * @author jshixiong + */ +@Data +@ExcelIgnoreUnannotated +public class DeviceTypeVO { + + @ExcelProperty(value = "装备名称") + private String name; + + @ExcelProperty(value = "装备代号") + private String typeNumber; + + @ExcelProperty(value = "工作模式") + private String pattern; + + @ExcelProperty(value = "装备密级") + private String secretLevel; + + @ExcelProperty(value = "管理层级") + private String managementLevel; +} diff --git a/web/src/main/java/com/imitate/web/vo/DeviceVO.java b/web/src/main/java/com/imitate/web/vo/DeviceVO.java new file mode 100644 index 0000000..da311bd --- /dev/null +++ b/web/src/main/java/com/imitate/web/vo/DeviceVO.java @@ -0,0 +1,38 @@ +package com.imitate.web.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author jshixiong + */ +@Data +@ExcelIgnoreUnannotated +public class DeviceVO { + private Long id; + + @ExcelProperty(value = "设备ID") + private String deviceId; + + @ExcelProperty(value = "设备名称") + private String name; + + @ExcelProperty(value = "设备型号") + private String typeName; + + private Long type; + + private Long producerId; + + @ExcelProperty(value = "生产厂商") + private String producerName; + + private String producerSimpleName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone = "GMT+8") + private LocalDateTime addTime; +} diff --git a/web/src/main/java/com/imitate/web/vo/LocalManagerInitVO.java b/web/src/main/java/com/imitate/web/vo/LocalManagerInitVO.java new file mode 100644 index 0000000..72ef89e --- /dev/null +++ b/web/src/main/java/com/imitate/web/vo/LocalManagerInitVO.java @@ -0,0 +1,47 @@ +package com.imitate.web.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * 本地管理终端初始化资源类 + * @author jshixiong + */ +@Data +@ExcelIgnoreUnannotated +public class LocalManagerInitVO { + @ExcelProperty(value = "配发管理—状态") + private String distributionStatus; + + @ExcelProperty(value = "配发管理—新建调拨单—发往节点") + private String distributionNode; + + @ExcelProperty(value = "密码长度") + private String keyLength; + + @ExcelProperty(value = "推送节点") + private String keyNode; + + private List distributionStatusList; + + private List distributionNodeList; + + private List keyLengthList; + + private List keyNodeList; + + public LocalManagerInitVO() {} + + public LocalManagerInitVO(boolean isList) { + if (isList){ + this.distributionStatusList = new ArrayList<>(); + this.distributionNodeList = new ArrayList<>(); + this.keyLengthList = new ArrayList<>(); + this.keyNodeList = new ArrayList<>(); + } + } +} diff --git a/web/src/main/resources/application.properties b/web/src/main/resources/application.properties new file mode 100644 index 0000000..829ba82 --- /dev/null +++ b/web/src/main/resources/application.properties @@ -0,0 +1,62 @@ +server.port=8088 +server.servlet.context-path=/xgd +server.max-http-header-size=8192 +server.compression.enabled=true +server.compression.min-response-size=1024 +server.compression.mime-types=text/plain,text/css,text/xml,text/javascript,application/json,application/javascript,application/xml,application/xml+rss,application/x-javascript,application/x-httpd-php,image/jpeg,image/gif,image/png +server.tomcat.uri-encoding=UTF-8 + + + +spring.config.import=classpath:common.properties + + + +# mysql +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.datasource.url=jdbc:mysql://testeducoder-public.mysql.polardb.rds.aliyuncs.com:3306/imitsys?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false +spring.datasource.username=testeducoder +spring.datasource.password=TEST@123 +spring.datasource.type=com.alibaba.druid.pool.DruidDataSource +spring.datasource.initialSize=200 +spring.datasource.maxActive=400 +spring.datasource.minIdle=200 +spring.datasource.validationQuery=select 1 +spring.datasource.testOnBorrow=false +spring.datasource.testOnReturn=false +spring.datasource.testWhileIdle=true +mybatis.type-aliases-package=com.imitate.web.persistence.beans +mybatis.mapperLocations=classpath*:mybatis/*.xml +mybatis.configuration.map-underscore-to-camel-case=true + +#xgd init +imitate.init.path=/data/workspace/platform/eva/datacenter +#imitate.init.path=C:\\xgd +imitate.init.xml=xgdImitateInit.xml +imitate.init.xlsx=xgdImitateInit.xlsx + +#mapper +mapper.mappers=com.imitate.common.util.BaseMapper +mapper.not-empty=false +mapper.identity=MYSQL + + +# pagehelper +pagehelper.helper-dialect=mysql +pagehelper.reasonable=true +pagehelper.support-methods-arguments=true +pagehelper.params=count=countSql + + +#showSql +logging.level.com.imitate.web.persistence.mapper=debug + + +# redis +spring.redis.host=127.0.0.1 +spring.redis.port=6379 +spring.redis.password= + + + + diff --git a/web/src/main/resources/mybatis/CerificateMapper.xml b/web/src/main/resources/mybatis/CerificateMapper.xml new file mode 100644 index 0000000..22f9d1d --- /dev/null +++ b/web/src/main/resources/mybatis/CerificateMapper.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id,status,company,db_type,db_drive,db_ip,db_port,db_name,db_passwd,db_is_conn,target_ip, +target_userdn,target_passwd,cert_url,cert_num,import_cert_file1,import_cert_file2,create_time,update_time + + + + + + + + diff --git a/web/src/main/resources/mybatis/DataTerminalMapper.xml b/web/src/main/resources/mybatis/DataTerminalMapper.xml new file mode 100644 index 0000000..b4c18fc --- /dev/null +++ b/web/src/main/resources/mybatis/DataTerminalMapper.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + id, name, type, number, producer_id, manager_num, physics_num, status, create_time, update_time + + + + + + + + diff --git a/web/src/main/resources/mybatis/DeviceDistributionMapper.xml b/web/src/main/resources/mybatis/DeviceDistributionMapper.xml new file mode 100644 index 0000000..eb84b8d --- /dev/null +++ b/web/src/main/resources/mybatis/DeviceDistributionMapper.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, type, status, number, basis, user_name, phone, send_node, begin_time, end_time, create_time, update_time + + + + + + diff --git a/web/src/main/resources/mybatis/DeviceMapper.xml b/web/src/main/resources/mybatis/DeviceMapper.xml new file mode 100644 index 0000000..22b203d --- /dev/null +++ b/web/src/main/resources/mybatis/DeviceMapper.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, device_id, name, type, producer_id,status, add_time + + + + + + + + + + + + UPDATE + device + SET + distribution_id = 0 + WHERE + distribution_id = #{distributionId} + + diff --git a/web/src/main/resources/mybatis/DeviceTypeMapper.xml b/web/src/main/resources/mybatis/DeviceTypeMapper.xml new file mode 100644 index 0000000..6f27c0d --- /dev/null +++ b/web/src/main/resources/mybatis/DeviceTypeMapper.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + id, name, type_number, pattern, secret_level, management_level, create_time, update_time + + + + + + diff --git a/web/src/main/resources/mybatis/DeviceTypeProducerMapper.xml b/web/src/main/resources/mybatis/DeviceTypeProducerMapper.xml new file mode 100644 index 0000000..1e6d970 --- /dev/null +++ b/web/src/main/resources/mybatis/DeviceTypeProducerMapper.xml @@ -0,0 +1,17 @@ + + + + + + + id, type_id, producer_id, create_time, update_time + + + + DELETE + FROM + device_type_producer + WHERE + type_id = #{id} + + diff --git a/web/src/main/resources/mybatis/ProducerMapper.xml b/web/src/main/resources/mybatis/ProducerMapper.xml new file mode 100644 index 0000000..cdac4dd --- /dev/null +++ b/web/src/main/resources/mybatis/ProducerMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/web/src/main/resources/mybatis/ResourceMapper.xml b/web/src/main/resources/mybatis/ResourceMapper.xml new file mode 100644 index 0000000..8366a26 --- /dev/null +++ b/web/src/main/resources/mybatis/ResourceMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, status, db_user, db_passwd, db_server_ip, `type` ,data_name,node_name,device_no,support_unit,manager_node, +file1,file2,file3,file4,create_time,update_time + + + + + + + + diff --git a/web/src/main/resources/mybatis/SecretKeyMapper.xml b/web/src/main/resources/mybatis/SecretKeyMapper.xml new file mode 100644 index 0000000..755f795 --- /dev/null +++ b/web/src/main/resources/mybatis/SecretKeyMapper.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + id, type, length, count,algorithm + + + + + + UPDATE + secret_key a + SET + a.count = a.count + #{count} + WHERE + a.type = #{type} + AND a.length = #{length} + + + + UPDATE + secret_key a + SET + a.count = a.count + #{count} + WHERE + a.type = #{type} + AND a.algorithm = #{algorithm} + + + + + + UPDATE + secret_key a + SET + a.count = a.count - #{count} + WHERE + a.type = #{type} + + AND a.algorithm = #{algorithm} + + + AND a.length = #{length} + + AND a.count >= #{count} + + + + DELETE FROM secret_key + + diff --git a/web/src/main/resources/mybatis/SysLogMapper.xml b/web/src/main/resources/mybatis/SysLogMapper.xml new file mode 100644 index 0000000..cc6c550 --- /dev/null +++ b/web/src/main/resources/mybatis/SysLogMapper.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + id, operation, method, params, time, ip, module_name, method_path, class_path, http_type, result, create_time, update_time + + + + + diff --git a/web/web.iml b/web/web.iml new file mode 100644 index 0000000..6f25881 --- /dev/null +++ b/web/web.iml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file