项目实战之网络电话本之发送邮件名片和导出word版个人信息
1、项目介绍
1)项目功能
用户管理:分为管理员、和普通用户,设置不同用户的权限
电话本信息管理:支持管理员和普通用户对电话本的信息进行增删改操作,模糊查询(根据姓名、地址、单位)
文件批量导入:支持管理员通过excel文件批量导入电话本信息
分页功能:对电话本信息管理页面支持分页查看
电话本分组管理:对电话本进行分组,修改、移动、删除
邮件发送名片功能:支持管理员根据电话本信息向用户发送邮件,邮件内容为个人信息名片和附件
用户信息导出功能:导出个人用户的用户信息word文档
2)技术栈描述
前端 html+thymeleaf+jquery+css
后端 Spring Boot + Spring MVC + MyBatis Plus
数据库 MySQL
其他技术 POI Excel 、word文件导入导出、JavaMail API邮件发送
2、邮件发送具体实现
1)导入发送邮件需要的依赖
<!-- 邮件发送--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>
2)添加邮件配置的参数(在application.yml配置文件中)
mail:host: smtp.qq.com #qq邮件服务器地址 有其他地址username: xxxxxxx@qq.com #发件人邮箱password: rwcafxsrjxfndfee #授权码default-encoding: UTF-8 #邮件登录字符集编码port: 25 #发件人邮件服务器端口
授权码的获取:首先登录QQ邮箱>>>登录成功后找到设置>>>然后找到邮箱设置>>>点击账户>>>找到POP3|SMTP服务>>>点击开启(开启需要验证,验证成功后会有一串授权码用于发送邮件使用)>>>验证成功
3)创建邮件发送controller
以发送个人信息为例
@AutowiredMailUtil mailUtil;/*** 邮件发送名片功能* @param contactId* @param userId* @return*/@RequestMapping("/sendEmailCard")public void sendEmailCard(Integer contactId, Integer userId){Contacts contacts = this.contactsService.getById(contactId);Users user = this.usersService.getById(contacts.getUserId());Integer gender0 = contacts.getGender();String gender = "男";if(gender0==1){gender="女";}String email = contacts.getEmail();String content="<html><body><h1>个人名片</h1><p>姓名:" +user.getUsername()+"</p><p>单位:" +contacts.getCompany()+"</p><p>性别:" +gender+"</p><p>年龄:" +contacts.getAge()+"</p><p>办公电话:" +contacts.getOfficePhone()+"</p><p>传真:" +contacts.getFax()+"</p><p>手机号码:" +contacts.getMobile()+"</p><p>电子邮件:" +contacts.getEmail()+"</p><p>地址:" +contacts.getAddress()+"</p><p>备注:" +contacts.getRemarks()+"</p></body></html>";String imgPath = "D:\\email\\个人信息表.docx";mailUtil.sendAttachmentsMail(email, "主题:电话信息验证", content, imgPath);}
4) 引入邮件发送工具包
package com.qcby.onlinephonebook.util;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;/*** <p><p/>** @Author: porridge* @Date:2022/3/30 10:17*/
@Component
public class MailUtil {@Value("${spring.mail.username}")String from;@AutowiredJavaMailSender mailSender;//简单邮件public void sendSimpleMail(String to, String subject, String content){SimpleMailMessage message = new SimpleMailMessage();message.setFrom(from); //发件人message.setTo(to);//收件人message.setSubject(subject); //标题message.setText(content); //文件内容try {mailSender.send(message);System.out.println("简单邮件发送成功!");} catch (Exception e){System.out.println("发送简单邮件时发生异常!"+e);}}//html格式邮件public void sendHtmlMail(String to, String subject, String content){MimeMessage message = mailSender.createMimeMessage();try {//true表示需要创建一个multipart messageMimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(from);helper.setTo(to);helper.setSubject(subject);helper.setText(content, true);mailSender.send(message);System.out.println("html邮件发送成功!");} catch (MessagingException e) {System.out.println("发送html邮件时发生异常!"+e);}}//带附件的邮件public void sendAttachmentsMail(String to, String subject, String content, String filePath){MimeMessage message = mailSender.createMimeMessage();try {MimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(from);helper.setTo(to);helper.setSubject(subject);helper.setText(content, true);FileSystemResource file = new FileSystemResource(new File(filePath));String fileName = filePath.substring(filePath.lastIndexOf(File.separator));helper.addAttachment(fileName, file);mailSender.send(message);System.out.println("带附件的邮件已经发送。");} catch (MessagingException e) {System.out.println("发送带附件的邮件时发生异常!" + e);}}//带静态资源的邮件public void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId){MimeMessage message = mailSender.createMimeMessage();try {MimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(from);helper.setTo(to);helper.setSubject(subject);helper.setText(content, true);FileSystemResource res = new FileSystemResource(new File(rscPath));helper.addInline(rscId, res);mailSender.send(message);System.out.println("嵌入静态资源的邮件已经发送。");} catch (MessagingException e) {System.out.println("发送嵌入静态资源的邮件时发生异常!" + e);}}
}
发送成功样例
3、word导出具体实现
1)实现思路
①组装数据
②获取根目录,创建模板文件
③将模板文件写入到根目录
④编译模板,渲染数据
⑤写入到指定目录位置,临时文件
⑥提供前端下载
⑦删除临时文件
2)导入word导出需要的依赖
<!-- word导出--><dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.10.0</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency>
3)在项目resource目录下创建word模板
word模板如下:
根据需要,{{}}里面写入需要写入的参数名
4)创建word导出的controller
/*** 个人信息word导出* @param response*/@RequestMapping("/exportWord")public void exportWord(Integer contactId, Integer userId, HttpServletResponse response) {Contacts contacts = this.contactsService.getById(contactId);String gender = "男";if(contacts.getGender()==1){gender = "女";}//1.组装数据Map<String, Object> params = new HashMap<>();params.put("name",contacts.getName());params.put("company", contacts.getCompany());params.put("gender", gender);params.put("age", contacts.getAge());params.put("officePhone", contacts.getOfficePhone());params.put("fax", contacts.getFax());params.put("mobile", contacts.getMobile());params.put("email", contacts.getEmail());params.put("address", contacts.getAddress());params.put("remarks", contacts.getRemarks());//2.获取根目录,创建模板文件String path = copyTempFile("word/info.docx");String fileName = System.currentTimeMillis() + ".docx";String tmpPath = "D:\\email\\" + fileName;try {//3.将模板文件写入到根目录//4.编译模板,渲染数据XWPFTemplate template = XWPFTemplate.compile(path).render(params);//5.写入到指定目录位置FileOutputStream fos = new FileOutputStream(tmpPath);template.write(fos);fos.flush();fos.close();template.close();//6.提供前端下载down(response, tmpPath, fileName);} catch (Exception e) {e.printStackTrace();} finally {//7.删除临时文件File file = new File(tmpPath);file.delete();File copyFile = new File(path);copyFile.delete();}}/*** 用于将文件下载到客户端* @param response* @param filePath 文件路径* @param realFileName 文件名称*/private void down(HttpServletResponse response, String filePath, String realFileName) {String percentEncodedFileName = null;try {percentEncodedFileName = percentEncode(realFileName);} catch (UnsupportedEncodingException e) {throw new RuntimeException(e);}StringBuilder contentDispositionValue = new StringBuilder();contentDispositionValue.append("attachment; filename=").append(percentEncodedFileName).append(";").append("filename*=").append("utf-8''").append(percentEncodedFileName);response.addHeader("Access-Control-Allow-Origin", "*");response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");response.setHeader("Content-disposition", contentDispositionValue.toString());response.setHeader("download-filename", percentEncodedFileName);try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));// 输出流BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());) {byte[] buff = new byte[1024];int len = 0;while ((len = bis.read(buff)) > 0) {bos.write(buff, 0, len);}} catch (Exception e) {e.printStackTrace();}}/*** 百分号编码工具方法* @param s 需要百分号编码的字符串* @return 百分号编码后的字符串*/public static String percentEncode(String s) throws UnsupportedEncodingException {String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());return encode.replaceAll("\\+", "%20");}/*** 复制模板文件用于写入,得到临时路径* @param s 模板文件的路径* @return*/private String copyTempFile(String s) {InputStream inputStream = getClass().getClassLoader().getResourceAsStream(s);String tempFileName = System.getProperty("user.home") + "/" + "info.docx";File tempFile = new File(tempFileName);try {FileUtils.copyInputStreamToFile(inputStream, tempFile);} catch (IOException e) {throw new RuntimeException(e);}return tempFile.getPath();}
导出成功样例:
相关文章:

项目实战之网络电话本之发送邮件名片和导出word版个人信息
1、项目介绍 1)项目功能 用户管理:分为管理员、和普通用户,设置不同用户的权限 电话本信息管理:支持管理员和普通用户对电话本的信息进行增删改操作,模糊查询(根据姓名、地址、单位) 文件批…...
前端面试问题汇总 - HTTP篇
1. 登录拦截如何实现? 在前端,可以拦截所有需要登录的请求,如果用户未登录或者登录过期,则跳转到登录页面。 2. http 缓存有哪些? 强缓存: 强缓存是指在客户端请求资源时,先检查本地是否存在缓存…...
Java的IO流
Day35 Java的IO流 概念 Java的IO流是用来处理输入和输出操作的机制,用于在程序和外部数据源(如文件、网络连接、内存等)之间进行数据传输。Java的IO流主要分为字节流和字符流两种类型,每种类型又分为输入流和输出流。 理解&#…...

Node.js 中的 RSA 加密、解密、签名与验证详解
引言 在现代的网络通信中,数据安全显得尤为重要。RSA加密算法因其非对称的特性,广泛应用于数据的加密、解密、签名和验证等安全领域。本文将详细介绍RSA算法的基本原理,并结合Node.js环境,展示如何使用内置的crypto模块和第三方库…...

vue+element作用域插槽
作用域插槽的样式由父组件决定,内容却由子组件控制。 在el-table使用作用域插槽 <el-table><el-table-column slot-scope" { row, column, $index }"></el-table-column> </el-table>在el-tree使用作用域插槽 <el-tree>…...
MUSA模型
MUSA模型在软件可靠性工程中起到的作用是估计软件的故障/失效数量和故障率。具体来说,MUSA模型包括基本模型和对数模型。 MUSA基本模型假设故障发生的时间间隔服从参数为lambda的指数分布。在这个模型中,当故障被检测到时,发生故障的部分会被…...

avicat连接异常,错误编号2059-authentication plugin…
错误原因为密码方式不对,具体可自行百度 首先管理员执行cmd进入 mysql安装目录 bin下边 我的是C:\Program Files\MySQL\MySQL Server 8.2\bin> 执行 mysql -u -root -p 然后输入密码 123456 进入mysql数据库 use mysql 执行 ALTER USER rootlocalhost IDE…...

阿里云云效CI/CD配置
1.NODEJS项目流水线配置(vue举例) nodejs构建配置 官方教程 注意:下图的dist是vue项目打包目录名称,根据实际名称配置 # input your command here cnpm cache clean --force cnpm install cnpm run build 主机部署配置 rm -rf /home/vipcardmall/frontend/ mkdir -p /home/…...
个人开发者,Spring Boot 项目如何部署
今天给大家分享一下,作为个人开发者,Spring Boot 项目是如何部署的。 环境介绍 Linux docker docker-compose 目录结构 erwin-windrunner - backups - data - jars - build-docker-compose.sh - docker-compose.yml - Dockerfile文件 Dockerfile …...

【Spring进阶系列丨第九篇】基于XML的面向切面编程(AOP)详解
文章目录 一、基于XML的AOP1.1、打印日志案例1.1.1、beans.xml中添加aop的约束1.1.2、定义Bean 1.2、定义记录日志的类【切面】1.3、导入AOP的依赖1.4、主配置文件中配置AOP1.5、测试1.6、切入点表达式1.6.1、访问修饰符可以省略1.6.2、返回值可以使用通配符,表示任…...
学习记录:转发和重定向
转发(Forward)和重定向(Redirect)是两种不同的 Web 请求处理方式,它们在功能和行为上有着显著的区别。 区别 转发(Forward): 服务器内部跳转:转发是服务器内部的行为&…...
实现(图像、视频等)数据上云存储
实现(图像、视频等)数据上云存储 实现(图像、视频等)数据上云存储通常涉及以下几个步骤: 选择云存储服务商: 根据您的需求、预算、地域覆盖、数据安全性、服务稳定性等因素,选择一家合适的云存储…...
LeetCode 454.四数相加II
LeetCode 454.四数相加II 1、题目 题目链接:454. 四数相加 II - 力扣(LeetCode) 给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足: 0 <…...

GoogleNet网络训练集和测试集搭建
测试集和训练集都是在之前搭建好的基础上进行修改的,重点记录与之前不同的代码。 还是使用的花分类的数据集进行训练和测试的。 一、训练集 1、搭建网络 设置参数:使用辅助分类器,采用权重初始化 net GoogleNet(num_classes5, aux_logi…...

将数字状态码在后台转换为中文状态
这是我们的实体类 可以看出我们的状态status是2如过返回到前端我们根本不知道2代表的是什么,所以我们需要再这里将数字转换成能看懂的中文状态,首先我们创建一个枚举类 先将我们状态码所对应的中文状态枚举出来,然后创建一个静态方法&#…...

2017NOIP普及组真题 4. 跳房子
线上OJ: 一本通:http://ybt.ssoier.cn:8088/problem_show.php?pid1417\ 核心思想 首先、本题中提到 “ 至少 要花多少金币改造机器人,能获得 至少 k分 ”。看到这样的话语,基本可以考虑要使用 二分答案。 那么,本题中…...
网络与 Internet因特网的基本概念
目录 网络Internet (互联网或互连网)Internet(因特网)待续、更新中 网络 指将分布在不同地理位置的、相同或不同类型的网络通过网络互连设备(中继器、网桥、路由器或网关等)相互连接,形成一个范…...
vue-router 中 router-link 与 a 标签的区别
文章目录 前言 a标签定义 router-link定义 总结 前言 vue-router 中 router-link 与 a 标签的区别 a标签定义 <a> 标签定义超链接,用于从一张页面链接到另一张页面。 从一张页面跳转到另一张页面,但从这里来说就违背了多视图的单页Web应用这个…...

MySQL基础知识——MySQL事务
事务背景 什么是事务? 一组由一个或多个数据库操作组成的操作组,能够原子的执行,且事务间相互独立; 简单来说,事务就是要保证一组数据库操作,要么全部成功,要么全部失败。 注:MyS…...

【架构方法论(一)】架构的定义与架构要解决的问题
文章目录 一. 架构定义与架构的作用1. 系统与子系统2. 模块与组件3. 框架与架构4. 重新定义架构:4R 架构 二、架构设计的真正目的-别掉入架构设计的误区1. 是为了解决软件复杂度2. 简单的复杂度分析案例 三. 案例思考 本文关键字 架构定义 架构与系统的关系从业务逻…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
CppCon 2015 学习:Time Programming Fundamentals
Civil Time 公历时间 特点: 共 6 个字段: Year(年)Month(月)Day(日)Hour(小时)Minute(分钟)Second(秒) 表示…...