版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Steriles_/article/details/82286818
根据模板生成文件
@Override
public File exportStuFileExcelNew(Studengt student, Page<StuFile> page)throws Exception{
//获取当前系统时间
LocalDate today = LocalDate.now();
//打印日志报告------->根据模板生成文件
logger.info("=============>正在生成企业档案报告");
//读取模板路径(E:\workspace\test\demo\target\classes\template\test.xls)
//this.getClass().getResource是得到当前对象对应的类文件(*.class)所在的目录下的文件。
String excelPath = this.getClass().getResource("/").getPath()+"template/test.xls";
//创建工作簿对象
Workbook workbook = null;
try {
//把设定好的路径下的.xls的数据表读到workbook里
workbook = new HSSFWorkbook(new FileInputStream(new File(excelPath)));
}catch (Exception ex){
logger.info("============>.xls文件创建出错",ex);
}
//设置单元格样式
CellStyle style = workbook.createCellStyle();
//单元格居中
style.setAlignment(CellStyle.ALIGN_CENTER);
//获取当前工作表序号
Sheet sheet = workbook.getSheetAt(0);
//设置行、单元格
Row row = null;
Cell cell = null;
//根据条件查询,获取结果
//传入参数为相关对象和导出的工作表页数
Map<String, Object> map = this.findByInformation(student, page);
Page<StuFile> page1 = (Page<StuFile>) map.get("page");
List<StuFile> studentList = page1.getResults();
//判断查询结果是否为空
if(CollectionUtils.isNotEmpty(studentList)){
//遍历查询出来的数据条数
for (int i = 0,length = studentList.size(); i < length; i++) {
//获取某学生的各种信息
StuFile stu = studentList.get(i);
StuFileOverView overView = new StuFileOverView();
//设置学生唯一标识ID
overView.setEid(stu.getEid());
//由唯一标识去查询其他表中关联的学生信息
StuFileOverView stuFileOverView = stuFileOverViewService.getByEid(overView);
//作为判断条件,查询所得结果是否为空
boolean flag = entFileOverView == null ? false : true;
//行数加1,因为已经存在作为注解的第一行了
row = sheet.createRow(i+1);
//创建新的单元格,插入学生姓名信息
Cell cell0 = row.createCell(0);
//判断查询出来的结果是否为空,不为空则插入单元格
if(StringUtils.isNotBlank(stu.getStuName())){
cell0.setCellValue(stu.getStuName());
}
//创建下一个新的单元格,插入学生学号
Cell cell1 = row.createCell(1);
//判断查询出来的结果是否为空,不为空则插入单元格
if(StringUtils.isNotBlank(ent.getStuCode())){
cell1.setCellValue(ent.getStuCode());
}
}
}
//读取properties文件中的配置信息,即插入所有数据之后形成excel文件后保存的路径
String dirPath = ReadConfig.UPLOAD_PATH;
//.xls文件的路径
String filePath = dirPath +"学生数据信息"+".xls";
//先用File类打开本地文件,实例化输出流,然后调用流的读写方法写入数据,最后关闭流
File file1 = new File(filePath);
//应用输出流FileOutputStream把数据写入本地文件
FileOutputStream fout = FileUtils.openOutputStream(file1);
//用workbook对象是因为之前把---模板.xls---的数据表读到workbook里面了
workbook.write(fout);
fout.close();
return file1;
}
此段仅仅介绍由模板创建新的文件并写入相关查询所得数据,其中用到的有关查询方法的代码细则就不贴了。
根据ftl模板发送邮件及邮件附件
/**
* 根据ftl模板发送邮件
*
* @param toEmail 收件人邮箱地址,多个地址用英文逗号(,)隔开
* @param sendEmailType 邮件类型
* @param path 附件路径
*/
public void sendEmailWithAttachment(Map<String, Object> map,String toEmail, SendEmailType sendEmailType, String path) {
//创建一个线程,完成异步调用
Thread th = new Thread(() -> {
//新建一个MimeMessage对象,该类是个能理解MIME类型和头的电子邮件消息
MimeMessage msg;
try {
//MimeMessages为复杂邮件模板,支持文本、附件、html、图片等。
msg = mailSender.createMimeMessage();
//创建MimeMessageHelper对象,处理MimeMessage的辅助类
//true表示是否为multiparty邮件,ENCODING表示MimeMessage的编码内容的字符集
MimeMessageHelper helper = new MimeMessageHelper(msg, true, ENCODING);
//使用辅助类MimeMessage设定参数:发件人邮箱
helper.setFrom(Config.FROM_EMAIL);
//收件人邮箱地址,多个地址用英文逗号(,)隔开
String[] toEmails = toEmail.split(",");
//设置收件人地址
helper.setTo(toEmails);
//设置邮件标题,sendEmailType.getSubject()获取邮件标题类型
//ENCODING表示编码内容的字符集
//"B"表示为目标编码格式,Base64的编码方式(加密)
helper.setSubject(MimeUtility.encodeText(sendEmailType.getSubject(), ENCODING, "B"));
//sendEmailType.getModelName()获取邮件模板的名称
// true表示text的内容为html
helper.setText(getMailText(map,sendEmailType.getModelName()), true);
// 这里的方法调用和插入图片是不同的,解决附件名称的中文问题
File file = new File(path);
//给附件重命名,不会影响本地下载好的文件的名称
File newNameFile =new File("企业数据信息.xls");
//添加附件文件,newNameFile.getName()新的文件名称,file为传入参数path路径下的文件
helper.addAttachment(MimeUtility.encodeWord(newNameFile.getName()), file);
//发送邮件
mailSender.send(msg);
logger.info("邮件发送成功,主题为:" + sendEmailType.getSubject() + " >>> 邮件模板为:" + sendEmailType.getModelName() + ";参数为:" + JsonUtil.toJsonString(map));
} catch (Exception e) {
logger.error("邮件发送失败,主题为:" + sendEmailType.getSubject() + " >>> 邮件模板为:" + sendEmailType.getModelName() + ";参数为:" + JsonUtil.toJsonString(map) + ";" + e);
}
});
th.start();
}
/**
* 构造邮件,map中的参数将替换ftl对应参数的值
*
* @return modelName 邮件模板名称(包括后缀)
* @throws Exception 异常抛出
*/
private String getMailText(Map<String, Object> map, String modelName) throws Exception {
// 通过指定模板名获取FreeMarker模板实例
Template template = freeMarkerConfigurer.getConfiguration().getTemplate(modelName);
// 解析模板并替换动态数据,最终content将替换模板文件中的${content}标签。
return FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
}
//下面这两个方法要在spring中配置
public void setMailSender(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public void setFreeMarkerConfigurer(FreeMarkerConfigurer freeMarkerConfigurer) {
this.freeMarkerConfigurer = freeMarkerConfigurer;
}
}
有关spring-email.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="freeMarkerConfigurer"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="classpath:template" /> <!-- 指定模板文件目录 -->
<property name="freemarkerSettings"><!-- 设置FreeMarker环境属性 -->
<props>
<prop key="template_update_delay">1800</prop> <!--刷新模板的周期,单位为秒 -->
<prop key="default_encoding">UTF-8</prop> <!--模板的编码格式 -->
<prop key="locale">zh_CN</prop> <!--本地化设置 -->
</props>
</property>
<property name="freemarkerVariables">
<map>
<entry key="webRoot" value="${webRoot}"></entry><!-- 模板中图片访问路径,一般是http://localhost:8080 -->
</map>
</property>
</bean>
<!-- 注意:这里的参数(如用户名、密码)都是针对邮件发送者的 -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${regist.email.host}"/> <!-- 服务器 -->
<property name="port" value="${regist.email.port}"/> <!-- 一般情况下都为25 -->
<property name="protocol" value="smtp"/>
<property name="username" value="${regist.email.username}"/> <!-- 发送者用户名 -->
<property name="password" value="${regist.email.password}"/><!-- 发送者密码 -->
<property name="defaultEncoding" value="UTF-8"/>
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.timeout">1800</prop>
</props>
</property>
</bean>
<bean id="emailService" class="com.test.demo.service.SendEmailService">
<property name="mailSender" ref="mailSender"></property>
<property name="freeMarkerConfigurer" ref="freeMarkerConfigurer"></property>
</bean>
</beans>
邮件模板:先创建html格式文件,然后重命名为 .ftl 后缀名
模板中插入的图片放在项目里,然后通过url去访问,不然在邮件中是看不到图片的。当然也可以放在服务器里,就需要另一种方式了。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style type="text/css">
body {
color: #333;
}
p a {
text-decoration:none;
}
.content2 {
margin-left: 20px;
margin-bottom: 20px;
margin-top: 180px;
}
.text-indent-2em {
text-indent: 2em;
}
</style>
</head>
<body>
<div style="width: 800px; height: 350px; margin-left: auto; margin-right: auto; border: 1px solid #e5e5e5;">
<div style="width: 100%; height: 110px;">
<table style="width: 100%;">
<tr>
<img alt="发送邮件" style="width: 800px; "src="${webRoot}/dist/images/email.png"/>
</tr>
</table>
</div>
<div style="margin: 0 0px 0 0px;">
<p class="content2" style="margin-top: 60px;font-size: 25PX; margin-left: 120px;">您好,附件请注意查收。 </p>
</div>
</div>
</body>
</html>
文件下载
/**
* 学生档案列表导出
* @param student
* @param page
* @param response
* @return
*/
@RequestMapping(value = "exportStuFileExcelNew",method = RequestMethod.GET)
@ResponseBody
public ResponseWrapper exportStuFileExcelNew(Student student, Page<EntFile> page, HttpServletResponse response){
//创建邮件发送的对象
EmailSendInformation emailSendInformation = new EmailSendInformation();
/*
原功能为文件由浏览器下载,现在改为邮箱直接发送文件
//设置导出的数量,即excel中sheet的页面数
page.setPageNum(1);
//设置excel文件数据导出数量上限
page.setPageSize(Integer.parseInt(WebConfig.STUFILE_EXPORT_NUM));
//map中放入参数
Map<String, Object> map = new HashMap<>();
map.put("exportDate","发送附件");
try {
//把信息插入文件模板,生成新的文件
//这里调用了开头的方法
File file = stuFileService.exportStuFileExcelNew(student, page);
//输入流
FileInputStream stream = new FileInputStream(file);
response.setCharacterEncoding("utf-8");
//使用Content-Type来表示具体请求中的媒体类型信息。
response.setContentType("multipart/form-data");
//response.setContentType("application/vnd.ms-excel");
String fileName = new String(file.getName().getBytes("gb2312"), "ISO8859-1");
response.setHeader("Content-Disposition", "attachment; fileName=" + fileName);
//输出流,
OutputStream os = response.getOutputStream();
//2048是保证数组的容量
byte[] b = new byte[2048];
int length;
//接受屏幕输入,存入b数组,同时将读取的个数赋值给length
//stream.read()从输入流中都去一定数量的字节,并将其存储在缓冲区数组b中
//以整数形式返回实际读取的字节数
while ((length = stream.read(b)) > 0){
//参数b,源缓冲区被写入到流
//参数0,开始在数据偏移,指b数据中偏移量
//参数length,字节写数
//write方法会一次从b数组中写入length个长度的b[i]值
os.write(b,0,length);
}
*/
//获取相对路径下的文件作为邮件附件发送
emailService.sendEmailWithAttachment(map,"此处填写收件人邮箱地址", SendEmailType.EXPORT_DATA,file.getPath());
logger.info("=============>学生档案导出成功");
return ResponseWrapper.markSuccess("导出成功");
}catch (Exception ex){
logger.info("=============>学生档案导出失败",ex);
return ResponseWrapper.markError("导出失败");
}
}
其中提到的数据偏移是指,像"abcdefg"这一字符串,index标好序列的话,依次是0、1、2、3、4、5、6,那么数据偏移数字为3的话,就是从字符"d"开始读取;偏移数字为0的话,就是从字符"a"开始读取;