Commit fab1cd77 by chenzy

迈瑞开发服务第一个提交

parent bd84f9d7
FROM image-registry.openshift-image-registry.svc:5000/openshift/java:openjdk-11-ubi8
ENV APP_NAME publicplatform
ENV APP_PORT 9099
VOLUME /tmp
ENV USER_NAME jboss
ENV WORKING_DIR /home/iapdg${APP_NAME}
USER root
RUN echo 'Asia/Shanghai' >/etc/timezone && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && mkdir -p ${WORKING_DIR} && mkdir -p /data/logs/${USER_NAME}/
ADD ./build/target/${APP_NAME}-dist.tar.gz $WORKING_DIR/
RUN chown -R ${USER_NAME}:${USER_NAME} ${WORKING_DIR} && chown -R ${USER_NAME}:${USER_NAME} /data/logs/${USER_NAME}/ && cd $WORKING_DIR
USER ${USER_NAME}
EXPOSE ${APP_PORT}
ENTRYPOINT ["/bin/bash", "-c", "${WORKING_DIR}/${APP_NAME}/bin/startup.sh"]
\ No newline at end of file
<assembly>
<id>dist</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>kits</directory>
<outputDirectory>${file.separator}bin</outputDirectory>
<includes>
<include>**/*.sh</include>
</includes>
<fileMode>755</fileMode>
</fileSet>
<fileSet>
<directory>kits</directory>
<outputDirectory>${file.separator}config</outputDirectory>
<includes>
<include>**/*.xml</include>
</includes>
<fileMode>755</fileMode>
</fileSet>
<fileSet>
<directory>${user.dir}/runtime/target</directory>
<outputDirectory>${file.separator}</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
<fileMode>755</fileMode>
</fileSet>
<fileSet>
<directory>resources</directory>
<outputDirectory>resources</outputDirectory>
<includes>
<include>**/*</include>
</includes>
<fileMode>755</fileMode>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProperty scope="context" name="SPRING_PROFILES_ACTIVE" source="spring.profiles.active"/>
<springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
<!-- 日志文件相关配置 -->
<springProperty scope="context" name="LOG_FILE_SIZE" source="logging.file.size" defaultValue="32MB"/>
<springProperty scope="context" name="LOG_FILE_HISTORY" source="logging.file.history" defaultValue="15"/>
<springProperty scope="context" name="LOG_FILE_CAPACITY" source="logging.file.capacity" defaultValue="5GB"/>
<!-- 读取配置文件的日志级别,容器环境不用重新打包,灵活配置,默认WARN级别 -->
<springProperty scope="context" name="LOG_LEVEL_ROOT" source="logging.level.root" defaultValue="INFO"/>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<springProperty scope="context" name="FILE_LOG_PATH" source="logging.path" defaultValue="/home/jboss/logs"/>
<!--控制台格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符-->
<springProperty scope="context" name="CONSOLE_LOG_PATTERN" source="logging.console-log-pattern"
defaultValue="%green(%d{yyyy-MM-dd HH:mm:ss.SSS}:[%level]) %yellow([${APP_NAME}]:%r) %magenta([%t]) %boldCyan([%X{traceId} %X{sampled} %X{spanId}]) %red([%logger{50}.%M:%L]) --> %msg%n"/>
<!--日志文件格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符-->
<springProperty scope="context" name="FILE_LOG_PATTERN" source="logging.file-log-pattern"
defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS}:[%level] [${APP_NAME}:%r] [%t] [%X{traceId} %X{sampled} %X{spanId}] [%logger{50}.%M:%L] --> %msg%n"/>
<!--控制台日志输出 -->
<appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
<!-- 本地环境正常单行日志 -->
<springProfile name="local">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder" charset="UTF-8">
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</springProfile>
<!-- OCP容器环境JSON格式日志 -->
<springProfile name="dev,uat,prod">
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<providers>
<pattern>
<pattern>
{
"timestamp": "%date{\"yyyy-MM-dd HH:mm:ss.SSS\"}",
"level": "%level",
"lifeCycle":"%r",
"appName": "${APP_NAME}",
"traceId" : "%X{traceId:-}",
"sampled" : "%X{sampled:-}",
"spanId" : "%X{spanId:-}",
"thread": "%thread",
"logger": "%logger{50}",
"message": "%message",
"stackTrace": "%exception"
}
</pattern>
</pattern>
</providers>
</encoder>
</springProfile>
</appender>
<!-- 控制台异步实时输出 -->
<appender name="ASYNC_CONSOLE_APPENDER" class="ch.qos.logback.classic.AsyncAppender" immediateFlush="false"
neverBlock="true">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>2048</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="CONSOLE_APPENDER"/>
</appender>
<!-- 文件日志 -->
<appender name="FILE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${FILE_LOG_PATH}/${APP_NAME}/app.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 每天一归档 -->
<fileNamePattern>${FILE_LOG_PATH}/${APP_NAME}/%d{yyyy-MM}/app-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
<!-- 单个日志文件最多 32MB, 7天的日志周期,最大不能超过5GB -->
<maxFileSize>${LOG_FILE_SIZE}</maxFileSize>
<maxHistory>${LOG_FILE_HISTORY}</maxHistory>
<totalSizeCap>${LOG_FILE_CAPACITY}</totalSizeCap>
</rollingPolicy>
</appender>
<!-- 文件异步实时输出 -->
<appender name="ASYNC_FILE_APPENDER" class="ch.qos.logback.classic.AsyncAppender" immediateFlush="false"
neverBlock="true">
<discardingThreshold>0</discardingThreshold>
<queueSize>2048</queueSize>
<appender-ref ref="FILE_APPENDER"/>
</appender>
<!-- 本地环境只输出console的日志 -->
<springProfile name="local">
<root level="${LOG_LEVEL_ROOT}">
<appender-ref ref="CONSOLE_APPENDER"/>
</root>
</springProfile>
<!-- 线上DEV环境输出console的JSON格式日志和普通的文件日志 -->
<springProfile name="dev">
<root level="${LOG_LEVEL_ROOT}">
<appender-ref ref="CONSOLE_APPENDER"/>
<appender-ref ref="FILE_APPENDER"/>
</root>
</springProfile>
<!-- UAT环境只输出console的JSON格式日志 -->
<springProfile name="uat">
<root level="${LOG_LEVEL_ROOT}">
<appender-ref ref="ASYNC_CONSOLE_APPENDER"/>
</root>
</springProfile>
<!-- 生产环境只输出console的JSON格式日志 -->
<springProfile name="prod">
<root level="${LOG_LEVEL_ROOT}">
<appender-ref ref="ASYNC_CONSOLE_APPENDER"/>
</root>
</springProfile>
</configuration>
\ No newline at end of file
#!/bin/bash
set -x;
TEMP_DIR="-Djava.io.tmpdir=/tmp"
APP_NAME="publicplatform"
OS_USER_NAME="iapdg$APP_NAME"
BASE_LOC="/home/$OS_USER_NAME/$APP_NAME"
JAR_NAME="$APP_NAME.jar"
JAR_LOC=${BASE_LOC}/${JAR_NAME}
PROFILE="prod"
CONFIG_URL="http://SMS-KFSJGK-S02:8082"
JAVA_OPTS="$JAVA_OPTS -server $JVM_OPTS -XX:+UseCompressedOops -XX:+UseG1GC -Dnamespace=${namespaceId}"
SPRING_OPTS="--spring.config.location=$BASE_LOC/config/yml/application.yml --spring.profiles.active=$PROFILE --logging.config=$BASE_LOC/config/logback-custom.xml"
CURR_DIR=`pwd`
cd $BASE_LOC
#nohup java $JAVA_OPTS $TEMP_DIR -jar $JAR_LOC $SPRING_OPTS > $BASE_LOC/console.log 2>&1 &
java $JAVA_OPTS $TEMP_DIR -jar $JAR_LOC $SPRING_OPTS
echo "$JAR_NAME started."
cd $CURR_DIR
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.keymobile.publicplatform</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>build</artifactId>
<build>
<finalName>publicplatform</finalName>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>assembly/server-dist.xml</descriptor>
</descriptors>
<tarLongFileMode>posix</tarLongFileMode>
</configuration>
<executions>
<execution>
<id>create-assemblies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.keymobile.publicplatform</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>runtime</module>
<module>build</module>
</modules>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<auth.version>3.0.12-release</auth.version>
<harvester.version>2.0.2-release</harvester.version>
<pds.version>1.1.0-release</pds.version>
<odata.version>4.8.0</odata.version>
</properties>
<parent>
<groupId>com.keymobile</groupId>
<artifactId>parent</artifactId>
<version>1.1.3-release</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.keymobile</groupId>
<artifactId>config</artifactId>
<version>1.1.3-release</version>
</dependency>
<dependency>
<groupId>com.keymobile</groupId>
<artifactId>crypto</artifactId>
<version>1.1.3-release</version>
</dependency>
</dependencies>
</dependencyManagement>
<distributionManagement>
<snapshotRepository>
<id>nexus-snapshots</id>
<url>http://139.198.127.28:18081/repository/maven-snapshots/</url>
</snapshotRepository>
<repository>
<id>nexus-releases</id>
<url>http://139.198.127.28:18081/repository/maven-releases/</url>
</repository>
</distributionManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.4.0.905</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.keymobile.publicplatform</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>runtime</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.openjfx</groupId>
<artifactId>javafx.base</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- JUnit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.keymobile.auth</groupId>
<artifactId>security</artifactId>
<version>${auth.version}</version>
</dependency>
<dependency>
<groupId>com.keymobile</groupId>
<artifactId>config</artifactId>
</dependency>
<dependency>
<groupId>com.keymobile</groupId>
<artifactId>crypto</artifactId>
</dependency>
<dependency>
<groupId>com.keymobile.metadataharvester</groupId>
<artifactId>api</artifactId>
<version>${harvester.version}</version>
<exclusions>
<exclusion>
<groupId>com.keymobile.metadataharvester</groupId>
<artifactId>common</artifactId>
</exclusion>
<exclusion>
<groupId>com.keymobile.metadataharvester</groupId>
<artifactId>core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
<dependency>
<groupId>io.jaegertracing</groupId>
<artifactId>jaeger-client</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-jaeger-web-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>6.6</version>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
<build>
<finalName>publicplatform</finalName>
<resources>
<resource>
<directory>lib</directory>
<targetPath>BOOT-INF/lib/</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>application-*.yml</exclude>
<exclude>logback-custom.xml</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package com.keymobile.publicplatform.runtime;
import com.keymobile.config.security.ApplicationHelper;
import com.ulisesbocchio.jasyptspringboot.environment.StandardEncryptableEnvironment;
import lombok.extern.slf4j.Slf4j;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* @author 50267262
*/
@Slf4j
@EnableAsync
@EnableJpaAuditing
@EnableFeignClients(basePackages = {"com.keymobile.publicplatform.runtime.remote"})
@ComponentScan(basePackages = {"com.keymobile.publicplatform", "com.keymobile.config.logging"})
@SpringBootApplication
public class PublicPlatformApplication {
public static void main(String[] args) {
new SpringApplicationBuilder()
.environment(StandardEncryptableEnvironment.builder().encryptor(stringEncryptor()).build())
.sources(PublicPlatformApplication.class).run(args);
log.info("PublicPlatform Application run success");
}
private static StringEncryptor stringEncryptor() {
return new StringEncryptor() {
@Override
public String encrypt(String s) {
return ApplicationHelper.getEncryptor().encrypt(s);
}
@Override
public String decrypt(String s) {
return ApplicationHelper.getEncryptor().decrypt(s);
}
};
}
}
package com.keymobile.publicplatform.runtime.conf;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignClientConfig {
@Value("${security.authUser}")
private String authUser;
@Value("${security.authPwd}")
private String authPwd;
@Bean
public BasicAuthRequestInterceptor getBasicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor(authUser, authPwd);
}
}
\ No newline at end of file
package com.keymobile.publicplatform.runtime.conf;
import io.jaegertracing.internal.MDCScopeManager;
import io.opentracing.contrib.java.spring.jaeger.starter.TracerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JaegerConfig {
@Bean
public TracerBuilderCustomizer mdcBuilderCustomizer() {
return builder -> builder.withScopeManager(new MDCScopeManager.Builder().build());
}
}
package com.keymobile.publicplatform.runtime.conf;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* @author 50260863
*/
@Configuration
@RequiredArgsConstructor
public class RestTemplateConfig {
private final RestTemplateBuilder builder;
/**
* 使用HttpClient优化RestTemplate连接
*
* @return RestTemplate客户端
*/
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = builder.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setConnectTimeout(500);
requestFactory.setConnectionRequestTimeout(500);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(requestFactory));
return restTemplate;
}
}
package com.keymobile.publicplatform.runtime.conf;
import com.keymobile.publicplatform.runtime.ldaplogin.LdapAuthenticationProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import java.util.Collections;
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private LdapAuthenticationProvider ldapAuthenticationProvider;
@Value("${security.permit}")
private boolean permit = true;
@Override
protected void configure(HttpSecurity http) throws Exception {
if (permit) {
http.httpBasic().and().authorizeRequests().anyRequest().permitAll();
} else {
http.httpBasic().and()
// http
.authorizeRequests().antMatchers("/actuator/**").permitAll().and()
.authorizeRequests().anyRequest().authenticated();
}
//将默认加载的登录页配置删除
http.csrf().disable();
}
@Override
protected AuthenticationManager authenticationManager() throws Exception {
ProviderManager authenticationManager = new ProviderManager(Collections.singletonList(
//inMemoryAuthenticationProvider,
ldapAuthenticationProvider));
//不擦除认证密码,擦除会导致TokenBasedRememberMeServices因为找不到Credentials再调用UserDetailsService而抛出UsernameNotFoundException
authenticationManager.setEraseCredentialsAfterAuthentication(false);
return authenticationManager;
}
}
package com.keymobile.publicplatform.runtime.constant;
/**
* 公共常量类
*
* @author lmg
*/
public class PublicConstant {
//PO URL
//发起portal审批流程接口
public static final String APPROVAL_PROCESS_URL = "/RESTAdapter/DAP/PropertyProcssInterface";
}
package com.keymobile.publicplatform.runtime.controller;
import com.keymobile.publicplatform.runtime.model.Result;
import com.keymobile.publicplatform.runtime.model.dto.ApprovalProcessDTO;
import com.keymobile.publicplatform.runtime.model.dto.ApprovedDTO;
import com.keymobile.publicplatform.runtime.model.dto.ProcessSuspendDTO;
import com.keymobile.publicplatform.runtime.service.PortalApprovalProcessService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* PORTAL流程审批调用接口
*
* @author 50267262
*/
@Slf4j
@RestController
@RequestMapping("/external")
public class PortalApprovalProcessController {
@Autowired
private PortalApprovalProcessService portalApprovalProcessService;
@PostMapping("/propertyProcess")
public Result<Void> propertyProcess(@RequestBody @Validated ApprovalProcessDTO param) {
portalApprovalProcessService.propertyProcess(param);
return Result.ok();
}
@PostMapping("/workFlowReleaseApprovedCallBack")
public Result<Void> workFlowReleaseApprovedCallBack(@RequestBody @Validated ApprovedDTO param) {
portalApprovalProcessService.workFlowReleaseApprovedCallBack(param);
return Result.ok();
}
@PostMapping("/workFlowReleaseRejectedCallBack")
public Result<Void> workFlowReleaseRejectedCallBack(@RequestBody @Validated ProcessSuspendDTO param) {
portalApprovalProcessService.workFlowReleaseRejectedCallBack(param);
return Result.ok();
}
@PostMapping("/workFlowReleaseInterruptedCallBack")
public Result<Void> workFlowReleaseInterruptedCallBack(@RequestBody @Validated ProcessSuspendDTO param) {
portalApprovalProcessService.workFlowReleaseInterruptedCallBack(param);
return Result.ok();
}
@PostMapping("/workFlowPostAuthorApprovedCallBack")
public Result<Void> workFlowPostAuthorApprovedCallBack(@RequestBody @Validated ApprovedDTO param) {
portalApprovalProcessService.workFlowPostAuthorApprovedCallBack(param);
return Result.ok();
}
@PostMapping("/workFlowPostAuthorRejectedCallBack")
public Result<Void> workFlowPostAuthorRejectedCallBack(@RequestBody @Validated ProcessSuspendDTO param) {
portalApprovalProcessService.workFlowPostAuthorRejectedCallBack(param);
return Result.ok();
}
@PostMapping("/workFlowPostAuthorInterruptedCallBack")
public Result<Void> workFlowPostAuthorInterruptedCallBack(@RequestBody @Validated ProcessSuspendDTO param) {
portalApprovalProcessService.workFlowPostAuthorInterruptedCallBack(param);
return Result.ok();
}
}
package com.keymobile.publicplatform.runtime.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 资产审批流程--状态
*
* @author lmg
*/
@AllArgsConstructor
@Getter
public enum PropertyProcessStateEnum {
/**
* 多语言信息--业务类型
*/
APPROVED("approved", "审批通过"),
REJECTED("rejected", "审批不通过"),
INTERRUPTED("interrupted", "审批中止"),
DOING("doing", "审批中"),
;
/**
* 类型
*/
private final String type;
/**
* 描述
*/
private final String desc;
}
package com.keymobile.publicplatform.runtime.exception;
import com.keymobile.publicplatform.runtime.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;
import java.sql.SQLException;
import java.util.Optional;
/**
* 全局异常处理器
*
* @author 50260863
*/
@RestControllerAdvice
@Slf4j
public class UnifiedExceptionHandler {
/**
* 参数校验异常捕获 @Validated
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
BindingResult result = e.getBindingResult();
Optional<ObjectError> first = result.getAllErrors().stream().findFirst();
if (first.isPresent()) {
return Result.fail(first.get().getDefaultMessage());
}
return Result.fail(e.getMessage());
}
/**
* 实体校验异常捕获
*/
@ExceptionHandler(value = MissingServletRequestParameterException.class)
public Result<Void> handler(MissingServletRequestParameterException e) {
log.warn("missing request parameters:{}", e.getMessage());
return Result.fail("missing request parameters: " + e.getParameterName() + "= " + e.getMessage());
}
@ExceptionHandler(value = IllegalArgumentException.class)
public Result<Void> handler(IllegalArgumentException e) {
log.error("Assert异常:----------------{}", e.getMessage(), e);
return Result.fail(e.getMessage());
}
@ExceptionHandler(value = IllegalStateException.class)
public Result<Void> handler(IllegalStateException e) {
log.warn("IllegalStateException:----------------{}", e.getMessage());
return Result.fail(e.getMessage());
}
/**
* 缺少json请求参数异常
*
* @param e 读取不到JSON参数
* @return 统一异常封装结果
*/
@ExceptionHandler(value = HttpMessageNotReadableException.class)
public Result<Void> handler(HttpMessageNotReadableException e) {
log.warn("miss request body error :{} ", e.getMessage());
return Result.fail(e.getMessage());
}
@ExceptionHandler(value = AccessDeniedException.class)
public Result<Void> handler(AccessDeniedException e) {
log.warn("access forbidden :----------------{}", e.getMessage());
return Result.fail(e.getMessage());
}
@ExceptionHandler(value = AuthenticationException.class)
public Result<Void> handler(AuthenticationException e) {
log.warn("unauthorized error:----------------{}", e.getMessage());
return Result.fail(e.getMessage());
}
/**
* not mapping endpoint
*/
@ExceptionHandler(value = NoHandlerFoundException.class)
public Result<Void> handler(NoHandlerFoundException e) {
return Result.fail(e.getMessage());
}
/*
* ================== 以下是系统异常,需要开发人员处理 ==========================
*/
/**
* 处理SQL语法异常
*
* @param e SQL异常
*/
@ExceptionHandler(value = SQLException.class)
public Result<Void> handler(SQLException e) {
log.error("SQL :----------------{}", e.getMessage());
return Result.fail(e.getMessage());
}
@ExceptionHandler(value = BadSqlGrammarException.class)
public Result<Void> handler(BadSqlGrammarException e) {
log.error("SQL语法异常:----------------{}", e.getMessage());
return Result.fail("SQL语法异常");
}
@ExceptionHandler(value = Exception.class)
public Result<Void> handler(Exception e) {
log.error("运行时异常:----------------{}", e.getMessage(), e);
return Result.fail(e.getMessage());
}
}
package com.keymobile.publicplatform.runtime.ldaplogin;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.ldap.userdetails.LdapUserDetails;
import org.springframework.security.ldap.userdetails.LdapUserDetailsImpl;
import java.util.Set;
public class LDAPUser extends LdapUserDetailsImpl {
private static final long serialVersionUID = -903206904770597340L;
private String mail;
private String sn;
private String cn;
private String displayName;
private String name;
private String accountName;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LDAPUser() {
super();
}
public static class Essence extends LdapUserDetailsImpl.Essence {
public Essence() {
super();
}
public Essence(DirContextOperations context) {
super(context);
//this.setRealname(context.getStringAttribute("cn"));
this.setMail(context.getStringAttribute("mail"));
this.setSn(context.getStringAttribute("sn"));
this.setCn(context.getStringAttribute("cn"));
this.setDisplayName(context.getStringAttribute("displayName"));
this.setName(context.getStringAttribute("name"));
this.setSAMAccountName(context.getStringAttribute("sAMAccountName"));
this.setUsername(context.getStringAttribute("sAMAccountName"));
// we use user's member of to set up user's roles
//e.g. when memberOf=CN=sale,OU=Buisness,DC=thomas,DC=com
// user will got role: ROLE_SALE
Set<String> groups = context.getAttributeSortedStringSet("memberOf");
if (groups != null) {
for (String group : groups) {
for (String role : RoleMapping.findRolesForGroup(group)) {
this.addAuthority(new SimpleGrantedAuthority(role));
}
}
}
//user will got USER role by default
this.addAuthority(new SimpleGrantedAuthority(RoleMapping.ROLE_PREFIX + "USER"));
}
/**
* make sure (User)this.instance could work
*/
@Override
protected final LdapUserDetailsImpl createTarget() {
return new LDAPUser();
}
@Override
public LdapUserDetails createUserDetails() {
//LdapUserDetails userDetails = super.createUserDetails();
LDAPUser user = (LDAPUser) super.createUserDetails();
return user;
}
public void setMail(String mail) {
((LDAPUser) this.instance).mail = mail;
}
private void setSAMAccountName(String sAMAccountName) {
((LDAPUser) this.instance).accountName = sAMAccountName;
}
private void setName(String name) {
((LDAPUser) this.instance).name = name;
}
private void setCn(String cn) {
((LDAPUser) this.instance).cn = cn;
}
private void setDisplayName(String displayName) {
((LDAPUser) this.instance).displayName = displayName;
}
private void setSn(String sn) {
((LDAPUser) this.instance).sn = sn;
}
}
}
package com.keymobile.publicplatform.runtime.ldaplogin;
import com.keymobile.publicplatform.runtime.remote.AuthService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ldap.core.*;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.ldap.userdetails.LdapUserDetails;
import org.springframework.stereotype.Component;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import java.util.List;
@Component
public class LdapAuthenticationProvider implements AuthenticationProvider {
private static final Logger log = LoggerFactory.getLogger(LdapAuthenticationProvider.class);
@Autowired
private LdapTemplate ldapTemplate;
@Value(value = "${searchFilter}")
private String searchFilter;
@Value(value = "${searchBase}")
private String searchBase;
@Autowired
private AuthService authService;
private static final Log LOGLOG = LogFactory.getLog(LdapAuthenticationProvider.class);
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Authentication result = null;
if (authentication instanceof UsernamePasswordAuthenticationToken) {
UsernamePasswordAuthenticationToken userToken = (UsernamePasswordAuthenticationToken) authentication;
String username = userToken.getName();
String password = (String) userToken.getCredentials();
boolean flag = true;
//先调用平台authService服务查看是否有用户,没有用户就跳出,有用户就通过进行LDAP认证
List<LDAPUser> users = authService.getUserByName(username);
for (LDAPUser usertemp : users) {
if (usertemp.getName().equals(username)) {
flag = false;
break;
}
}
if (flag) {
throw new RuntimeException("该用户非平台用户");
}
UserDetails user = this.authenticate(username, password);
//User user = ldapService.getUserById(username);
//this.ldapTemplate.authenticate(base, filter, password, callback);
// log.info("username = " + username + " password = " + password);
// log.info("user = " + user);
if (null == user){
throw new RuntimeException("LDAP认证找不到该用户");
}
result = new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
}
return result;
}
private UserDetails authenticate(String username, String password) {
Callback callback = new Callback();
boolean authenticated = this.ldapTemplate.authenticate(
this.searchBase, String.format(this.searchFilter, username), password, callback);
if (!authenticated) {
return null;
}
return callback.getUserDetails();
}
@SuppressWarnings("rawtypes")
class Callback implements AuthenticatedLdapEntryContextCallback, ContextMapper {
private LdapUserDetails userDetails = null;
@Override
public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
try {
Object context = ctx.lookupLink(ldapEntryIdentification.getRelativeName());
userDetails = (LdapUserDetails) this.mapFromContext(context);
} catch (NamingException e) {
throw new RuntimeException("Failure to look up ldap entry! " + ldapEntryIdentification, e);
}
}
/**
* @param
* @return
* @throws NamingException
*/
@Override
public Object mapFromContext(Object ctx) throws NamingException {
DirContextOperations context = (DirContextOperations) ctx;
LDAPUser.Essence user = new LDAPUser.Essence(context);
LdapUserDetails userDetails = user.createUserDetails();
return userDetails;
}
public LdapUserDetails getUserDetails() {
return userDetails;
}
}
@Override
public boolean supports(Class<?> arg0) {
return true;
}
}
package com.keymobile.publicplatform.runtime.ldaplogin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.AuthenticationSource;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
@Configuration
@EnableConfigurationProperties(LdapProperty.class)
public class LdapConfig {
@Autowired
private LdapProperty ldapProperty;
@Bean
public LdapTemplate ldapTemplate() {
LdapTemplate ldapTemplate = new LdapTemplate();
ldapTemplate.setContextSource(ldapContextSource());
return ldapTemplate;
}
@Bean
public LdapContextSource ldapContextSource() {
LdapContextSource ldapContextSource = new LdapContextSource();
ldapContextSource.setCacheEnvironmentProperties(false);
ldapContextSource.setUrl(ldapProperty.getUrl());
ldapContextSource.setBase(ldapProperty.getBase());
/* ldapContextSource.setUserDn(ldapProperty.getUserDn());
ldapContextSource.setPassword(ldapProperty.getPassword());*/
ldapContextSource.setAuthenticationSource(new AuthenticationSource() {
@Override
public String getCredentials() {
return ldapProperty.getPassword();
}
@Override
public String getPrincipal() {
return ldapProperty.getUserDn();
}
});
return ldapContextSource;
}
}
package com.keymobile.publicplatform.runtime.ldaplogin;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "ldap")
public class LdapProperty {
private boolean enabled;
private String url;
private String base;
private String userDn;
private String password;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public String getUserDn() {
return userDn;
}
public void setUserDn(String userDn) {
this.userDn = userDn;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package com.keymobile.publicplatform.runtime.ldaplogin;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RoleMapping {
private static final Pattern REGEX = Pattern.compile("CN=([A-Za-z0-9-]+),.*");
public static final String ROLE_PREFIX = "ROLE_";
public static Set<String> findRolesForGroup(String group) {
Set<String> results = new HashSet<String>();
if (group != null) {
Matcher m = RoleMapping.REGEX.matcher(group);
if (m.matches()) {
results.add(ROLE_PREFIX + m.group(1).toUpperCase());
}
}
return results;
}
}
package com.keymobile.publicplatform.runtime.logging;
public class LogConstants {
public static final String CTX_REQUEST = "pdsOData.REQUEST";
public static final String CTX_AUDIT = "pdsOData.AUDIT";
public static final String CTX_EXEC = "pdsOData.EXEC";
}
package com.keymobile.publicplatform.runtime.logging;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogManager {
public static void logTrace(String context, Throwable e, String message) {
Logger logger = LoggerFactory.getLogger(context);
if (logger.isTraceEnabled()) {
logger.trace(message, e);
}
}
public static void logTrace(String context, String message) {
logTrace(context, null, message);
}
public static void logDebug(String context, String message) {
Logger logger = LoggerFactory.getLogger(context);
if (logger.isDebugEnabled()) {
logger.debug(message);
}
}
public static void logInfo(String context, String message) {
Logger logger = LoggerFactory.getLogger(context);
if (logger.isInfoEnabled()) {
logger.info(message);
}
}
public static void logWarning(String context, Throwable e, String message) {
Logger logger = LoggerFactory.getLogger(context);
if (logger.isWarnEnabled()) {
logger.warn(message, e);
}
}
public static void logWarning(String context, String message) {
logWarning(context, null, message);
}
public static void logError(String context, Throwable e, String message) {
Logger logger = LoggerFactory.getLogger(context);
if (logger.isErrorEnabled()) {
logger.error(message, e);
}
}
public static void logError(String context, String message) {
logError(context, null, message);
}
}
package com.keymobile.publicplatform.runtime.model;
import lombok.Data;
import java.io.Serializable;
/**
* 响应信息主体.
*
* @author 50267262
*/
@Data
public class Result<T> implements Serializable {
private static final long serialVersionUID = -8329890391319606862L;
/**
*响应码
*/
private String code;
/**
*响应消息
*/
private String msg;
/**
*数据体
*/
private T data;
/**
* 时间戳
*/
private Long timestamp = System.currentTimeMillis();
/**
* 链路追踪ID
*/
private String traceId;
private Result() {
}
private static <T> Result<T> restResult(String code, String msg, T data) {
Result<T> apiResult = new Result<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
apiResult.setTimestamp(System.currentTimeMillis());
return apiResult;
}
public static <T> Result<T> ok() {
return restResult("200", "成功", null);
}
public static <T> Result<T> ok(String msg, T data) {
return restResult("200", msg, data);
}
public static <T> Result<T> ok(String code, String msg, T data) {
return restResult(code, msg, data);
}
public static <T> Result<T> fail(String msg) {
return restResult("400", msg, null);
}
public static <T> Result<T> fail(String code, String msg) {
return restResult(code, msg, null);
}
}
\ No newline at end of file
package com.keymobile.publicplatform.runtime.model.dto;
import cn.hutool.core.collection.CollUtil;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* 发起portal审批流程DTO
*
* @author 50267262
*/
@Data
public class ApprovalProcessDTO {
/**
* 流程实例ID(重新提交时,必填)
*/
private String procinsId;
/**
* 申请人/处理人工号(必填)
*/
@NotBlank(message = "申请人/处理人工号不能为空")
private String applicanter;
/**
* 申请类型(0上架流程 1下架流程)(必填)
*/
@NotBlank(message = "申请类型(0上架流程 1下架流程)不能为空")
private String applicationType;
/**
* 发布原因
*/
private String reason;
/**
* 资产明细
*/
@NotEmpty(message = "资产明细不能为空")
private List<Property> propertyList;
@Data
public static class Property {
/**
* 数据关键用户
*/
@NotBlank(message = "数据关键用户不能为空")
private String keyUserId;
/**
* 数据Owner
*/
@NotBlank(message = "数据Owner不能为空")
private String dataOwner;
/**
* IT责任人
*/
@NotBlank(message = "IT责任人不能为空")
private String itResponsibilityer;
/**
* 资产目录负责人
*/
@NotBlank(message = "资产目录负责人不能为空")
private String propertyUserId;
/**
* 资产的连接地址
*/
@NotBlank(message = "资产的连接地址不能为空")
private String propertyLink;
/**
* 资产类型
*/
@NotBlank(message = "资产类型不能为空")
private String propertyType;
/**
* 资产编码
*/
@NotBlank(message = "资产编码不能为空")
private String propertyNo;
/**
* 资产名称
*/
@NotBlank(message = "资产名称不能为空")
private String propertyName;
}
public ApprovalProcessPortalDTO toPortal() {
ApprovalProcessPortalDTO portalDTO = new ApprovalProcessPortalDTO();
portalDTO.setProcinsId(this.procinsId);
portalDTO.setApplicanter(this.applicanter);
portalDTO.setApplicationType(this.applicationType);
portalDTO.setReason(this.reason);
List<ApprovalProcessPortalDTO.Property> PropertyList = CollUtil.newArrayList();
this.propertyList.forEach(v -> {
ApprovalProcessPortalDTO.Property property = new ApprovalProcessPortalDTO.Property();
property.setKeyUserId(v.getKeyUserId());
property.setDataOwner(v.getDataOwner());
property.setItResponsibilityer(v.getItResponsibilityer());
property.setPropertyUserId(v.getPropertyUserId());
property.setPropertyLink(v.getPropertyLink());
property.setPropertyType(v.getPropertyType());
property.setPropertyNo(v.getPropertyNo());
property.setPropertyName(v.getPropertyName());
PropertyList.add(property);
});
portalDTO.setPropertyList(PropertyList);
return portalDTO;
}
}
\ No newline at end of file
package com.keymobile.publicplatform.runtime.model.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* 发起portal审批流程DTO
*
* @author 50267262
*/
@Data
public class ApprovalProcessPortalDTO {
/**
* 流程实例ID(重新提交时,必填)
*/
@JsonProperty("ProcinsId")
private String ProcinsId;
/**
* 申请人/处理人工号(必填)
*/
@NotBlank(message = "申请人/处理人工号不能为空")
@JsonProperty("Applicanter")
private String Applicanter;
/**
* 申请类型(0上架流程 1下架流程)(必填)
*/
@NotBlank(message = "申请类型(0上架流程 1下架流程)不能为空")
@JsonProperty("ApplicationType")
private String ApplicationType;
/**
* 发布原因
*/
@JsonProperty("Reason")
private String Reason;
/**
* 资产明细
*/
@NotEmpty(message = "资产明细不能为空")
@JsonProperty("PropertyList")
private List<Property> PropertyList;
@Data
public static class Property {
/**
* 数据关键用户
*/
@NotBlank(message = "数据关键用户不能为空")
@JsonProperty("KeyUserId")
private String KeyUserId;
/**
* 数据Owner
*/
@NotBlank(message = "数据Owner不能为空")
@JsonProperty("DataOwner")
private String DataOwner;
/**
* IT责任人
*/
@NotBlank(message = "IT责任人不能为空")
@JsonProperty("ItResponsibilityer")
private String ItResponsibilityer;
/**
* 资产目录负责人
*/
@NotBlank(message = "资产目录负责人不能为空")
@JsonProperty("PropertyUserId")
private String PropertyUserId;
/**
* 资产的连接地址
*/
@NotBlank(message = "资产的连接地址不能为空")
@JsonProperty("PropertyLink")
private String PropertyLink;
/**
* 资产类型
*/
@NotBlank(message = "资产类型不能为空")
@JsonProperty("PropertyType")
private String PropertyType;
/**
* 资产编码
*/
@NotBlank(message = "资产编码不能为空")
@JsonProperty("PropertyNo")
private String PropertyNo;
/**
* 资产名称
*/
@NotBlank(message = "资产名称不能为空")
@JsonProperty("PropertyName")
private String PropertyName;
}
}
\ No newline at end of file
package com.keymobile.publicplatform.runtime.model.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.util.List;
/**
* portal审批流程通过DTO
*
* @author 50267262
*/
@Data
public class ApprovedDTO {
/**
* 流程实例ID
*/
@NotBlank(message = "流程实例ID不能为空")
private String procinsId;
private List<OperationRequest> operationRequests;
@Data
public static class OperationRequest {
/**
* 资产类型
*/
private String propertyType;
/**
* 资产编码
*/
private String propertyNo;
/**
* 上架:RELEASE 下架:WITHDRAW
*/
private String operation;
/**
* 资产名称
* 例 岗位1
*/
private String propertyName;
private List<NestedProperty> nestedProperties;
}
@Data
public static class NestedProperty {
/**
* 资产类型
*/
private String propertyType;
/**
* 资产编码
*/
private String propertyNo;
/**
* 资产名称
*/
private String propertyName;
}
}
\ No newline at end of file
package com.keymobile.publicplatform.runtime.model.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* portal审批流程中止
*
* @author 50267262
*/
@Data
public class ProcessSuspendDTO {
/**
* 流程实例ID
*/
@NotBlank(message = "流程实例ID不能为空")
private String procinsId;
}
\ No newline at end of file
package com.keymobile.publicplatform.runtime.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @author 50267262
*/
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "process_relation")
@EntityListeners(AuditingEntityListener.class)
public class ProcessRelationAbstract implements Serializable {
private static final long serialVersionUID = -4425077517320374105L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 数据资产资产类型
*/
@Column(nullable = false, length = 100)
private String propertyType;
/**
* 数据资产资产ID
*/
@Column(nullable = false, length = 100)
private String propertyId;
/**
* 流程实例ID(portal)
*/
@Column(nullable = false, length = 100)
private String procinsId;
/**
* 流程审批状态
*/
@Column(nullable = false, length = 20)
private String state;
/**
* 创建时间
*/
@CreatedDate
private LocalDateTime createTime;
/**
* 更新时间
*/
@LastModifiedDate
private LocalDateTime updateTime;
}
package com.keymobile.publicplatform.runtime.model.vo;
import lombok.Data;
/**
* 发起portal审批流程VO
*
* @author 50267262
*/
@Data
public class ApprovalProcessVO {
/**
* 流程实例ID
*/
private String procinsId;
}
\ No newline at end of file
package com.keymobile.publicplatform.runtime.remote;
import com.keymobile.publicplatform.runtime.ldaplogin.LDAPUser;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@FeignClient(value = "authService", url = "http://${dg.authservice.name:authservice-service}.${dg.namespace:data-governance}:${dg.authservice.port:8080}")
//@FeignClient(value = "authService", url = "http://127.0.0.1:8077")
public interface AuthService {
// 根据用户username获取用户
@RequestMapping(value = "/users/findByName", method = RequestMethod.GET)
List<LDAPUser> getUserByName(@RequestParam(value = "match") String match);
}
package com.keymobile.publicplatform.runtime.repository;
import com.keymobile.publicplatform.runtime.model.entity.ProcessRelationAbstract;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.time.LocalDateTime;
/**
* @author 50267262
*/
public interface ProcessRelationRepository extends JpaRepository<ProcessRelationAbstract, Long> {
@Modifying
@Query("update ProcessRelationAbstract pr set pr.state=?2, pr.updateTime=?3 where pr.procinsId=?1")
void updateStateByProcinsId(String procinsId, String state, LocalDateTime updateTime);
}
package com.keymobile.publicplatform.runtime.service;
import com.keymobile.publicplatform.runtime.model.dto.ApprovalProcessDTO;
import com.keymobile.publicplatform.runtime.model.dto.ApprovedDTO;
import com.keymobile.publicplatform.runtime.model.dto.ProcessSuspendDTO;
/**
* @author 50267262
*/
public interface PortalApprovalProcessService {
/**
* 发起流程审批
* @param param 请求参数
*/
void propertyProcess(ApprovalProcessDTO param);
/**
* 流程审批通过(发布)
* @param param 请求参数
*/
void workFlowReleaseApprovedCallBack(ApprovedDTO param);
/**
* 流程审批不通过(发布)
* @param param 请求参数
*/
void workFlowReleaseRejectedCallBack(ProcessSuspendDTO param);
/**
* 流程审批中止(发布)
* @param param 请求参数
*/
void workFlowReleaseInterruptedCallBack(ProcessSuspendDTO param);
/**
* 流程审批通过(岗位)
* @param param 请求参数
*/
void workFlowPostAuthorApprovedCallBack(ApprovedDTO param);
/**
* 流程审批不通过(岗位)
* @param param 请求参数
*/
void workFlowPostAuthorRejectedCallBack(ProcessSuspendDTO param);
/**
* 流程审批中止(岗位)
* @param param 请求参数
*/
void workFlowPostAuthorInterruptedCallBack(ProcessSuspendDTO param);
}
package com.keymobile.publicplatform.runtime.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.keymobile.publicplatform.runtime.constant.PublicConstant;
import com.keymobile.publicplatform.runtime.enums.PropertyProcessStateEnum;
import com.keymobile.publicplatform.runtime.model.Result;
import com.keymobile.publicplatform.runtime.model.dto.ApprovalProcessDTO;
import com.keymobile.publicplatform.runtime.model.dto.ApprovedDTO;
import com.keymobile.publicplatform.runtime.model.dto.ProcessSuspendDTO;
import com.keymobile.publicplatform.runtime.model.entity.ProcessRelationAbstract;
import com.keymobile.publicplatform.runtime.model.vo.ApprovalProcessVO;
import com.keymobile.publicplatform.runtime.repository.ProcessRelationRepository;
import com.keymobile.publicplatform.runtime.service.PortalApprovalProcessService;
import com.keymobile.publicplatform.runtime.util.RestTemplateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
/**
* 定价条件表管理
*
* @author lmg
*/
@Service
@Slf4j
public class PortalApprovalProcessServiceImpl implements PortalApprovalProcessService {
@Value("${mindray.po.url}")
private String baseUrl;
@Value("${mindray.po.auth}")
private String poAuth;
@Autowired
private ProcessRelationRepository processRelationRepository;
@Override
@Transactional(rollbackFor = Exception.class)
public void propertyProcess(ApprovalProcessDTO param) {
/* 调用portal发起/重新提交审批流程 */
String url = baseUrl + PublicConstant.APPROVAL_PROCESS_URL;
Result<ApprovalProcessVO> result = RestTemplateUtils.postJsonPO(url, param.toPortal(), poAuth, new ParameterizedTypeReference<>() {
});
ApprovalProcessVO approvalProcessVO = result.getData();
// TODO 流程重新提交的状态维护、是否存在资产调整可能
/* 维护资产与流程的关系及状态 */
List<ProcessRelationAbstract> relations = CollUtil.newArrayList();
param.getPropertyList().forEach(property -> {
relations.add(ProcessRelationAbstract.builder()
.propertyType(property.getPropertyType())
.propertyId(property.getPropertyNo())
.procinsId(approvalProcessVO.getProcinsId())
.state(PropertyProcessStateEnum.DOING.getType())
.build());
});
processRelationRepository.saveAll(relations);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void workFlowReleaseApprovedCallBack(ApprovedDTO param) {
// TODO 通知业务服务
processRelationRepository.updateStateByProcinsId(param.getProcinsId(), PropertyProcessStateEnum.APPROVED.getType(), LocalDateTime.now());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void workFlowReleaseRejectedCallBack(ProcessSuspendDTO param) {
processRelationRepository.updateStateByProcinsId(param.getProcinsId(), PropertyProcessStateEnum.REJECTED.getType(), LocalDateTime.now());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void workFlowReleaseInterruptedCallBack(ProcessSuspendDTO param) {
processRelationRepository.updateStateByProcinsId(param.getProcinsId(), PropertyProcessStateEnum.INTERRUPTED.getType(), LocalDateTime.now());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void workFlowPostAuthorApprovedCallBack(ApprovedDTO param) {
// TODO 通知业务服务
processRelationRepository.updateStateByProcinsId(param.getProcinsId(), PropertyProcessStateEnum.APPROVED.getType(), LocalDateTime.now());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void workFlowPostAuthorRejectedCallBack(ProcessSuspendDTO param) {
processRelationRepository.updateStateByProcinsId(param.getProcinsId(), PropertyProcessStateEnum.REJECTED.getType(), LocalDateTime.now());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void workFlowPostAuthorInterruptedCallBack(ProcessSuspendDTO param) {
processRelationRepository.updateStateByProcinsId(param.getProcinsId(), PropertyProcessStateEnum.INTERRUPTED.getType(), LocalDateTime.now());
}
}
package com.keymobile.publicplatform.runtime.util;
import com.alibaba.fastjson.JSON;
import com.keymobile.publicplatform.runtime.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
/**
* @author 50267262
*/
@Slf4j
@Component
public class RestTemplateUtils {
private static RestTemplate restTemplate;
@Autowired
public void setRestTemplate(RestTemplate restTemplate) {
RestTemplateUtils.restTemplate = restTemplate;
}
/**
* @param url url
* @param requestBody 请求体
* @param auth auth
* @param <T> 响应类型
* @return 响应
*/
public static <T> Result<T> postJsonPO(String url, Object requestBody, String auth, ParameterizedTypeReference<Result<T>> responseType) {
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + auth);
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Object> requestEntity = new HttpEntity<>(requestBody, headers);
log.info("PO url:{}, request:{}", url, JSON.toJSONString(requestBody));
ResponseEntity<Result<T>> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, responseType);
return responseEntity.getBody();
}
}
eureka:
client:
enabled: false
spring:
session:
store-type: redis
redis:
namespace: dev
redis:
host: 10.27.33.41
port: 6379
jpa:
hibernate:
ddl-auto: update
datasource:
url: jdbc:mysql://10.27.33.42:3306/dg?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
username: dg
initialization-mode: always
continue-on-error: true
driver-class-name: com.mysql.cj.jdbc.Driver
server:
port: 8080
connection-timeout: PT5S
security:
authUser: root
authPwd: pwd
permit: true
ribbon:
ReadTimeout: 180000
ConnectTimeout: 180000
OkToRetryOnAllOperations: true
MaxAutoRetries: 3
feign:
client:
config:
default:
connectTimeout: 180000
ReadTimeout: 180000
logging:
config: file:logback-custom.xml
# jaeger 链路追踪配置
opentracing:
jaeger:
enable-b3-propagation: false
udp-sender:
host: jaeger-agent.dev-istio.svc.cluster.local
port: 6831
log-spans: false
ldap:
enabled: true
url: ldap://ldap.mindray.com:3268
base: ""
userDn: "CN=LDAPdadomain,OU=Service Accounts,DC=cn,DC=mindray,DC=gb"
password: 1jnc3eeDveHex8QF
searchFilter: "(&(objectclass=person)(sAMAccountName=%1$s))"
searchBase: "DC=mindray,DC=gb"
mindray:
po:
url: "https://podev.mindray.com"
auth: "UEJDX1BPRDpXcjI4NTJoc0Bk"
\ No newline at end of file
server:
port: 8080
eureka:
client:
registryFetchIntervalSeconds: 5
region: default
serviceUrl:
defaultZone: http://192.168.0.37:8081/eureka/
enabled: false
spring:
session:
store-type: redis
redis:
namespace: dg
redis:
host: 10.27.33.41
port: 6379
password: dg@2924redis913
jpa:
hibernate:
ddl-auto: update
datasource:
url: jdbc:mysql://10.27.33.42:3306/dg?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
username: dg
password: dg@2924BI913
initialization-mode: always
continue-on-error: true
driver-class-name: com.mysql.cj.jdbc.Driver
logging:
config: classpath:logback-custom.xml
security:
authUser: root
authPwd: Root@2022
permit: false
ribbon:
ReadTimeout: 180000
ConnectTimeout: 180000
OkToRetryOnAllOperations: true
MaxAutoRetries: 3
feign:
client:
config:
default:
connectTimeout: 180000
ReadTimeout: 180000
ldap:
enabled: true
url: ldap://ldap.mindray.com:3268
base: ""
userDn: "CN=LDAPdadomain,OU=Service Accounts,DC=cn,DC=mindray,DC=gb"
password: 1jnc3eeDveHex8QF
searchFilter: "(&(objectclass=person)(sAMAccountName=%1$s))"
searchBase: "DC=mindray,DC=gb"
mindray:
po:
url: "https://podev.mindray.com"
auth: "UEJDX1BPRDpXcjI4NTJoc0Bk"
#logging:
# level:
# root: debug
eureka:
client:
enabled: false
spring:
session:
store-type: redis
redis:
namespace: uat
redis:
host: 10.27.33.31
port: 6379
jpa:
hibernate:
ddl-auto: update
datasource:
url: jdbc:mysql://10.27.33.31:3306/dg?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
username: dg
initialization-mode: always
continue-on-error: true
driver-class-name: com.mysql.cj.jdbc.Driver
server:
port: 8080
connection-timeout: PT5S
security:
authUser: root
authPwd: pwd
permit: true
ribbon:
ReadTimeout: 180000
ConnectTimeout: 180000
OkToRetryOnAllOperations: true
MaxAutoRetries: 3
feign:
client:
config:
default:
connectTimeout: 180000
ReadTimeout: 180000
logging:
config: file:logback-custom.xml
# jaeger 链路追踪配置
opentracing:
jaeger:
enable-b3-propagation: false
udp-sender:
host: jaeger-agent.dev-istio.svc.cluster.local
port: 6831
log-spans: false
ldap:
enabled: true
url: ldap://ldap.mindray.com:3268
base: ""
userDn: "CN=LDAPdadomain,OU=Service Accounts,DC=cn,DC=mindray,DC=gb"
password: 1jnc3eeDveHex8QF
searchFilter: "(&(objectclass=person)(sAMAccountName=%1$s))"
searchBase: "DC=mindray,DC=gb"
mindray:
po:
url: "https://poqas.mindray.com"
auth: "UEJDX1BPUTpXcjI4NTJoc0Bx"
\ No newline at end of file
management:
metrics:
tags:
application: ${spring.application.name}
endpoints:
health:
show-details: always
web:
exposure:
include: prometheus
\ No newline at end of file
spring:
application:
name: publicplatform
profiles:
active: local
#cloud:
#config:
#uri: http://localhost:8082
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProperty scope="context" name="SPRING_PROFILES_ACTIVE" source="spring.profiles.active"/>
<springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
<!-- 日志文件相关配置 -->
<springProperty scope="context" name="LOG_FILE_SIZE" source="logging.file.size" defaultValue="32MB"/>
<springProperty scope="context" name="LOG_FILE_HISTORY" source="logging.file.history" defaultValue="15"/>
<springProperty scope="context" name="LOG_FILE_CAPACITY" source="logging.file.capacity" defaultValue="5GB"/>
<!-- 读取配置文件的日志级别,容器环境不用重新打包,灵活配置,默认WARN级别 -->
<springProperty scope="context" name="LOG_LEVEL_ROOT" source="logging.level.root" defaultValue="INFO"/>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<springProperty scope="context" name="FILE_LOG_PATH" source="logging.path" defaultValue="/home/jboss/logs"/>
<!--控制台格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符-->
<springProperty scope="context" name="CONSOLE_LOG_PATTERN" source="logging.console-log-pattern"
defaultValue="%green(%d{yyyy-MM-dd HH:mm:ss.SSS}:[%level]) %yellow([${APP_NAME}]:%r) %magenta([%t]) %boldCyan([%X{traceId} %X{sampled} %X{spanId}]) %red([%logger{50}.%M:%L]) --> %msg%n"/>
<!--日志文件格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符-->
<springProperty scope="context" name="FILE_LOG_PATTERN" source="logging.file-log-pattern"
defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS}:[%level] [${APP_NAME}:%r] [%t] [%X{traceId} %X{sampled} %X{spanId}] [%logger{50}.%M:%L] --> %msg%n"/>
<!--控制台日志输出 -->
<appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
<!-- 本地环境正常单行日志 -->
<springProfile name="local">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder" charset="UTF-8">
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</springProfile>
<!-- OCP容器环境JSON格式日志 -->
<springProfile name="dev,uat,prod">
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<providers>
<pattern>
<pattern>
{
"timestamp": "%date{\"yyyy-MM-dd HH:mm:ss.SSS\"}",
"level": "%level",
"lifeCycle":"%r",
"appName": "${APP_NAME}",
"traceId" : "%X{traceId:-}",
"sampled" : "%X{sampled:-}",
"spanId" : "%X{spanId:-}",
"thread": "%thread",
"logger": "%logger{50}",
"message": "%message",
"stackTrace": "%exception"
}
</pattern>
</pattern>
</providers>
</encoder>
</springProfile>
</appender>
<!-- 控制台异步实时输出 -->
<appender name="ASYNC_CONSOLE_APPENDER" class="ch.qos.logback.classic.AsyncAppender" immediateFlush="false"
neverBlock="true">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>2048</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="CONSOLE_APPENDER"/>
</appender>
<!-- 文件日志 -->
<appender name="FILE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${FILE_LOG_PATH}/${APP_NAME}/app.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 每天一归档 -->
<fileNamePattern>${FILE_LOG_PATH}/${APP_NAME}/%d{yyyy-MM}/app-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
<!-- 单个日志文件最多 32MB, 7天的日志周期,最大不能超过5GB -->
<maxFileSize>${LOG_FILE_SIZE}</maxFileSize>
<maxHistory>${LOG_FILE_HISTORY}</maxHistory>
<totalSizeCap>${LOG_FILE_CAPACITY}</totalSizeCap>
</rollingPolicy>
</appender>
<!-- 文件异步实时输出 -->
<appender name="ASYNC_FILE_APPENDER" class="ch.qos.logback.classic.AsyncAppender" immediateFlush="false"
neverBlock="true">
<discardingThreshold>0</discardingThreshold>
<queueSize>2048</queueSize>
<appender-ref ref="FILE_APPENDER"/>
</appender>
<!-- 本地环境只输出console的日志 -->
<springProfile name="local">
<root level="${LOG_LEVEL_ROOT}">
<appender-ref ref="CONSOLE_APPENDER"/>
</root>
</springProfile>
<!-- 线上DEV环境输出console的JSON格式日志和普通的文件日志 -->
<springProfile name="dev">
<root level="${LOG_LEVEL_ROOT}">
<appender-ref ref="CONSOLE_APPENDER"/>
<appender-ref ref="FILE_APPENDER"/>
</root>
</springProfile>
<!-- UAT环境只输出console的JSON格式日志 -->
<springProfile name="uat">
<root level="${LOG_LEVEL_ROOT}">
<appender-ref ref="ASYNC_CONSOLE_APPENDER"/>
</root>
</springProfile>
<!-- 生产环境只输出console的JSON格式日志 -->
<springProfile name="prod">
<root level="${LOG_LEVEL_ROOT}">
<appender-ref ref="ASYNC_CONSOLE_APPENDER"/>
</root>
</springProfile>
</configuration>
\ No newline at end of file
package com.keymobile.publicplatform.runtime;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Base64;
import java.util.Date;
@SpringBootTest
public class PublicPlatformApplicationTests {
@Test
public void contextLoads() {
}
public static void main(String[] args) {
String credentials = "PBC_POQ:Wr2852hs@q";
String encodedCredentials = Base64.getEncoder().encodeToString(credentials.getBytes());
System.out.println(encodedCredentials);
}
/**
* 把时间戳转为站点的 LocalDateTime
*
* @param timeMillis 时间戳
* @return LocalDateTime
*/
public static LocalDateTime getSiteLocalDateTime(Long timeMillis) {
return LocalDateTime.ofInstant(new Date(timeMillis).toInstant(), ZoneId.systemDefault());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment