创建文件、文件下载以及发送邮件附件功能(超详细注解)

版权声明:本文为博主原创文章,未经博主允许不得转载。 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"开始读取;

猜你喜欢

转载自blog.csdn.net/Steriles_/article/details/82286818