引入依赖 javamail、jcommon、jfreechart
<javamail-version>1.8.3</javamail-version> <jcommon.version>1.0.23</jcommon.version> <jfreechart.version>1.0.17</jfreechart.version>
<dependency> <groupId>org.apache.geronimo.javamail</groupId> <artifactId>geronimo-javamail_1.4_provider</artifactId> <version>${javamail-version}</version> </dependency> <dependency> <groupId>org.jfree</groupId> <artifactId>jcommon</artifactId> <version>${jcommon.version}</version> </dependency> <dependency> <groupId>org.jfree</groupId> <artifactId>jfreechart</artifactId> <version>${jfreechart.version}</version> </dependency>
创建邮件发送模板,delay-mail.vm
<!DOCTYPE html> <html lang="zh"> <head> <META http-equiv=Content-Type content='text/html; charset=UTF-8'> <title>Title</title> <style type="text/css"> table.reference, table.tecspec { border-collapse: collapse; width: 100%; margin-bottom: 4px; margin-top: 4px; } table.reference tr:nth-child(even) { background-color: #fff; } table.reference tr:nth-child(odd) { background-color: #f6f4f0; } table.reference th { color: #fff; background-color: #555; border: 1px solid #555; font-size: 12px; padding: 3px; vertical-align: top; } table.reference td { line-height: 2em; min-width: 24px; border: 1px solid #d4d4d4; padding: 5px; padding-top: 7px; padding-bottom: 7px; vertical-align: top; } .article-body h3 { font-size: 1.8em; margin: 2px 0; line-height: 1.8em; } </style> </head> <body> <h3 style=";">滞留率分析报表</h3> <div> <table class="reference"> <tbody> <tr> <th>仓库</th> <th>初始化</th> <th>拣货中</th> <th>拣货完成</th> <th>装箱中</th> <th>装箱完成</th> <th>交接中</th> <th>交接完成</th> <th>已出库</th> <th>合计</th> <th>滞留率</th> <th>及时率</th> </tr> #foreach($element in $datas) <tr> <td> #if($element.warehouseName) $element.warehouseName #end </td> <td> #if($element.countInit) $element.countInit #end </td> <td> #if($element.countPicking) $element.countPicking #end </td> <td> #if($element.countPickFinish) $element.countPickFinish #end </td> <td> #if($element.countPacking) $element.countPacking #end </td> <td> #if($element.countPackFinish) $element.countPackFinish #end </td> <td> #if($element.countTransferring) $element.countTransferring #end </td> <td> #if($element.countTransferFinish) $element.countTransferFinish #end </td> <td> #if($element.countDelivery) $element.countDelivery #end </td> <td> #if($element.countTotal) $element.countTotal #end </td> <td> #if($element.delayRate) $element.delayRate #end </td> <td> #if($element.timelyRate) $element.timelyRate #end </td> </tr> #end </tbody> </table> <img src="$imgPath" style=" 100%"> <div style="float: left; margin-top: 300px;;"> <p>系统邮件(请勿回复) | 药品技术中心—供应链</p> </div> </div> </body> </html>
邮件工具类 MailUtil.java
package com.yyw.scs.util; import com.yyw.scs.model.Email; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.velocity.app.VelocityEngine; import org.omg.CORBA.OBJ_ADAPTER; import org.springframework.ui.velocity.VelocityEngineUtils; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.mail.*; import javax.mail.internet.*; import javax.mail.util.ByteArrayDataSource; import java.io.*; import java.util.*; public class MailUtils { private static Logger log = Logger.getLogger(MailUtils.class); public static final String HTML_CONTENT = "text/html;charset=UTF-8"; public static final String ATTACHMENT_CONTENT = "text/plain;charset=gb2312"; private static VelocityEngine velocityEngine; public <T extends List> void sendEmail(T t, String title, String[] to, String[] bcc, String templateName) { Map map = new HashMap(); map.put("datas", t); Email email = new Email.Builder(title, to, null).model(map).templateName(templateName).bcc(bcc).build(); sendEmail(email); } public <T extends List> void sendEmail(T t, String imgPath, String title, String[] to, String[] bcc, String templateName) { Map map = new HashMap(); map.put("datas", t); map.put("imgPath", imgPath); Email email = new Email.Builder(title, to, null).model(map).templateName(templateName).bcc(bcc).build(); sendEmail(email); } public <T extends List> void sendEmail(String title, String[] to, String[] bcc, String templateName, Map<String, Object> data) { Email email = new Email.Builder(title, to, null).model(data).templateName(templateName).bcc(bcc).build(); sendEmail(email); } public void sendEmail(String title, String[] to, String[] bcc, String content, byte[] data, String fileName, String fileType) { Email email = new Email.Builder(title, to, content).bcc(bcc).data(data).fileName(fileName).fileType(fileType).build(); sendEmail(email); } public <T extends List> void sendEmail(String title, String[] to, String[] bcc, String templateName, byte[] data, String fileName, String fileType, Map map) { Email email = new Email.Builder(title, to, null).model(map).templateName(templateName).bcc(bcc).data(data).fileType(fileType).fileName(fileName).build(); sendEmail(email); } public <T extends List> void sendEmail(T t, String title, String[] to, String[] bcc, String templateName, byte[] data, String fileName, String fileType) { Map map = new HashMap(); map.put("datas", t); Email email = new Email.Builder(title, to, null).model(map).templateName(templateName).bcc(bcc).data(data).fileType(fileType).fileName(fileName).build(); sendEmail(email); } public void sendEmail(String title, String[] to, String content) { Email email = new Email.Builder(title, to, content).bcc(null).build(); sendEmail(email); } public void sendEmail(String title, String[] to, String[] bcc, String content) { Email email = new Email.Builder(title, to, content).bcc(bcc).build(); sendEmail(email); } //发送html模板邮件 private void sendEmail(Email email) { Long startTime = System.currentTimeMillis(); // 发件人 try { MimeMessage message = this.getMessage(email); // 新建一个存放信件内容的BodyPart对象 Multipart multiPart = new MimeMultipart(); MimeBodyPart mdp = new MimeBodyPart(); // 给BodyPart对象设置内容和格式/编码方式 setContent(email); mdp.setContent(email.getContent(), HTML_CONTENT); multiPart.addBodyPart(mdp); // 新建一个MimeMultipart对象用来存放BodyPart对象(事实上可以存放多个) if (null != email.getData()) { MimeBodyPart attchment = new MimeBodyPart(); ByteArrayInputStream in = new ByteArrayInputStream(email.getData()); DataSource fds = new ByteArrayDataSource(in, email.getFileType()); attchment.setDataHandler(new DataHandler(fds)); attchment.setFileName(MimeUtility.encodeText(email.getFileName())); multiPart.addBodyPart(attchment); if (in != null) { in.close(); } } message.setContent(multiPart); message.saveChanges(); Transport.send(message); Long endTime = System.currentTimeMillis(); log.info("邮件发送成功 耗时:" + (endTime - startTime) / 1000 + "s"); } catch (Exception e) { log.error("Error while sending mail.", e); } } private Email setContent(Email email) { if (StringUtils.isEmpty(email.getContent())) { email.setContent(""); } if (StringUtils.isNotEmpty(email.getTemplateName()) && null != email.getModel()) { String content = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, email.getTemplateName(), "UTF-8", email.getModel()); email.setContent(content); } return email; } public void setVelocityEngine(VelocityEngine velocityEngine) { this.velocityEngine = velocityEngine; } private MimeMessage getMessage(Email email) { Properties props = new Properties(); props.put("mail.smtp.host", "10.6.8.19"); props.put("mail.smtp.auth", "true"); props.put("username", "gyl_sys"); props.put("password", "wms,123456"); // 发件人 MimeMessage message = null; try { if (email.getTo() == null || email.getTo().length == 0 || StringUtils.isEmpty(email.getSubject())) { throw new Exception("接收人或主题为空"); } InternetAddress fromAddress = new InternetAddress("gyl_sys@111.com.cn"); // toemails(字符串,多个收件人用,隔开) Session mailSession = Session.getDefaultInstance(props, new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication("gyl_sys", "wms,123456"); } }); message = new MimeMessage(mailSession); message.setFrom(fromAddress); for (String mailTo : email.getTo()) { message.addRecipient(Message.RecipientType.TO, new InternetAddress(mailTo)); } List<InternetAddress> ccAddress = new ArrayList<>(); if (null != email.getBcc()) { for (String mailCC : email.getBcc()) { ccAddress.add(new InternetAddress(mailCC)); } message.addRecipients(Message.RecipientType.CC, ccAddress.toArray(new InternetAddress[email.getBcc().length])); } message.setSentDate(new Date()); message.setSubject(email.getSubject()); } catch (Exception e) { log.error("Error while sending mail." + e.getMessage(), e); } return message; } }
绘制图表以及发送 SendDelayMailJobServiceImpl.java
package com.yyw.scs.service.impl; import com.yyw.scs.model.request.DelayResultDto; import com.yyw.scs.service.SendDelayMailJobService; import com.yyw.scs.util.DiamondScsConfig; import com.yyw.scs.util.MailUtils; import com.yyw.scs.wms.service.DelayRateService; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartUtilities; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.CategoryAxis; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.title.TextTitle; import org.jfree.data.category.CategoryDataset; import org.jfree.data.category.DefaultCategoryDataset; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.awt.*; import java.io.File; import java.io.FileOutputStream; import java.util.List; @Service("sendDelayMailJobService") public class SendDelayMailJobServiceImpl implements SendDelayMailJobService { @Autowired private MailUtils mailUtils; @Autowired private DelayRateService delayRateService; private final static Logger LOGGER = Logger.getLogger(SendDelayMailJobServiceImpl.class); @Override public Boolean send() { try { // 1. 得到数据 List<DelayResultDto> res = delayRateService.findDelayResultDtoList(null, null, null, 1); if (!CollectionUtils.isNotEmpty(res)) { LOGGER.info("SendDelayMailJobServiceImpl.send nodata:"); return null; } CategoryDataset dataset = getDataSet(res); // 2. 构造chart JFreeChart chart = ChartFactory.createBarChart3D( "仓库履约实时分析", // 图表标题 "状态", // 目录轴的显示标签--横轴 "数量", // 数值轴的显示标签--纵轴 dataset, // 数据集 PlotOrientation.VERTICAL, // 图表方向:水平、 true, // 是否显示图例(对于简单的柱状图必须 false, // 是否生成工具 false // 是否生成URL链接 ); // 3. 处理chart中文显示问题 processChart(chart); // 4. chart输出图片 // 输出到本机TOMCAT路径 // File directory = new File("."); // String path = null; // try { // path = directory.getCanonicalPath(); // } catch (IOException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // path += "\img\delay.jpg"; // 输出到本机绝对路径 String path = "/app/img/"; File file = new File(path); System.out.println(path); if (!file.exists() && !file.isDirectory()) { file.mkdir(); } path += "delay.jpg"; writeChartAsImage(chart, path); // 5. chart 以swing形式输出 // ChartFrame pieFrame = new ChartFrame("XXX", chart); // pieFrame.pack(); // pieFrame.setVisible(true); // 6.发送邮件 List<String> toList = DiamondScsConfig.getJobSendDelayToList(); if (CollectionUtils.isNotEmpty(toList)) { String[] toArr = (String[]) toList.toArray(new String[toList.size()]); mailUtils.sendEmail(res, path, "滞留率分析报表", toArr, null, "spring/email/delay-mail.vm"); } else { LOGGER.info("发送邮件: 未获取到收件人列表"); } } catch (Exception e) { LOGGER.error("SendDelayMailJobServiceImpl.send error:", e); // todo 发送报警邮件 return false; } return true; } /** * 获取一个演示用的组合数据集对象 * * @return */ private CategoryDataset getDataSet(List<DelayResultDto> res) { DefaultCategoryDataset dataset = new DefaultCategoryDataset(); for (DelayResultDto item : res) { dataset.addValue(item.getCountInit(), item.getWarehouseName(), "初始化"); dataset.addValue(item.getCountPicking(), item.getWarehouseName(), "拣货中"); dataset.addValue(item.getCountPickFinish(), item.getWarehouseName(), "拣货完成"); dataset.addValue(item.getCountPacking(), item.getWarehouseName(), "装箱中"); dataset.addValue(item.getCountPackFinish(), item.getWarehouseName(), "装箱完成"); dataset.addValue(item.getCountTransferring(), item.getWarehouseName(), "交接中"); dataset.addValue(item.getCountTransferFinish(), item.getWarehouseName(), "交接完成"); dataset.addValue(item.getCountDelivery(), item.getWarehouseName(), "已出库"); } return dataset; } private CategoryDataset getDemoDataSet() { DefaultCategoryDataset dataset = new DefaultCategoryDataset(); dataset.addValue(100, "北京", "苹果"); dataset.addValue(120, "上海", "苹果"); dataset.addValue(160, "广州", "苹果"); dataset.addValue(210, "北京", "梨子"); dataset.addValue(220, "上海", "梨子"); dataset.addValue(230, "广州", "梨子"); dataset.addValue(330, "北京", "葡萄"); dataset.addValue(340, "上海", "葡萄"); dataset.addValue(340, "广州", "葡萄"); dataset.addValue(420, "北京", "香蕉"); dataset.addValue(430, "上海", "香蕉"); dataset.addValue(400, "广州", "香蕉"); dataset.addValue(510, "北京", "荔枝"); dataset.addValue(530, "上海", "荔枝"); dataset.addValue(510, "广州", "荔枝"); return dataset; } /** * 解决图表汉字显示问题 * * @param chart */ private static void processChart(JFreeChart chart) { CategoryPlot plot = chart.getCategoryPlot(); CategoryAxis domainAxis = plot.getDomainAxis(); ValueAxis rAxis = plot.getRangeAxis(); chart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); TextTitle textTitle = chart.getTitle(); textTitle.setFont(new Font("宋体", Font.PLAIN, 20)); domainAxis.setTickLabelFont(new Font("sans-serif", Font.PLAIN, 11)); domainAxis.setLabelFont(new Font("宋体", Font.PLAIN, 12)); rAxis.setTickLabelFont(new Font("sans-serif", Font.PLAIN, 12)); rAxis.setLabelFont(new Font("宋体", Font.PLAIN, 12)); chart.getLegend().setItemFont(new Font("宋体", Font.PLAIN, 12)); // renderer.setItemLabelGenerator(new LabelGenerator(0.0)); // renderer.setItemLabelFont(new Font("宋体", Font.PLAIN, 12)); // renderer.setItemLabelsVisible(true); } /** * 输出图片 * * @param chart */ private static void writeChartAsImage(JFreeChart chart, String path) { FileOutputStream fos_jpg = null; try { fos_jpg = new FileOutputStream(path); ChartUtilities.writeChartAsJPEG(fos_jpg, 1, chart, 800, 500, null); } catch (Exception e) { e.printStackTrace(); } finally { try { fos_jpg.close(); } catch (Exception e) { } } } }
补充:如果图片不能正常显示,需要将图片写入邮件附件,并用cid读取图片进行显示
ImageMailDto.java
package com.yyw.scs.model.request; import java.io.Serializable; /** * 邮件发送图片 */ public class ImageMailDto implements Serializable { private static final long serialVersionUID = 1L; private byte[] imageData; private String imageCid; // "好好工作<img src="cid:abcd">" private String mimeType; // like image/jpeg、image/bmp、image/gif public byte[] getImageData() { return imageData; } public void setImageData(byte[] imageData) { this.imageData = imageData; } public String getImageCid() { return imageCid; } public void setImageCid(String imageCid) { this.imageCid = imageCid; } public String getMimeType() { return mimeType; } public void setMimeType(String mimeType) { this.mimeType = mimeType; } }
MailUtil.java中
/** * 发送html模板邮件 */ private void sendEmail(Email email) { Long startTime = System.currentTimeMillis(); // 发件人 try { MimeMessage message = this.getMessage(email); // 新建一个存放信件内容的BodyPart对象 Multipart multiPart = new MimeMultipart(); MimeBodyPart mdp = new MimeBodyPart(); setContent(email); // 给BodyPart对象设置内容和格式/编码方式 mdp.setContent(email.getContent(), HTML_CONTENT); // 将BodyPart加入到MimeMultipart对象中(可以加入多个BodyPart) multiPart.addBodyPart(mdp); if (null != email.getData()) { MimeBodyPart attchment = new MimeBodyPart(); ByteArrayInputStream in = new ByteArrayInputStream(email.getData()); DataSource fds = new ByteArrayDataSource(in, email.getFileType()); attchment.setDataHandler(new DataHandler(fds)); attchment.setFileName(MimeUtility.encodeText(email.getFileName())); multiPart.addBodyPart(attchment); if (in != null) { in.close(); } } // 添加图片 if (email.getImageData() != null) { for (ImageMailDto dto : email.getImageData()) { MimeBodyPart image = new MimeBodyPart(); //javamail jaf image.setDataHandler(new DataHandler(new ByteArrayDataSource(dto.getImageData(), dto.getMimeType()))); image.setContentID(dto.getImageCid()); multiPart.addBodyPart(image); } } //把multiPart作为消息对象的内容 message.setContent(multiPart); message.saveChanges(); Transport.send(message); Long endTime = System.currentTimeMillis(); log.info("邮件发送成功 耗时:" + (endTime - startTime) / 1000 + "s"); } catch (Exception e) { log.error("Error while sending mail.", e); } }
最后发送邮件
byte[] data = null; try { FileOutputStream fos_jpg = new FileOutputStream(path); ParamChecks.nullNotPermitted(fos_jpg, "out"); ParamChecks.nullNotPermitted(chart, "chart"); BufferedImage image = chart.createBufferedImage(800, 500, 1, null); data = ChartUtilities.encodeAsPNG(image); } catch (Exception e) { e.printStackTrace(); } List<String> toList = DiamondScsConfig.getJobSendDelayToList(); if (CollectionUtils.isNotEmpty(toList)) { String[] toArr = (String[]) toList.toArray(new String[toList.size()]); ImageMailDto[] imageMailDtos = new ImageMailDto[1]; ImageMailDto imageMailDto = new ImageMailDto(); imageMailDto.setImageCid("delay"); imageMailDto.setMimeType("image/png"); imageMailDto.setImageData(data); imageMailDtos[0] = imageMailDto; mailUtils.sendEmail(res, "滞留率分析报表", toArr, null, "spring/email/delay-mail.vm", imageMailDtos); } else { LOGGER.info("发送邮件: 未获取到收件人列表"); }
增加Email.java
package com.yyw.scs.model; import com.yyw.scs.model.request.ImageMailDto; import java.util.Map; public class Email { private String subject ; private String[] to; private String from = ""; private String content; // html邮件模板名称 private String templateName; private String[] bcc; private String logo; // html邮件data private Map model; // html邮件cid private String cid; private String fileName; // 附件邮件文件类型 private String fileType; // 附件byte流 private byte[] data; // 增加图片数据 private ImageMailDto[] imageData; public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String[] getTo() { return to; } public void setTo(String[] to) { this.to = to; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getTemplateName() { return templateName; } public void setTemplateName(String templateName) { this.templateName = templateName; } public String[] getBcc() { return bcc; } public void setBcc(String[] bcc) { this.bcc = bcc; } public String getLogo() { return logo; } public void setLogo(String logo) { this.logo = logo; } public Map getModel() { return model; } public void setModel(Map model) { this.model = model; } public String getCid() { return cid; } public void setCid(String cid) { this.cid = cid; } public String getFileType() { return fileType; } public void setFileType(String fileType) { this.fileType = fileType; } public byte[] getData() { return data; } public void setData(byte[] data) { this.data = data; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public ImageMailDto[] getImageData() { return imageData; } public void setImageData(ImageMailDto[] imageData) { this.imageData = imageData; } public static class Builder{ private String subject ; private String[] to; private String from = ""; private String content; // html邮件模板名称 private String templateName; private String[] bcc; private String logo; // html邮件data private Map model; // html邮件cid private String cid; private String fileName; // 附件邮件文件类型 private String fileType; //附件byte流 private byte[] data; // 增加图片数据 private ImageMailDto[] imageData; public Builder(final String subject, final String[] to, final String content) { this.subject = subject; this.to = to; this.content = content; } public Builder(final String subject, final String[] to, final String content, final ImageMailDto[] imageData) { this.subject = subject; this.to = to; this.content = content; this.imageData = imageData; } public Builder subject(String subject) { this.subject = subject; return this; } public Builder to(String[] to) { this.to = to; return this; } public Builder from(String from) { this.from = from; return this; } public Builder content(String content) { this.content = content; return this; } public Builder templateName(String templateName) { this.templateName = templateName; return this; } public Builder bcc(String[] bcc) { this.bcc = bcc; return this; } public Builder logo(String logo) { this.logo = logo; return this; } public Builder model(Map model) { this.model = model; return this; } public Builder cid(String cid) { this.cid = cid; return this; } public Builder fileName(String fileName) { this.fileName = fileName; return this; } public Builder fileType(String fileType) { this.fileType = fileType; return this; } public Builder data(byte[] data) { this.data = data; return this; } public Builder imageData(ImageMailDto[] imageData) { this.imageData = imageData; return this; } public Email build(){ return new Email(this); } } private Email(Builder b) { this.subject = b.subject; this.to = b.to; this.from = b.from; this.content = b.content; this.templateName = b.templateName; this.bcc = b.bcc; this.logo = b.logo; this.model = b.model; this.cid = b.cid; this.fileName = b.fileName; this.fileType = b.fileType; this.data = b.data; this.imageData = b.imageData; } }