From 1624b00522cef32f4396ad825ce93a43f804351d Mon Sep 17 00:00:00 2001 From: nagocoler Date: Fri, 10 Jan 2025 01:14:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=82=AE=E4=BB=B6=E5=8F=91?= =?UTF-8?q?=E9=80=81=E6=AD=BB=E4=BF=A1=E9=98=9F=E5=88=97=E5=92=8C=E8=BF=87?= =?UTF-8?q?=E6=9C=9F=E6=9C=BA=E5=88=B6=EF=BC=8C=E5=8F=91=E9=80=81=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E8=87=AA=E5=8A=A8=E5=A4=84=E7=90=86=E8=BF=9B=E5=85=A5?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/config/RabbitConfiguration.java | 38 ++++++++++++++++++- .../java/com/example/entity/QueueMessage.java | 30 +++++++++++++++ .../example/entity/dto/VerifyMailError.java | 21 ++++++++++ .../example/listener/ErrorQueueListener.java | 37 ++++++++++++++++++ .../example/listener/MailQueueListener.java | 23 ++++++----- .../example/mapper/VerifyMailErrorMapper.java | 9 +++++ .../service/impl/AccountServiceImpl.java | 7 ++-- .../main/java/com/example/utils/Const.java | 1 + .../src/main/resources/application-dev.yml | 6 +++ 9 files changed, 157 insertions(+), 15 deletions(-) create mode 100644 my-project-backend/src/main/java/com/example/entity/QueueMessage.java create mode 100644 my-project-backend/src/main/java/com/example/entity/dto/VerifyMailError.java create mode 100644 my-project-backend/src/main/java/com/example/listener/ErrorQueueListener.java create mode 100644 my-project-backend/src/main/java/com/example/mapper/VerifyMailErrorMapper.java diff --git a/my-project-backend/src/main/java/com/example/config/RabbitConfiguration.java b/my-project-backend/src/main/java/com/example/config/RabbitConfiguration.java index 2e21a8f..0c98639 100644 --- a/my-project-backend/src/main/java/com/example/config/RabbitConfiguration.java +++ b/my-project-backend/src/main/java/com/example/config/RabbitConfiguration.java @@ -1,7 +1,9 @@ package com.example.config; -import org.springframework.amqp.core.Queue; -import org.springframework.amqp.core.QueueBuilder; +import org.springframework.amqp.core.*; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -10,10 +12,42 @@ import org.springframework.context.annotation.Configuration; */ @Configuration public class RabbitConfiguration { + + @Bean + public MessageConverter jsonMessageConverter() { + return new Jackson2JsonMessageConverter(); + } + + @Bean("errorQueue") + public Queue dlQueue(){ + return QueueBuilder + .durable("error") + .ttl(24 * 60 * 60 * 1000) + .build(); + } + + @Bean("errorExchange") + public Exchange dlExchange(){ + return ExchangeBuilder.directExchange("dlx.direct").build(); + } + + @Bean("dlBinding") //死信交换机和死信队列进绑定 + public Binding dlBinding(@Qualifier("errorExchange") Exchange exchange, + @Qualifier("errorQueue") Queue queue){ + return BindingBuilder + .bind(queue) + .to(exchange) + .with("error-message") + .noargs(); + } + @Bean("mailQueue") public Queue queue(){ return QueueBuilder .durable("mail") + .deadLetterExchange("dlx.direct") + .deadLetterRoutingKey("error-message") + .ttl(3 * 60 * 1000) .build(); } } diff --git a/my-project-backend/src/main/java/com/example/entity/QueueMessage.java b/my-project-backend/src/main/java/com/example/entity/QueueMessage.java new file mode 100644 index 0000000..69f0698 --- /dev/null +++ b/my-project-backend/src/main/java/com/example/entity/QueueMessage.java @@ -0,0 +1,30 @@ +package com.example.entity; + +import lombok.Getter; +import lombok.ToString; + +import java.util.HashMap; +import java.util.Map; + +@Getter +@ToString +public class QueueMessage { + private String messageType; + private final Map data = new HashMap<>(); + + public static QueueMessage create(String messageType) { + QueueMessage queueMessage = new QueueMessage(); + queueMessage.messageType = messageType; + return queueMessage; + } + + public QueueMessage put(String key, Object value) { + data.put(key, value); + return this; + } + + @SuppressWarnings("unchecked") + public T get(String key) { + return (T) data.get(key); + } +} diff --git a/my-project-backend/src/main/java/com/example/entity/dto/VerifyMailError.java b/my-project-backend/src/main/java/com/example/entity/dto/VerifyMailError.java new file mode 100644 index 0000000..5c4db28 --- /dev/null +++ b/my-project-backend/src/main/java/com/example/entity/dto/VerifyMailError.java @@ -0,0 +1,21 @@ +package com.example.entity.dto; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Date; + +@Data +@Accessors(chain = true) +@TableName("db_error_verify_mail") +public class VerifyMailError { + @TableId(type = IdType.AUTO) + Integer id; + String email; + String type; + String code; + Date time; +} diff --git a/my-project-backend/src/main/java/com/example/listener/ErrorQueueListener.java b/my-project-backend/src/main/java/com/example/listener/ErrorQueueListener.java new file mode 100644 index 0000000..5216854 --- /dev/null +++ b/my-project-backend/src/main/java/com/example/listener/ErrorQueueListener.java @@ -0,0 +1,37 @@ +package com.example.listener; + +import com.example.entity.QueueMessage; +import com.example.entity.dto.VerifyMailError; +import com.example.mapper.VerifyMailErrorMapper; +import com.example.utils.Const; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.annotation.RabbitHandler; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Component; + +import java.util.Date; + +@Slf4j +@Component +@RabbitListener(queues = Const.MQ_ERROR) +public class ErrorQueueListener { + + @Resource + VerifyMailErrorMapper mapper; + + @RabbitHandler + public void saveErrorToDatabase(QueueMessage message) { + log.error("出现一条错误的队列消息: {}", message); + switch (message.getMessageType()) { + case "email" -> { + VerifyMailError error = new VerifyMailError() + .setCode(message.get("code").toString()) + .setType(message.get("type")) + .setEmail(message.get("email")) + .setTime(new Date()); + mapper.insert(error); + } + } + } +} diff --git a/my-project-backend/src/main/java/com/example/listener/MailQueueListener.java b/my-project-backend/src/main/java/com/example/listener/MailQueueListener.java index d0a724f..0cf90e1 100644 --- a/my-project-backend/src/main/java/com/example/listener/MailQueueListener.java +++ b/my-project-backend/src/main/java/com/example/listener/MailQueueListener.java @@ -1,6 +1,9 @@ package com.example.listener; +import com.example.entity.QueueMessage; +import com.example.utils.Const; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Value; @@ -8,13 +11,12 @@ import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Component; -import java.util.Map; - /** * 用于处理邮件发送的消息队列监听器 */ +@Slf4j @Component -@RabbitListener(queues = "mail") +@RabbitListener(queues = Const.MQ_MAIL, concurrency = "10") public class MailQueueListener { @Resource @@ -25,13 +27,13 @@ public class MailQueueListener { /** * 处理邮件发送 - * @param data 邮件信息 + * @param message 邮件信息 */ @RabbitHandler - public void sendMailMessage(Map data) { - String email = data.get("email").toString(); - Integer code = (Integer) data.get("code"); - SimpleMailMessage message = switch (data.get("type").toString()) { + public void sendMailMessage(QueueMessage message) { + String email = message.get("email"), type = message.get("type"); + Integer code = message.get("code"); + SimpleMailMessage mailMessage = switch (type) { case "register" -> createMessage("欢迎注册我们的网站", "您的邮件注册验证码为: "+code+",有效时间3分钟,为了保障您的账户安全,请勿向他人泄露验证码信息。", @@ -46,8 +48,9 @@ public class MailQueueListener { email); default -> null; }; - if(message == null) return; - sender.send(message); + if(mailMessage == null) return; + log.info("正在向 {} 发送 {} 类型的电子邮件...", email, type); + sender.send(mailMessage); } /** diff --git a/my-project-backend/src/main/java/com/example/mapper/VerifyMailErrorMapper.java b/my-project-backend/src/main/java/com/example/mapper/VerifyMailErrorMapper.java new file mode 100644 index 0000000..ea57bed --- /dev/null +++ b/my-project-backend/src/main/java/com/example/mapper/VerifyMailErrorMapper.java @@ -0,0 +1,9 @@ +package com.example.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.example.entity.dto.VerifyMailError; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface VerifyMailErrorMapper extends BaseMapper { +} diff --git a/my-project-backend/src/main/java/com/example/service/impl/AccountServiceImpl.java b/my-project-backend/src/main/java/com/example/service/impl/AccountServiceImpl.java index 3079482..25f0490 100644 --- a/my-project-backend/src/main/java/com/example/service/impl/AccountServiceImpl.java +++ b/my-project-backend/src/main/java/com/example/service/impl/AccountServiceImpl.java @@ -2,6 +2,7 @@ package com.example.service.impl; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.example.entity.QueueMessage; import com.example.entity.dto.Account; import com.example.entity.dto.AccountDetails; import com.example.entity.dto.AccountPrivacy; @@ -23,7 +24,6 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.Date; -import java.util.Map; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -86,8 +86,9 @@ public class AccountServiceImpl extends ServiceImpl impl return "请求频繁,请稍后再试"; Random random = new Random(); int code = random.nextInt(899999) + 100000; - Map data = Map.of("type",type,"email", email, "code", code); - rabbitTemplate.convertAndSend(Const.MQ_MAIL, data); + QueueMessage message = QueueMessage.create("email"); + message.put("type",type).put("email", email).put("code", code); + rabbitTemplate.convertAndSend(Const.MQ_MAIL, message); stringRedisTemplate.opsForValue() .set(Const.VERIFY_EMAIL_DATA + email, String.valueOf(code), 3, TimeUnit.MINUTES); return null; diff --git a/my-project-backend/src/main/java/com/example/utils/Const.java b/my-project-backend/src/main/java/com/example/utils/Const.java index cba5e18..c921352 100644 --- a/my-project-backend/src/main/java/com/example/utils/Const.java +++ b/my-project-backend/src/main/java/com/example/utils/Const.java @@ -21,6 +21,7 @@ public final class Const { public final static String ATTR_USER_ID = "userId"; //消息队列 public final static String MQ_MAIL = "mail"; + public final static String MQ_ERROR = "error"; //用户角色 public final static String ROLE_DEFAULT = "user"; public final static String ROLE_ADMIN = "admin"; diff --git a/my-project-backend/src/main/resources/application-dev.yml b/my-project-backend/src/main/resources/application-dev.yml index 4010740..107c8e3 100644 --- a/my-project-backend/src/main/resources/application-dev.yml +++ b/my-project-backend/src/main/resources/application-dev.yml @@ -13,6 +13,12 @@ spring: username: admin password: admin virtual-host: / + listener: + simple: + retry: + enabled: true + max-attempts: 3 + initial-interval: 1000ms datasource: url: jdbc:mysql://localhost:3306/study username: root