feat(任务资源库): 任务与用户行为数据

This commit is contained in:
liuhuazhong 2025-03-21 09:00:15 +08:00
parent 17c3882691
commit f798cae717
24 changed files with 1251 additions and 0 deletions

View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.microservices</groupId>
<artifactId>microservices-modules</artifactId>
<version>3.6.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microservices-modules-dms</artifactId>
<description>
microservices-modules-dms数据管理体系模块
</description>
<dependencies>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Swagger UI -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Microservices Common Async -->
<dependency>
<groupId>com.microservices</groupId>
<artifactId>microservices-common-async</artifactId>
</dependency>
<!-- Microservices Common DataSource -->
<dependency>
<groupId>com.microservices</groupId>
<artifactId>microservices-common-datasource</artifactId>
</dependency>
<!-- Microservices Common DataScope -->
<dependency>
<groupId>com.microservices</groupId>
<artifactId>microservices-common-datascope</artifactId>
</dependency>
<!-- Microservices Common Log -->
<dependency>
<groupId>com.microservices</groupId>
<artifactId>microservices-common-log</artifactId>
</dependency>
<!-- Microservices Common Swagger -->
<dependency>
<groupId>com.microservices</groupId>
<artifactId>microservices-common-swagger</artifactId>
</dependency>
<dependency>
<groupId>com.microservices</groupId>
<artifactId>microservices-common-security</artifactId>
</dependency>
<dependency>
<groupId>com.microservices</groupId>
<artifactId>microservices-common-swagger</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency>
<groupId>com.microservices</groupId>
<artifactId>microservices-common-log</artifactId>
</dependency>
<dependency>
<groupId>com.microservices</groupId>
<artifactId>microservices-common-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 处理访问Gitlink相关接口 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<dependency>
<groupId>com.microservices</groupId>
<artifactId>microservices-common-httpClient</artifactId>
<version>3.6.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,25 @@
package com.microservices.dms;
import com.microservices.common.security.annotation.EnableCustomConfig;
import com.microservices.common.security.annotation.EnableRyFeignClients;
import com.microservices.common.swagger.annotation.EnableCustomSwagger2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 项目管理模块
*
* @author otto
*/
@EnableCustomConfig
@EnableCustomSwagger2
@EnableRyFeignClients
@SpringBootApplication
@EnableScheduling
public class MicroservicesDmsApplication {
public static void main(String[] args) {
SpringApplication.run(MicroservicesDmsApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 数据管理体系模块启动成功 ლ(´ڡ`ლ)゙ \n");
}
}

View File

@ -0,0 +1,30 @@
package com.microservices.dms.common.controller;
import com.microservices.common.core.web.controller.BaseController;
import com.microservices.common.core.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author otto
*/
@RestController
@Api(tags = "数据管理体系-公开接口")
@RequestMapping("/open")
@RefreshScope
public class OpenController extends BaseController {
@GetMapping("/loginUrl")
@ApiOperation(value = "获取登录地址")
public AjaxResult loginUrl() {
return success( );
}
}

View File

@ -0,0 +1,11 @@
package com.microservices.dms.constant;
public class TaskConstant {
public static final String TASK_TYPE_WATCHERS = "MakerTask";
public static final String TASK_TYPE_JOURNALS = "makerSpaceTask";
public static final String TASK_TYPE_PAPERS = "";
public static final String TASK_TYPE_OTHER = "makerSpaceTask";
private TaskConstant() {
}
}

View File

@ -0,0 +1,41 @@
package com.microservices.dms.task.controller;
import com.microservices.common.core.web.domain.AjaxResult;
import com.microservices.dms.task.domain.Clicker;
import com.microservices.dms.task.domain.Downloader;
import com.microservices.dms.task.domain.Searcher;
import com.microservices.dms.task.service.TaskResourceLibraryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api(tags = "数据管理体系-用户行为信息接口")
@RestController
@RequestMapping("/collectUserActData")
@RequiredArgsConstructor
public class CollectUserActDataController {
private final TaskResourceLibraryService taskResourceLibraryService;
@PostMapping("/addClicker")
@ApiOperation(value = "记录点击次数")
public AjaxResult addTaskClick(Clicker clicker) {
return AjaxResult.success(taskResourceLibraryService.addClick(clicker));
}
@PostMapping("/addDownloader")
@ApiOperation(value = "记录下载次数")
public AjaxResult addDownloader(Downloader downloader) {
return AjaxResult.success(taskResourceLibraryService.addDownloader(downloader));
}
@PostMapping("/addSearcher")
@ApiOperation(value = "记录搜索次数")
public AjaxResult addSearcher(Searcher searcher) {
return AjaxResult.success(taskResourceLibraryService.addSearcher(searcher));
}
}

View File

@ -0,0 +1,83 @@
package com.microservices.dms.task.controller;
import com.microservices.common.core.utils.PageUtils;
import com.microservices.common.core.web.controller.BaseController;
import com.microservices.common.core.web.page.GenericsTableDataInfo;
import com.microservices.dms.task.domain.vo.TaskListVo;
import com.microservices.dms.task.domain.vo.UserActionDataVo;
import com.microservices.dms.task.service.TaskResourceLibraryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Api(tags = "数据管理体系-任务资源库接口")
@RestController
@RequestMapping("/taskResourceLibrary")
@RequiredArgsConstructor
public class TaskResourceLibraryController extends BaseController {
private final TaskResourceLibraryService taskResourceLibraryService;
@GetMapping("/selectTaskJournalsCondition")
@ApiOperation(value = "查询用户评论")
public GenericsTableDataInfo<UserActionDataVo> selectTaskJournalsCondition(@RequestParam UserActionDataVo taskJournals) {
PageUtils.startPage();
List<UserActionDataVo> userActionDataVos = taskResourceLibraryService.selectTaskJournalsCondition(taskJournals);
return PageUtils.toPage(userActionDataVos);
}
@GetMapping("selectClickerCondition")
@ApiOperation(value = "查询用户点击")
public GenericsTableDataInfo<UserActionDataVo> selectClickerCondition(@RequestParam UserActionDataVo taskJournals) {
PageUtils.startPage();
List<UserActionDataVo> userActionDataVos = taskResourceLibraryService.selectClickerCondition(taskJournals);
return PageUtils.toPage(userActionDataVos);
}
@GetMapping("selectDownloaderCondition")
@ApiOperation(value = "查询用户下载")
public GenericsTableDataInfo<UserActionDataVo> selectDownloaderCondition(@RequestParam UserActionDataVo taskJournals) {
PageUtils.startPage();
List<UserActionDataVo> userActionDataVos = taskResourceLibraryService.selectDownloaderCondition(taskJournals);
return PageUtils.toPage(userActionDataVos);
}
@GetMapping("selectPapersCondition")
@ApiOperation(value = "查询用户交稿")
public GenericsTableDataInfo<UserActionDataVo> selectPapersCondition(@RequestParam UserActionDataVo taskJournals) {
PageUtils.startPage();
List<UserActionDataVo> userActionDataVos = taskResourceLibraryService.selectPapersCondition(taskJournals);
return PageUtils.toPage(userActionDataVos);
}
@GetMapping("selectWatcherCondition")
@ApiOperation(value = "查询用户关注")
public GenericsTableDataInfo<UserActionDataVo> selectWatcherCondition(@RequestParam UserActionDataVo taskJournals) {
PageUtils.startPage();
List<UserActionDataVo> userActionDataVos = taskResourceLibraryService.selectWatcherCondition(taskJournals);
return PageUtils.toPage(userActionDataVos);
}
@GetMapping("selectSearcherCondition")
@ApiOperation(value = "查询用户搜索")
public GenericsTableDataInfo<UserActionDataVo> selectSearcherCondition(@RequestParam UserActionDataVo taskJournals) {
PageUtils.startPage();
List<UserActionDataVo> userActionDataVos = taskResourceLibraryService.selectSearcherCondition(taskJournals);
return PageUtils.toPage(userActionDataVos);
}
@GetMapping("selectTaskListCondition")
@ApiOperation(value = "查询任务列表")
public GenericsTableDataInfo<TaskListVo> selectTaskListCondition(@RequestParam TaskListVo taskListVo) {
PageUtils.startPage();
List<TaskListVo> userActionDataVos = taskResourceLibraryService.selectTaskListCondition(taskListVo);
return PageUtils.toPage(userActionDataVos);
}
}

View File

@ -0,0 +1,19 @@
package com.microservices.dms.task.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class Clicker{
private Long id;
private String clickType;
private Long clickId;
private Long userId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "")
private Date createdAt;
private String extInfo;
}

View File

@ -0,0 +1,16 @@
package com.microservices.dms.task.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class Downloader {
private Long id;
private String downloadType;
private Long downloadId;
private Long userId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "")
private Date createdAt;
private String extInfo;
}

View File

@ -0,0 +1,18 @@
package com.microservices.dms.task.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class Searcher {
private Long id;
private String clickType;
private Long clickId;
private Long userId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "")
private Date createdAt;
private String extInfo;
}

View File

@ -0,0 +1,22 @@
package com.microservices.dms.task.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class TaskListVo {
private Long id;
private String name;
private String categoryName;
private Long categoryId;
private BigDecimal bounty;
private Long totalTaskDays;
private Long taskClickCount;
private Long taskWatcherCount;
private Long taskPapersCount;
private Long taskJournalCount;
private Long taskSearchCount;
private Long taskDownloadCount;
}

View File

@ -0,0 +1,18 @@
package com.microservices.dms.task.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class UserActionDataVo {
private Long id;
private String itemType;
private Integer itemId;
private String itemName;
private Integer userId;
private String userName;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "")
private Date createdAt;
}

View File

@ -0,0 +1,45 @@
package com.microservices.dms.task.mapper;
import com.microservices.dms.task.domain.Clicker;
import com.microservices.dms.task.domain.Downloader;
import com.microservices.dms.task.domain.Searcher;
import com.microservices.dms.task.domain.vo.TaskListVo;
import com.microservices.dms.task.domain.vo.UserActionDataVo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface TaskResourceLibraryMapper {
int insertClicker(Clicker record);
int insertSearcher(Searcher record);
int insertDownloader(Downloader record);
List<UserActionDataVo> selectClickerCondition(UserActionDataVo clicker);
List<UserActionDataVo> selectSearcherCondition(UserActionDataVo searcher);
List<UserActionDataVo> selectDownloaderCondition(UserActionDataVo downloader);
List<UserActionDataVo> selectWatcherCondition(UserActionDataVo watcher);
List<UserActionDataVo> selectPapersCondition(UserActionDataVo paper);
List<UserActionDataVo> selectTaskJournalsCondition(UserActionDataVo taskJournals);
List<TaskListVo> selectTaskListCondition(TaskListVo taskListVo);
long countClickerCondition(UserActionDataVo clicker);
long countSearcherCondition(UserActionDataVo searcher);
long countDownloaderCondition(UserActionDataVo downloader);
long countWatcherCondition(UserActionDataVo watcher);
long countPapersCondition(UserActionDataVo paper);
long countTaskJournalsCondition(UserActionDataVo taskJournals);
}

View File

@ -0,0 +1,86 @@
package com.microservices.dms.task.service;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.dms.constant.TaskConstant;
import com.microservices.dms.task.domain.Clicker;
import com.microservices.dms.task.domain.Downloader;
import com.microservices.dms.task.domain.Searcher;
import com.microservices.dms.task.domain.vo.TaskListVo;
import com.microservices.dms.task.domain.vo.UserActionDataVo;
import com.microservices.dms.task.mapper.TaskResourceLibraryMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class TaskResourceLibraryService {
private final TaskResourceLibraryMapper taskResourceLibraryMapper;
public int addClick(Clicker click) {
click.setCreatedAt(DateUtils.getNowDate());
return taskResourceLibraryMapper.insertClicker(click);
}
public int addSearcher(Searcher searcher) {
searcher.setCreatedAt(DateUtils.getNowDate());
return taskResourceLibraryMapper.insertSearcher(searcher);
}
public int addDownloader(Downloader downloader) {
downloader.setCreatedAt(DateUtils.getNowDate());
return taskResourceLibraryMapper.insertDownloader(downloader);
}
public List<UserActionDataVo> selectClickerCondition(UserActionDataVo actionDataVo) {
return taskResourceLibraryMapper.selectClickerCondition(actionDataVo);
}
public List<UserActionDataVo> selectSearcherCondition(UserActionDataVo searcher) {
return taskResourceLibraryMapper.selectSearcherCondition(searcher);
}
public List<UserActionDataVo> selectDownloaderCondition(UserActionDataVo downloader) {
return taskResourceLibraryMapper.selectDownloaderCondition(downloader);
}
public List<UserActionDataVo> selectWatcherCondition(UserActionDataVo watcher) {
return taskResourceLibraryMapper.selectWatcherCondition(watcher);
}
public List<UserActionDataVo> selectPapersCondition(UserActionDataVo paper) {
return taskResourceLibraryMapper.selectPapersCondition(paper);
}
public List<UserActionDataVo> selectTaskJournalsCondition(UserActionDataVo taskJournals) {
return taskResourceLibraryMapper.selectTaskJournalsCondition(taskJournals);
}
public List<TaskListVo> selectTaskListCondition(TaskListVo taskListVo) {
List<TaskListVo> taskListVos = taskResourceLibraryMapper.selectTaskListCondition(taskListVo);
for (TaskListVo vo : taskListVos) {
UserActionDataVo c = new UserActionDataVo();
c.setId(vo.getId());
c.setItemType(TaskConstant.TASK_TYPE_PAPERS);
long papers = taskResourceLibraryMapper.countPapersCondition(c);
c.setItemType(TaskConstant.TASK_TYPE_WATCHERS);
long watcher = taskResourceLibraryMapper.countWatcherCondition(c);
c.setItemType(TaskConstant.TASK_TYPE_JOURNALS);
long clicker = taskResourceLibraryMapper.countClickerCondition(c);
long downloader = taskResourceLibraryMapper.countDownloaderCondition(c);
long taskJournals = taskResourceLibraryMapper.countTaskJournalsCondition(c);
long searcher = taskResourceLibraryMapper.countSearcherCondition(c);
vo.setTaskClickCount(clicker);
vo.setTaskWatcherCount(watcher);
vo.setTaskPapersCount(papers);
vo.setTaskDownloadCount(downloader);
vo.setTaskJournalCount(taskJournals);
vo.setTaskSearchCount(searcher);
}
return taskListVos;
}
}

View File

@ -0,0 +1,37 @@
package com.microservices.dms.utils;
import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.threadPool.ThreadPoolExecutorWrap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 线程池工厂
*
* @author OTTO
*/
public class CustomExecutorFactory {
/**
* 创建线程池
* 存在并发处理的情况设置核心线程为2设置有界队列长度为100最大线程数为10
* 当超出队列已满且达到最大线程数时抛出异常
* Ncpu=CPU数量
* Ucpu=目标CPU的使用率0<=Ucpu<=1
* W/C=任务等待时间与任务计算时间的比率
* Nthreads =Ncpu*Ucpu*(1+W/C)
*/
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutorWrap(
4
, 10
, 10
, TimeUnit.SECONDS
, new ArrayBlockingQueue<>(100)
, Executors.defaultThreadFactory()
, (r, executor) -> {
throw new ServiceException("目前处理的人太多了,请稍后再试");
}
);
}

View File

@ -0,0 +1,5 @@
package com.microservices.dms.utils;
public class DmsConstants {
}

View File

@ -0,0 +1,82 @@
package com.microservices.dms.utils;
import com.microservices.common.core.exception.ServiceException;
import java.util.Date;
import java.util.HashMap;
import java.util.UUID;
import java.util.function.Function;
/**
* @author otto
*/
public class DmsUtils {
/**
* 产品标识使用六位随机值
*
* @return 产品标识
*/
public static String generateRandomProductIdentifier() {
UUID uuid = UUID.randomUUID();
// 截取UUID的一部分例如前6个字符
return uuid.toString().substring(0, 6).toUpperCase();
}
/**
* 校验开始时间和结束时间
*
* @param startDate 开始时间
* @param endDate 结束时间
*/
public static void validStartTimeAndEndTime(Date startDate, Date endDate) {
if (startDate != null && endDate != null) {
if (endDate.before(startDate)) {
throw new ServiceException("结束时间不能早于开始时间");
}
}
}
/**
* 从HashMap中获取缓存数据当HashMap中不存在时执行传入的数据查询方法获取数据并存入缓存当HashMap为null时直接返回执行数据查询的结果
* 使用方法名和输入参数作为缓存Key简化代码
*
* @param hashMap 缓存
* @param dataRetrievalFunction 数据查询方法
* @param args 查询方法输入参数
* @param <T> 查询方法输入参数类型
* @param <R> 返回数据类型
* @return 结果
*/
public static <T, R> R getSelectObjectInCache(HashMap<String, Object> hashMap, Function<T, R> dataRetrievalFunction, T args) {
if (dataRetrievalFunction == null) {
return null;
}
String cacheKey = dataRetrievalFunction.getClass().getSimpleName() + "-" + args;
if (hashMap == null) {
return dataRetrievalFunction.apply(args);
} else if (hashMap.containsKey(cacheKey)) {
@SuppressWarnings("unchecked")
R r = (R) hashMap.get(cacheKey);
return r;
} else {
R r = dataRetrievalFunction.apply(args);
hashMap.put(cacheKey, r);
return r;
}
}
/**
* 获取文件路径中文件所在的文件夹
*
* @return 文件夹
*/
public static String parseDirectory(String filePath) {
// 找到最后一个"/"的位置
int lastSlashIndex = filePath.lastIndexOf('/');
if (lastSlashIndex > 0) {
// 截取到"/"之前的所有字符作为文件夹路径
return filePath.substring(0, lastSlashIndex);
}
return "";
}
}

View File

@ -0,0 +1,58 @@
package com.microservices.dms.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import com.microservices.common.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.io.StringWriter;
@Slf4j
public class YamlUtil {
/**
* 将yaml字符串转成类对象
*
* @param yamlStr 字符串
* @param clazz 目标类
* @param <T> 泛型
* @return 目标类
*/
public static <T> T toObject(String yamlStr, Class<T> clazz) {
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
mapper.findAndRegisterModules();
try {
return mapper.readValue(yamlStr, clazz);
} catch (JsonProcessingException e) {
log.error("yaml文本解析成java对象错误", e);
throw new ServiceException("yaml文本解析成java对象错误");
}
}
/**
* 将类对象转yaml字符串
*
* @param object 对象
* @return yaml字符串
*/
public static String toYaml(Object object) {
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
mapper.findAndRegisterModules();
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
mapper = new ObjectMapper(new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER));
StringWriter stringWriter = new StringWriter();
try {
mapper.writeValue(stringWriter, object);
return stringWriter.toString();
} catch (IOException e) {
log.error("Java对象解析成Yaml文本错误", e);
}
return null;
}
}

View File

@ -0,0 +1,10 @@
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}
_
(_)
_ __ _ _ ___ _ _ _ ______ _ __ _ __ ___ ___
| '__|| | | | / _ \ | | | || ||______|| '_ \ | '_ ` _ \ / __|
| | | |_| || (_) || |_| || | | |_) || | | | | |\__ \
|_| \__,_| \___/ \__, ||_| | .__/ |_| |_| |_||___/
__/ | | |
|___/ |_|

View File

@ -0,0 +1,34 @@
# Tomcat
server:
port: 9118
# Spring
spring:
application:
# 应用名称
name: microservices-dms
config:
activate:
# 环境配置
on-profile:
prod
cloud:
sentinel:
# 取消控制台懒加载
eager: true
nacos:
discovery:
# 服务注册地址
server-addr: ${nacos_ip}:${nacos_port}
username: ${nacos_username}
password: ${nacos_password}
config:
# 配置中心地址
server-addr: ${nacos_ip}:${nacos_port}
username: ${nacos_username}
password: ${nacos_password}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- { dataId: "application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}",refresh: true }

View File

@ -0,0 +1,32 @@
# Tomcat
server:
port: 9118
# Spring
spring:
application:
# 应用名称
name: microservices-dms
profiles:
# 环境配置
active: dev
cloud:
sentinel:
# 取消控制台懒加载
eager: true
nacos:
discovery:
# 服务注册地址
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
config:
# 配置中心地址
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- { dataId: "application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}",refresh: true }

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/microservices-pms"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.microservices" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<!-- add converter for %tid -->
<conversionRule conversionWord="tid"
converterClass="org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackPatternConverter"/>
<!-- add converter for %sw_ctx -->
<conversionRule conversionWord="sw_ctx"
converterClass="org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackSkyWalkingContextPatternConverter"/>
<appender name="skywalking_grpc"
class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
<Pattern>
{
"level": "%level",
"tid": "%tid",
"skyWalkingContext": "%sw_ctx",
"thread": "%thread",
"class": "%logger{1.}:%L",
"message": "%message",
"stackTrace": "%exception{10}"
}
</Pattern>
</layout>
</encoder>
</appender>
<root level="info">
<appender-ref ref="skywalking_grpc"/>
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -0,0 +1,267 @@
<?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.microservices.dms.task.mapper.TaskResourceLibraryMapper">
<insert id="insertClicker" useGeneratedKeys="true" keyColumn="id" keyProperty="id"
parameterType="com.microservices.dms.task.domain.Clicker">
INSERT INTO clickers
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="null != clickType and '' != clickType">
click_type,
</if>
<if test="null != clickId ">
click_id,
</if>
<if test="null != userId ">
user_id,
</if>
<if test="null != createdAt ">
created_at,
</if>
<if test="null != extInfo and '' != extInfo">
ext_info
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="null != clickType and '' != clickType">
#{clickType},
</if>
<if test="null != clickId ">
#{clickId},
</if>
<if test="null != userId ">
#{userId},
</if>
<if test="null != createdAt ">
#{createdAt},
</if>
<if test="null != extInfo and '' != extInfo">
#{extInfo}
</if>
</trim>
</insert>
<insert id="insertSearcher" useGeneratedKeys="true" keyColumn="id" keyProperty="id"
parameterType="com.microservices.dms.task.domain.Searcher">
INSERT INTO searchers
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="null != searchType and '' != searchType">
search_type,
</if>
<if test="null != searchId ">
search_id,
</if>
<if test="null != userId ">
user_id,
</if>
<if test="null != createdAt ">
created_at,
</if>
<if test="null != extInfo and '' != extInfo">
ext_info
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="null != searchType and '' != searchType">
#{searchType},
</if>
<if test="null != searchId ">
#{searchId},
</if>
<if test="null != userId ">
#{userId},
</if>
<if test="null != createdAt ">
#{createdAt},
</if>
<if test="null != extInfo and '' != extInfo">
#{extInfo}
</if>
</trim>
</insert>
<insert id="insertDownloader" useGeneratedKeys="true" keyColumn="id" keyProperty="id"
parameterType="com.microservices.dms.task.domain.Downloader">
INSERT INTO downloaders
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="null != downloadType and '' != downloadType">
download_type,
</if>
<if test="null != downloadId ">
download_id,
</if>
<if test="null != userId ">
user_id,
</if>
<if test="null != createdAt ">
created_at,
</if>
<if test="null != extInfo and '' != extInfo">
ext_info
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="null != downloadType and '' != downloadType">
#{downloadType},
</if>
<if test="null != downloadId ">
#{downloadId},
</if>
<if test="null != userId ">
#{userId},
</if>
<if test="null != createdAt ">
#{createdAt},
</if>
<if test="null != extInfo and '' != extInfo">
#{extInfo}
</if>
</trim>
</insert>
<select id="selectClickerCondition" resultType="com.microservices.dms.task.domain.vo.UserActionDataVo">
select click_type as itemType, click_id as itemId, user_id as userId, created_at as createAt,
(select login from users where id = user_id) as userName from clickers
<where>
<if test="itemType != null and itemType.trim() != ''">
AND click_type = #{itemType}
</if>
<if test="itemId != null">
AND click_id = #{itemId}
</if>
</where>
</select>
<select id="selectSearcherCondition" resultType="com.microservices.dms.task.domain.vo.UserActionDataVo">
select search_type as itemType, search_id as itemId, user_id as userId, created_at as createAt from searchers
<where>
<if test="itemType != null and itemType.trim() != ''">
AND search_type = #{itemType}
</if>
<if test="itemId != null">
AND search_id = #{itemId}
</if>
</where>
</select>
<select id="selectDownloaderCondition" resultType="com.microservices.dms.task.domain.vo.UserActionDataVo">
select download_type as itemType, download_id as itemId, user_id as userId, created_at as createAt from downloaders
<where>
<if test="itemType != null and itemType.trim() != ''">
AND download_type = #{itemType}
</if>
<if test="itemId != null">
AND download_id = #{itemId}
</if>
</where>
</select>
<select id="selectWatcherCondition" resultType="com.microservices.dms.task.domain.vo.UserActionDataVo">
select watchable_type as itemType, watchable_id as itemId, user_id as userId, created_at as createAt from downloaders
<where>
<if test="itemType != null and itemType.trim() != ''">
AND download_type = #{itemType}
</if>
<if test="downloadId != null">
AND download_id = #{itemId}
</if>
</where>
</select>
<select id="selectTaskJournalsCondition" resultType="com.microservices.dms.task.domain.vo.UserActionDataVo">
select journalized_type as itemType, journalized_id as itemId, user_id as userId, created_at as createAt from task_journals
<where>
<if test="itemType != null and itemType.trim() != ''">
AND journalized_type = #{itemType}
</if>
<if test="downloadId != null">
AND journalized_id = #{itemId}
</if>
</where>
</select>
<select id="selectPapersCondition" resultType="com.microservices.dms.task.domain.vo.UserActionDataVo">
select task_id as itemId, user_id as userId, created_at as createAt from papers
<where>
<if test="downloadId != null">
AND task_id = #{itemId}
</if>
</where>
</select>
<select id="selectTaskListCondition" resultType="com.microservices.dms.task.domain.vo.TaskListVo">
select name,id,bounty,category_id,DATEDIFF(expired_at, published_at) as totalTaskDays,
(select c.name from categories c where id = category_id) as categoryName
from tasks
<where>
<if test="categoryId != null">
AND category_id = #{categoryId}
</if>
<if test="name != null and name.trim() != ''">
AND `name` like concat('%', #{name}, '%')
</if>
</where>
</select>
<select id="countClickerCondition" resultType="long">
select count(*) from clickers
<where>
<if test="itemType != null and itemType.trim() != ''">
AND click_type = #{itemType}
</if>
<if test="itemId != null">
AND click_id = #{itemId}
</if>
</where>
</select>
<select id="countSearcherCondition" resultType="long">
select count(*) from searchers
<where>
<if test="itemType != null and itemType.trim() != ''">
AND search_type = #{itemType}
</if>
<if test="itemId != null">
AND search_id = #{itemId}
</if>
</where>
</select>
<select id="countDownloaderCondition" resultType="long">
select count(*) from downloaders
<where>
<if test="itemType != null and itemType.trim() != ''">
AND download_type = #{itemType}
</if>
<if test="itemId != null">
AND download_id = #{itemId}
</if>
</where>
</select>
<select id="countWatcherCondition" resultType="long">
select count(*) from downloaders
<where>
<if test="itemType != null and itemType.trim() != ''">
AND download_type = #{itemType}
</if>
<if test="downloadId != null">
AND download_id = #{itemId}
</if>
</where>
</select>
<select id="countTaskJournalsCondition" resultType="long">
select count(*) from task_journals
<where>
<if test="itemType != null and itemType.trim() != ''">
AND journalized_type = #{itemType}
</if>
<if test="downloadId != null">
AND journalized_id = #{itemId}
</if>
</where>
</select>
<select id="countPapersCondition" resultType="long">
select count(*) from papers
<where>
<if test="downloadId != null">
AND task_id = #{itemId}
</if>
</where>
</select>
</mapper>

View File

@ -0,0 +1,63 @@
package com.microservices.pms.test;
import com.alibaba.fastjson2.JSON;
import com.microservices.pms.enums.TestCaseStatus;
import com.microservices.pms.project.domain.PmsProjectTestsheetCases;
import com.microservices.pms.project.domain.vo.PmsProjectTestcaseStepDataVo;
import com.microservices.pms.project.domain.vo.PmsProjectTestsheetCaseStepVo;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
public class PmsProjectTestSheetTest {
public static void main(String[] args) {
List<PmsProjectTestsheetCases> testsheetCasesList= new ArrayList<PmsProjectTestsheetCases>();
PmsProjectTestsheetCases a = new PmsProjectTestsheetCases();
a.setTestStatus(1l);
PmsProjectTestsheetCases b = new PmsProjectTestsheetCases();
b.setTestStatus(1l);
PmsProjectTestsheetCases c = new PmsProjectTestsheetCases();
c.setTestStatus(3l);
PmsProjectTestsheetCases d = new PmsProjectTestsheetCases();
d.setTestStatus(3l);
testsheetCasesList.add(a);
testsheetCasesList.add(b);
testsheetCasesList.add(c);
testsheetCasesList.add(d);
Map<Long, Integer> listMap = Optional.ofNullable(testsheetCasesList).orElse(Collections.emptyList()).stream()
.collect(Collectors.groupingBy(PmsProjectTestsheetCases::getTestStatus, Collectors.summingInt(value -> 1)));
listMap.forEach((key, value) -> System.out.println("" + key + ":" + value));
Long passCount = Optional.ofNullable(testsheetCasesList).orElse(Collections.emptyList()).stream()
.filter(testCase -> testCase.getTestStatus().intValue() == 1).count();
// = 失败+通过+阻塞+未执行(或者排除跳过的)
Long execTotalCount = Optional.ofNullable(testsheetCasesList).orElse(Collections.emptyList()).stream()
.filter(testCase -> testCase.getTestStatus().intValue() != 2).count();
//Long execTotalCount = testsheetCasesList.stream().filter(testCase -> new HashSet<>(Arrays.asList(0L, 1L, 2L, 3L)).contains(testCase.getTestStatus())).count();
// 通过率s
System.out.println(passCount);
System.out.println(execTotalCount);
System.out.println(BigDecimal.valueOf(passCount / execTotalCount.doubleValue()).setScale(2, BigDecimal.ROUND_HALF_UP));
// System.out.println(BigDecimal.valueOf(0 / 0d).setScale(2, BigDecimal.ROUND_HALF_UP));
System.out.println(BigDecimal.valueOf(new Double("0.1114")));
List<PmsProjectTestsheetCaseStepVo> testcaseStepList = new ArrayList<>();
PmsProjectTestsheetCaseStepVo aaa = new PmsProjectTestsheetCaseStepVo();
aaa.setStepId(1l);
aaa.setStepStatus(1);
PmsProjectTestsheetCaseStepVo bbb = new PmsProjectTestsheetCaseStepVo();
bbb.setStepId(2l);
bbb.setStepStatus(1);
testcaseStepList.add(aaa);
testcaseStepList.add(bbb);
System.out.println(JSON.toJSONString(Optional.ofNullable(testcaseStepList).orElse(Collections.emptyList())));
System.out.println(JSON.parseArray("[{\"stepId\":1,\"stepStatus\":1},{\"stepId\":2,\"stepStatus\":1}]", PmsProjectTestcaseStepDataVo.class));
System.out.println(JSON.parseArray("[{\"stepId\":1,\"stepStatus\":1},{\"stepId\":2,\"stepStatus\":1}]", HashMap.class));
Long[] testsheetCasesIds = testsheetCasesList.stream().map(PmsProjectTestsheetCases::getTestStatus).toArray(Long[]::new);
}
}

View File

@ -18,6 +18,7 @@
<module>microservices-modules-pms</module>
<module>microservices-modules-wiki</module>
<module>microservices-modules-dss</module>
<module>microservices-modules-dms</module>
</modules>
<artifactId>microservices-modules</artifactId>