Merge branch 'main' of ssh://192.168.1.205:9922/cf_devdept2/cf_imes_server

This commit is contained in:
lym
2024-07-26 11:18:46 +08:00
10 changed files with 68 additions and 117 deletions
@@ -11,16 +11,16 @@ import com.cf.imes.framework.common.exception.ErrorCode;
public final class ErrorCodeConstants {
// ========== UREPORT template模块 1-003-001-000 ==========
public static ErrorCode TEMPLATE_NOT_EXISTS = new ErrorCode(1_003_001_001, "报表模板信息不存在");
public static final ErrorCode TEMPLATE_NOT_EXISTS = new ErrorCode(1_003_001_001, "报表模板信息不存在");
// ========== UREPORT datasource模块 1-003-002-000 ==========
public static ErrorCode DATASOURCE_NOT_EXISTS = new ErrorCode(1_003_002_001, "报表数据源不存在");
public static ErrorCode DATASOURCE_CONNECT_FAIL = new ErrorCode(1_003_002_001, "报表数据源连接失败");
public static final ErrorCode DATASOURCE_NOT_EXISTS = new ErrorCode(1_003_002_001, "报表数据源不存在");
public static final ErrorCode DATASOURCE_CONNECT_FAIL = new ErrorCode(1_003_002_001, "报表数据源连接失败");
// ========== UREPORT dataset模块 1-003-003-000 ==========
public static ErrorCode DATASET_NOT_EXISTS = new ErrorCode(1_003_003_001, "报表数据集不存在");
public static ErrorCode DATASET_SQL_INJECTION_RISK = new ErrorCode(1_003_003_002, "存在SQL注入风险");
public static ErrorCode DATASET_SQL_REQUIRED = new ErrorCode(1_003_003_003, "SQL语句不能为空");
public static ErrorCode DATASET_SQL_ILLEGAL = new ErrorCode(1_003_003_004, "SQL语句非法");
public static ErrorCode DATASET_GET_FIELDS_ERROR = new ErrorCode(1_003_003_005, "获取表字段");
public static final ErrorCode DATASET_NOT_EXISTS = new ErrorCode(1_003_003_001, "报表数据集不存在");
public static final ErrorCode DATASET_SQL_INJECTION_RISK = new ErrorCode(1_003_003_002, "存在SQL注入风险");
public static final ErrorCode DATASET_SQL_REQUIRED = new ErrorCode(1_003_003_003, "SQL语句不能为空");
public static final ErrorCode DATASET_SQL_ILLEGAL = new ErrorCode(1_003_003_004, "SQL语句非法");
public static final ErrorCode DATASET_GET_FIELDS_ERROR = new ErrorCode(1_003_003_005, "获取表字段");
}
@@ -18,11 +18,11 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
@@ -43,7 +43,7 @@ import static com.cf.imes.framework.common.pojo.CommonResult.success;
@Validated
@Slf4j
public class ReportTemplateController {
@Autowired
@Resource
private ReportTemplateService templateService;
@PutMapping("/template")
@@ -1,29 +0,0 @@
package com.cf.imes.module.report.framework.ureport.bean;
import com.cf.imes.module.report.framework.ureport.annotation.CfReportSpringbeanDatasource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Gqr
* @since 2024/7/11 17:15
*/
@CfReportSpringbeanDatasource(value = "MockBeanDatasource", name = "模拟bean数据源")
public class MockBeanDatasource {
public List<Map<String, Object>> mockList(String dsName, String datasetName, Map<String, Object> parameters) {
List<Map<String, Object>> testList = new ArrayList<>();
testList.add(new HashMap<String, Object>() {{
put("a", "11111");
put("b", "一一一一一一");
}});
testList.add(new HashMap<String, Object>() {{
put("a", "22222");
put("b", "二二二二二二");
}});
return testList;
}
}
@@ -44,6 +44,7 @@ public class OrderSummaryBeanDatasource {
* @return
*/
public List<Map<String, Object>> orderInfo(String dsName, String datasetName, Map<String, Object> parameters) {
log.info("报表数据源[OrderSummaryBeanDatasource][orderInfo][{}][{}]调用开始", dsName, datasetName);
List<Map<String, Object>> resultList = new ArrayList<>();
Object orderId = parameters.get(ORDER_ID_FIELD_NAME);
@@ -57,20 +58,20 @@ public class OrderSummaryBeanDatasource {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
if (orderDTO != null) {
// 把orderInfo转map并put到resultList中
resultList.add(new HashMap<>() {{
// 构造报表所需结构
put(ORDER_ID_FIELD_NAME, orderDTO.getId());
put("customOrderNo", orderDTO.getCustomOrderNo());
put("dealer", orderDTO.getDealer());
LocalDateTime orderDate = orderDTO.getOrderDate();
put("orderDate", ObjectUtil.isNotNull(orderDate) ? formatter.format(orderDate) : null);
LocalDateTime deliveryDate = orderDTO.getDeliveryDate();
put("deliveryDate", ObjectUtil.isNotNull(deliveryDate) ? formatter.format(deliveryDate) : null);
put("customer", orderDTO.getCustomer());
put("phoneNumber", orderDTO.getPhoneNumber());
}});
HashMap<String, Object> resultMap = new HashMap<>();
// 构造报表所需结构
resultMap.put(ORDER_ID_FIELD_NAME, orderDTO.getId());
resultMap.put("customOrderNo", orderDTO.getCustomOrderNo());
resultMap.put("dealer", orderDTO.getDealer());
LocalDateTime orderDate = orderDTO.getOrderDate();
resultMap.put("orderDate", ObjectUtil.isNotNull(orderDate) ? formatter.format(orderDate) : null);
LocalDateTime deliveryDate = orderDTO.getDeliveryDate();
resultMap.put("deliveryDate", ObjectUtil.isNotNull(deliveryDate) ? formatter.format(deliveryDate) : null);
resultMap.put("customer", orderDTO.getCustomer());
resultMap.put("phoneNumber", orderDTO.getPhoneNumber());
resultList.add(resultMap);
}
log.info("报表数据源[OrderSummaryBeanDatasource][orderInfo][{}][{}]调用结束", dsName, datasetName);
return resultList;
}
@@ -83,6 +84,7 @@ public class OrderSummaryBeanDatasource {
* @return
*/
public List<Map<String, Object>> orderPlateSummaryByPlate(String dsName, String datasetName, Map<String, Object> parameters) {
log.info("报表数据源[OrderSummaryBeanDatasource][orderPlateSummaryByPlate][{}][{}]调用开始", dsName, datasetName);
List<Map<String, Object>> resultList = new ArrayList<>();
Object orderId = parameters.get(ORDER_ID_FIELD_NAME);
@@ -92,24 +94,25 @@ public class OrderSummaryBeanDatasource {
if (CollUtil.isNotEmpty(plateGoodsRespDTOS)) {
plateGoodsRespDTOS.forEach(p -> {
resultList.add(new HashMap<>() {{
BigDecimal area = p.getArea();
Integer count = p.getCount();
// 构造报表所需结构
put("roomName", p.getRoomName());
put("bodyName", p.getBodyName());
put("thickness", p.getThickness());
put("name", p.getName());
put("height", p.getHeight());
put("width", p.getWidth());
put("count", count);
put("area", area);
put("openDoorType", p.getOpenDoorType());
put("remark", p.getRemark());
put("areaAll", area.multiply(BigDecimal.valueOf(count)));
}});
Map<String, Object> resultMap = new HashMap<>();
BigDecimal area = p.getArea();
Integer count = p.getCount();
// 构造报表所需结构
resultMap.put("roomName", p.getRoomName());
resultMap.put("bodyName", p.getBodyName());
resultMap.put("thickness", p.getThickness());
resultMap.put("name", p.getName());
resultMap.put("height", p.getHeight());
resultMap.put("width", p.getWidth());
resultMap.put("count", count);
resultMap.put("area", area);
resultMap.put("openDoorType", p.getOpenDoorType());
resultMap.put("remark", p.getRemark());
resultMap.put("areaAll", area.multiply(BigDecimal.valueOf(count)));
resultList.add(resultMap);
});
}
log.info("报表数据源[OrderSummaryBeanDatasource][orderPlateSummaryByPlate][{}][{}]调用结束", dsName, datasetName);
return resultList;
}
}
@@ -31,21 +31,22 @@ public class CfReportSpringbeanRegistrar implements ImportBeanDefinitionRegistra
Set<BeanDefinition> candidates = scanner.findCandidateComponents("com.cf.imes.module.report.framework.ureport.bean");
for (BeanDefinition candidate : candidates) {
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition beanDef = (AnnotatedBeanDefinition) candidate;
Map<String, Object> attributes = beanDef.getMetadata().getAnnotationAttributes(CfReportSpringbeanDatasource.class.getName());
if (attributes != null) {
// 校验注解上的value
String value = (String) attributes.get("value");
if (!StringUtils.hasText(value)) {
throw new IllegalArgumentException("@CfReportSpringbean requires a non-empty 'value' attribute.");
}
// 校验注解上的name
String name = (String) attributes.get("name");
if (!StringUtils.hasText(name)) {
throw new IllegalArgumentException("@CfReportSpringbean requires a non-empty 'name' attribute.");
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(candidate.getBeanClassName());
AnnotatedBeanDefinition beanDef = (AnnotatedBeanDefinition) candidate;
Map<String, Object> attributes = beanDef.getMetadata().getAnnotationAttributes(CfReportSpringbeanDatasource.class.getName());
if (attributes != null) {
// 校验注解上的value
String value = (String) attributes.get("value");
if (!StringUtils.hasText(value)) {
throw new IllegalArgumentException("@CfReportSpringbean requires a non-empty 'value' attribute.");
}
// 校验注解上的name
String name = (String) attributes.get("name");
if (!StringUtils.hasText(name)) {
throw new IllegalArgumentException("@CfReportSpringbean requires a non-empty 'name' attribute.");
}
String beanClassName = candidate.getBeanClassName();
if (StringUtils.hasText(beanClassName)) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClassName);
registry.registerBeanDefinition(value, builder.getBeanDefinition());
}
}
@@ -2,6 +2,7 @@ package com.cf.imes.module.report.service.datasource;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils;
import com.bstek.ureport.definition.dataset.Field;
import com.bstek.ureport.definition.dataset.Parameter;
import com.bstek.ureport.definition.dataset.SqlDatasetDefinition;
@@ -222,13 +223,14 @@ public class ReportDatasourceServiceImpl implements ReportDatasourceService {
}
// 获取数据库连接
conn = buildConn(reqVO);
// 校验sql
// 自定义工具校验sql
if (SqlInjectionUtil.checkEditSql(sql)) {
throw exception(DATASET_SQL_ILLEGAL);
}
// 检查参数sql注入
for (ReportDatasetParameterVO parameterVO : parameters) {
if (SqlInjectionUtil.checkParam(parameterVO.getDefaultValue())) {
// mybatis-plus util检查参数
if (SqlInjectionUtils.check(parameterVO.getDefaultValue())) {
throw exception(DATASET_SQL_INJECTION_RISK);
}
}
@@ -16,12 +16,6 @@ public class SqlInjectionUtil {
private static final Pattern SQL_EDIT_PATTERN = Pattern.compile("(insert|delete|update|create|drop|truncate|grant|alter|deny|revoke|call|execute|exec|declare|show|rename|set)" +
"\\s+.*(into|from|set|where|table|database|view|index|on|cursor|procedure|trigger|for|password|union|and|or)", Pattern.CASE_INSENSITIVE);
/**
* SQL语法检查正则:符合两个关键字(有先后顺序)才算匹配
*/
private static final Pattern SQL_SYNTAX_PATTERN = Pattern.compile("(insert|delete|update|select|create|drop|truncate|grant|alter|deny|revoke|call|execute|exec|declare|show|rename|set)" +
"\\s+.*(into|from|set|where|table|database|view|index|on|cursor|procedure|trigger|for|password|union|and|or)|(select\\s*\\*\\s*from\\s+)|(and|or)\\s+.*(like|=|>|<|in|between|is|not|exists)", Pattern.CASE_INSENSITIVE);
/**
* 使用'、;或注释截断SQL检查正则
*/
@@ -38,26 +32,6 @@ public class SqlInjectionUtil {
return SQL_COMMENT_PATTERN.matcher(sql).find() || SQL_EDIT_PATTERN.matcher(sql).find();
}
/**
* 检查参数是否存在 SQL 注入
*
* @param value 检查参数
* @return true 非法 false 合法
*/
public static boolean checkParam(String value) {
Objects.requireNonNull(value);
// 处理是否包含SQL注释字符 || 检查是否包含SQL注入敏感字符
return SQL_COMMENT_PATTERN.matcher(value).find() || SQL_SYNTAX_PATTERN.matcher(value).find();
}
/**
* 刪除字段转义符单引号双引号
*
* @param text 待处理字段
* @return
*/
public static String removeEscapeCharacter(String text) {
Objects.nonNull(text);
return text.replace("\"", "").replace("'", "");
private SqlInjectionUtil() {
}
}
@@ -88,7 +88,7 @@ public class ReportDatasetServiceImplTest extends ReportCommonServiceImplTest{
List<ReportDatasetDO> datasetList = reportDatasetService.getDatasetList(reqVO);
assertNotNull(datasetList);
assertNotEquals(datasetList.size(), 0);
assertNotEquals(0, datasetList.size());
// 删除
reportTemplateService.deleteReportTemplate(templateId);
@@ -73,7 +73,7 @@ public class ReportDatasourceServiceImplTest extends ReportCommonServiceImplTest
List<ReportDatasourceDO> templateDatasourceList = reportDatasourceService.getTemplateDatasourceList(reqVO);
assertNotNull(templateDatasourceList);
assertNotEquals(templateDatasourceList.size(),0);
assertNotEquals(0, templateDatasourceList.size());
// 删除
reportTemplateService.deleteReportTemplate(templateId);
@@ -44,7 +44,7 @@ public class ReportTemplateServiceImplTest extends ReportCommonServiceImplTest {
String templateUnZip = template.getContent();
System.out.println("从库中读取template大小:" + templateUnZip.length());
// 校验解压内容是否正确
assertEquals(JsonUtil.unzipString(templateUnZip),TEMPLATE);
assertEquals(TEMPLATE, JsonUtil.unzipString(templateUnZip));
// 删除
reportTemplateService.deleteReportTemplate(templateId);
}
@@ -120,8 +120,8 @@ public class ReportTemplateServiceImplTest extends ReportCommonServiceImplTest {
List<ReportTemplateDO> reportTemplateList = reportTemplateService.getReportTemplateList(reqVO);
assertNotNull(reportTemplateList);
assertNotEquals(reportTemplateList.size(),0);
assertEquals(reportTemplateList.get(0).getOrganId(),2L);
assertNotEquals(0, reportTemplateList.size());
assertEquals(2L, reportTemplateList.get(0).getOrganId());
// 删除
reportTemplateService.deleteReportTemplate(templateId);