From 01b3ad05d84d25ff241c59f0b18351c17ed87003 Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Fri, 8 Jul 2022 04:52:26 -0400 Subject: [PATCH] =?UTF-8?q?feat(=E7=B3=BB=E7=BB=9F=E7=AE=A1=E7=90=86):=20?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E6=8A=A5=E5=91=8A=E5=A2=9E=E5=8A=A0=E5=8F=91?= =?UTF-8?q?=E9=80=81=E8=A7=86=E5=9B=BE=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commons/model/excel/ExcelSheetModel.java | 16 ++ .../io/dataease/commons/utils/ExcelUtils.java | 59 ++++++++ .../strategy/impl/EmailTaskHandler.java | 12 +- .../strategy/impl/EmailTaskViewHandler.java | 63 ++++++++ .../service/chart/ViewExportExcel.java | 139 ++++++++++++++++++ .../dataease/service/system/EmailService.java | 50 +++++++ .../resources/i18n/messages_en_US.properties | 8 +- .../resources/i18n/messages_zh_CN.properties | 5 + .../resources/i18n/messages_zh_TW.properties | 8 +- 9 files changed, 352 insertions(+), 8 deletions(-) create mode 100644 backend/src/main/java/io/dataease/commons/model/excel/ExcelSheetModel.java create mode 100644 backend/src/main/java/io/dataease/commons/utils/ExcelUtils.java create mode 100644 backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskViewHandler.java create mode 100644 backend/src/main/java/io/dataease/service/chart/ViewExportExcel.java diff --git a/backend/src/main/java/io/dataease/commons/model/excel/ExcelSheetModel.java b/backend/src/main/java/io/dataease/commons/model/excel/ExcelSheetModel.java new file mode 100644 index 0000000000..0e2a1d6401 --- /dev/null +++ b/backend/src/main/java/io/dataease/commons/model/excel/ExcelSheetModel.java @@ -0,0 +1,16 @@ +package io.dataease.commons.model.excel; + +import java.util.List; + +import lombok.Data; + +@Data +public class ExcelSheetModel { + + private String sheetName; + + private List heads; + + private List> datas; + +} diff --git a/backend/src/main/java/io/dataease/commons/utils/ExcelUtils.java b/backend/src/main/java/io/dataease/commons/utils/ExcelUtils.java new file mode 100644 index 0000000000..b6a911baf3 --- /dev/null +++ b/backend/src/main/java/io/dataease/commons/utils/ExcelUtils.java @@ -0,0 +1,59 @@ +package io.dataease.commons.utils; + +import java.io.File; +import io.dataease.commons.model.excel.ExcelSheetModel; +import java.util.List; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.IndexedColors; + +import cn.hutool.core.util.IdUtil; + +public class ExcelUtils { + + public static File exportExcel(List sheets) throws Exception { + String fastUUID = IdUtil.fastUUID(); + File result = new File("/opt/dataease/data/" + fastUUID + ".xls"); + HSSFWorkbook wb = new HSSFWorkbook(); + sheets.forEach(sheet -> { + List> details = sheet.getDatas(); + details.add(0, sheet.getHeads()); + HSSFSheet curSheet = wb.createSheet(sheet.getSheetName()); + CellStyle cellStyle = wb.createCellStyle(); + Font font = wb.createFont(); + font.setFontHeightInPoints((short) 12); + font.setBold(true); + cellStyle.setFont(font); + cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + if (CollectionUtils.isNotEmpty(details)) { + for (int i = 0; i < details.size(); i++) { + HSSFRow row = curSheet.createRow(i); + List rowData = details.get(i); + if (rowData != null) { + for (int j = 0; j < rowData.size(); j++) { + HSSFCell cell = row.createCell(j); + cell.setCellValue(rowData.get(j)); + if (i == 0) {// 头部 + cell.setCellStyle(cellStyle); + // 设置列的宽度 + curSheet.setColumnWidth(j, 255 * 20); + } + } + } + } + } + }); + wb.write(result); + return result; + } + +} diff --git a/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskHandler.java b/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskHandler.java index 6f75180583..1ad73bee3d 100644 --- a/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskHandler.java +++ b/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskHandler.java @@ -28,7 +28,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; -@Service +@Service("emailTaskHandler") public class EmailTaskHandler extends TaskHandler implements Job { private static final Integer RUNING = 0; @@ -50,8 +50,8 @@ public class EmailTaskHandler extends TaskHandler implements Job { return jobDataMap; } - public EmailTaskHandler proxy() { - return CommonBeanFactory.getBean(EmailTaskHandler.class); + public EmailTaskHandler proxy(String handlerName) { + return (EmailTaskHandler) CommonBeanFactory.getBean(handlerName); } @Override @@ -86,7 +86,7 @@ public class EmailTaskHandler extends TaskHandler implements Job { XpackEmailTemplateDTO emailTemplate = (XpackEmailTemplateDTO) jobDataMap.get("emailTemplate"); SysUserEntity creator = (SysUserEntity) jobDataMap.get("creator"); LogUtil.info("start execute send panel report task..."); - proxy().sendReport(taskInstance, emailTemplate, creator); + proxy(taskEntity.getTaskType()).sendReport(taskInstance, emailTemplate, creator); } @@ -109,14 +109,14 @@ public class EmailTaskHandler extends TaskHandler implements Job { return taskInstance; } - private void success(GlobalTaskInstance taskInstance) { + protected void success(GlobalTaskInstance taskInstance) { taskInstance.setStatus(SUCCESS); taskInstance.setFinishTime(System.currentTimeMillis()); EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class); emailXpackService.saveInstance(taskInstance); } - private void error(GlobalTaskInstance taskInstance, Throwable t) { + protected void error(GlobalTaskInstance taskInstance, Throwable t) { taskInstance.setStatus(ERROR); taskInstance.setInfo(t.getMessage()); EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class); diff --git a/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskViewHandler.java b/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskViewHandler.java new file mode 100644 index 0000000000..902399c751 --- /dev/null +++ b/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/EmailTaskViewHandler.java @@ -0,0 +1,63 @@ +package io.dataease.job.sechedule.strategy.impl; + +import io.dataease.auth.entity.SysUserEntity; +import io.dataease.commons.utils.CronUtils; +import io.dataease.commons.utils.LogUtil; +import io.dataease.dto.PermissionProxy; +import io.dataease.plugins.common.entity.GlobalTaskInstance; +import io.dataease.plugins.config.SpringContextUtil; +import io.dataease.plugins.xpack.email.dto.request.XpackEmailTaskRequest; +import io.dataease.plugins.xpack.email.dto.response.XpackEmailTemplateDTO; +import io.dataease.plugins.xpack.email.service.EmailXpackService; +import io.dataease.service.chart.ViewExportExcel; +import io.dataease.service.system.EmailService; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.File; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Service("emailTaskViewHandler") +public class EmailTaskViewHandler extends EmailTaskHandler { + + @Resource + private ViewExportExcel viewExportExcel; + + @Async("priorityExecutor") + public void sendReport(GlobalTaskInstance taskInstance, XpackEmailTemplateDTO emailTemplateDTO, + SysUserEntity user) { + EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class); + try { + XpackEmailTaskRequest taskForm = emailXpackService.taskForm(taskInstance.getTaskId()); + if (ObjectUtils.isEmpty(taskForm) || CronUtils.taskExpire(taskForm.getEndTime())) { + return; + } + String panelId = emailTemplateDTO.getPanelId(); + + // 下面继续执行发送邮件的 + byte[] content = emailTemplateDTO.getContent(); + EmailService emailService = SpringContextUtil.getBean(EmailService.class); + + String contentStr = ""; + if (ObjectUtils.isNotEmpty(content)) { + contentStr = new String(content, "UTF-8"); + } + String viewIds = emailTemplateDTO.getPixel(); + List viewIdList = Arrays.asList(viewIds.split(",")).stream().map(s -> (s.trim())) + .collect(Collectors.toList()); + PermissionProxy proxy = new PermissionProxy(); + proxy.setUserId(user.getUserId()); + List files = viewExportExcel.export(panelId, viewIdList, proxy); + emailService.sendWithFiles(emailTemplateDTO.getRecipients(), emailTemplateDTO.getTitle(), contentStr, + files); + success(taskInstance); + } catch (Exception e) { + error(taskInstance, e); + LogUtil.error(e.getMessage(), e); + } + } +} diff --git a/backend/src/main/java/io/dataease/service/chart/ViewExportExcel.java b/backend/src/main/java/io/dataease/service/chart/ViewExportExcel.java new file mode 100644 index 0000000000..15dcf608fc --- /dev/null +++ b/backend/src/main/java/io/dataease/service/chart/ViewExportExcel.java @@ -0,0 +1,139 @@ +package io.dataease.service.chart; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import com.google.gson.Gson; + +import io.dataease.auth.annotation.DePermissionProxy; +import io.dataease.commons.exception.DEException; +import io.dataease.commons.model.excel.ExcelSheetModel; +import io.dataease.commons.utils.ExcelUtils; +import io.dataease.commons.utils.LogUtil; +import io.dataease.controller.request.chart.ChartExtRequest; +import io.dataease.dto.PermissionProxy; +import io.dataease.dto.chart.ChartViewDTO; +import io.dataease.dto.panel.PanelGroupDTO; +import io.dataease.plugins.common.dto.chart.ChartViewFieldDTO; +import io.dataease.plugins.common.request.chart.ChartExtFilterRequest; +import io.dataease.plugins.config.SpringContextUtil; +import io.dataease.service.panel.PanelGroupService; + +import java.io.File; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.google.gson.reflect.TypeToken; + +@Service +public class ViewExportExcel { + + private final static Gson gson = new Gson(); + private Type tokenType = new TypeToken>>() { + }.getType(); + + @DePermissionProxy(paramIndex = 2) + public List export(String panelId, List viewIds, PermissionProxy proxy) throws Exception { + PanelGroupService panelGroupService = SpringContextUtil.getBean(PanelGroupService.class); + + PanelGroupDTO panelDto = panelGroupService.findOne(panelId); + String componentsJson = panelDto.getPanelData(); + List> components = gson.fromJson(componentsJson, tokenType); + ChartExtRequest chartExtRequest = buildViewRequest(componentsFilter(components, "custom", null, null)); + List results = new ArrayList<>(); + List sheets = viewIds.stream().map(viewId -> viewFiles(viewId, chartExtRequest)) + .collect(Collectors.toList()); + + File excelFile = ExcelUtils.exportExcel(sheets); + results.add(excelFile); + return results; + } + + private List> componentsFilter(List> components, String type, + String componentType, String serviceName) { + return components.stream().filter(component -> { + String ctype = component.get("type").toString(); + String cComponentType = component.get("component").toString(); + String cServiceName = Optional.ofNullable(component.get("serviceName")).orElse("").toString(); + + boolean typeMatch = true; + boolean componentTypeMatch = true; + boolean serviceNameMatch = true; + + if (StringUtils.isNotBlank(type)) { + typeMatch = StringUtils.equals(type, ctype); + } + + if (StringUtils.isNotBlank(componentType)) { + componentTypeMatch = StringUtils.equals(componentType, cComponentType); + } + + if (StringUtils.isNotBlank(serviceName)) { + serviceNameMatch = StringUtils.equals(serviceName, cServiceName); + } + + return typeMatch && componentTypeMatch && serviceNameMatch; + + }).collect(Collectors.toList()); + + } + + private ChartExtRequest buildViewRequest(List> filters) { + ChartExtRequest chartExtRequest = new ChartExtRequest(); + filters = Optional.ofNullable(filters).orElse(new ArrayList<>()); + + List panelFilters = filters.stream().map(item -> { + ChartExtFilterRequest curentFilter = new ChartExtFilterRequest(); + return curentFilter; + }).collect(Collectors.toList()); + + chartExtRequest.setQueryFrom("panel"); + chartExtRequest.setFilter(panelFilters); + return chartExtRequest; + } + + private ExcelSheetModel viewFiles(String viewId, ChartExtRequest request) { + ExcelSheetModel result = new ExcelSheetModel(); + ChartViewDTO chartViewDTO = null; + try { + ChartViewService chartViewService = SpringContextUtil.getBean(ChartViewService.class); + chartViewDTO = chartViewService.getData(viewId, request); + } catch (Exception e) { + LogUtil.error(e.getMessage()); + DEException.throwException(e); + } + String title = Optional.ofNullable(chartViewDTO.getTitle()).orElse(chartViewDTO.getName()); + Map chart = chartViewDTO.getData(); + + Object objectFields = chart.get("fields"); + List fields = (List) objectFields; + List heads = new ArrayList<>(); + List headKeys = new ArrayList<>(); + fields.forEach(field -> { + if (ObjectUtils.isNotEmpty(field.getName()) && ObjectUtils.isNotEmpty(field.getDataeaseName())) { + heads.add(field.getName()); + headKeys.add(field.getDataeaseName()); + } + }); + + Object objectTableRow = chart.get("tableRow"); + List> tableRow = (List>) objectTableRow; + + List> details = tableRow.stream().map(row -> headKeys.stream().map(key -> { + Object val = row.get(key); + if (ObjectUtils.isEmpty(val)) + return StringUtils.EMPTY; + return val.toString(); + }).collect(Collectors.toList())).collect(Collectors.toList()); + result.setHeads(heads); + result.setDatas(details); + + result.setSheetName(title); + return result; + } +} diff --git a/backend/src/main/java/io/dataease/service/system/EmailService.java b/backend/src/main/java/io/dataease/service/system/EmailService.java index 005afb33c8..845d2c94b8 100644 --- a/backend/src/main/java/io/dataease/service/system/EmailService.java +++ b/backend/src/main/java/io/dataease/service/system/EmailService.java @@ -16,14 +16,19 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; +import org.springframework.util.Assert; + import javax.activation.DataHandler; +import javax.activation.FileDataSource; import javax.annotation.Resource; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; +import javax.mail.internet.MimeUtility; import javax.mail.util.ByteArrayDataSource; +import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Properties; @@ -58,6 +63,7 @@ public class EmailService { if (StringUtils.isBlank(to)) return; MailInfo mailInfo = proxy().mailInfo(); + checkMailInfo(mailInfo); JavaMailSenderImpl driver = driver(mailInfo); MimeMessage mimeMessage = driver.createMimeMessage(); @@ -75,10 +81,45 @@ public class EmailService { } } + public void sendWithFiles(String to, String title, String content, List files) { + if (StringUtils.isBlank(to)) + return; + MailInfo mailInfo = proxy().mailInfo(); + checkMailInfo(mailInfo); + JavaMailSenderImpl driver = driver(mailInfo); + MimeMessage mimeMessage = driver.createMimeMessage(); + String uuid = UUID.randomUUID().toString(); + MimeBodyPart text = new MimeBodyPart(); + try { + text.setContent(content + "
", + "text/html; charset=gb2312"); + MimeMultipart multipart = new MimeMultipart(); + multipart.addBodyPart(text); + multipart.setSubType("related"); + for (int i = 0; i < files.size(); i++) { + File file = files.get(i); + MimeBodyPart attach = new MimeBodyPart(); + FileDataSource fileDataSource = new FileDataSource(file); + attach.setDataHandler(new DataHandler(fileDataSource)); + attach.setFileName(MimeUtility.encodeText(file.getName())); + multipart.addBodyPart(attach); + } + mimeMessage.setFrom(driver.getUsername()); + mimeMessage.setSubject(title); + mimeMessage.setRecipients(Message.RecipientType.TO, to); + mimeMessage.setContent(multipart); + driver.send(mimeMessage); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + DEException.throwException(e); + } + } + public void sendWithImage(String to, String title, String content, byte[] bytes) { if (StringUtils.isBlank(to)) return; MailInfo mailInfo = proxy().mailInfo(); + checkMailInfo(mailInfo); JavaMailSenderImpl driver = driver(mailInfo); MimeMessage mimeMessage = driver.createMimeMessage(); @@ -156,9 +197,18 @@ public class EmailService { } } } + return mailInfo; } + public void checkMailInfo(MailInfo info) { + + Assert.notNull(info, Translator.get("I18N_EMAIL_CONFIG_ERROR")); + Assert.notNull(info.getHost(), Translator.get("I18N_EMAIL_HOST_ERROR")); + Assert.notNull(info.getPort(), Translator.get("I18N_EMAIL_PORT_ERROR")); + Assert.notNull(info.getAccount(), Translator.get("I18N_EMAIL_ACCOUNT_ERROR")); + } + public List getParamList(String type) { SystemParameterExample example = new SystemParameterExample(); example.createCriteria().andParamKeyLike(type + "%"); diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties index fddd3ec241..50c40edd76 100644 --- a/backend/src/main/resources/i18n/messages_en_US.properties +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -188,4 +188,10 @@ I18N_NO_PERMISSION=You do not have permission to I18N_PLEASE_CONCAT_ADMIN=Please contact the administrator for authorization -I18N_SQL_variable_limit=SQL variables can only be used in where conditions \ No newline at end of file +I18N_SQL_variable_limit=SQL variables can only be used in where conditions + + +I18N_EMAIL_CONFIG_ERROR=Email config error +I18N_EMAIL_HOST_ERROR=Email host can not be empty +I18N_EMAIL_PORT_ERROR=Email port can not be empty +I18N_EMAIL_ACCOUNT_ERROR=Email account can not be empty \ No newline at end of file diff --git a/backend/src/main/resources/i18n/messages_zh_CN.properties b/backend/src/main/resources/i18n/messages_zh_CN.properties index 11c7975d32..85ec0db965 100644 --- a/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -192,3 +192,8 @@ I18N_NO_PERMISSION=当前用户没有权限 I18N_PLEASE_CONCAT_ADMIN=请联系管理员开通 I18N_SQL_variable_limit=SQL 变量只能在 WHERE 条件中使用 + +I18N_EMAIL_CONFIG_ERROR=邮件配置错误 +I18N_EMAIL_HOST_ERROR=邮件主机不能为空 +I18N_EMAIL_PORT_ERROR=邮件端口不能为空 +I18N_EMAIL_ACCOUNT_ERROR=邮件账号不能为空 diff --git a/backend/src/main/resources/i18n/messages_zh_TW.properties b/backend/src/main/resources/i18n/messages_zh_TW.properties index 8e34447c8a..4c0bde8941 100644 --- a/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -186,4 +186,10 @@ I18N_NO_PERMISSION=當前用戶沒有權限 I18N_PLEASE_CONCAT_ADMIN=請聯系管理員開通 -I18N_SQL_variable_limit=SQL變數只能在WHERE條件中使用 \ No newline at end of file +I18N_SQL_variable_limit=SQL變數只能在WHERE條件中使用 + + +I18N_EMAIL_CONFIG_ERROR=郵件配置錯誤 +I18N_EMAIL_HOST_ERROR=郵件主機不能為空 +I18N_EMAIL_PORT_ERROR=郵件端口不能為空 +I18N_EMAIL_ACCOUNT_ERROR=郵件賬號不能為空 \ No newline at end of file