国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

唐山seo快速排名seo全稱是什么

唐山seo快速排名,seo全稱是什么,佛山市新城開發(fā)建設(shè)有限公司網(wǎng)站,如何自己做網(wǎng)站推廣前言 發(fā)送郵件功能,借鑒 剛果商城,根據(jù)文檔及項(xiàng)目代碼實(shí)現(xiàn)。整理總結(jié)便有了此文,文章有不對的點(diǎn),請聯(lián)系博主指出,請多多點(diǎn)贊收藏,您的支持是我最大的動力~ 發(fā)送郵件功能主要借助 mail、freemarker以及rocke…

前言

發(fā)送郵件功能,借鑒 剛果商城,根據(jù)文檔及項(xiàng)目代碼實(shí)現(xiàn)。整理總結(jié)便有了此文,文章有不對的點(diǎn),請聯(lián)系博主指出,請多多點(diǎn)贊收藏,您的支持是我最大的動力~

發(fā)送郵件功能主要借助 mail、freemarker以及rocketmq實(shí)現(xiàn)。

剛果商城是個分布式項(xiàng)目,近看發(fā)送消息模塊即可。

image-20231205211959763

標(biāo)準(zhǔn)的DDD分層架構(gòu)。

RocketMQ部署

方便起見,使用docker部署環(huán)境

RocketMQ 4.5.1 安裝部署

安裝 NameServer

docker run -d -p 9876:9876 --name rmqnamesrv foxiswho/rocketmq:server-4.5.1

安裝 Brocker

1)新建配置目錄

mkdir -p /mydata/rocketmq/conf

2)新建配置文件 broker.conf

brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
# 此處為本地ip, 如果部署服務(wù)器, 需要填寫服務(wù)器外網(wǎng)ip
brokerIP1 = xx.xx.xx.xx

3)創(chuàng)建容器

docker run -d \
-p 10911:10911 \
-p 10909:10909 \
--name rmqbroker \
--link rmqnamesrv:namesrv \
-v /mydata/rocketmq/conf/broker.conf:/etc/rocketmq/broker.conf \
-e "NAMESRV_ADDR=namesrv:9876" \
-e "JAVA_OPTS=-Duser.home=/opt" \
-e "JAVA_OPT_EXT=-server -Xms512m -Xmx512m" \
foxiswho/rocketmq:broker-4.5.1

安裝 rocketmq 控制臺

docker pull pangliang/rocketmq-console-ng
docker run -d \
--link rmqnamesrv:namesrv \
-e "JAVA_OPTS=-Drocketmq.config.namesrvAddr=namesrv:9876 -Drocketmq.config.isVIPChannel=false" \
--name rmqconsole \
-p 8088:8080 \
-t pangliang/rocketmq-console-ng

運(yùn)行成功,稍等幾秒啟動時間,瀏覽器輸入 ip:8088 查看。

記得放行上述所有端口,最終結(jié)果如下:

image-20231205220952290

RocketMQ安裝成功~

引入主要依賴

        <!-- 發(fā)送郵件主要依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency><!-- 模板引擎 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><!-- 消息隊(duì)列 實(shí)現(xiàn)解耦 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-stream-rocketmq</artifactId></dependency>

配置文件

image-20231205212430700

主要看application.yaml 和 application-dev.yaml

application.yaml

server:port: 8001spring:profiles:active: devapplication:name: message-servicestream:bindings:# 主要是如下兩個通道的配置 (消費(fèi)者通道)mailSend:consumer:concurrency: 4max-attempts: 1content-type: application/jsondestination: message-center_topicgroup: message-center_mail-send_cg# 生產(chǎn)者通道   messageOutput:content-type: application/jsondestination: message-center_topicgroup: message-center_general-send_pgrocketmq:bindings:mailSend:consumer:delay-level-when-next-consume: -1tags: common_message-center_mail-send_tag# ...        

application-dev.yaml

spring:cloud:nacos:discovery:server-addr: 127.0.0.1:8848stream:rocketmq:binder:name-server: 127.0.0.1:9876 # rocketmq服務(wù)mail:default-encoding: UTF-8host: smtp.163.compassword: xxxport: 25protocol: smtpusername: xxx@163.com

重要的是mail中參數(shù)(用的是網(wǎng)易郵箱),username:網(wǎng)易郵箱賬號,password:登錄 SMTP server 的密碼

登錄 SMTP server 密碼

password獲取步驟如下

一、登錄網(wǎng)頁版郵箱(https://email.163.com/),進(jìn)入郵箱首頁。

二、點(diǎn)擊上方設(shè)置,選擇POP/SMTP/IMAP選項(xiàng)。

image-20231205213826857

三、在客戶端協(xié)議界面,選擇開啟對應(yīng)的協(xié)議,IMAP或者POP3分別為不同的收信協(xié)議,選擇只開啟需要的收信協(xié)議,比如IMAP,推薦使用IMAP協(xié)議來收發(fā)郵件,它可以和網(wǎng)頁版完全同步。

image-20231205214131071

四、點(diǎn)擊開啟,繼續(xù)開啟,手機(jī)掃碼發(fā)送短信后,得到的一串密碼即為登錄密碼

image-20231205214306587

image-20231205214336717

image-20231205214600255

真正代碼實(shí)現(xiàn)

interfaces層

image-20231205214957319

用戶接口層,入?yún)?code>CQRS風(fēng)格,參數(shù)都在application層

發(fā)送郵件入?yún)?#xff1a;

@Data
@ApiModel("郵箱發(fā)送")
public class MailSendCommand {@ApiModelProperty(value = "標(biāo)題", example = "剛果商城郵箱驗(yàn)證碼提醒")@NotBlank(message = "郵箱標(biāo)題不能為空")private String title;@Email@ApiModelProperty(value = "發(fā)送者", example = "congomall@163.com")@NotBlank(message = "郵箱發(fā)送者不能為空")private String sender;@Email@ApiModelProperty(value = "接收者", example = "7798432@163.com", notes = "實(shí)際發(fā)送時更改為自己郵箱")@NotBlank(message = "郵箱接收者不能為空")private String receiver;@Email@ApiModelProperty("抄送者")private String cc;@ApiModelProperty(value = "消息參數(shù)")private List<String> paramList;// 與數(shù)據(jù)庫對應(yīng)@ApiModelProperty(value = "模板ID", example = "userRegisterVerification")@NotBlank(message = "郵箱模板ID不能為空")private String templateId;
}

application層

image-20231205215452481

直接調(diào)用到application層Service實(shí)現(xiàn)類方法,該層封裝好參數(shù)直接調(diào)用基礎(chǔ)層中消息生產(chǎn)者。

domain層

image-20231205215755887

領(lǐng)域?qū)永锩嬷饕且恍┏A?、?shí)體類,接口以及倉儲接口具體實(shí)現(xiàn)在基礎(chǔ)層。

infrastructure層 ☆

image-20231205220340090

image-20231205221308019

消息通道配置

source -> sink

public interface MessageSource {String OUTPUT = "messageOutput";@Output(MessageSource.OUTPUT)MessageChannel messageOutput();
}
public interface MessageSink {String MAIL_SEND = "mailSend";@Input(MessageSink.MAIL_SEND)SubscribableChannel mailSend();
}

常量與配置文件中通道名稱保持一致

消息生產(chǎn)者

@Slf4j
@Component
@AllArgsConstructor
public class MessageSendProduce {// 屬性名與配置文件中通道名保持一致private final MessageChannel messageOutput;/*** 郵箱消息發(fā)送*/public void mailMessageSend(MailMessageSendEvent mailMessageSendEvent) {String keys = UUID.randomUUID().toString();Message<?> message = MessageBuilder.withPayload(JSON.toJSONString(mailMessageSendEvent)).setHeader(MessageConst.PROPERTY_KEYS, keys).setHeader(MessageConst.PROPERTY_TAGS, MessageRocketMQConstants.MESSAGE_MAIL_SEND_TAG).build();long startTime = SystemClock.now();boolean sendResult = false;try {// 發(fā)送消息給mqsendResult = messageOutput.send(message, 2000L);} finally {log.info("郵箱消息發(fā)送,發(fā)送狀態(tài): {}, Keys: {}, 執(zhí)行時間: {} ms, 消息內(nèi)容: {}", sendResult, keys, SystemClock.now() - startTime, JSON.toJSONString(mailMessageSendEvent));}}
}

消息消費(fèi)者

@Slf4j
@Component
@RequiredArgsConstructor
public class MailMessageSendConsume {private final MessageSendFacade messageSendFacade;// 冪等性注解,還沒研究@Idempotent(uniqueKeyPrefix = "mail_message_send:",key = "#event.messageSendId+'_'+#event.hashCode()",type = IdempotentTypeEnum.SPEL,scene = IdempotentSceneEnum.MQ,keyTimeout = 600L)@StreamListener(MessageSink.MAIL_SEND)public void mailMessageSend(@Payload MailMessageSendEvent event, @Headers Map headers) {long startTime = System.currentTimeMillis();try {MessageSend messageSend = BeanUtil.toBean(event, MessageSend.class);// 【外觀模式】: 抽象消息發(fā)送、消息存儲以及失敗回調(diào)業(yè)務(wù)方等邏輯messageSendFacade.mailMessageSend(messageSend);} finally {log.info("Keys: {}, Msg id: {}, Execute time: {} ms, Message: {}", headers.get("rocketmq_KEYS"), headers.get("rocketmq_MESSAGE_ID"), System.currentTimeMillis() - startTime,JSON.toJSONString(event));}}
}

【外觀模式】

直接與外觀類交互,外觀類封裝了做某件事的所有操作,無需與一個個子操作一一交互,降低了復(fù)雜性,提高了可維護(hù)性

以消息發(fā)送為例,將發(fā)送郵箱以及消息存儲和失敗回調(diào)業(yè)務(wù)封裝為一個方法降低調(diào)用處理復(fù)雜度。

image-20231205221631822

發(fā)送郵箱核心實(shí)現(xiàn)類

@Slf4j
@Component
@AllArgsConstructor
public class MailMessageProduceImpl implements ApplicationListener<ApplicationInitializingEvent>, MailMessageProduce {private final MailTemplateMapper mailTemplateMapper;private final JavaMailSender javaMailSender;private final Configuration configuration;@SneakyThrows@Overridepublic boolean send(MessageSend messageSend) {try {// 根據(jù)模板id查詢模板 模板id:userRegisterVerificationMailTemplateDO mailTemplateDO = mailTemplateMapper.selectOne(Wrappers.lambdaQuery(MailTemplateDO.class).eq(MailTemplateDO::getTemplateId, messageSend.getTemplateId()));MimeMessage mimeMessage = javaMailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);helper.setFrom(messageSend.getSender());helper.setSubject(messageSend.getTitle());if (StrUtil.isNotBlank(messageSend.getCc())) {helper.setCc(messageSend.getCc().split(","));}if (StrUtil.isNotBlank(messageSend.getReceiver())) {helper.setTo(messageSend.getReceiver().split(","));}Map<String, Object> model = Maps.newHashMap();// 模板參數(shù)名稱與下面freemarker模板中參數(shù)一一對應(yīng)String[] templateParams = mailTemplateDO.getTemplateParam().split(",");if (ArrayUtil.isNotEmpty(templateParams)) {for (int i = 0; i < templateParams.length; i++) {model.put(templateParams[i], messageSend.getParamList().get(i));}}// 模板id就是模板名String templateKey = messageSend.getTemplateId() + ".ftl";// 從單例對象容器獲取模板Template template = Singleton.get(templateKey, () -> {try {return configuration.getTemplate(templateKey);} catch (IOException e) {throw new RuntimeException(e);}});String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);helper.setText(html, true);// freemarker填充參數(shù),發(fā)送郵箱javaMailSender.send(mimeMessage);} catch (Throwable ex) {log.error("郵件發(fā)送失敗,Request: {}", JSONUtil.toJsonStr(messageSend), ex);return false;}return true;}/*** 初始化郵箱模板 【率先先將所有模板初始化到單例對象容器中】*/@SneakyThrows@Overridepublic void onApplicationEvent(ApplicationInitializingEvent event) {Resource[] resources = new PathMatchingResourcePatternResolver().getResources(ResourceUtils.CLASSPATH_URL_PREFIX + "templates/*.ftl");for (Resource resource : resources) {String templateName = resource.getFilename();Singleton.put(templateName, configuration.getTemplate(templateName));}}
}

image-20231205222229490

模板具體內(nèi)容:

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<div><p style="caret-color: rgb(86, 90, 92); color: rgb(86, 90, 92); font-family: Helvetica, 微軟雅黑, 宋體; text-size-adjust: auto; font-size: 20px;">親愛的用戶:</p><p style="caret-color: rgb(86, 90, 92); color: rgb(86, 90, 92); font-family: Helvetica, 微軟雅黑, 宋體; font-size: 18px; text-size-adjust: auto;">您好!感謝您的使用,您本次的驗(yàn)證碼為:<span class="Apple-converted-space">&nbsp;</span></p><bstyle="font-family: Helvetica, 微軟雅黑, 宋體; text-size-adjust: auto; font-size: 32px; color: rgb(45, 123, 255);">${validCode}</b><p style="caret-color: rgb(86, 90, 92); color: rgb(86, 90, 92); font-family: Helvetica, 微軟雅黑, 宋體; text-size-adjust: auto; font-size: 20px;">安全提示:</p><p style="caret-color: rgb(86, 90, 92); color: rgb(86, 90, 92); font-family: Helvetica, 微軟雅黑, 宋體; font-size: 18px; text-size-adjust: auto;">為保障您的帳戶安全,請?jiān)?5 分鐘內(nèi)完成驗(yàn)證,否則驗(yàn)證碼將自動失效。<span class="Apple-converted-space">&nbsp;</span></p>
</div>
<div><includetail><!--<![endif]--></includetail>
</div>
</body>
</html>

image-20231205222432490

最終實(shí)現(xiàn)效果

測試結(jié)果如下:

收件為QQ郵箱:

image-20231205210059105

收件為谷歌郵箱:

image-20231205225618465

經(jīng)我測試發(fā)現(xiàn),配置的是網(wǎng)易郵箱,發(fā)送者就只能是網(wǎng)易郵箱,接收者可以是任意郵箱。

http://aloenet.com.cn/news/32070.html

相關(guān)文章:

  • 汕頭百度網(wǎng)站建設(shè)成都網(wǎng)絡(luò)營銷品牌代理機(jī)構(gòu)
  • 織夢修改網(wǎng)站后備份網(wǎng)絡(luò)軟文
  • 搭建平臺暢通渠道網(wǎng)站seo推廣
  • 自己做網(wǎng)絡(luò)棋牌網(wǎng)站流程泉州seo報價
  • 商城網(wǎng)站建設(shè)招聘百度搜索風(fēng)云榜總榜
  • 網(wǎng)站app開發(fā)平臺網(wǎng)站搭建谷歌seo
  • wordpress插件裝多了卡seo代碼優(yōu)化包括哪些
  • 巴中網(wǎng)站建設(shè)免費(fèi)自助建站網(wǎng)站
  • 煙臺seo網(wǎng)站診斷短視頻營銷推廣方式
  • 南寧美容網(wǎng)站建設(shè)seo智能優(yōu)化公司
  • php動態(tài)網(wǎng)站怎么做商旅100網(wǎng)頁版
  • 做地方門戶網(wǎng)站如何做可靠的網(wǎng)站優(yōu)化
  • 怎么自己做網(wǎng)站發(fā)優(yōu)惠券seo搜索引擎優(yōu)化業(yè)務(wù)
  • 佛山電商網(wǎng)站制作seo自學(xué)教程
  • 租網(wǎng)站服務(wù)器價格seo霸屏
  • 網(wǎng)頁與網(wǎng)站設(shè)計(jì)nbsp的意思合肥做網(wǎng)站哪家好
  • 做家庭影院的有哪些網(wǎng)站防城港網(wǎng)站seo
  • 環(huán)保企業(yè)的網(wǎng)站怎么做指數(shù)基金是什么意思
  • seo外包 靠譜長沙seo咨詢
  • 網(wǎng)站二維碼鏈接怎么做的遼陽網(wǎng)站seo
  • 筑巢網(wǎng)站百度地圖廣告投放
  • 網(wǎng)站建設(shè)需要域名嗎鄭州seo網(wǎng)站有優(yōu)化
  • 外賣網(wǎng)站制作seo 關(guān)鍵詞優(yōu)化
  • 想做一個部門的網(wǎng)站怎么做頭條熱點(diǎn)新聞
  • 公司手機(jī)網(wǎng)站模板優(yōu)化大師win10下載
  • 手機(jī)如果做網(wǎng)站市場調(diào)研方案怎么寫
  • 網(wǎng)站開發(fā)工程師社交百度代發(fā)收錄
  • 做局域網(wǎng)網(wǎng)站百度圖片識別搜索引擎
  • szfob外貿(mào)論壇網(wǎng)站重慶seo推廣公司
  • 衡水哪有做網(wǎng)站的網(wǎng)站推廣的概念