init
This commit is contained in:
當前提交
34e481f0a5
35
.gitignore
vendored
Normal file
35
.gitignore
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
src/main/resources/application.yml
|
||||||
|
|
||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
135
pom.xml
Normal file
135
pom.xml
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.5.2</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.weilab</groupId>
|
||||||
|
<artifactId>biology</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>biology</name>
|
||||||
|
<description>Demo project for Spring Boot</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-mail</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>1.2.76</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
<version>3.4.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.python</groupId>
|
||||||
|
<artifactId>jython-standalone</artifactId>
|
||||||
|
<version>2.7.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.validation</groupId>
|
||||||
|
<artifactId>validation-api</artifactId>
|
||||||
|
<version>2.0.1.Final</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
<version>5.7.19</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>biology</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>public</id>
|
||||||
|
<name>aliyun nexus</name>
|
||||||
|
<url>https://maven.aliyun.com/nexus/content/groups/public/</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</releases>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>public</id>
|
||||||
|
<name>aliyun nexus</name>
|
||||||
|
<url>https://maven.aliyun.com/nexus/content/groups/public/</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
|
||||||
|
</project>
|
13
src/main/java/com/weilab/biology/BiologyApplication.java
Normal file
13
src/main/java/com/weilab/biology/BiologyApplication.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.weilab.biology;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class BiologyApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(BiologyApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
src/main/java/com/weilab/biology/config/FilterConfig.java
Normal file
33
src/main/java/com/weilab/biology/config/FilterConfig.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package com.weilab.biology.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||||
|
|
||||||
|
import javax.servlet.DispatcherType;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by skyyemperor on 2020-12-27 10:54
|
||||||
|
* Description :
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class FilterConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TokenFilter tokenFilter;
|
||||||
|
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean tokenFilterRegistration() {
|
||||||
|
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||||
|
registration.setFilter(tokenFilter);
|
||||||
|
registration.addUrlPatterns("/*");
|
||||||
|
registration.setName("tokenFilter");
|
||||||
|
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
|
||||||
|
return registration;
|
||||||
|
}
|
||||||
|
}
|
33
src/main/java/com/weilab/biology/config/TokenFilter.java
Normal file
33
src/main/java/com/weilab/biology/config/TokenFilter.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package com.weilab.biology.config;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class TokenFilter implements Filter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||||
|
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||||
|
response.setHeader("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS");
|
||||||
|
response.setHeader("Access-Control-Allow-Headers", "*");
|
||||||
|
response.setHeader("Access-Control-Expose-Headers", "*");
|
||||||
|
response.setHeader("Access-Control-Max-Age", "36000");
|
||||||
|
|
||||||
|
if ("OPTIONS".equals(request.getMethod())) {
|
||||||
|
response.setStatus(200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
}
|
||||||
|
}
|
124
src/main/java/com/weilab/biology/controller/JobController.java
Normal file
124
src/main/java/com/weilab/biology/controller/JobController.java
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package com.weilab.biology.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||||
|
import com.weilab.biology.core.data.enums.JobStatusEnum;
|
||||||
|
import com.weilab.biology.core.data.vo.result.CommonError;
|
||||||
|
import com.weilab.biology.core.data.vo.result.Result;
|
||||||
|
import com.weilab.biology.core.data.vo.result.error.JobError;
|
||||||
|
import com.weilab.biology.core.validation.EnumValidation;
|
||||||
|
import com.weilab.biology.service.JobService;
|
||||||
|
import com.weilab.biology.util.FileUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("job")
|
||||||
|
public class JobController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JobService jobService;
|
||||||
|
|
||||||
|
@Value("${biology.request-path}")
|
||||||
|
private String requestPath;
|
||||||
|
|
||||||
|
@PostMapping("/submit")
|
||||||
|
public Result submit(@RequestParam(required = false) String dataStr,
|
||||||
|
@RequestParam(required = false) MultipartFile dataFile,
|
||||||
|
@RequestParam String param,
|
||||||
|
@RequestParam String mail,
|
||||||
|
@RequestParam(defaultValue = "0") Integer type,
|
||||||
|
@RequestParam(required = false) MultipartFile file1,
|
||||||
|
@RequestParam(required = false) MultipartFile file2,
|
||||||
|
@RequestParam(required = false) MultipartFile file3,
|
||||||
|
@RequestParam(required = false) MultipartFile file4,
|
||||||
|
@RequestParam(required = false) MultipartFile file5,
|
||||||
|
@RequestParam(required = false) MultipartFile file6,
|
||||||
|
@RequestParam(required = false) MultipartFile file7,
|
||||||
|
@RequestParam(required = false) MultipartFile file8,
|
||||||
|
@RequestParam(required = false) MultipartFile file9,
|
||||||
|
@RequestParam(required = false) MultipartFile file10,
|
||||||
|
@RequestParam(required = false) MultipartFile file11,
|
||||||
|
@RequestParam(required = false) MultipartFile file12,
|
||||||
|
@RequestParam(required = false) MultipartFile file13,
|
||||||
|
@RequestParam(required = false) MultipartFile file14,
|
||||||
|
@RequestParam(required = false) MultipartFile file15,
|
||||||
|
@RequestParam(required = false) MultipartFile file16,
|
||||||
|
@RequestParam(required = false) MultipartFile file17,
|
||||||
|
@RequestParam(required = false) MultipartFile file18,
|
||||||
|
@RequestParam(required = false) MultipartFile file19,
|
||||||
|
@RequestParam(required = false) MultipartFile file20) {
|
||||||
|
if (dataFile == null && StringUtils.isBlank(dataStr))
|
||||||
|
return Result.getResult(JobError.PARAM_CAN_NOT_BE_EMPTY);
|
||||||
|
|
||||||
|
JSONObject obj = null;
|
||||||
|
try {
|
||||||
|
obj = JSON.parseObject(param);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Result.getResult(CommonError.PARAM_WRONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedInputStream dataStream = null;
|
||||||
|
if (dataFile != null) {
|
||||||
|
dataStream = FileUtil.getInputStream(FileUtils.multipartToFile(dataFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<MultipartFile> files = Arrays.asList(file1, file2, file3, file4, file5,
|
||||||
|
file6, file7, file8, file9, file10, file11, file12, file13, file14, file15,
|
||||||
|
file16, file17, file18, file19, file20);
|
||||||
|
for (MultipartFile file : files) {
|
||||||
|
if (file != null) {
|
||||||
|
String filePath = requestPath + FileUtil.FILE_SEPARATOR + "file" + FileUtil.FILE_SEPARATOR + IdUtil.fastUUID() + "." + FileUtil.extName(file.getOriginalFilename());
|
||||||
|
FileUtil.writeFromStream(file.getInputStream(), filePath);
|
||||||
|
obj.put(file.getName(), filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return Result.getResult(JobError.FILE_READ_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jobService.submit(dataStr, dataStream, obj, mail, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/status/update")
|
||||||
|
public Result updateJobStatus(@RequestParam Integer jobId,
|
||||||
|
@EnumValidation(clazz = JobStatusEnum.class, message = "没有此状态")
|
||||||
|
@RequestParam Integer status,
|
||||||
|
@RequestParam(required = false) String result) {
|
||||||
|
if (status.equals(JobStatusEnum.WAIT.getKey()))
|
||||||
|
return Result.getResult(CommonError.PARAM_WRONG);
|
||||||
|
if (status.equals(JobStatusEnum.SUCCESS.getKey())) {
|
||||||
|
if (StringUtils.isBlank(result))
|
||||||
|
return Result.getResult(CommonError.PARAM_WRONG);
|
||||||
|
try {
|
||||||
|
JSON.parseObject(result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Result.getResult(CommonError.PARAM_WRONG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jobService.updateJobStatus(jobId, JobStatusEnum.getEnumByKey(status), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/info/{jobId}")
|
||||||
|
public Result getJobInfo(@PathVariable Integer jobId) {
|
||||||
|
return jobService.getJobInfo(jobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
public Result getJobList(@RequestParam(required = false) Integer type) {
|
||||||
|
return jobService.getJobList(type);
|
||||||
|
}
|
||||||
|
}
|
78
src/main/java/com/weilab/biology/core/data/dto/JobDto.java
Normal file
78
src/main/java/com/weilab/biology/core/data/dto/JobDto.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package com.weilab.biology.core.data.dto;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.weilab.biology.core.data.enums.JobStatusEnum;
|
||||||
|
import com.weilab.biology.core.data.po.Job;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JobDto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jobId
|
||||||
|
*/
|
||||||
|
private Integer jobId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务状态
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求参数
|
||||||
|
*/
|
||||||
|
private JSONObject param;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行结果
|
||||||
|
*/
|
||||||
|
private JSONObject result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime requestTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime completeTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求类型
|
||||||
|
*/
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
public static JobDto parseJob(Job job) {
|
||||||
|
return new JobDto(
|
||||||
|
job.getJobId(),
|
||||||
|
JobStatusEnum.getRemark(job.getStatus()),
|
||||||
|
JSON.parseObject(job.getParam()),
|
||||||
|
job.getResult() == null ? null : JSON.parseObject(job.getResult()),
|
||||||
|
job.getRequestTime(),
|
||||||
|
job.getCreateTime(),
|
||||||
|
job.getCompleteTime(),
|
||||||
|
job.getType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package com.weilab.biology.core.data.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.weilab.biology.core.data.enums.JobStatusEnum;
|
||||||
|
import com.weilab.biology.core.data.po.Job;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by skyyemperor on 2021-09-22
|
||||||
|
* Description :
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JobLessDto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jobId
|
||||||
|
*/
|
||||||
|
private Integer jobId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务状态
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime requestTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime completeTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求类型
|
||||||
|
*/
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
public static JobLessDto parseJob(Job job) {
|
||||||
|
return new JobLessDto(
|
||||||
|
job.getJobId(),
|
||||||
|
JobStatusEnum.getRemark(job.getStatus()),
|
||||||
|
job.getRequestTime(),
|
||||||
|
job.getCreateTime(),
|
||||||
|
job.getCompleteTime(),
|
||||||
|
job.getType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.weilab.biology.core.data.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校区的枚举类
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum JobStatusEnum {
|
||||||
|
WAIT(0, "waiting"),
|
||||||
|
REQED(3, "requested"),
|
||||||
|
RUNNING(1, "running"),
|
||||||
|
SUCCESS(2, "success"),
|
||||||
|
FAIL(-1, "failed"),
|
||||||
|
TIMEOUT(-2, "timeout"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final Integer key;
|
||||||
|
private final String remark;
|
||||||
|
|
||||||
|
private JobStatusEnum(Integer key, String remark) {
|
||||||
|
this.key = key;
|
||||||
|
this.remark = remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getRemark(Integer key) {
|
||||||
|
for (JobStatusEnum enums : JobStatusEnum.values()) {
|
||||||
|
if (enums.key.equals(key))
|
||||||
|
return enums.getRemark();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JobStatusEnum getEnumByKey(Integer key) {
|
||||||
|
for (JobStatusEnum enums : JobStatusEnum.values()) {
|
||||||
|
if (enums.key.equals(key))
|
||||||
|
return enums;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
97
src/main/java/com/weilab/biology/core/data/po/Job.java
Normal file
97
src/main/java/com/weilab/biology/core/data/po/Job.java
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package com.weilab.biology.core.data.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import jnr.ffi.annotations.In;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by skyyemperor on 2021-09-19
|
||||||
|
* Description :
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@TableName(value = "job")
|
||||||
|
public class Job implements Serializable {
|
||||||
|
/**
|
||||||
|
* jobId
|
||||||
|
*/
|
||||||
|
@TableId(value = "job_id", type = IdType.AUTO)
|
||||||
|
private Integer jobId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基因序列数据
|
||||||
|
*/
|
||||||
|
@TableField(value = "`data`")
|
||||||
|
private String data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求参数
|
||||||
|
*/
|
||||||
|
@TableField(value = "param")
|
||||||
|
private String param;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系邮箱
|
||||||
|
*/
|
||||||
|
@TableField(value = "mail")
|
||||||
|
private String mail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行结果
|
||||||
|
*/
|
||||||
|
@TableField(value = "result")
|
||||||
|
private String result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务状态。0为待运行,1为正在运行,2为运行成功,-1为运行失败
|
||||||
|
*/
|
||||||
|
@TableField(value = "`status`")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "request_time")
|
||||||
|
private LocalDateTime requestTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "create_time")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "complete_time")
|
||||||
|
private LocalDateTime completeTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求类型
|
||||||
|
*/
|
||||||
|
@TableField(value = "type")
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
public Job(String data, String param, String mail, Integer status, LocalDateTime requestTime, Integer type) {
|
||||||
|
this.data = data;
|
||||||
|
this.param = param;
|
||||||
|
this.mail = mail;
|
||||||
|
this.status = status;
|
||||||
|
this.requestTime = requestTime;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package com.weilab.biology.core.data.vo.result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by skyyemperor on 2021-01-30
|
||||||
|
* Description : 通用异常返回
|
||||||
|
*/
|
||||||
|
public enum CommonError implements ResultError {
|
||||||
|
PARAM_WRONG(40000, "参数范围或格式错误"),
|
||||||
|
NETWORK_WRONG(40001, "网络错误"),
|
||||||
|
REQUEST_NOT_ALLOW(40002, "当前条件或时间不允许〒▽〒"),
|
||||||
|
REQUEST_FREQUENTLY(40003, "请求繁忙,请稍后再试"),
|
||||||
|
CONTENT_NOT_FOUND(40004, "你要找的东西好像走丢啦X﹏X"),
|
||||||
|
METHOD_NOT_ALLOW(40005, "方法不允许"),
|
||||||
|
THIS_IS_LAST_PAGE(40006, "这是最后一页,再怎么找也没有啦"),
|
||||||
|
THIS_IS_FIRST_PAGE(40007, "没有上一页啦"),
|
||||||
|
PIC_FORMAT_ERROR(40008, "图片格式只能为jpg, jpeg, png, gif, bmp, webp"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private CommonError(int code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
package com.weilab.biology.core.data.vo.result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* web层统一返回类型
|
||||||
|
*/
|
||||||
|
public class Result {
|
||||||
|
private int code = 0;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private Object data;
|
||||||
|
|
||||||
|
public Result() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result(int code, String message, Object data) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result(ResultError resultError) {
|
||||||
|
this.code = resultError.getCode();
|
||||||
|
this.message = resultError.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result getResult(int code, String message) {
|
||||||
|
return getResult(code, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result getResult(int code, String message, Object data) {
|
||||||
|
return new Result(code, message, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result success() {
|
||||||
|
return success(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result success(Object data) {
|
||||||
|
return success("success", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result success(String message, Object data) {
|
||||||
|
return new Result(0, message, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result fail() {
|
||||||
|
return fail(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result fail(Object data) {
|
||||||
|
return fail("请求失败", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result fail(String message, Object data) {
|
||||||
|
return new Result(-1, message, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result getResult(ResultError resultError) {
|
||||||
|
return getResult(resultError.getCode(), resultError.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(Object data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Info{" +
|
||||||
|
"code=" + code +
|
||||||
|
", message='" + message + '\'' +
|
||||||
|
", data=" + data +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.weilab.biology.core.data.vo.result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by skyyemperor on 2021-01-30
|
||||||
|
* Description : 通用异常返回的父接口
|
||||||
|
*/
|
||||||
|
public interface ResultError {
|
||||||
|
|
||||||
|
int getCode();
|
||||||
|
|
||||||
|
String getMessage();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.weilab.biology.core.data.vo.result.error;
|
||||||
|
|
||||||
|
import com.weilab.biology.core.data.vo.result.ResultError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by skyyemperor on 2021-09-19
|
||||||
|
* Description :
|
||||||
|
*/
|
||||||
|
public enum JobError implements ResultError {
|
||||||
|
PARAM_CAN_NOT_BE_EMPTY(40100, "文本框和文件不能同时为空"),
|
||||||
|
FILE_READ_FAIL(40101, "文件读取出错"),
|
||||||
|
STATUS_UPDATE_FAIL(40102,"当前状态下不允许更新为指定状态"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
|
||||||
|
private JobError(int code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.weilab.biology.core.exception;
|
||||||
|
|
||||||
|
import com.weilab.biology.core.data.vo.result.ResultError;
|
||||||
|
|
||||||
|
public class BaseException extends RuntimeException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private Object data;
|
||||||
|
|
||||||
|
public BaseException(int code, String message, Object data) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseException(int code, String message) {
|
||||||
|
this(code, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseException(ResultError error) {
|
||||||
|
this(error.getCode(), error.getMessage(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(Object data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,119 @@
|
|||||||
|
package com.weilab.biology.core.exception;
|
||||||
|
|
||||||
|
import com.weilab.biology.core.data.vo.result.CommonError;
|
||||||
|
import com.weilab.biology.core.data.vo.result.Result;
|
||||||
|
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import org.springframework.validation.FieldError;
|
||||||
|
import org.springframework.validation.ObjectError;
|
||||||
|
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||||
|
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.method.annotation.MethodArgumentTypeMismatchException;
|
||||||
|
import org.springframework.web.multipart.support.MissingServletRequestPartException;
|
||||||
|
|
||||||
|
import javax.validation.ConstraintViolationException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义异常捕获
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(BaseException.class)
|
||||||
|
public Result handleBaseException(BaseException e) {
|
||||||
|
return Result.getResult(e.getCode(), e.getMessage(), e.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器错误。常见有数据库错误
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public Result handleException(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return Result.fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON解析异常,最常见NullPointerException,这里均将其过滤
|
||||||
|
*/
|
||||||
|
@ExceptionHandler({NullPointerException.class})
|
||||||
|
public Result handleJSONException(Exception e){
|
||||||
|
return Result.getResult(CommonError.REQUEST_NOT_ALLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数校验错误异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
|
public Result validationBodyException(MethodArgumentNotValidException e) {
|
||||||
|
BindingResult result = e.getBindingResult();
|
||||||
|
String message = CommonError.PARAM_WRONG.getMessage();
|
||||||
|
if (result.hasErrors()) {
|
||||||
|
List<ObjectError> errors = result.getAllErrors();
|
||||||
|
if (errors.size() > 0) {
|
||||||
|
FieldError fieldError = (FieldError) errors.get(0);
|
||||||
|
message = fieldError.getDefaultMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Result.getResult(CommonError.PARAM_WRONG.getCode(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数类型转换错误
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
||||||
|
public Result methodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
|
||||||
|
return Result.getResult(CommonError.PARAM_WRONG.getCode(),
|
||||||
|
e.getName() + "参数类型转换错误");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数转换JSON出错
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||||
|
public Result httpMessageNotReadableException(HttpMessageNotReadableException e) {
|
||||||
|
return Result.getResult(CommonError.PARAM_WRONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求方法不允许
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
||||||
|
public Result methodNotSupportedException(HttpRequestMethodNotSupportedException e) {
|
||||||
|
return Result.getResult(CommonError.METHOD_NOT_ALLOW.getCode(),
|
||||||
|
e.getMethod() + "方法不允许");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缺少请求参数
|
||||||
|
*/
|
||||||
|
@ExceptionHandler({MissingServletRequestParameterException.class, MissingServletRequestPartException.class})
|
||||||
|
public Result missingParameterException(Exception e) {
|
||||||
|
String message = CommonError.PARAM_WRONG.getMessage();
|
||||||
|
if (e instanceof MissingServletRequestParameterException) {
|
||||||
|
message = ((MissingServletRequestParameterException) e).getParameterName() + "不能为空";
|
||||||
|
} else if (e instanceof MissingServletRequestPartException) {
|
||||||
|
message = ((MissingServletRequestPartException) e).getRequestPartName() + "不能为空";
|
||||||
|
}
|
||||||
|
return Result.getResult(CommonError.PARAM_WRONG.getCode(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求参数格式错误
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(ConstraintViolationException.class)
|
||||||
|
public Result ConstraintViolationException(ConstraintViolationException e) {
|
||||||
|
if (e.getConstraintViolations().size() > 0) {
|
||||||
|
return Result.getResult(CommonError.PARAM_WRONG.getCode(),
|
||||||
|
e.getConstraintViolations().iterator().next().getMessageTemplate());
|
||||||
|
}
|
||||||
|
return Result.getResult(CommonError.PARAM_WRONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.weilab.biology.core.exception;
|
||||||
|
|
||||||
|
import com.weilab.biology.core.data.vo.result.CommonError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by skyyemperor on 2021-04-30
|
||||||
|
* Description : 网络异常
|
||||||
|
*/
|
||||||
|
public class NetworkException extends BaseException {
|
||||||
|
public NetworkException() {
|
||||||
|
super(CommonError.NETWORK_WRONG);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package com.weilab.biology.core.validation;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.validation.Constraint;
|
||||||
|
import javax.validation.Payload;
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Repeatable;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.*;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Repeatable(EnumValidation.List.class)
|
||||||
|
@Constraint(validatedBy = {EnumValidator.class})
|
||||||
|
public @interface EnumValidation {
|
||||||
|
String message() default "{*.validation.constraint.Enum.message}";
|
||||||
|
|
||||||
|
Class<?>[] groups() default {};
|
||||||
|
|
||||||
|
Class<? extends Payload>[] payload() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the enum's class-type
|
||||||
|
*
|
||||||
|
* @return Class
|
||||||
|
*/
|
||||||
|
Class<?> clazz();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the method's name ,which used to validate the enum's value
|
||||||
|
*
|
||||||
|
* @return method's name
|
||||||
|
*/
|
||||||
|
String method() default "getKey";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许为空
|
||||||
|
*
|
||||||
|
* @return true or false
|
||||||
|
*/
|
||||||
|
boolean allowNull() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines several {@link EnumValidation} annotations on the same element.
|
||||||
|
*
|
||||||
|
* @see EnumValidation
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@interface List {
|
||||||
|
EnumValidation[] value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.weilab.biology.core.validation;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.validation.ConstraintValidator;
|
||||||
|
import javax.validation.ConstraintValidatorContext;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller入参对象中属性枚举项校验
|
||||||
|
*/
|
||||||
|
public class EnumValidator implements ConstraintValidator<EnumValidation, Object> {
|
||||||
|
|
||||||
|
private EnumValidation annotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the validator in preparation for
|
||||||
|
* {@link #isValid(Object, ConstraintValidatorContext)} calls.
|
||||||
|
* The constraint annotation for a given constraint declaration
|
||||||
|
* is passed.
|
||||||
|
* <p>
|
||||||
|
* This method is guaranteed to be called before any use of this instance for
|
||||||
|
* validation.
|
||||||
|
* <p>
|
||||||
|
* The default implementation is a no-op.
|
||||||
|
*
|
||||||
|
* @param constraintAnnotation annotation instance for a given constraint declaration
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initialize(EnumValidation constraintAnnotation) {
|
||||||
|
this.annotation = constraintAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the validation logic.
|
||||||
|
* The state of {@code value} must not be altered.
|
||||||
|
* <p>
|
||||||
|
* This method can be accessed concurrently, thread-safety must be ensured
|
||||||
|
* by the implementation.
|
||||||
|
*
|
||||||
|
* @param value object to validate
|
||||||
|
* @param context context in which the constraint is evaluated
|
||||||
|
* @return {@code false} if {@code value} does not pass the constraint
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValid(Object value, ConstraintValidatorContext context) {
|
||||||
|
if (value == null) {
|
||||||
|
return annotation.allowNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object[] objects = annotation.clazz().getEnumConstants();
|
||||||
|
try {
|
||||||
|
Method method = annotation.clazz().getMethod(annotation.method());
|
||||||
|
for (Object o : objects) {
|
||||||
|
if (value.equals(method.invoke(o))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
26
src/main/java/com/weilab/biology/mapper/JobMapper.java
Normal file
26
src/main/java/com/weilab/biology/mapper/JobMapper.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.weilab.biology.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.weilab.biology.core.data.dto.JobLessDto;
|
||||||
|
import com.weilab.biology.core.data.po.Job;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.python.modules.itertools.count;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by skyyemperor on 2021-09-19
|
||||||
|
* Description :
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface JobMapper extends BaseMapper<Job> {
|
||||||
|
|
||||||
|
List<Job> selectRunningJobs();
|
||||||
|
|
||||||
|
Job selectNextWaitingJob();
|
||||||
|
|
||||||
|
List<Job> selectJobList(@Param("type") Integer type,
|
||||||
|
@Param("count") Integer count);
|
||||||
|
|
||||||
|
}
|
242
src/main/java/com/weilab/biology/service/JobService.java
Normal file
242
src/main/java/com/weilab/biology/service/JobService.java
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
package com.weilab.biology.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.weilab.biology.core.data.dto.JobDto;
|
||||||
|
import com.weilab.biology.core.data.dto.JobLessDto;
|
||||||
|
import com.weilab.biology.core.data.enums.JobStatusEnum;
|
||||||
|
import com.weilab.biology.core.data.po.Job;
|
||||||
|
import com.weilab.biology.core.data.vo.result.CommonError;
|
||||||
|
import com.weilab.biology.core.data.vo.result.Result;
|
||||||
|
import com.weilab.biology.core.data.vo.result.error.JobError;
|
||||||
|
import com.weilab.biology.mapper.JobMapper;
|
||||||
|
import com.weilab.biology.util.FileUtils;
|
||||||
|
import com.weilab.biology.util.MailUtil;
|
||||||
|
import com.weilab.biology.util.TaskExecutorUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by skyyemperor on 2021-09-19
|
||||||
|
* Description :
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class JobService {
|
||||||
|
|
||||||
|
@Value("${biology.python-cmd}")
|
||||||
|
private String pythonCmd;
|
||||||
|
|
||||||
|
@Value("${biology.request-path}")
|
||||||
|
private String requestPath;
|
||||||
|
|
||||||
|
@Value("${biology.result-path}")
|
||||||
|
private String resultDataPath;
|
||||||
|
|
||||||
|
@Value("${biology.log-path}")
|
||||||
|
private String logPath;
|
||||||
|
|
||||||
|
@Value("${biology.concurrent-num}")
|
||||||
|
private Integer concurrentNum;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JobMapper jobMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MailUtil mailUtil;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TaskExecutorUtil<?> taskExecutorUtil;
|
||||||
|
|
||||||
|
private static final String SUBJECT = "【DeepBIO Result Notice】";
|
||||||
|
private static final String SUCCESS_EMAIL_CONTENT = "Your request has been completed, click http://server.wei-group.net/front/biology/#/resultMail?jobId=%s to check the detail information";
|
||||||
|
private static final String FAIL_EMAIL_CONTENT = "We are very sorry, but some errors occurred in the task you submitted, click http://server.wei-group.net/front/biology/#/resultMail?jobId=%s to check the detail information";
|
||||||
|
private static final String TIMEOUT_EMAIL_CONTENT = "We are very sorry, but the task you submitted was overtime, click http://server.wei-group.net/front/biology/#/resultMail?jobId=%s to check the detail information";
|
||||||
|
private static final String RECEIVED_EMAIL_CONTENT = "Your request has been received, click http://server.wei-group.net/front/biology/#/resultMail?jobId=%s to check the detail information";
|
||||||
|
private static final String START_RUNNING_EMAIL_CONTENT = "Your task has started running, click http://server.wei-group.net/front/biology/#/resultMail?jobId=%s to check the detail information";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交job
|
||||||
|
*
|
||||||
|
* @param dataStr 文本内容
|
||||||
|
* @param param 其他参数(json格式)
|
||||||
|
* @param mail 邮箱
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Transactional
|
||||||
|
public Result submit(String dataStr, BufferedInputStream dataStream, JSONObject param, String mail, Integer type) {
|
||||||
|
Job job = new Job("", JSON.toJSONString(param), mail, JobStatusEnum.WAIT.getKey(), LocalDateTime.now(), type);
|
||||||
|
jobMapper.insert(job);
|
||||||
|
sendEmail(job.getJobId(), JobStatusEnum.WAIT, mail);
|
||||||
|
|
||||||
|
try {
|
||||||
|
//将请求数据写入本地文件,之后向python传递文件路径参数
|
||||||
|
String dataPath = String.format(requestPath + File.separator + "job-%d-dataStr.txt", job.getJobId());
|
||||||
|
if (dataStream != null) {
|
||||||
|
FileUtil.writeFromStream(dataStream, dataPath);
|
||||||
|
} else {
|
||||||
|
FileUtils.writeStringToFile(dataPath, dataStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//将jobId和dataPath参数添加至param中
|
||||||
|
param.put("jobId", job.getJobId());
|
||||||
|
param.put("requestDataPath", dataPath);
|
||||||
|
param.put("resultDataPath", resultDataPath);
|
||||||
|
|
||||||
|
//更新数据库param字段
|
||||||
|
job.setParam(JSON.toJSONString(param));
|
||||||
|
jobMapper.updateById(job);
|
||||||
|
|
||||||
|
runNextJob();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
updateJobStatus(job.getJobId(), JobStatusEnum.FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getJobInfo(job.getJobId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result getJobInfo(Integer jobId) {
|
||||||
|
Job job = jobMapper.selectById(jobId);
|
||||||
|
if (job == null)
|
||||||
|
return Result.getResult(CommonError.CONTENT_NOT_FOUND);
|
||||||
|
return Result.success(JobDto.parseJob(job));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result updateJobStatus(Integer jobId, JobStatusEnum status) {
|
||||||
|
return updateJobStatus(jobId, status, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result updateJobStatus(Integer jobId, JobStatusEnum status, String result) {
|
||||||
|
System.out.println(status.getRemark());
|
||||||
|
Job job = jobMapper.selectById(jobId);
|
||||||
|
if (job == null)
|
||||||
|
return Result.getResult(CommonError.CONTENT_NOT_FOUND);
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case WAIT:
|
||||||
|
break;
|
||||||
|
case SUCCESS:
|
||||||
|
job.setCompleteTime(LocalDateTime.now());
|
||||||
|
job.setResult(result);
|
||||||
|
break;
|
||||||
|
case FAIL:
|
||||||
|
case TIMEOUT:
|
||||||
|
if (!job.getStatus().equals(JobStatusEnum.RUNNING.getKey())
|
||||||
|
&& !job.getStatus().equals(JobStatusEnum.REQED.getKey()))
|
||||||
|
return Result.getResult(JobError.STATUS_UPDATE_FAIL);
|
||||||
|
job.setCompleteTime(LocalDateTime.now());
|
||||||
|
break;
|
||||||
|
case RUNNING:
|
||||||
|
if (!job.getStatus().equals(JobStatusEnum.REQED.getKey()))
|
||||||
|
return Result.getResult(JobError.STATUS_UPDATE_FAIL);
|
||||||
|
job.setCreateTime(LocalDateTime.now());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
job.setStatus(status.getKey());
|
||||||
|
jobMapper.updateById(job);
|
||||||
|
|
||||||
|
sendEmail(jobId, status, job.getMail());
|
||||||
|
runNextJob();
|
||||||
|
|
||||||
|
return getJobInfo(jobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result getJobList(Integer type) {
|
||||||
|
List<Job> jobs = jobMapper.selectJobList(type, 200);
|
||||||
|
return Result.success(jobs.stream().map(JobLessDto::parseJob).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行下一个job
|
||||||
|
*/
|
||||||
|
private synchronized void runNextJob() {
|
||||||
|
Job nextJob = null;
|
||||||
|
try {
|
||||||
|
//并发数小于concurrentNum,运行该job
|
||||||
|
if (jobMapper.selectRunningJobs().size() < concurrentNum) {
|
||||||
|
if ((nextJob = jobMapper.selectNextWaitingJob()) != null) {
|
||||||
|
//更新job状态
|
||||||
|
nextJob.setStatus(JobStatusEnum.REQED.getKey());
|
||||||
|
jobMapper.updateById(nextJob);
|
||||||
|
|
||||||
|
waitRunning(nextJob.getJobId());
|
||||||
|
|
||||||
|
String logFilePath = String.format(logPath + File.separator + "task-log-%s.txt", nextJob.getJobId());
|
||||||
|
String cmd = String.format("%s -setting '%s' >> %s 2>&1", pythonCmd, nextJob.getParam(), logFilePath);
|
||||||
|
|
||||||
|
log.info("执行命令: " + cmd);
|
||||||
|
|
||||||
|
String[] cmds = new String[]{"/bin/sh", "-c", cmd};
|
||||||
|
|
||||||
|
Runtime.getRuntime().exec(cmds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (nextJob != null) {
|
||||||
|
nextJob.setStatus(JobStatusEnum.FAIL.getKey());
|
||||||
|
jobMapper.updateById(nextJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等待运行,超时时间60秒
|
||||||
|
*/
|
||||||
|
private void waitRunning(Integer jobId) {
|
||||||
|
//等待60秒,检查是否已运行
|
||||||
|
taskExecutorUtil.schedule(() -> {
|
||||||
|
Job job = jobMapper.selectById(jobId);
|
||||||
|
if (job.getStatus().equals(JobStatusEnum.REQED.getKey())) {
|
||||||
|
updateJobStatus(jobId, JobStatusEnum.FAIL);
|
||||||
|
}
|
||||||
|
}, 60, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
//等待4小时,查看是否执行完成
|
||||||
|
taskExecutorUtil.schedule(() -> {
|
||||||
|
Job job = jobMapper.selectById(jobId);
|
||||||
|
if (job.getStatus().equals(JobStatusEnum.RUNNING.getKey())) {
|
||||||
|
updateJobStatus(jobId, JobStatusEnum.TIMEOUT);
|
||||||
|
}
|
||||||
|
}, 4, TimeUnit.HOURS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendEmail(Integer jobId, JobStatusEnum status, String mail) {
|
||||||
|
String content = null;
|
||||||
|
switch (status) {
|
||||||
|
case WAIT:
|
||||||
|
content = String.format(RECEIVED_EMAIL_CONTENT, jobId);
|
||||||
|
break;
|
||||||
|
case SUCCESS:
|
||||||
|
content = String.format(SUCCESS_EMAIL_CONTENT, jobId);
|
||||||
|
break;
|
||||||
|
case FAIL:
|
||||||
|
content = String.format(FAIL_EMAIL_CONTENT, jobId);
|
||||||
|
break;
|
||||||
|
case TIMEOUT:
|
||||||
|
content = String.format(TIMEOUT_EMAIL_CONTENT, jobId);
|
||||||
|
break;
|
||||||
|
case RUNNING:
|
||||||
|
content = String.format(START_RUNNING_EMAIL_CONTENT, jobId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (content != null)
|
||||||
|
mailUtil.send(mail, SUBJECT, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
118
src/main/java/com/weilab/biology/util/FileUtils.java
Normal file
118
src/main/java/com/weilab/biology/util/FileUtils.java
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package com.weilab.biology.util;
|
||||||
|
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件读取工具类
|
||||||
|
*/
|
||||||
|
public class FileUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MultipartFile 转换成File
|
||||||
|
*
|
||||||
|
* @param multfile 原文件类型
|
||||||
|
* @return File
|
||||||
|
*/
|
||||||
|
public static File multipartToFile(MultipartFile multfile) {
|
||||||
|
File file = null;
|
||||||
|
try {
|
||||||
|
file = File.createTempFile("prefix", "_" + multfile.getOriginalFilename());
|
||||||
|
multfile.transferTo(file);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取文件内容,作为字符串返回
|
||||||
|
*/
|
||||||
|
public static String readFileAsString(String filePath) throws IOException {
|
||||||
|
File file = new File(filePath);
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new FileNotFoundException(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return readFileAsString(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取文件内容,作为字符串返回
|
||||||
|
*/
|
||||||
|
public static String readFileAsString(File file) throws IOException {
|
||||||
|
StringBuilder sb = new StringBuilder((int) (file.length()));
|
||||||
|
// 创建字节输入流
|
||||||
|
FileInputStream fis = new FileInputStream(file);
|
||||||
|
// 创建一个长度为10240的Buffer
|
||||||
|
byte[] bbuf = new byte[10240];
|
||||||
|
// 用于保存实际读取的字节数
|
||||||
|
int hasRead = 0;
|
||||||
|
while ((hasRead = fis.read(bbuf)) > 0) {
|
||||||
|
sb.append(new String(bbuf, 0, hasRead));
|
||||||
|
}
|
||||||
|
fis.close();
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文件路径读取byte[] 数组
|
||||||
|
*/
|
||||||
|
public static byte[] readFileAsBytes(String filePath) throws IOException {
|
||||||
|
File file = new File(filePath);
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new FileNotFoundException(filePath);
|
||||||
|
} else {
|
||||||
|
return readFileAsBytes(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文件读取byte[]数组
|
||||||
|
*/
|
||||||
|
public static byte[] readFileAsBytes(File file) throws IOException {
|
||||||
|
if (file == null) {
|
||||||
|
throw new FileNotFoundException();
|
||||||
|
} else {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
|
||||||
|
BufferedInputStream in = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
in = new BufferedInputStream(new FileInputStream(file));
|
||||||
|
short bufSize = 1024;
|
||||||
|
byte[] buffer = new byte[bufSize];
|
||||||
|
int len1;
|
||||||
|
while (-1 != (len1 = in.read(buffer, 0, bufSize))) {
|
||||||
|
bos.write(buffer, 0, len1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bos.toByteArray();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (in != null) {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
} catch (IOException var14) {
|
||||||
|
var14.printStackTrace();
|
||||||
|
}
|
||||||
|
bos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void writeStringToFile(String filePath, String content) throws IOException {
|
||||||
|
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath));
|
||||||
|
bufferedOutputStream.write(content.getBytes());
|
||||||
|
bufferedOutputStream.flush();
|
||||||
|
bufferedOutputStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeByteToFile(String filePath, byte[] content) throws IOException {
|
||||||
|
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath));
|
||||||
|
bufferedOutputStream.write(content);
|
||||||
|
bufferedOutputStream.flush();
|
||||||
|
bufferedOutputStream.close();
|
||||||
|
}
|
||||||
|
}
|
39
src/main/java/com/weilab/biology/util/MailUtil.java
Normal file
39
src/main/java/com/weilab/biology/util/MailUtil.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package com.weilab.biology.util;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.mail.SimpleMailMessage;
|
||||||
|
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class MailUtil {
|
||||||
|
@Autowired
|
||||||
|
private JavaMailSenderImpl mailSender;
|
||||||
|
|
||||||
|
@Value("${spring.mail.username}")
|
||||||
|
private String sender;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TaskExecutorUtil<?> taskExecutorUtil;
|
||||||
|
|
||||||
|
public void send(String receiver, String subject, String content) {
|
||||||
|
taskExecutorUtil.run(() -> {
|
||||||
|
SimpleMailMessage message = new SimpleMailMessage();
|
||||||
|
message.setSubject(subject);//设置标题
|
||||||
|
message.setText(content);//设置内容
|
||||||
|
|
||||||
|
message.setTo(receiver);
|
||||||
|
message.setFrom(sender);
|
||||||
|
|
||||||
|
mailSender.send(message);
|
||||||
|
|
||||||
|
log.info("Mail已发送: " + message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
43
src/main/java/com/weilab/biology/util/TaskExecutorUtil.java
Normal file
43
src/main/java/com/weilab/biology/util/TaskExecutorUtil.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package com.weilab.biology.util;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class TaskExecutorUtil<C> {
|
||||||
|
|
||||||
|
public TaskExecutorUtil() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ThreadFactory factory = new ThreadFactory() {
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
return new Thread(r);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final ThreadPoolExecutor cachePool = new ThreadPoolExecutor(
|
||||||
|
2, 40,
|
||||||
|
60L, TimeUnit.SECONDS,
|
||||||
|
new SynchronousQueue<Runnable>(),
|
||||||
|
factory
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final ScheduledExecutorService scheduledThreadPool =
|
||||||
|
Executors.newScheduledThreadPool(5);
|
||||||
|
|
||||||
|
public void run(Runnable r) {
|
||||||
|
cachePool.execute(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<C> submit(Callable<C> c) {
|
||||||
|
return cachePool.submit(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void schedule(Runnable runnable, long delay, TimeUnit timeUnit) {
|
||||||
|
scheduledThreadPool.schedule(runnable, delay, timeUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
src/main/resources/mapper/JobMapper.xml
Normal file
59
src/main/resources/mapper/JobMapper.xml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.weilab.biology.mapper.JobMapper">
|
||||||
|
<resultMap id="BaseResultMap" type="com.weilab.biology.core.data.po.Job">
|
||||||
|
<id column="job_id" jdbcType="INTEGER" property="jobId"/>
|
||||||
|
<result column="data" jdbcType="LONGVARCHAR" property="data"/>
|
||||||
|
<result column="param" jdbcType="VARCHAR" property="param"/>
|
||||||
|
<result column="mail" jdbcType="VARCHAR" property="mail"/>
|
||||||
|
<result column="result" jdbcType="LONGVARCHAR" property="result"/>
|
||||||
|
<result column="status" jdbcType="TINYINT" property="status"/>
|
||||||
|
<result column="request_time" jdbcType="TIMESTAMP" property="requestTime"/>
|
||||||
|
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||||
|
<result column="complete_time" jdbcType="TIMESTAMP" property="completeTime"/>
|
||||||
|
<result column="type" jdbcType="INTEGER" property="type"/>
|
||||||
|
</resultMap>
|
||||||
|
<sql id="JobSql">
|
||||||
|
SELECT job_id,
|
||||||
|
`data`,
|
||||||
|
param,
|
||||||
|
mail,
|
||||||
|
result,
|
||||||
|
`status`,
|
||||||
|
request_time,
|
||||||
|
create_time,
|
||||||
|
complete_time,
|
||||||
|
type
|
||||||
|
FROM job
|
||||||
|
</sql>
|
||||||
|
<sql id="JobLessSql">
|
||||||
|
SELECT job_id,
|
||||||
|
`status`,
|
||||||
|
request_time,
|
||||||
|
create_time,
|
||||||
|
complete_time,
|
||||||
|
type
|
||||||
|
FROM job
|
||||||
|
</sql>
|
||||||
|
<select id="selectRunningJobs" resultMap="BaseResultMap">
|
||||||
|
<include refid="JobSql"/>
|
||||||
|
WHERE status = '${@com.weilab.biology.core.data.enums.JobStatusEnum@RUNNING.getKey()}'
|
||||||
|
OR status = '${@com.weilab.biology.core.data.enums.JobStatusEnum@REQED.getKey()}'
|
||||||
|
</select>
|
||||||
|
<select id="selectNextWaitingJob" resultMap="BaseResultMap">
|
||||||
|
<include refid="JobSql"/>
|
||||||
|
WHERE status = '${@com.weilab.biology.core.data.enums.JobStatusEnum@WAIT.getKey()}'
|
||||||
|
ORDER BY request_time
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
<select id="selectJobList" resultMap="BaseResultMap">
|
||||||
|
<include refid="JobLessSql"/>
|
||||||
|
<where>
|
||||||
|
<if test="type != null">
|
||||||
|
AND type = #{type}
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
ORDER BY job_id DESC
|
||||||
|
LIMIT #{count}
|
||||||
|
</select>
|
||||||
|
</mapper>
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.weilab.biology;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class BiologyApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
載入中…
x
新增問題並參考
Block a user