当前位置: 首页 > news >正文

公司网站属于信息化建设吗做网站如何分工

公司网站属于信息化建设吗,做网站如何分工,做音乐网站要什么源码,网站如何添加百度商桥Springboot 读取模板excel信息内容并发送邮件 背景技术选型搭建过程数据加密隐藏问题暴露背景追溯解决背景 在我们日常开发中, 会遇到这样一种场景, 就是读取表格中的数据, 并将数据以附件的形式通过邮箱发送到表格中的每个人 即: excel 读取 excel 写入 发送邮件(携带附件), 例… Springboot 读取模板excel信息内容并发送邮件 背景技术选型搭建过程数据加密隐藏问题暴露背景追溯解决背景 在我们日常开发中, 会遇到这样一种场景, 就是读取表格中的数据, 并将数据以附件的形式通过邮箱发送到表格中的每个人 即: excel 读取 excel 写入 发送邮件(携带附件), 例如: 公司在做工资单发送功能时, 财务将所有人的工资单excel上传, 后台通过excel 读取, 然后将每个人的工资信息写入到一个excel, 最后以邮件的形式发送. 为了应对这一场景, 我们来进行技术选型. 然而功能实现了, 使用就没有问题吗? 通过对后续暴露问题的分析来体会下利用技术实现功能往往是开发的第一步, 后面仍需要我们根据具体的软硬件情况对代码进行优化. 技术选型 excel文件读取和写入: easyexcel 社区活跃度, 可写入数据条数以及可并发量都不错, 因此采用easy邮箱发送: spring-boot-starter-mail Spring官方集成的, 底层是jakarta-mail, 与Springboot兼容性较好信息加密: jasypt 隐藏需求, 需要对邮箱的pop3密码进行加密 搭建过程 首先以无加密方式搭建 相关jar !--EasyExcel--dependencygroupIdcom.alibaba/groupIdartifactIdeasyexcel/artifactIdversion${easyexcel.version}/version/dependency!--开启邮箱验证 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-mail/artifactId/dependency!--jasypt加密字符串--dependencygroupIdcom.github.ulisesbocchio/groupIdartifactIdjasypt-spring-boot/artifactIdversion${jasypt-spring-boot.version}/version/dependency配置文件进行配置 #邮箱配置 spring.mail.host邮箱所在服务器域名/ip地址 spring.mail.username邮箱账号 spring.mail.password邮箱密码 spring.mail.properties.mail.smtp.authtrue spring.mail.properties.mail.smtp.starttls.enabletrue spring.mail.properties.mail.smtp.starttls.requiredtrueExcel 数据列列名实体 ExcelProperty 中 index 属性用于文件读取时, 指定读取的列, 而 value 用于在列写入时, 指定列的表头. 采取 value {序号, 序号} 是因为存在复合表头, 这里需要根据自己业务具体情况去编写 import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import lombok.Data;import java.io.Serializable;/*** info: 工资单实体** Author chy*/ Data public class WagesDTO {ExcelProperty(value {序号, 序号}, index 0)private Integer id;ExcelProperty(value {月份, 月份}, index 1)private Integer mounth;ExcelProperty(value {部门, 部门}, index 2)private String deptName;ExcelProperty(value {工号, 工号}, index 3)private String jobNumber;ExcelProperty(value {姓名, 姓名}, index 4)private String name;/*** 入职时间*/DateTimeFormat(yyyy-MM-dd HH:mm:ss)ExcelProperty(value {入职时间, 入职时间}, index 5)private String entryTime;ExcelProperty(value {岗位, 岗位}, index 6)private String position;/*** 出勤*/ExcelProperty(value {出勤, 出勤}, index 7)private String attendance;ExcelProperty(value {基本工资, 固定工资}, index 8)private Double fixedSalary;ExcelProperty(value {基本工资, 工龄}, index 9)private Double workAge;/*** 岗位绩效*/ExcelProperty(value {岗位绩效, 岗位绩效},index 10)private Double achievements;/*** 考核评分*/ExcelProperty(value {考核评分, 考核评分}, index 11)private Integer assessmentScore;/*** 考评绩效*/ExcelProperty(value {考评绩效, 考评绩效}, index 12)private Double evaluatePerformance;/*** 转正*/ExcelProperty(value {转正, 转正}, index 13)private Double become;/*** 补贴*/ExcelProperty(value {补贴, 补贴}, index 14)private Double subsidy;/*** 加班*/ExcelProperty(value {加班, 加班}, index 15)private Double workExtra;/*** 津贴及其他*/ExcelProperty(value {津贴及其他,津贴及其他}, index 16)private Double otherSalary;/*** 缺勤及其他*/ExcelProperty(value {缺勤及其他, 缺勤及其他}, index 17)private Double absenceFromDuty;/*** 应得工资*/ExcelProperty(value {应得工资, 应得工资}, index 18)private Double observeSalary;/*** 养老*/ExcelProperty(value {扣除款项, 养老}, index 19)private Double elderlyCare;/*** 医保*/ExcelProperty(value {扣除款项, 医保}, index 20)private Double medicalInsurance;/*** 失业*/ExcelProperty(value {扣除款项, 失业}, index 21)private Double lossWork;/*** 大病*/ExcelProperty(value {扣除款项, 大病}, index 22)private Double seriousIllness;/*** 公积金*/ExcelProperty(value {扣除款项, 公积金}, index 23)private Double accumulationFund;/*** 累计专项附加扣除*/ExcelProperty(value {扣除款项, 累计专项附加扣除}, index 24)private Double accumulatedSpecialAdditionalDeduction;/*** 所得税*/ExcelProperty(value {扣除款项, 所得税}, index 25)private Double incomeTax;/*** 公款*/ExcelProperty(value {扣除款项, 公款}, index 26)private Double publicFunds;/*** 其他*/ExcelProperty(value {扣除款项, 其他}, index 27)private Double other;/*** 实发工资*/ExcelProperty(value {实发工资, 实发工资}, index 28)private Double netSalary; } 业务代码 //controller方法ApiOperation(文件上传)PostMapping(/upload)public RpcServiceResult upload(RequestParam(file) MultipartFile file) throws IOException {return RpcServiceResult.getSuccessResult(wagesService.handle(file));}//sevice接口/*** 处理* param file* return*/ListWagesDTO handle(MultipartFile file) throws IOException;//业务实现类ServiceSlf4jpublic class WagesServiceImpl implements WagesService {Resourceprivate JavaMailSender mailSender;/*** 这里需要在redis中构建, 员工工号和邮箱的联系. 如果用户表中有, 那么直接查询出来即可*/Resourceprivate RedisUtils redisUtils;/**** 1. 创建excel对应的实体对象 参照{link WagesDTO}* 2. 由于默认一行行的读取excel所以需要创建excel一行一行的回调监听器参照{link EasyExcelStudentListener}* 3. 直接读即可*/Overridepublic ListWagesDTO handle(MultipartFile file) throws IOException {//发送人员列表ListWagesDTO dataList new ArrayList();//发送失败人员列表ListWagesDTO failuresList new ArrayList();AtomicInteger result new AtomicInteger();// 读取excelEasyExcel.read(file.getInputStream(), WagesDTO.class, new EasyExcelStudentListener(dataList)).sheet().headRowNumber(3).doRead();System.out.println(JSONArray.toJSONString(dataList));if (CollectionUtils.isEmpty(dataList)) {throw new ExcelUploadException(上传Excel表格内容为空, 请核对后再次上传!);}/*** 邮件发送失败的三种情况:* 1. 找不到工号* 2. 找不到邮箱* 3. 网络原因导致邮件发送失败*/dataList.forEach(item - {String empName item.getName();Integer mounth item.getMounth();String jobNumber item.getJobNumber();//获取对应邮箱String emailName ;if (StringUtils.isNotBlank(item.getJobNumber()) StringUtils.isNotBlank(redisUtils.getCacheObject(BusinessConstant.JOB_NUMBER_EMAIL:jobNumber))) {emailName redisUtils.getCacheObject(BusinessConstant.JOB_NUMBER_EMAIL : jobNumber);String fileName empName - mounth 月份工资表 .xlsx;ListWagesDTO wagesTempList new ArrayList(1);wagesTempList.add(item);try {org.springframework.core.io.Resource resource new ClassPathResource(static/ 工资表模板.xlsx);//excel文件写入EasyExcel.write(fileName, WagesDTO.class).needHead(false).withTemplate(resource.getInputStream()).sheet().doWrite(wagesTempList);} catch (IOException e) {e.printStackTrace();}//邮箱发送MimeMessage mimeMessage mailSender.createMimeMessage();try {MimeMessageHelper messageHelper new MimeMessageHelper(mimeMessage, true);//接受者邮箱messageHelper.setTo(emailName);//邮箱主题messageHelper.setSubject(fileName.substring(0, fileName.lastIndexOf(.)));//发送文字内容messageHelper.setText(empName: 您 Calendar.getInstance().get(Calendar.YEAR)年mounth月份的工资单已到, 请查收!);//发送附件messageHelper.addAttachment(fileName, new File(fileName));//发送者邮箱messageHelper.setFrom(发件人邮箱);mailSender.send(mimeMessage);result.incrementAndGet();} catch (MessagingException e) {failuresList.add(item);e.printStackTrace();}//发送结束后删除文件对应文件FileUtils.delete(new File(fileName));}else {//统计失败人员信息failuresList.add(item);}});log.info(\n成功给{}人发送工资单, result.get());log.info(\n发送失败人数: {}, \n发送失败人员信息{}, failuresList.size(), failuresList);return failuresList;}} 附: redisUtils工具类代码 package com.sxd.mis.util;import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.sxd.mis.constant.BusinessConstant; import com.sxd.mis.entity.dto.UserDTO; import com.sxd.mis.entity.po.UserPO; import com.sxd.mis.exception.UselessTokenException; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.*; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils;import javax.annotation.Resource; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern;/*** author cyy* 使用此工具类时使用 Autowired 注解* 保存实体类时 实体类需要实现implements Serializable 接口 不然会报序列化错误*/ Component public class RedisUtils {Resourceprivate RedisTemplate redisTemplate;Value(${ding.params.appkey})public String appKey;/*** 缓存基本的对象Integer、String、实体类等** param key 缓存的键值* param value 缓存的值* return 缓存的对象*/public T ValueOperationsString, T setCacheObject(String key, T value){ValueOperationsString, T operation redisTemplate.opsForValue();operation.set(key, value);return operation;}/*** 缓存基本的对象Integer、String、实体类等** param key 缓存的键值* param value 缓存的值* param timeout 时间* param timeUnit 时间颗粒度* return 缓存的对象*/public T ValueOperationsString, T setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit){ValueOperationsString, T operation redisTemplate.opsForValue();operation.set(key, value, timeout, timeUnit);return operation;}/*** 获得缓存的基本对象。** param key 缓存键值* return 缓存键值对应的数据*/public T T getCacheObject(String key){ValueOperationsString, T operation redisTemplate.opsForValue();return operation.get(key);}/*** 删除单个对象** param key*/public void deleteObject(String key){redisTemplate.delete(key);}/*** 根据key前缀批量删除** param keyPrefix 键前缀字符串* return 结果*/public boolean delAll(String keyPrefix) {if (keyPrefix ! null) {SetString keys redisTemplate.keys(Pattern.matches(\\*$, keyPrefix) ? keyPrefix : keyPrefix *);redisTemplate.delete(keys);return true;}return false;}/*** 删除集合对象** param collection*/public void deleteObject(Collection collection){redisTemplate.delete(collection);}/*** 缓存List数据** param key 缓存的键值* param dataList 待缓存的List数据* return 缓存的对象*/public T ListOperationsString, T setCacheList(String key, ListT dataList){ListOperations listOperation redisTemplate.opsForList();if (null ! dataList){int size dataList.size();for (int i 0; i size; i){listOperation.leftPush(key, dataList.get(i));}}return listOperation;}/*** 获得缓存的list对象** param key 缓存的键值* return 缓存键值对应的数据*/public T ListT getCacheList(String key){ListT dataList new ArrayListT();ListOperationsString, T listOperation redisTemplate.opsForList();Long size listOperation.size(key);for (int i 0; i size; i){dataList.add(listOperation.index(key, i));}return dataList;}/*** 缓存Set** param key 缓存键值* param dataSet 缓存的数据* return 缓存数据的对象*/public T BoundSetOperationsString, T setCacheSet(String key, SetT dataSet){BoundSetOperationsString, T setOperation redisTemplate.boundSetOps(key);IteratorT it dataSet.iterator();while (it.hasNext()){setOperation.add(it.next());}return setOperation;}/*** 获得缓存的set** param key* return*/public T SetT getCacheSet(String key){SetT dataSet new HashSetT();BoundSetOperationsString, T operation redisTemplate.boundSetOps(key);dataSet operation.members();return dataSet;}/*** 缓存Map** param key* param dataMap* return*/public T HashOperationsString, String, T setCacheMap(String key, MapString, T dataMap){HashOperations hashOperations redisTemplate.opsForHash();if (null ! dataMap){for (Map.EntryString, T entry : dataMap.entrySet()){hashOperations.put(key, entry.getKey(), entry.getValue());}}return hashOperations;}/*** 获得缓存的Map** param key* return*/public T MapString, T getCacheMap(String key){MapString, T map redisTemplate.opsForHash().entries(key);return map;}/*** 获得缓存的基本对象列表** param pattern 字符串前缀* return 对象列表*/public CollectionString keys(String pattern){return redisTemplate.keys(pattern);} }//需要添加的pom文件!-- redis --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency数据加密 利用jasypt 对项目配置文件中, 敏感信息进行加密. Jasypt 是一个 Java 库它允许开发人员以最小的努力为项目添加基本的加密功能而无需深入了解密码学的工作原理. 使用步骤 引入jar !--jasypt加密字符串--dependencygroupIdcom.github.ulisesbocchio/groupIdartifactIdjasypt-spring-boot/artifactIdversion2.0.0/version/dependency启动类使用 EnableEncryptableProperties 敏感信息加密 引入jar坐标之后, 找到所下载的位置, 如果使用的是idea, 默认jar存储路径在 C:\Users\Administrator\.m2\repository\org\jasypt\jasypt\1.9.2下 利用jar进行加密 进入命令行, 输入java -cp命令 java -cp jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI inputtest passwordsalt algorithmPBEWithMD5AndDES-- input参数你想要加密的密码 -- password参数jasypt用来加密你的密码的密码 -- output: 输出的参数就是你用于替代原明文密码的字符串!!!对配置文件中的邮箱密码(pop3)进行加密 spring.mail.host邮箱所在服务器域名/ip地址 spring.mail.username邮箱账号 spring.mail.passwordENC(xcGyDdk8DOlDMOW0ij3k5A) spring.mail.properties.mail.smtp.authtrue spring.mail.properties.mail.smtp.starttls.enabletrue spring.mail.properties.mail.smtp.starttls.requiredtrue #jasypt加密配置 jasypt.encryptor.passwordsalt隐藏问题暴露 背景 在测试上述技术时, 由于当初使用的是腾讯企业邮箱, 在开发自测以及测试小规模测试之后并未发现问题. 但是在项目发布到生产环境之后问题方才暴露出来. 那是一个周五的晚上. 收到消息的我真的是血压突突上涨… 追溯 好在我也是老鸟了, 马上就冷静下来, 询问发送情况, 当时成功人数未知且前端服务一直没有获取到后端的响应. 由于涉及到生产环境日志, 只能初步判断应该是邮箱那边的限制. 在周一的时候, 在相关人员的帮忙下拿到了生产环境的日志. 从日志这里可以判断出连接被smtp服务器关闭了. 我第一反应就是为什么会关闭? 然后去搜索相关相关内容未果. 因此问题又回到我之前的推测上. 而和腾讯邮箱那边的客服佐证了我的推测 通过和客服的对话我们可以知道, 腾讯的发送邮箱是有限制的, 也就是说: 单个邮箱账号发送邮件需要满足频率不超过 10封/min, 1000封/天. 而上面那种写法是通过spring自带的邮箱api建立连接之后, 一直发送邮件直到超过每分钟发送数限制后smtp服务端阻塞线程, 待下一分钟继续发送, 当超过smtp服务器规定的最大连接时间(推测大概为120s左右)之后就会强制断开连接.最终导致邮件发送失败. 分析到这里, 我们就可以对现有业务进行优化, 首先针对业务长时间未返回, 我们可以将同步操作改为异步操作. 读取Excel表格并验证邮箱之后, 直接进行返回. 然后针对smtp服务器超时断开连接的情况, 我的处理是: 开启多线程, 用于专门处理邮件发送操作, 并且每次发送邮件都手动开启和断开连接, 每次发送之后休眠6秒, 保证一分钟最多发10封邮件. 因此, 基于以上逻辑改造原有代码如下: 解决 同步改异步, 长连接改为短连接 修改主业务流程类 Resourceprivate SendmailUtil sendMailUtils;Overridepublic MapString, Object handle(MultipartFile file, String content) throws IOException {String suffix file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(.) 1);if (!(suffix.equals(xlsx) || suffix.equals(xls))) {throw new BusinessException(上传文件格式有误!);}MapString, Object resultMap Maps.newHashMap();//发送人员列表ListWagesDTO dataList new LinkedList();//发送失败人员列表ListWagesDTO failDtoList new LinkedList();// 读取excelEasyExcel.read(file.getInputStream(), WagesDTO.class, new EasyExcelStudentListener(dataList)).sheet().headRowNumber(3).doRead();if (CollectionUtils.isEmpty(dataList)) {throw new ExcelUploadException(上传Excel表格内容为空, 请核对后再次上传!);}//验证邮箱是否存在, 存在则返回给前端, 不存在则提示失败AtomicInteger successCount new AtomicInteger(0);MapString, WagesDTO emailAndWagesInfoMap Maps.newLinkedHashMap();for (WagesDTO item : dataList) {String empName item.getName();String jobNumber item.getJobNumber();//获取对应邮箱String emailName ;if (StringUtils.isNotBlank(item.getJobNumber()) StringUtils.isNotBlank(redisUtils.getCacheObject(BusinessConstant.JOB_NUMBER_EMAIL : jobNumber empName))) {emailName redisUtils.getCacheObject(BusinessConstant.JOB_NUMBER_EMAIL : jobNumber empName);if (StringUtils.isNotBlank(emailName)) {emailAndWagesInfoMap.put(emailName, item);successCount.incrementAndGet();}}else {failDtoList.add(item);}}//将邮箱发送给对应人员sendMailToEmployees(content, emailAndWagesInfoMap);log.info(\n成功给{}人发送, successCount.get());log.info(\n发送失败人数: {}, \n发送失败人员信息{}, failDtoList.size(), failDtoList);resultMap.put(successCount, successCount.get());resultMap.put(failList, failDtoList);return resultMap;}异步线程类 用于发送邮件 /**** param content 邮箱内容说明* param emailAndWagesInfoMap 发送邮件的集合体* param*/private void sendMailToEmployees(String content, MapString, WagesDTO emailAndWagesInfoMap) {ThreadFactory namedThreadFactory new ThreadFactoryBuilder().setNameFormat(thread-pool-sendMailToEmployees-%d).build();ExecutorService singleThreadPool new ThreadPoolExecutor(1, 1, 60L, TimeUnit.MINUTES,new LinkedBlockingQueueRunnable(16), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());singleThreadPool.execute(() - {//邮件发送失败的列表MapString, WagesDTO failMap Maps.newLinkedHashMap();/*** 邮件发送失败的三种情况:* 1. 找不到工号* 2. 找不到邮箱* 3. 网络原因导致邮件发送失败*/AtomicInteger successCount new AtomicInteger(0);emailAndWagesInfoMap.forEach((email,wagesDto)-{String empName wagesDto.getName();Integer mounth wagesDto.getMounth();//获取对应邮箱if (StringUtils.isNotBlank(wagesDto.getJobNumber())) {String fileName empName - mounth 月份数据 .xlsx;ListWagesDTO wagesTempList new ArrayList(1);wagesTempList.add(wagesDto);try {org.springframework.core.io.Resource resource new ClassPathResource(static/ 模板.xlsx);EasyExcel.write(fileName, WagesDTO.class).needHead(false).withTemplate(resource.getInputStream()).sheet().doWrite(wagesTempList);} catch (IOException e) {e.printStackTrace();}/*** 邮件单发* param toEmailAddress 收件箱地址* param emailTitle 邮件主题* param emailContent 邮件内容* param fileName 附件名称*/String emailTitle fileName.substring(0, fileName.lastIndexOf(.));String emailContent empName : 您 mounth 月份数据已发送, 请查收! content;try {sendMailUtils.sendEmail(email, emailTitle, emailContent, fileName);successCount.incrementAndGet();log.info(step successCount.get() : 向 empName 发送邮件);Thread.sleep(6);} catch (Exception e) {failMap.put(email, wagesDto);e.printStackTrace();}FileUtils.delete(new File(fileName));} else {failMap.put(email, wagesDto);}});if (!CollectionUtils.isEmpty(failMap)) {log.info(存在发送人间失败的人,重新进行发送);//这里可以丢给redis或者消息队列进行处理}});singleThreadPool.shutdown();}邮件发送工具类 实现手动创建连接, 发送邮件, 关闭连接操作 import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.mail.Address; import javax.mail.Message; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.*; import com.sun.mail.util.MailSSLSocketFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;import java.io.File; import java.util.Properties;/*** info:** Author caoHaiYang* Date 2023/2/21 19:18*/ Component public class SendmailUtil {/*** 邮件服务器主机名*/Value(${spring.mail.host})private String myEmailSMTPHost;/*** 发件人邮箱*/Value(${spring.mail.username})private String myEmailAccount;/*** 在开启SMTP服务时会获取到一个授权码把授权码填在这里*/Value(${spring.mail.password})private String myEmailPassword;/*** 邮件单发** param toEmailAddress 收件箱地址* param emailTitle 邮件主题* param emailContent 邮件内容* param fileName 附件名称* throws Exception*/public void sendEmail(String toEmailAddress, String emailTitle, String emailContent, String fileName) throws Exception {Properties props new Properties();// 开启debug调试(如果遇到邮箱发送失败时可开启) // props.setProperty(mail.debug, true);// 发送服务器需要身份验证props.setProperty(mail.smtp.auth, true);// 端口号props.put(mail.smtp.port, 465);//设置邮件服务器主机名props.setProperty(mail.smtp.host, myEmailSMTPHost);// 发送邮件协议名称props.setProperty(mail.transport.protocol, smtp);/**SSL认证注意腾讯邮箱是基于SSL加密的所以需要开启才可以使用**/MailSSLSocketFactory sf new MailSSLSocketFactory();sf.setTrustAllHosts(true);//设置是否使用ssl安全连接一般都使用props.put(mail.smtp.ssl.enable, true);props.put(mail.smtp.ssl.socketFactory, sf);//创建会话Session session Session.getInstance(props);//获取邮件对象//发送的消息基于观察者模式进行设计的Message msg new MimeMessage(session);//设置邮件标题msg.setSubject(emailTitle);//向multipart对象中添加邮件的各个部分内容包括文本内容和附件MimeMultipart multipart new MimeMultipart();//设置邮件的文本内容MimeBodyPart contentPart new MimeBodyPart();contentPart.setContent(emailContent, text/html;charsetUTF-8);multipart.addBodyPart(contentPart);//添加附件MimeBodyPart filePart new MimeBodyPart();DataSource source new FileDataSource(fileName);//添加附件的内容filePart.setDataHandler(new DataHandler(source));//添加附件的标题filePart.setFileName(MimeUtility.encodeText(fileName));multipart.addBodyPart(filePart);multipart.setSubType(mixed);//将multipart对象放到message中msg.setContent(multipart);//设置发件人邮箱// InternetAddress 的三个参数分别为: 发件人邮箱, 显示的昵称(只用于显示, 没有特别的要求), 昵称的字符集编码String nickName myEmailAccount.split()[0];msg.setFrom(new InternetAddress(myEmailAccount, nickName, UTF-8));//得到邮差对象Transport transport session.getTransport();//连接自己的邮箱账户//密码不是自己QQ邮箱的密码而是在开启SMTP服务时所获取到的授权码//connect(host, user, password)transport.connect(myEmailSMTPHost, myEmailAccount, myEmailPassword);//发送邮件transport.sendMessage(msg, new Address[]{new InternetAddress(toEmailAddress)});transport.close();} } 通过对问题的深入挖掘和分析最终解决了问题, 由此可见在不少场景下, 仅仅实现功能是不够的, 还需要我们结合实际情况对业务交互方式进行修改. 例如同步改异步, 串行改并行, 立即执行与延迟执行, 长短连接的取舍等等… 让用户体验良好, 就需要后端同学多做功课, 给予前端快速响应. 无论是异步执行还是接口性能优化, 都需要我们具体情况具体分析. 学无止境, 我们下次再见!!! 更多jasypt的配置可见 小白入门之 Jasypt 加密和解密
http://www.tj-hxxt.cn/news/136572.html

相关文章:

  • 建设田达摩托车官方网站小说百度搜索风云榜
  • 做公司网站都需要什么博山信息港
  • 响应式外贸网站价格朝阳网站建设 高碑店
  • 微网站开发不用模板网站的百度地图怎么做
  • 一个网站需要服务器吗桂林论坛网app
  • 黔东南手机网站建设国外教做蛋糕的网站
  • 怎么查网站注册信息浙江建站优化品牌
  • 南康建设局官方网站抖音seo优化系统招商
  • 贵州安顺建设主管部门网站ui界面
  • 城市建设者官方网站wordpress域名地址设置方法
  • 宁波慈溪网站建设电力行业企业网站建设
  • 可以做锚文本链接的网站搭建一个微信小程序要多少钱
  • 嘉祥做网站如何做电影网站
  • flash国外网站wordpress实现视频播放
  • 抚州律师网站建设哪个网站找到做箱包厂外发的
  • 一个网站怎么做软件网站空间多少
  • 宁夏众擎达网站建设小程序开发教程
  • 淘宝建设网站虚拟主机评测
  • 江苏营销型网站推广网站跳出率是什么意思
  • 满天星建设网站名人朋友圈网页版qq登录入口
  • 做旅游网站挣钱吗学网站开发的软件
  • 网站策划专有技术久久建筑网cad
  • 北京网站优化页面做网站卖大闸蟹
  • 网站运营策划提案静态网站入侵
  • 怎么用网络推广南昌网络排名优化
  • 北京做erp报价的网站网站做301好不好
  • 嘉兴秀宏建设公司网站来宾网站建设公司
  • 网站模板内容页排名优化是怎么做的
  • 建设网站要那些小程序开发费用明细怎么填
  • 网站建设商城软件项目外包平台