Merge remote-tracking branch 'origin/main'

This commit is contained in:
liuzhaotian
2024-09-06 14:32:06 +08:00
16 changed files with 239 additions and 203 deletions
@@ -1,5 +1,6 @@
package com.cf.imes.framework.security.core.util;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cf.imes.framework.security.core.LoginUser;
@@ -132,4 +133,14 @@ public class SecurityFrameworkUtils {
return loginUser.getOrganId();
}
/**
* 当前用户是否超级管理员
*
* @return
*/
public static boolean isSuperAdmin() {
LoginUser loginUser = getLoginUser();
return ObjectUtil.isNotNull(loginUser) && loginUser.getIsSupAdmin();
}
}
@@ -161,9 +161,8 @@
,CONCAT(YEAR(p.create_time), '-', MONTH(p.create_time), '-', DAY(p.create_time)) as date
</if>
from order_plan p
join order_plan_item opi on p.id = opi.plan_id
join order_item oi on oi.id = opi.item_id
join order_plate op on oi.plate_id = op.id
join order_goods g on g.plan_id = p.id
join order_plate op on op.goods_id = g.id
where p.create_time between #{req.createTime[0]} and #{req.createTime[1]}
and p.deleted = 0
group by date;
@@ -13,6 +13,8 @@ public final class ErrorCodeConstants {
// ========== UREPORT template模块 1-003-001-000 ==========
public static final ErrorCode TEMPLATE_NOT_EXISTS = new ErrorCode(1_003_001_001, "报表模板信息不存在");
public static final ErrorCode TEMPLATE_BUILDIN_OPERATION_PERMISSION_ERROR = new ErrorCode(1_003_001_002, "内置模板操作权限不足");
public static final ErrorCode TEMPLATE_NAME_UNIQE_ERROR = new ErrorCode(1_003_001_003, "模板名【{}】已存在,请编辑模板名后重试");
// ========== UREPORT datasource模块 1-003-002-000 ==========
public static final ErrorCode DATASOURCE_NOT_EXISTS = new ErrorCode(1_003_002_001, "报表数据源不存在");
@@ -6,6 +6,7 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
@@ -31,6 +32,7 @@ public class ReportDatasetSaveReqVO implements Serializable {
private String name;
@Schema(description = "数据源id", example = "1")
@NotNull(message = "数据源id不能为空")
private Long datasourceId;
@Schema(description = "动态查询SQL")
@@ -8,7 +8,6 @@ import com.bstek.ureport.definition.dataset.Field;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.module.report.controller.admin.datasource.vo.ReportBeanDatasourceRespVO;
import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasourceReqVO;
import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasourceRespVO;
import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasourceSaveReqVO;
import com.cf.imes.module.report.dal.dataobject.datasource.ReportDatasourceDO;
@@ -82,12 +81,11 @@ public class ReportDatasourceController {
return success(BeanUtils.toBean(datasource, ReportDatasourceRespVO.class));
}
@GetMapping("/{templateId}/datasources")
@Operation(summary = "获取报表模板下的报表数据源")
@GetMapping("/datasources")
@Operation(summary = "获取报表数据源列表")
// @PreAuthorize("@ss.hasPermission('report:datasource:query')")
@Parameter(name = "templateId", description = "模版id", required = true)
public CommonResult<List<ReportDatasourceRespVO>> getDatasourcePage(@PathVariable(value = "templateId") Long templateId) {
return success(BeanUtils.toBean(datasourceService.getTemplateDatasourceList(ReportDatasourceReqVO.builder().templateId(templateId).build()), ReportDatasourceRespVO.class));
public CommonResult<List<ReportDatasourceRespVO>> getDatasourcePage() {
return success(BeanUtils.toBean(datasourceService.getDatasourceList(), ReportDatasourceRespVO.class));
}
@GetMapping("/datasource/beans")
@@ -136,7 +134,7 @@ public class ReportDatasourceController {
}
@PostMapping("/datasource/tables")
@Operation(summary = "获取数据表列表")
@Operation(summary = "获取数据表列表")
// @PreAuthorize("@ss.hasPermission('report:datasource:query')")
public CommonResult<List<Map<String, String>>> getDatasourceTables(@RequestBody DataSourceInfo info) {
return success(ureportDataSourceService.selectTableList(info));
@@ -1,6 +1,7 @@
package com.cf.imes.module.report.controller.admin.datasource.vo;
import com.cf.imes.module.report.controller.admin.dataset.vo.ReportDatasetRespVO;
import com.cf.imes.module.report.enums.datasource.ReportDatasourceTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -29,7 +30,13 @@ public class ReportDatasourceRespVO {
private String name;
@Schema(description = "数据源类型,jdbc、spring、api", example = "0")
private Integer type;
private ReportDatasourceTypeEnum type;
@Schema(description = "内置类型:0是、1否")
private Integer buildinType;
@Schema(description = "spring型数据源id")
private String beanId;
@Schema(description = "数据源驱动类",example = "com.mysql.cj.jdbc.Driver")
private String driver;
@@ -2,6 +2,7 @@ package com.cf.imes.module.report.controller.admin.datasource.vo;
import com.cf.imes.module.report.controller.admin.dataset.vo.ReportDatasetSaveReqVO;
import com.cf.imes.module.report.validation.datasource.ReportDatasourceTypeInEnum;
import com.cf.imes.module.report.validation.template.ReportTemplateTypeInEnum;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
@@ -31,9 +32,6 @@ public class ReportDatasourceSaveReqVO implements Serializable {
@Schema(description = "数据源id", example = "1")
private Long id;
@Schema(description = "模板id", example = "1")
private Long templateId;
@Schema(description = "数据源名称", example = "测试库")
private String name;
@@ -41,7 +39,8 @@ public class ReportDatasourceSaveReqVO implements Serializable {
@ReportDatasourceTypeInEnum
private String type;
@JsonIgnore
@Schema(description = "内置数据源类型,0是、1否", example = "1")
@ReportTemplateTypeInEnum
private Integer buildinType;
@Schema(description = "spring型数据源id")
@@ -62,9 +61,6 @@ public class ReportDatasourceSaveReqVO implements Serializable {
@Schema(description = "备注", example = "该模板仅供生产使用")
private String remark;
@Schema(description = "数据集")
private List<ReportDatasetSaveReqVO> datasets = new ArrayList<>();
@Schema(description = "请求头参数")
private List<Map<String, String>> headers;
}
@@ -1,14 +1,13 @@
package com.cf.imes.module.report.controller.admin.template.vo;
import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasourceSaveReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @author Gqr
@@ -30,9 +29,12 @@ public class ReportTemplateSaveReqVO {
@Schema(description = "报表模板")
private String content;
@Schema(description = "数据源")
private List<ReportDatasourceSaveReqVO> datasource = new ArrayList<>();
@Schema(description = "备注", example = "该模板仅供生产使用")
private String remark;
@Schema(description = "数据源id列表")
private Set<Long> datasourceIds;
@Schema(description = "数据集id列表")
private Set<Long> datasetIds;
}
@@ -39,10 +39,7 @@ public class ReportDatasourceDO extends BaseDO {
*/
@TableId
private Long id;
/**
* 模板id
*/
private Long templateId;
/**
* 数据源名称
*/
@@ -3,11 +3,14 @@ package com.cf.imes.module.report.dal.dataobject.template;
import com.baomidou.mybatisplus.annotation.*;
import com.cf.imes.framework.mybatis.core.dataobject.BaseDO;
import com.cf.imes.framework.mybatis.core.type.CompressStringTypeHandler;
import com.cf.imes.framework.mybatis.core.type.JsonLongSetTypeHandler;
import com.cf.imes.framework.mybatis.core.type.LongListTypeHandler;
import com.cf.imes.module.report.dal.dataobject.datasource.ReportDatasourceDO;
import com.cf.imes.module.report.enums.template.ReportTemplateTypeEnum;
import lombok.*;
import java.util.List;
import java.util.Set;
/**
* 报表模板信息DO
@@ -57,4 +60,16 @@ public class ReportTemplateDO extends BaseDO {
*/
@TableField(exist = false)
private List<ReportDatasourceDO> datasource;
/**
* 数据源id列表
*/
@TableField(typeHandler = JsonLongSetTypeHandler.class)
private Set<Long> datasourceIds;
/**
* 数据集id列表
*/
@TableField(typeHandler = JsonLongSetTypeHandler.class)
private Set<Long> datasetIds;
}
@@ -1,12 +1,17 @@
package com.cf.imes.module.report.service.dataset;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.report.controller.admin.dataset.vo.ReportDatasetReqVO;
import com.cf.imes.module.report.controller.admin.dataset.vo.ReportDatasetSaveReqVO;
import com.cf.imes.module.report.dal.dataobject.dataset.ReportDatasetDO;
import com.cf.imes.module.report.dal.dataobject.datasource.ReportDatasourceDO;
import com.cf.imes.module.report.dal.mysql.dataset.ReportDatasetMapper;
import com.cf.imes.module.report.dal.mysql.datasource.ReportDatasourceMapper;
import com.cf.imes.module.report.enums.template.ReportTemplateTypeEnum;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@@ -15,6 +20,8 @@ import java.util.List;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.module.report.enums.ErrorCodeConstants.DATASET_NOT_EXISTS;
import static com.cf.imes.module.report.enums.ErrorCodeConstants.DATASOURCE_BUILDIN_OPERATION_PERMISSION_ERROR;
import static com.cf.imes.module.report.enums.ErrorCodeConstants.DATASOURCE_NOT_EXISTS;
/**
* 报表数据集 Service 实现类
@@ -25,6 +32,9 @@ import static com.cf.imes.module.report.enums.ErrorCodeConstants.DATASET_NOT_EXI
@Service
@Validated
public class ReportDatasetServiceImpl implements ReportDatasetService {
@Resource
private ReportDatasourceMapper reportDatasourceMapper;
@Resource
private ReportDatasetMapper datasetMapper;
@@ -32,6 +42,8 @@ public class ReportDatasetServiceImpl implements ReportDatasetService {
public Long createDataset(ReportDatasetSaveReqVO createReqVO) {
// 插入
ReportDatasetDO dataset = BeanUtils.toBean(createReqVO, ReportDatasetDO.class);
// 校验内置模板操作权限
validateSystemDataset(createReqVO.getDatasourceId());
datasetMapper.insert(dataset);
// 返回
return dataset.getId();
@@ -49,6 +61,8 @@ public class ReportDatasetServiceImpl implements ReportDatasetService {
public void updateDataset(ReportDatasetSaveReqVO updateReqVO) {
// 校验存在
validateDatasetExists(updateReqVO.getId());
// 校验内置模板操作权限
validateSystemDataset(updateReqVO.getDatasourceId());
// 更新
ReportDatasetDO updateObj = BeanUtils.toBean(updateReqVO, ReportDatasetDO.class);
datasetMapper.updateById(updateObj);
@@ -65,14 +79,35 @@ public class ReportDatasetServiceImpl implements ReportDatasetService {
@Override
public void deleteDataset(Long id) {
// 校验存在
validateDatasetExists(id);
ReportDatasetDO reportDatasetDO = validateDatasetExists(id);
// 校验内置模板操作权限
validateSystemDataset(reportDatasetDO.getDatasourceId());
// 删除
datasetMapper.deleteById(id);
}
private void validateDatasetExists(Long id) {
if (datasetMapper.selectById(id) == null) {
private ReportDatasetDO validateDatasetExists(Long id) {
ReportDatasetDO reportDatasetDO = datasetMapper.selectById(id);
if (ObjectUtil.isNull(reportDatasetDO)) {
throw exception(DATASET_NOT_EXISTS);
} else {
return reportDatasetDO;
}
}
/**
* 校验只有超管可以操作内置数据源
*
* @param datasourceId 数据源id
*/
private void validateSystemDataset(Long datasourceId) {
ReportDatasourceDO reportDatasourceDO = reportDatasourceMapper.selectById(datasourceId);
if (ObjectUtil.isNull(reportDatasourceDO)) {
throw exception(DATASOURCE_NOT_EXISTS);
}
// 非超管不能操作内置模板
if (ReportTemplateTypeEnum.SYSTEM.equals(reportDatasourceDO.getBuildinType()) && Boolean.FALSE.equals(SecurityFrameworkUtils.isSuperAdmin())) {
throw exception(DATASOURCE_BUILDIN_OPERATION_PERMISSION_ERROR);
}
}
@@ -53,7 +53,7 @@ public interface ReportDatasourceService {
* @param reqVO 查询参数
* @return 报表数据源分页
*/
List<ReportDatasourceDO> getTemplateDatasourceList(ReportDatasourceReqVO reqVO);
List<ReportDatasourceDO> getDatasourceList();
/**
* 获取springbean数据源列表
@@ -4,6 +4,7 @@ import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils;
import com.bstek.common.exception.ReportDesignException;
import com.bstek.common.utils.MultipleJdbcTemplate;
@@ -17,17 +18,18 @@ import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.organ.core.aop.OrganIgnore;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.report.controller.admin.dataset.vo.ReportDatasetReqVO;
import com.cf.imes.module.report.controller.admin.dataset.vo.ReportDatasetSaveReqVO;
import com.cf.imes.module.report.controller.admin.datasource.vo.ReportBeanDatasourceRespVO;
import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasourceReqVO;
import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasourceSaveReqVO;
import com.cf.imes.module.report.dal.dataobject.dataset.ReportDatasetDO;
import com.cf.imes.module.report.dal.dataobject.datasource.ReportDatasourceDO;
import com.cf.imes.module.report.dal.mysql.dataset.ReportDatasetMapper;
import com.cf.imes.module.report.dal.mysql.datasource.ReportDatasourceMapper;
import com.cf.imes.module.report.dal.mysql.template.ReportTemplateMapper;
import com.cf.imes.module.report.enums.template.ReportTemplateTypeEnum;
import com.cf.imes.module.report.framework.ureport.annotation.CfReportSpringbeanDatasource;
import com.cf.imes.module.report.service.dataset.ReportDatasetService;
@@ -92,6 +94,8 @@ public class ReportDatasourceServiceImpl implements ReportDatasourceService {
@Override
public Long createDatasource(ReportDatasourceSaveReqVO createReqVO) {
ReportDatasourceDO datasource = BeanUtils.toBean(createReqVO, ReportDatasourceDO.class);
// 校验内置数据源操作权限
validateSystemDatasource(createReqVO.getBuildinType());
// 插入
datasourceMapper.insert(datasource);
// 返回
@@ -102,6 +106,8 @@ public class ReportDatasourceServiceImpl implements ReportDatasourceService {
public void updateDatasource(ReportDatasourceSaveReqVO updateReqVO) {
// 校验存在
validateDatasourceExists(updateReqVO.getId());
// 校验内置数据源操作权限
validateSystemDatasource(updateReqVO.getBuildinType());
ReportDatasourceDO updateObj = BeanUtils.toBean(updateReqVO, ReportDatasourceDO.class);
// 更新
datasourceMapper.updateById(updateObj);
@@ -111,7 +117,9 @@ public class ReportDatasourceServiceImpl implements ReportDatasourceService {
@Override
public void deleteDatasource(Long id) {
// 校验存在
validateDatasourceExists(id);
ReportDatasourceDO reportDatasourceDO = validateDatasourceExists(id);
// 校验内置数据源操作权限
validateSystemDatasource(reportDatasourceDO.getBuildinType().getType());
// 删除
datasourceMapper.deleteById(id);
// 删除关联数据集
@@ -127,17 +135,25 @@ public class ReportDatasourceServiceImpl implements ReportDatasourceService {
}
@Override
public List<ReportDatasourceDO> getTemplateDatasourceList(ReportDatasourceReqVO reqVO) {
List<ReportDatasourceDO> reportDatasourceDOS = datasourceMapper.selectList(new LambdaQueryWrapperX<ReportDatasourceDO>()
.eqIfPresent(ReportDatasourceDO::getTemplateId, reqVO.getTemplateId())
.likeIfPresent(ReportDatasourceDO::getName, reqVO.getName())
.orderByDesc(ReportDatasourceDO::getCreateTime));
@OrganIgnore
public List<ReportDatasourceDO> getDatasourceList() {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
LambdaQueryWrapper<ReportDatasourceDO> queryWrapper = new LambdaQueryWrapperX<ReportDatasourceDO>().orderByDesc(ReportDatasourceDO::getCreateTime);
if (ObjectUtil.isNotNull(loginUser) && Boolean.FALSE.equals(loginUser.getIsSupAdmin())) {
// 普通用户查看机构下的和system数据源
queryWrapper.or(wrapper -> wrapper
.eq(ReportDatasourceDO::getOrganId, loginUser.getOrganId())
.eq(ReportDatasourceDO::getType, ReportTemplateTypeEnum.CUSTOM))
.or(wrapper -> wrapper.eq(ReportDatasourceDO::getType, ReportTemplateTypeEnum.SYSTEM));
}
List<ReportDatasourceDO> reportDatasourceDOS = datasourceMapper.selectList(queryWrapper);
// 查询数据集
if (CollUtil.isNotEmpty(reportDatasourceDOS)) {
reportDatasourceDOS.forEach(reportDatasourceDO -> {
queryDatasetInSource(reportDatasourceDO);
});
}
// 超管查看全部
return reportDatasourceDOS;
}
@@ -288,34 +304,34 @@ public class ReportDatasourceServiceImpl implements ReportDatasourceService {
@Override
public void saveBuildinDatasources(List<ReportDatasourceSaveReqVO> buildinDatasources) {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
boolean isSuperAdmin = loginUser != null && loginUser.getIsSupAdmin();
// 非超管不能操作内置模板
if (!isSuperAdmin) {
throw exception(DATASOURCE_BUILDIN_OPERATION_PERMISSION_ERROR);
}
// 全删内置数据源
int deleteNum = datasourceMapper.physicsDeleteBuildinDatasource();
log.info("[ReportDatasourceService][saveBuildinDatasources]删除内置数据源{}条", deleteNum);
buildinDatasources.forEach(ds -> {
// 新增数据源
ds.setBuildinType(ReportTemplateTypeEnum.SYSTEM.getType());
ds.setId(null);
Long datasourceId = createDatasource(ds);
List<ReportDatasetSaveReqVO> datasets = ds.getDatasets();
List<ReportDatasetSaveReqVO> batchInsertDataset = new ArrayList<>();
datasets.forEach(dataset -> {
// 新增数据集
dataset.setDatasourceId(datasourceId);
dataset.setId(null);
batchInsertDataset.add(dataset);
});
// 批量插入数据集
if (CollUtil.isNotEmpty(batchInsertDataset)) {
datasetService.batchCreateDataset(batchInsertDataset);
}
});
// LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
// boolean isSuperAdmin = loginUser != null && loginUser.getIsSupAdmin();
// // 非超管不能操作内置模板
// if (!isSuperAdmin) {
// throw exception(DATASOURCE_BUILDIN_OPERATION_PERMISSION_ERROR);
// }
// // 全删内置数据源
// int deleteNum = datasourceMapper.physicsDeleteBuildinDatasource();
// log.info("[ReportDatasourceService][saveBuildinDatasources]删除内置数据源{}条", deleteNum);
// buildinDatasources.forEach(ds -> {
// // 新增数据源
// ds.setBuildinType(ReportTemplateTypeEnum.SYSTEM.getType());
// ds.setId(null);
// Long datasourceId = createDatasource(ds);
// List<ReportDatasetSaveReqVO> datasets = ds.getDatasets();
// List<ReportDatasetSaveReqVO> batchInsertDataset = new ArrayList<>();
// datasets.forEach(dataset -> {
// // 新增数据集
// dataset.setDatasourceId(datasourceId);
// dataset.setId(null);
// batchInsertDataset.add(dataset);
// });
//
// // 批量插入数据集
// if (CollUtil.isNotEmpty(batchInsertDataset)) {
// datasetService.batchCreateDataset(batchInsertDataset);
// }
// });
}
/**
@@ -334,11 +350,26 @@ public class ReportDatasourceServiceImpl implements ReportDatasourceService {
/**
* 校验数据源是否存在
*
* @param id
* @param id 数据源id
*/
private void validateDatasourceExists(Long id) {
if (datasourceMapper.selectById(id) == null) {
private ReportDatasourceDO validateDatasourceExists(Long id) {
ReportDatasourceDO reportDatasourceDO = datasourceMapper.selectById(id);
if (reportDatasourceDO == null) {
throw exception(DATASOURCE_NOT_EXISTS);
} else {
return reportDatasourceDO;
}
}
/**
* 校验只有超管可以操作内置数据源
*
* @param buildinType 内置数据源类型
*/
private void validateSystemDatasource(Integer buildinType) {
// 非超管不能操作内置模板
if (ReportTemplateTypeEnum.SYSTEM.getType().equals(buildinType) && Boolean.FALSE.equals(SecurityFrameworkUtils.isSuperAdmin())) {
throw exception(DATASOURCE_BUILDIN_OPERATION_PERMISSION_ERROR);
}
}
}
@@ -28,17 +28,12 @@ import com.bstek.ureport.export.html.HtmlReport;
import com.bstek.ureport.model.Report;
import com.bstek.ureport.parser.ReportParser;
import com.bstek.ureport.utils.ToolUtils;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.organ.core.aop.OrganIgnore;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.report.api.template.dto.ReportTemplateGenerateReqDTO;
import com.cf.imes.module.report.controller.admin.dataset.vo.ReportDatasetReqVO;
import com.cf.imes.module.report.controller.admin.dataset.vo.ReportDatasetSaveReqVO;
import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasourceReqVO;
import com.cf.imes.module.report.controller.admin.datasource.vo.ReportDatasourceSaveReqVO;
import com.cf.imes.module.report.controller.admin.template.vo.ReportTemplateReqVO;
import com.cf.imes.module.report.controller.admin.template.vo.ReportTemplateSaveReqVO;
import com.cf.imes.module.report.dal.dataobject.dataset.ReportDatasetDO;
@@ -67,9 +62,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.module.report.enums.ErrorCodeConstants.TEMPLATE_BUILDIN_OPERATION_PERMISSION_ERROR;
import static com.cf.imes.module.report.enums.ErrorCodeConstants.TEMPLATE_NAME_UNIQE_ERROR;
import static com.cf.imes.module.report.enums.ErrorCodeConstants.TEMPLATE_NOT_EXISTS;
/**
@@ -84,21 +81,20 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
@Resource
private ReportTemplateMapper templateMapper;
@Resource
private ReportDatasourceService datasourceService;
@Resource
private ReportDatasetService datasetService;
@Resource
private ReportDatasourceMapper datasourceMapper;
@Resource
private ReportDatasetMapper datasetMapper;
private static final String UTF8_CHARSET = CharsetUtil.UTF_8;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createReportTemplate(ReportTemplateSaveReqVO createReqVO) {
boolean isSuperAdmin = SecurityFrameworkUtils.isSuperAdmin();
// 校验模板名唯一性
validateTemplateNameUnique(createReqVO, isSuperAdmin);
// url解码xml
String content = createReqVO.getContent();
if (StringUtils.isNotEmpty(content)) {
@@ -107,8 +103,6 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
// 新增模板
ReportTemplateDO template = BeanUtils.toBean(createReqVO, ReportTemplateDO.class);
// 超管创建的作为内置模板
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
boolean isSuperAdmin = loginUser != null && loginUser.getIsSupAdmin();
if (isSuperAdmin) {
template.setType(ReportTemplateTypeEnum.SYSTEM);
} else {
@@ -116,8 +110,6 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
}
templateMapper.insert(template);
Long templateId = template.getId();
// 解析数据源
analyzeDatasource(createReqVO.getDatasource(), templateId);
// 返回主键
return templateId;
}
@@ -125,98 +117,37 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
@Override
@Transactional(rollbackFor = Exception.class)
public Long copyReportTemplate(ReportTemplateSaveReqVO createReqVO) {
boolean isSuperAdmin = SecurityFrameworkUtils.isSuperAdmin();
Long templateId = createReqVO.getId();
// 校验存在
ReportTemplateDO reportTemplateDO = validateTemplateExists(templateId);
// 校验模板名唯一性
validateTemplateNameUnique(createReqVO, isSuperAdmin);
// 校验内置模板操作权限
validateSystemTemplate(reportTemplateDO);
ReportTemplateDO copyTemplateDO = BeanUtils.toBean(reportTemplateDO, ReportTemplateDO.class);
// 重置id
copyTemplateDO.setId(null);
copyTemplateDO.setName(createReqVO.getName());
// 超管创建的作为内置模板
if (isSuperAdmin) {
copyTemplateDO.setType(ReportTemplateTypeEnum.SYSTEM);
} else {
copyTemplateDO.setType(ReportTemplateTypeEnum.CUSTOM);
}
// 新增模版
templateMapper.insert(copyTemplateDO);
Long newtemplateId = copyTemplateDO.getId();
// 复制datasource、dataset
List<ReportDatasourceDO> templateDatasourceList = datasourceService.getTemplateDatasourceList(ReportDatasourceReqVO.builder().templateId(templateId).build());
List<ReportDatasourceSaveReqVO> copyDatasourceList = new ArrayList<>();
// 遍历数据源
templateDatasourceList.forEach(ds -> {
ReportDatasourceSaveReqVO copyDatasourceSaveReqVO = JsonUtils.parseObject(JsonUtils.toJsonString(ds), ReportDatasourceSaveReqVO.class);
copyDatasourceSaveReqVO.setId(null);
copyDatasourceSaveReqVO.setTemplateId(newtemplateId);
List<ReportDatasetDO> templateDatasetList = ds.getDatasets();
// 遍历数据集
if (CollUtil.isNotEmpty(templateDatasetList)) {
List<ReportDatasetSaveReqVO> copyDatasetList = new ArrayList<>();
templateDatasetList.forEach(dt -> {
ReportDatasetSaveReqVO copyDatasetSaveReqVO = BeanUtils.toBean(dt, ReportDatasetSaveReqVO.class);
copyDatasetSaveReqVO.setId(null);
copyDatasetSaveReqVO.setDatasourceId(null);
copyDatasetList.add(copyDatasetSaveReqVO);
});
copyDatasourceSaveReqVO.setDatasets(copyDatasetList);
}
copyDatasourceList.add(copyDatasourceSaveReqVO);
});
// 更新数据源
analyzeDatasource(copyDatasourceList, newtemplateId);
// 返回主键
return newtemplateId;
}
/**
* 解析数据源集合并入库
*
* @param datasource 数据源列表
* @param templateId 模板id
*/
private void analyzeDatasource(List<ReportDatasourceSaveReqVO> datasource, Long templateId) {
if (CollUtil.isEmpty(datasource)) {
return;
}
datasource.forEach(ds -> {
// 更新/新增数据源
Long datasourceId;
if (ObjectUtil.isNotNull(ds.getId())) {
datasourceId = ds.getId();
datasourceService.updateDatasource(ds);
} else {
ds.setTemplateId(templateId);
datasourceId = datasourceService.createDatasource(ds);
}
List<ReportDatasetSaveReqVO> datasets = ds.getDatasets();
List<ReportDatasetSaveReqVO> batchInsertDataset = new ArrayList<>();
List<ReportDatasetSaveReqVO> batchupdateDataset = new ArrayList<>();
datasets.forEach(dataset -> {
// 更新/新增数据集
if (ObjectUtil.isNotNull(dataset.getId())) {
batchupdateDataset.add(dataset);
} else {
dataset.setDatasourceId(datasourceId);
batchInsertDataset.add(dataset);
}
});
// 批量插入数据集
if (CollUtil.isNotEmpty(batchInsertDataset)) {
datasetService.batchCreateDataset(batchInsertDataset);
}
// 批量更新数据集
if (CollUtil.isNotEmpty(batchupdateDataset)) {
datasetService.batchUpdateDataset(batchupdateDataset);
}
});
return copyTemplateDO.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateReportTemplate(ReportTemplateSaveReqVO updateReqVO) {
Long templateId = updateReqVO.getId();
// 校验存在
ReportTemplateDO reportTemplateDO = validateTemplateExists(templateId);
// 校验模板名唯一性
validateTemplateNameUnique(updateReqVO, SecurityFrameworkUtils.isSuperAdmin());
// 校验内置模板操作权限
validateSystemTemplate(reportTemplateDO);
// url解码xml
@@ -227,13 +158,9 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
// 更新模板
ReportTemplateDO updateObj = BeanUtils.toBean(updateReqVO, ReportTemplateDO.class);
templateMapper.updateById(updateObj);
// 更新数据源
analyzeDatasource(updateReqVO.getDatasource(), templateId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteReportTemplate(Long id) {
// 校验存在
ReportTemplateDO reportTemplateDO = validateTemplateExists(id);
@@ -241,15 +168,6 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
validateSystemTemplate(reportTemplateDO);
// 删除
templateMapper.deleteById(id);
// 删除关联数据源
List<ReportDatasourceDO> reportDatasourceDOS = datasourceMapper.selectList(new LambdaQueryWrapperX<ReportDatasourceDO>().eq(ReportDatasourceDO::getTemplateId, id));
if (CollUtil.isNotEmpty(reportDatasourceDOS)) {
// 模板下的数据源id
List<Long> datasourceIds = reportDatasourceDOS.stream().map(ReportDatasourceDO::getId).toList();
datasourceMapper.deleteBatchIds(datasourceIds);
// 删除关联数据集
datasetMapper.delete(new LambdaQueryWrapperX<ReportDatasetDO>().in(ReportDatasetDO::getDatasourceId, datasourceIds));
}
}
@@ -257,8 +175,7 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
* 校验只有超管可以操作内置模板
*/
private void validateSystemTemplate(ReportTemplateDO templateDO) {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
boolean isSuperAdmin = loginUser != null && loginUser.getIsSupAdmin();
boolean isSuperAdmin = SecurityFrameworkUtils.isSuperAdmin();
// 非超管不能操作内置模板
if (ReportTemplateTypeEnum.SYSTEM.equals(templateDO.getType()) && !isSuperAdmin) {
throw exception(TEMPLATE_BUILDIN_OPERATION_PERMISSION_ERROR);
@@ -279,22 +196,32 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
}
}
/**
* 校验唯一性约束
*
* @param reqVO
*/
private void validateTemplateNameUnique(ReportTemplateSaveReqVO reqVO, boolean isSuperAdmin) {
Long templateId = reqVO.getId();
String name = reqVO.getName();
LambdaQueryWrapper<ReportTemplateDO> wrapper = new LambdaQueryWrapperX<ReportTemplateDO>().eq(ReportTemplateDO::getName, name);
if (ObjectUtil.isNotNull(templateId)) {
wrapper.ne(ReportTemplateDO::getId, templateId);
}
if (isSuperAdmin) {
wrapper.eq(ReportTemplateDO::getType, ReportTemplateTypeEnum.SYSTEM);
}
if (templateMapper.exists(wrapper)) {
throw exception(TEMPLATE_NAME_UNIQE_ERROR, name);
}
}
@Override
public ReportTemplateDO getReportTemplate(Long id) {
// 校验模板
validateTemplateExists(id);
// 查询模板
ReportTemplateDO template = templateMapper.selectById(id);
if (ObjectUtil.isNotNull(template)) {
// 查询数据源
List<ReportDatasourceDO> datasourceList = datasourceService.getTemplateDatasourceList(ReportDatasourceReqVO.builder().templateId(template.getId()).build());
datasourceList.forEach(ds -> {
// 查询数据集
List<ReportDatasetDO> datasetList = datasetService.getDatasetList(ReportDatasetReqVO.builder().datasourceId(ds.getId()).build());
ds.setDatasets(datasetList);
});
template.setDatasource(datasourceList);
}
return template;
}
@@ -314,7 +241,7 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
// 解析xml
ReportDefinition reportDefinition = new ReportParser().parse(is, template.getName());
if (ObjectUtil.isNotNull(template)) {
queryDatasource(template.getId(), reportDefinition);
queryDatasource(template, reportDefinition);
}
return new ReportDefinitionWrapper(reportDefinition);
}
@@ -322,38 +249,55 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
/**
* 查询数据源信息(替代ureport xml中的数据源)
*
* @param templateId 模板id
* @param templateDO 模板
* @param reportDefinition 报表定义
*/
private void queryDatasource(Long templateId, ReportDefinition reportDefinition) {
private void queryDatasource(ReportTemplateDO templateDO, ReportDefinition reportDefinition) {
Set<Long> datasourceIds = templateDO.getDatasourceIds();
Set<Long> datasetIds = templateDO.getDatasetIds();
List<ReportDatasourceDO> reportDatasourceDOS = new ArrayList<>();
if (CollUtil.isNotEmpty(datasourceIds)) {
// 查询模板下的数据源
reportDatasourceDOS = datasourceMapper.selectList(new LambdaQueryWrapperX<ReportDatasourceDO>().in(ReportDatasourceDO::getId, datasourceIds));
}
List<ReportDatasetDO> reportDatasetDOS = new ArrayList<>();
if (CollUtil.isNotEmpty(datasetIds)) {
// 查询模板下的数据集
reportDatasetDOS = datasetMapper.selectList(new LambdaQueryWrapperX<ReportDatasetDO>().in(ReportDatasetDO::getId, datasetIds));
}
// 转换ureport对象后的数据源列表
List<DatasourceDefinition> datasourceDefinitions = new ArrayList<>();
// 查询数据源
List<ReportDatasourceDO> datasourceList = datasourceService.getTemplateDatasourceList(ReportDatasourceReqVO.builder().templateId(templateId).build());
for (ReportDatasourceDO ds : datasourceList) {
// 查询数据集
List<ReportDatasetDO> datasetList = datasetService.getDatasetList(ReportDatasetReqVO.builder().datasourceId(ds.getId()).build());
// 遍历列表转换为ureport对象
for (ReportDatasourceDO ds : reportDatasourceDOS) {
// 转换ureport对象后的数据集列表
List<DatasetDefinition> datasetDefinitions = new ArrayList<>();
// 匹配数据源下的数据集
List<ReportDatasetDO> datasetInDatasourceList = reportDatasetDOS.stream().filter(reportDatasetDO -> ds.getId().equals(reportDatasetDO.getDatasourceId())).toList();
// 忽略转换的字段名,手动转列表
String ignorePropertieName = "datasets";
switch (ds.getType()) {
case JDBC -> {
// 转换对应的ureport对象
JdbcDatasourceDefinition jdbcDatasourceDefinition = BeanUtil.copyProperties(ds, JdbcDatasourceDefinition.class, ignorePropertieName);
datasetDefinitions.addAll(BeanUtils.toBean(datasetList, SqlDatasetDefinition.class));
datasetDefinitions.addAll(BeanUtils.toBean(datasetInDatasourceList, SqlDatasetDefinition.class));
jdbcDatasourceDefinition.setDatasets(datasetDefinitions);
datasourceDefinitions.add(jdbcDatasourceDefinition);
}
case SPRING -> {
// 转换对应的ureport对象
SpringBeanDatasourceDefinition springBeanDatasourceDefinition = BeanUtil.copyProperties(ds, SpringBeanDatasourceDefinition.class, ignorePropertieName);
datasetDefinitions.addAll(BeanUtils.toBean(datasetList, BeanDatasetDefinition.class));
datasetDefinitions.addAll(BeanUtils.toBean(datasetInDatasourceList, BeanDatasetDefinition.class));
springBeanDatasourceDefinition.setDatasets(datasetDefinitions);
datasourceDefinitions.add(springBeanDatasourceDefinition);
}
case API -> {
// 转换对应的ureport对象
ApiDatasourceDefinition apiDatasourceDefinition = BeanUtil.copyProperties(ds, ApiDatasourceDefinition.class, ignorePropertieName);
datasetDefinitions.addAll(BeanUtils.toBean(datasetList, ApiDatasetDefinition.class));
datasetDefinitions.addAll(BeanUtils.toBean(datasetInDatasourceList, ApiDatasetDefinition.class));
apiDatasourceDefinition.setDatasets(datasetDefinitions);
datasourceDefinitions.add(apiDatasourceDefinition);
}
@@ -370,7 +314,7 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
.orderByDesc(ReportTemplateDO::getCreateTime)
// 不返回content xml,点击具体的模板中返回xml
.select(ReportTemplateDO::getId, ReportTemplateDO::getName, ReportTemplateDO::getCreateTime, ReportTemplateDO::getRemark);
if (loginUser != null && Boolean.FALSE.equals(loginUser.getIsSupAdmin())) {
if (ObjectUtil.isNotNull(loginUser) && Boolean.FALSE.equals(loginUser.getIsSupAdmin())) {
// 普通用户查看机构下的和system模板
queryWrapper.or(wrapper -> wrapper
.eq(ReportTemplateDO::getOrganId, loginUser.getOrganId())
@@ -401,12 +345,12 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
report.setChartImages(chartImages);
try {
OutputStream out = response.getOutputStream();
response.setCharacterEncoding("UTF-8");
response.setCharacterEncoding(UTF8_CHARSET);
response.setContentType("application/pdf; charset=UTF-8");
// 创建下载文件
ProducerEnum p = ProducerEnum.PDF;
String downFileName = com.bstek.common.utils.StringUtils.randomFileName() + com.bstek.common.utils.StringUtils.getFileSuffix(p);
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(downFileName, "UTF-8"));
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(downFileName, UTF8_CHARSET));
response.setHeader("code", "20000");
ExportUtils.export(out, report, p);
long end = System.currentTimeMillis();
@@ -425,12 +369,12 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
report.setChartImages(chartImages);
try {
OutputStream out = response.getOutputStream();
response.setCharacterEncoding("UTF-8");
response.setCharacterEncoding(UTF8_CHARSET);
response.setContentType("application/octet-stream; charset=UTF-8");
// 创建下载文件
ProducerEnum p = ProducerEnum.valueOf(type.toUpperCase());
String downFileName = com.bstek.common.utils.StringUtils.randomFileName() + com.bstek.common.utils.StringUtils.getFileSuffix(p);
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(downFileName, "UTF-8"));
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(downFileName, UTF8_CHARSET));
response.setHeader("code", "20000");
long start = System.currentTimeMillis();
ExportUtils.export(out, report, p);
@@ -485,7 +429,7 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
// 解析xml
ReportDefinition reportDefinition = reportRender.getReportDefinition(xmlContent, CharsetUtil.UTF_8);
// 查询数据源
queryDatasource(template.getId(), reportDefinition);
queryDatasource(template, reportDefinition);
// 设置参数
PreviewParameters previewParameters = new PreviewParameters();
previewParameters.setQuery(reqDTO.getParams());
@@ -30,7 +30,6 @@ public abstract class ReportCommonServiceImplTest {
.name("单元测试模板")
.content(JsonUtil.zipString(TEMPLATE))
.remark(RandomUtils.randomString())
.datasource(new ArrayList<>())
.build();
}
@@ -39,14 +38,12 @@ public abstract class ReportCommonServiceImplTest {
return ReportDatasourceSaveReqVO.builder()
.id(id)
.name("单元测试数据源")
.templateId(reportId)
.type(ReportDatasourceTypeEnum.SPRING.getDesc())
.driver("com.mysql.cj.jdbc.Driver")
.url("jdbc:mysql://192.168.1.205:3307/imes_base?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true")
.username("root")
.password("root")
.remark(RandomUtils.randomString())
.datasets(new ArrayList<>())
.build();
}
@@ -70,7 +70,7 @@ public class ReportDatasourceServiceImplTest extends ReportCommonServiceImplTest
reqVO.setTemplateId(templateId);
reqVO.setType(ReportDatasourceTypeEnum.JDBC.getCode());
reqVO.setName(updateReqVO.getName());
List<ReportDatasourceDO> templateDatasourceList = reportDatasourceService.getTemplateDatasourceList(reqVO);
List<ReportDatasourceDO> templateDatasourceList = reportDatasourceService.getDatasourceList();
assertNotNull(templateDatasourceList);
assertNotEquals(0, templateDatasourceList.size());