同步日志模块
This commit is contained in:
parent
268cacd2c1
commit
e50c4662dc
|
|
@ -0,0 +1,43 @@
|
||||||
|
package org.jeecg.modules.base.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步日志信息
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("stas_sync_log")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class StasSyncLog implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**主键*/
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
private String id;
|
||||||
|
/**记录id*/
|
||||||
|
@Excel(name = "记录id", width = 15)
|
||||||
|
private String recordId;
|
||||||
|
/**开始时间*/
|
||||||
|
@Excel(name = "开始时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date startTime;
|
||||||
|
/**描述*/
|
||||||
|
@Excel(name = "描述", width = 15)
|
||||||
|
private String description;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package org.jeecg.modules.base.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步数量
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("stas_sync_num")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class StasSyncNum implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**主键*/
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
private String id;
|
||||||
|
/**记录id*/
|
||||||
|
@Excel(name = "记录id", width = 15)
|
||||||
|
private String recordId;
|
||||||
|
/**同步表名*/
|
||||||
|
@Excel(name = "同步表名", width = 15)
|
||||||
|
private String tableName;
|
||||||
|
/**同步数据条数*/
|
||||||
|
@Excel(name = "同步数据条数", width = 15)
|
||||||
|
private Integer syncNum;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package org.jeecg.modules.base.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步记录表
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("stas_sync_record")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class StasSyncRecord implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**主键*/
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
private String id;
|
||||||
|
/**任务id*/
|
||||||
|
@Excel(name = "任务id", width = 15)
|
||||||
|
private String taskId;
|
||||||
|
/**源库id*/
|
||||||
|
@Excel(name = "源库id", width = 15)
|
||||||
|
private String sourceId;
|
||||||
|
/**目标库id*/
|
||||||
|
@Excel(name = "目标库id", width = 15)
|
||||||
|
private String targetId;
|
||||||
|
/**开始时间*/
|
||||||
|
@Excel(name = "开始时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date startTime;
|
||||||
|
/**结束时间*/
|
||||||
|
@Excel(name = "结束时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date endTime;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.jeecg.modules.base.mapper;
|
||||||
|
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncLog;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步日志信息
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
public interface StasSyncLogMapper extends BaseMapper<StasSyncLog> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.jeecg.modules.base.mapper;
|
||||||
|
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncNum;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步数量
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
public interface StasSyncNumMapper extends BaseMapper<StasSyncNum> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.jeecg.modules.base.mapper;
|
||||||
|
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncRecord;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步记录表
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
public interface StasSyncRecordMapper extends BaseMapper<StasSyncRecord> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?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="org.jeecg.modules.base.mapper.StasSyncLogMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?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="org.jeecg.modules.base.mapper.StasSyncNumMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?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="org.jeecg.modules.base.mapper.StasSyncRecordMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
package org.jeecg.syncLog.controller;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncLog;
|
||||||
|
import org.jeecg.syncLog.service.IStasSyncLogService;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步日志信息
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
@Tag(name="同步日志信息")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/stasSyncLog")
|
||||||
|
@Slf4j
|
||||||
|
public class StasSyncLogController extends JeecgController<StasSyncLog, IStasSyncLogService> {
|
||||||
|
@Autowired
|
||||||
|
private IStasSyncLogService stasSyncLogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页列表查询
|
||||||
|
*
|
||||||
|
* @param stasSyncLog
|
||||||
|
* @param pageNo
|
||||||
|
* @param pageSize
|
||||||
|
* @param req
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Operation(summary = "同步日志信息-分页列表查询")
|
||||||
|
@GetMapping(value = "/list")
|
||||||
|
public Result<IPage<StasSyncLog>> queryPageList(StasSyncLog stasSyncLog,
|
||||||
|
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||||
|
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
|
||||||
|
HttpServletRequest req) {
|
||||||
|
QueryWrapper<StasSyncLog> queryWrapper = QueryGenerator.initQueryWrapper(stasSyncLog, req.getParameterMap());
|
||||||
|
queryWrapper.orderByAsc("start_time");
|
||||||
|
Page<StasSyncLog> page = new Page<StasSyncLog>(pageNo, pageSize);
|
||||||
|
IPage<StasSyncLog> pageList = stasSyncLogService.page(page, queryWrapper);
|
||||||
|
return Result.OK(pageList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.jeecg.syncLog.service;
|
||||||
|
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncLog;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步日志信息
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
public interface IStasSyncLogService extends IService<StasSyncLog> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.jeecg.syncLog.service.impl;
|
||||||
|
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncLog;
|
||||||
|
import org.jeecg.modules.base.mapper.StasSyncLogMapper;
|
||||||
|
import org.jeecg.syncLog.service.IStasSyncLogService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步日志信息
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class StasSyncLogServiceImpl extends ServiceImpl<StasSyncLogMapper, StasSyncLog> implements IStasSyncLogService {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package org.jeecg.syncNum.controller;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncNum;
|
||||||
|
import org.jeecg.syncNum.service.IStasSyncNumService;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
|
import org.jeecg.syncNum.vo.PieChartVO;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步数量
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
@Tag(name="同步数量")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/stasSyncNum")
|
||||||
|
@Slf4j
|
||||||
|
public class StasSyncNumController extends JeecgController<StasSyncNum, IStasSyncNumService> {
|
||||||
|
@Autowired
|
||||||
|
private IStasSyncNumService stasSyncNumService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页列表查询
|
||||||
|
*
|
||||||
|
* @param stasSyncNum
|
||||||
|
* @param req
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
//@AutoLog(value = "同步数量-分页列表查询")
|
||||||
|
@Operation(summary = "同步数量-分页列表查询")
|
||||||
|
@GetMapping(value = "/list")
|
||||||
|
public Result<List<PieChartVO>> queryPageList(StasSyncNum stasSyncNum,
|
||||||
|
HttpServletRequest req) {
|
||||||
|
// 构建查询条件
|
||||||
|
QueryWrapper<StasSyncNum> queryWrapper = QueryGenerator.initQueryWrapper(stasSyncNum, req.getParameterMap());
|
||||||
|
// 查询数据并按表名分组统计
|
||||||
|
List<StasSyncNum> records = stasSyncNumService.list(queryWrapper);
|
||||||
|
|
||||||
|
// 按表名分组统计总同步量
|
||||||
|
Map<String, Integer> tableSyncMap = records.stream()
|
||||||
|
.collect(Collectors.groupingBy(
|
||||||
|
StasSyncNum::getTableName,
|
||||||
|
Collectors.summingInt(StasSyncNum::getSyncNum)
|
||||||
|
));
|
||||||
|
|
||||||
|
// 计算总同步量(用于计算百分比)
|
||||||
|
int total = tableSyncMap.values().stream().mapToInt(Integer::intValue).sum();
|
||||||
|
|
||||||
|
// 转换为饼图数据
|
||||||
|
List<PieChartVO> pieData = tableSyncMap.entrySet().stream()
|
||||||
|
.map(entry -> {
|
||||||
|
PieChartVO vo = new PieChartVO();
|
||||||
|
vo.setName(entry.getKey());
|
||||||
|
vo.setValue(entry.getValue());
|
||||||
|
if (total > 0) {
|
||||||
|
double percent = (entry.getValue() * 100.0) / total;
|
||||||
|
vo.setPercent(String.format("%.2f%%", percent));
|
||||||
|
}
|
||||||
|
return vo;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return Result.OK(pieData);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.jeecg.syncNum.service;
|
||||||
|
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncNum;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步数量
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
public interface IStasSyncNumService extends IService<StasSyncNum> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.jeecg.syncNum.service.impl;
|
||||||
|
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncNum;
|
||||||
|
import org.jeecg.modules.base.mapper.StasSyncNumMapper;
|
||||||
|
import org.jeecg.syncNum.service.IStasSyncNumService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步数量
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class StasSyncNumServiceImpl extends ServiceImpl<StasSyncNumMapper, StasSyncNum> implements IStasSyncNumService {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.jeecg.syncNum.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PieChartVO {
|
||||||
|
// 表名(饼图的每块名称)
|
||||||
|
private String name;
|
||||||
|
// 同步数量(饼图的每块值)
|
||||||
|
private Integer value;
|
||||||
|
// 可选:百分比
|
||||||
|
private String percent;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
package org.jeecg.syncRecord.controller;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
|
import org.jeecg.dataSource.service.IStasDataSourceService;
|
||||||
|
import org.jeecg.modules.base.entity.StasDataSource;
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncRecord;
|
||||||
|
import org.jeecg.modules.base.entity.StasTaskConfig;
|
||||||
|
import org.jeecg.syncRecord.service.IStasSyncRecordService;
|
||||||
|
import org.jeecg.syncRecord.vo.SyncRecordVO;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
|
import org.jeecg.taskConfig.service.IStasTaskConfigService;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步记录表
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
@Tag(name="同步记录表")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/stasSyncRecord")
|
||||||
|
@Slf4j
|
||||||
|
public class StasSyncRecordController extends JeecgController<StasSyncRecord, IStasSyncRecordService> {
|
||||||
|
@Autowired
|
||||||
|
private IStasSyncRecordService stasSyncRecordService;
|
||||||
|
@Autowired
|
||||||
|
private IStasDataSourceService stasDataSourceService;
|
||||||
|
@Autowired
|
||||||
|
private IStasTaskConfigService stasTaskConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页列表查询
|
||||||
|
*
|
||||||
|
* @param stasSyncRecord
|
||||||
|
* @param pageNo
|
||||||
|
* @param pageSize
|
||||||
|
* @param req
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
//@AutoLog(value = "同步记录表-分页列表查询")
|
||||||
|
@Operation(summary = "同步记录表-分页列表查询")
|
||||||
|
@GetMapping(value = "/list")
|
||||||
|
public Result<IPage<SyncRecordVO>> queryPageList(StasSyncRecord stasSyncRecord,
|
||||||
|
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||||
|
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
|
||||||
|
HttpServletRequest req) {
|
||||||
|
stasSyncRecord.setStartTime(null);
|
||||||
|
stasSyncRecord.setEndTime(null);
|
||||||
|
QueryWrapper<StasSyncRecord> queryWrapper = QueryGenerator.initQueryWrapper(stasSyncRecord, req.getParameterMap());
|
||||||
|
|
||||||
|
// 处理开始时间区间查询
|
||||||
|
String beginStartTime = req.getParameter("startTime");
|
||||||
|
String endStartTime = req.getParameter("endTime");
|
||||||
|
if (StringUtils.isNotBlank(beginStartTime)) {
|
||||||
|
queryWrapper.ge("start_time", beginStartTime);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(endStartTime)) {
|
||||||
|
queryWrapper.le("start_time", endStartTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
queryWrapper.orderByAsc("start_time");
|
||||||
|
Page<StasSyncRecord> page = new Page<>(pageNo, pageSize);
|
||||||
|
IPage<StasSyncRecord> pageList = stasSyncRecordService.page(page, queryWrapper);
|
||||||
|
List<StasSyncRecord> records = pageList.getRecords();
|
||||||
|
|
||||||
|
// 准备数据源和任务名称映射
|
||||||
|
Map<String, String> dataSourceMap = stasDataSourceService.list().stream()
|
||||||
|
.collect(Collectors.toMap(StasDataSource::getId, StasDataSource::getInstanceName));
|
||||||
|
Map<String, String> taskMap = stasTaskConfigService.list().stream()
|
||||||
|
.collect(Collectors.toMap(StasTaskConfig::getId, StasTaskConfig::getTaskName));
|
||||||
|
|
||||||
|
// 转换为VO列表
|
||||||
|
List<SyncRecordVO> syncRecordVOS = records.stream().map(record -> {
|
||||||
|
SyncRecordVO vo = new SyncRecordVO();
|
||||||
|
vo.setId(record.getId());
|
||||||
|
vo.setTaskName(taskMap.get(record.getTaskId()));
|
||||||
|
vo.setSourceName(dataSourceMap.get(record.getSourceId()));
|
||||||
|
vo.setTargetName(dataSourceMap.get(record.getTargetId()));
|
||||||
|
vo.setStartTime(record.getStartTime());
|
||||||
|
vo.setEndTime(record.getEndTime());
|
||||||
|
return vo;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 创建新的分页对象
|
||||||
|
Page<SyncRecordVO> resultPage = new Page<>();
|
||||||
|
BeanUtils.copyProperties(pageList, resultPage, "records");
|
||||||
|
resultPage.setRecords(syncRecordVOS);
|
||||||
|
|
||||||
|
return Result.OK(resultPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.jeecg.syncRecord.service;
|
||||||
|
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncRecord;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步记录表
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
public interface IStasSyncRecordService extends IService<StasSyncRecord> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.jeecg.syncRecord.service.impl;
|
||||||
|
|
||||||
|
import org.jeecg.modules.base.entity.StasSyncRecord;
|
||||||
|
import org.jeecg.modules.base.mapper.StasSyncRecordMapper;
|
||||||
|
import org.jeecg.syncRecord.service.IStasSyncRecordService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步记录表
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class StasSyncRecordServiceImpl extends ServiceImpl<StasSyncRecordMapper, StasSyncRecord> implements IStasSyncRecordService {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package org.jeecg.syncRecord.vo;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 同步记录表
|
||||||
|
* @Author: jeecg-boot
|
||||||
|
* @Date: 2025-10-14
|
||||||
|
* @Version: V1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SyncRecordVO implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**任务名称*/
|
||||||
|
private String id;
|
||||||
|
/**任务名称*/
|
||||||
|
private String taskName;
|
||||||
|
/**源库名称*/
|
||||||
|
private String sourceName;
|
||||||
|
/**目标库名称*/
|
||||||
|
private String targetName;
|
||||||
|
/**开始时间*/
|
||||||
|
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date startTime;
|
||||||
|
/**结束时间*/
|
||||||
|
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date endTime;
|
||||||
|
}
|
||||||
|
|
@ -7,12 +7,8 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jeecg.common.constant.enums.SourceDataTypeEnum;
|
import org.jeecg.common.constant.enums.SourceDataTypeEnum;
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
import org.jeecg.common.exception.JeecgBootException;
|
||||||
import org.jeecg.common.util.DBUtil;
|
import org.jeecg.common.util.DBUtil;
|
||||||
import org.jeecg.modules.base.entity.StasDataSource;
|
import org.jeecg.modules.base.entity.*;
|
||||||
import org.jeecg.modules.base.entity.StasSyncStrategy;
|
import org.jeecg.modules.base.mapper.*;
|
||||||
import org.jeecg.modules.base.entity.StasTaskConfig;
|
|
||||||
import org.jeecg.modules.base.mapper.StasDataSourceMapper;
|
|
||||||
import org.jeecg.modules.base.mapper.StasSyncStrategyMapper;
|
|
||||||
import org.jeecg.modules.base.mapper.StasTaskConfigMapper;
|
|
||||||
import org.jeecg.vo.DateRangeVO;
|
import org.jeecg.vo.DateRangeVO;
|
||||||
import org.jeecg.vo.IdRangeVO;
|
import org.jeecg.vo.IdRangeVO;
|
||||||
import org.quartz.Job;
|
import org.quartz.Job;
|
||||||
|
|
@ -37,6 +33,12 @@ public class SyncDataJob implements Job {
|
||||||
private StasDataSourceMapper stasDataSourceMapper;
|
private StasDataSourceMapper stasDataSourceMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private StasSyncStrategyMapper stasSyncStrategyMapper;
|
private StasSyncStrategyMapper stasSyncStrategyMapper;
|
||||||
|
@Resource
|
||||||
|
private StasSyncRecordMapper stasSyncRecordMapper;
|
||||||
|
@Resource
|
||||||
|
private StasSyncLogMapper stasSyncLogMapper;
|
||||||
|
@Resource
|
||||||
|
private StasSyncNumMapper stasSyncNumMapper;
|
||||||
|
|
||||||
private String parameter;
|
private String parameter;
|
||||||
|
|
||||||
|
|
@ -61,6 +63,14 @@ public class SyncDataJob implements Job {
|
||||||
StasDataSource sourceInfo = stasDataSourceMapper.selectById(stasTaskConfig.getSourceId());
|
StasDataSource sourceInfo = stasDataSourceMapper.selectById(stasTaskConfig.getSourceId());
|
||||||
StasDataSource targetInfo = stasDataSourceMapper.selectById(stasTaskConfig.getTargetId());
|
StasDataSource targetInfo = stasDataSourceMapper.selectById(stasTaskConfig.getTargetId());
|
||||||
|
|
||||||
|
StasSyncRecord stasSyncRecord = new StasSyncRecord();
|
||||||
|
stasSyncRecord.setTaskId(taskId);
|
||||||
|
stasSyncRecord.setSourceId(stasTaskConfig.getSourceId());
|
||||||
|
stasSyncRecord.setTargetId(stasTaskConfig.getTargetId());
|
||||||
|
stasSyncRecord.setStartTime(new Date());
|
||||||
|
stasSyncRecordMapper.insert(stasSyncRecord);
|
||||||
|
String recordId = stasSyncRecord.getId();
|
||||||
|
|
||||||
String sourceUrl = DBUtil.getUrl(sourceInfo.getIpAddress(), sourceInfo.getPort(), sourceInfo.getServeId());
|
String sourceUrl = DBUtil.getUrl(sourceInfo.getIpAddress(), sourceInfo.getPort(), sourceInfo.getServeId());
|
||||||
String targetUrl;
|
String targetUrl;
|
||||||
if(SourceDataTypeEnum.ORACLE.getKey().equals(targetInfo.getType())){
|
if(SourceDataTypeEnum.ORACLE.getKey().equals(targetInfo.getType())){
|
||||||
|
|
@ -79,27 +89,29 @@ public class SyncDataJob implements Job {
|
||||||
.selectList(new LambdaQueryWrapper<StasSyncStrategy>().eq(StasSyncStrategy::getTaskId, taskId));
|
.selectList(new LambdaQueryWrapper<StasSyncStrategy>().eq(StasSyncStrategy::getTaskId, taskId));
|
||||||
|
|
||||||
for (StasSyncStrategy stasSyncStrategy : stasSyncStrategies) {
|
for (StasSyncStrategy stasSyncStrategy : stasSyncStrategies) {
|
||||||
log.info("开始同步表: {} (依据字段: {})", stasSyncStrategy.getTableName(), stasSyncStrategy.getColumnName());
|
saveSyncLog(recordId,String.format("开始同步表: %s (依据字段: %s)", stasSyncStrategy.getTableName(), stasSyncStrategy.getColumnName()));
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isDateColumn(sourceConn, stasSyncStrategy, sourceInfo.getType())) {
|
if (isDateColumn(sourceConn, stasSyncStrategy, sourceInfo.getType())) {
|
||||||
syncByDateRange(sourceConn, targetConn, stasSyncStrategy,
|
syncByDateRange(sourceConn, targetConn, stasSyncStrategy,
|
||||||
stasTaskConfig.getSyncDay(), sourceInfo.getType(), targetInfo.getType());
|
stasTaskConfig.getSyncDay(), sourceInfo.getType(), targetInfo.getType(), recordId);
|
||||||
} else {
|
} else {
|
||||||
syncByIdRange(sourceConn, targetConn, stasSyncStrategy,
|
syncByIdRange(sourceConn, targetConn, stasSyncStrategy,
|
||||||
stasTaskConfig.getSyncCount(), sourceInfo.getType(), targetInfo.getType());
|
stasTaskConfig.getSyncCount(), sourceInfo.getType(), targetInfo.getType(), recordId);
|
||||||
}
|
}
|
||||||
} catch (SQLException | ParseException e) {
|
} catch (SQLException | ParseException e) {
|
||||||
log.error("同步表 {} 时出错: {}", stasSyncStrategy.getTableName(), e.getMessage());
|
saveSyncLog(recordId,String.format("同步表 %s 时出错: %s", stasSyncStrategy.getTableName(), e.getMessage()));
|
||||||
targetConn.rollback();
|
targetConn.rollback();
|
||||||
throw new JeecgBootException(e.getMessage());
|
throw new JeecgBootException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
long endTime = System.currentTimeMillis();
|
long endTime = System.currentTimeMillis();
|
||||||
log.info("表 {} 同步耗时: {} 毫秒", stasSyncStrategy.getTableName(), (endTime - startTime));
|
saveSyncLog(recordId,String.format("表 %s 同步耗时: %s 毫秒", stasSyncStrategy.getTableName(), (endTime - startTime)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stasSyncRecord.setEndTime(new Date());
|
||||||
|
stasSyncRecordMapper.updateById(stasSyncRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -136,10 +148,9 @@ public class SyncDataJob implements Job {
|
||||||
*/
|
*/
|
||||||
public void syncByDateRange(Connection sourceConn, Connection targetConn,
|
public void syncByDateRange(Connection sourceConn, Connection targetConn,
|
||||||
StasSyncStrategy stasSyncStrategy, Integer syncCount,
|
StasSyncStrategy stasSyncStrategy, Integer syncCount,
|
||||||
Integer sourceDbType, Integer targetDbType) throws SQLException, ParseException {
|
Integer sourceDbType, Integer targetDbType, String recordId) throws SQLException, ParseException {
|
||||||
// 获取最小和最大日期
|
// 获取最小和最大日期
|
||||||
DateRangeVO dateRange = getDateRange(sourceConn, stasSyncStrategy, sourceDbType);
|
DateRangeVO dateRange = getDateRange(sourceConn, stasSyncStrategy, sourceDbType);
|
||||||
log.info("日期范围: {} 至 {}", dateRange.getMinDate(), dateRange.getMaxDate());
|
|
||||||
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
|
@ -164,18 +175,20 @@ public class SyncDataJob implements Job {
|
||||||
"' AND TIMESTAMP '" + sdf.format(currentEnd) + "'";
|
"' AND TIMESTAMP '" + sdf.format(currentEnd) + "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("同步日期范围: {} 至 {}", sdf.format(currentStart), sdf.format(currentEnd));
|
saveSyncLog(recordId,String.format("%s表同步日期范围: %s 至 %s", stasSyncStrategy.getTableName(), sdf.format(currentStart), sdf.format(currentEnd)));
|
||||||
|
|
||||||
int rowsSynced = syncDataBatch(sourceConn, targetConn, stasSyncStrategy.getSourceOwner(),
|
int rowsSynced = syncDataBatch(sourceConn, targetConn, stasSyncStrategy.getSourceOwner(),
|
||||||
stasSyncStrategy.getTargetOwner(), stasSyncStrategy.getTableName(),
|
stasSyncStrategy.getTargetOwner(), stasSyncStrategy.getTableName(),
|
||||||
whereClause, sourceDbType, targetDbType);
|
whereClause, sourceDbType, targetDbType);
|
||||||
log.info("已同步 {} 行数据", rowsSynced);
|
|
||||||
|
saveSyncLog(recordId,String.format("%s表已同步 %s 行数据", stasSyncStrategy.getTableName(), rowsSynced));
|
||||||
|
saveSyncNum(recordId, stasSyncStrategy.getTableName(), rowsSynced);
|
||||||
|
|
||||||
// 更新同步位置
|
// 更新同步位置
|
||||||
if (currentEnd != null) {
|
if (currentEnd != null) {
|
||||||
stasSyncStrategy.setSyncOrigin(sdf.format(currentEnd));
|
stasSyncStrategy.setSyncOrigin(sdf.format(currentEnd));
|
||||||
stasSyncStrategyMapper.updateById(stasSyncStrategy);
|
stasSyncStrategyMapper.updateById(stasSyncStrategy);
|
||||||
log.info("最终同步位置已更新为: {}", sdf.format(currentEnd));
|
saveSyncLog(recordId, String.format("%s表最终同步位置已更新为: %s", stasSyncStrategy.getTableName(), sdf.format(currentEnd)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,10 +197,9 @@ public class SyncDataJob implements Job {
|
||||||
*/
|
*/
|
||||||
public void syncByIdRange(Connection sourceConn, Connection targetConn,
|
public void syncByIdRange(Connection sourceConn, Connection targetConn,
|
||||||
StasSyncStrategy stasSyncStrategy, Integer syncCount,
|
StasSyncStrategy stasSyncStrategy, Integer syncCount,
|
||||||
Integer sourceDbType, Integer targetDbType) throws SQLException {
|
Integer sourceDbType, Integer targetDbType, String recordId) throws SQLException {
|
||||||
// 获取最小和最大ID
|
// 获取最小和最大ID
|
||||||
IdRangeVO idRange = getIdRange(sourceConn, stasSyncStrategy, sourceDbType);
|
IdRangeVO idRange = getIdRange(sourceConn, stasSyncStrategy, sourceDbType);
|
||||||
log.info("ID范围: {} 至 {}", idRange.getMinId(), idRange.getMaxId());
|
|
||||||
|
|
||||||
// 获取上次同步的位置
|
// 获取上次同步的位置
|
||||||
String syncOrigin = stasSyncStrategy.getSyncOrigin();
|
String syncOrigin = stasSyncStrategy.getSyncOrigin();
|
||||||
|
|
@ -202,18 +214,20 @@ public class SyncDataJob implements Job {
|
||||||
|
|
||||||
String whereClause = stasSyncStrategy.getColumnName() + " BETWEEN " + currentStart + " AND " + currentEnd;
|
String whereClause = stasSyncStrategy.getColumnName() + " BETWEEN " + currentStart + " AND " + currentEnd;
|
||||||
|
|
||||||
log.info("同步ID范围: {} 至 {}", currentStart, currentEnd);
|
saveSyncLog(recordId,String.format("%s表同步ID范围: %s 至 %s", stasSyncStrategy.getTableName(), currentStart, currentEnd));
|
||||||
|
|
||||||
int rowsSynced = syncDataBatch(sourceConn, targetConn, stasSyncStrategy.getSourceOwner(),
|
int rowsSynced = syncDataBatch(sourceConn, targetConn, stasSyncStrategy.getSourceOwner(),
|
||||||
stasSyncStrategy.getTargetOwner(), stasSyncStrategy.getTableName(),
|
stasSyncStrategy.getTargetOwner(), stasSyncStrategy.getTableName(),
|
||||||
whereClause, sourceDbType, targetDbType);
|
whereClause, sourceDbType, targetDbType);
|
||||||
log.info("已同步 {} 行数据", rowsSynced);
|
|
||||||
|
saveSyncLog(recordId,String.format("%s表已同步 %s 行数据", stasSyncStrategy.getTableName(), rowsSynced));
|
||||||
|
saveSyncNum(recordId, stasSyncStrategy.getTableName(), rowsSynced);
|
||||||
|
|
||||||
// 更新同步位置
|
// 更新同步位置
|
||||||
if (currentEnd > 0) {
|
if (currentEnd > 0) {
|
||||||
stasSyncStrategy.setSyncOrigin(String.valueOf(currentEnd));
|
stasSyncStrategy.setSyncOrigin(String.valueOf(currentEnd));
|
||||||
stasSyncStrategyMapper.updateById(stasSyncStrategy);
|
stasSyncStrategyMapper.updateById(stasSyncStrategy);
|
||||||
log.info("最终同步位置已更新为: {}", currentEnd);
|
saveSyncLog(recordId,String.format("%s表最终同步位置已更新为: %s", stasSyncStrategy.getTableName(), currentEnd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -346,10 +360,27 @@ public class SyncDataJob implements Job {
|
||||||
return totalRows;
|
return totalRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void saveSyncLog(String recordId, String desc){
|
||||||
|
StasSyncLog stasSyncLog = new StasSyncLog();
|
||||||
|
stasSyncLog.setRecordId(recordId);
|
||||||
|
stasSyncLog.setStartTime(new Date());
|
||||||
|
stasSyncLog.setDescription(desc);
|
||||||
|
stasSyncLogMapper.insert(stasSyncLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveSyncNum(String recordId, String tableName, Integer num){
|
||||||
|
StasSyncNum stasSyncNum = new StasSyncNum();
|
||||||
|
stasSyncNum.setRecordId(recordId);
|
||||||
|
stasSyncNum.setTableName(tableName);
|
||||||
|
stasSyncNum.setSyncNum(num);
|
||||||
|
stasSyncNumMapper.insert(stasSyncNum);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算指定日期加上指定天数后的日期
|
* 计算指定日期加上指定天数后的日期
|
||||||
*/
|
*/
|
||||||
private static Date addDays(Date date, int days) {
|
private Date addDays(Date date, int days) {
|
||||||
long time = date.getTime() + (long)days * 24 * 60 * 60 * 1000;
|
long time = date.getTime() + (long)days * 24 * 60 * 60 * 1000;
|
||||||
return new Date(time);
|
return new Date(time);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user