整合rabbitmq+redis发送验证码消息

配置:

server:
  port: 8084
#邮件相关配置
spring:
  application:
    name: subtlechat-mailserver
  mail:
    host: smtp.qq.com
    protocol: smtp
    default-encoding: UTF-8
    #邮箱名
    username: 
    #申请的授权码
    password: 
    port: 587
    properties.mail.stmp.socketFactory.class: javax.net.ssl.SSLSocketFactory
    properties.mail.debug: true
  #RabbitMQ的配置
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: /subtlechat
    # 如果rabbitmq中没有创建这个名字的虚拟主机会报错
    #开启手动确认是否消息消费成功
    listener:
      simple:
        acknowledge-mode: manual
        prefetch: 100
  #Redis的配置
  redis:
    database: 0
    password: redis
    host: 
    port: 6379

rabbitmq配置:


/**
 * @author Hai
 * @date 2020/10/1 - 18:32
 */
@Configuration
public class RabbitMQConfig {

    @Value("${mail.exchange:mail-exchange}")
    private String mailExchange;

    @Value("${mail.queue.verifyCode:mail-queue-verifyCode}")
    private String mailQueueVerifyCode;

    @Value("${mail.route.verifyCode:mail-route-verifyCode}")
    private String mailRouteVerifyCode;

    @Value("${mail.queue.feedback:mail-queue-feedback}")
    private String mailQueueFeedback;

    @Value("${mail.route.feedback:mail-route-feedback}")
    private String mailRouteFeedback;


    @Bean
    DirectExchange mailExchange(){
        return new DirectExchange(mailExchange,true,false);
    }

    /**
     * 验证码消息队列
     * @return
     */
    @Bean
    Queue mailQueueVerifyCode(){
        return new Queue(mailQueueVerifyCode,true);
    }

    @Bean
    Binding mailQueueVerifyCodeBinding(){
        return BindingBuilder.bind(mailQueueVerifyCode()).to(mailExchange()).with(mailRouteVerifyCode);
    }


    }

}

自定义rabbitmqtemplate:


/**
 * 自定义消息发送RabbitTemplate
 * @author Hai
 * @date 2020/10/2 - 14:35
 */
@Configuration
public class RabbitMQConfig {
    public static final Logger LOGGER= LoggerFactory.getLogger(RabbitMQConfig.class);

    @Autowired
    CachingConnectionFactory cachingConnectionFactory;
    @Autowired
    MailSendLogService mailSendLogService;

    @Bean
    public RabbitTemplate rabbitTemplate(){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(cachingConnectionFactory);
        //成功投递消息到Broker交换机站点的回调函数
        rabbitTemplate.setConfirmCallback((data,ack,cause)->{
            String msgId = data.getId();
            if(ack){
                LOGGER.info(msgId+"消息发送成功");
                //修改数据库中的记录,消息发送成功,将status设为1
                mailSendLogService.updateMailSendLogStatus(msgId, MailConstants.SUCCESS);
            }else{
                LOGGER.error(msgId+"消息发送失败!");
            }
        });
        //消息投递到Queue队列失败的回调函数
        rabbitTemplate.setReturnCallback((msg,repCode,repText,exchange,routingKey)->{
            LOGGER.error(msg.getBody()+"----消息从交换机投递到队列失败!\n错误原因:"+repText);
            LOGGER.error("发送错误的交换机:"+exchange+",发生错误的路由key:"+routingKey);
        });
        return rabbitTemplate;
    }
}

验证码工具类

  /**
 * 生成验证码的工具类
 */
public class VerificationCode {

  private int width = 100;// 生成验证码图片的宽度
  private int height = 30;// 生成验证码图片的高度
  private String[] fontNames = { "宋体", "楷体", "隶书", "微软雅黑" };
  private Color bgColor = new Color(255, 255, 255);// 定义验证码图片的背景颜色为白色
  private Random random = new Random();
  private String codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  private String text;// 记录随机字符串

  /**
   * 获取一个随意颜色
   *
   * @return
   */
  private Color randomColor() {
    int red = random.nextInt(150);
    int green = random.nextInt(150);
    int blue = random.nextInt(150);
    return new Color(red, green, blue);
  }

  /**
   * 获取一个随机字体
   *
   * @return
   */
  private Font randomFont() {
    String name = fontNames[random.nextInt(fontNames.length)];
    int style = random.nextInt(4);
    int size = random.nextInt(5) + 24;
    return new Font(name, style, size);
  }

  /**
   * 获取一个随机字符
   *
   * @return
   */
  private char randomChar() {
    return codes.charAt(random.nextInt(codes.length()));
  }

  /**
   * 创建一个空白的BufferedImage对象
   *
   * @return
   */
  private BufferedImage createImage() {
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2 = (Graphics2D) image.getGraphics();
    g2.setColor(bgColor);// 设置验证码图片的背景颜色
    g2.fillRect(0, 0, width, height);
    return image;
  }

  public BufferedImage getImage() {
    BufferedImage image = createImage();
    Graphics2D g2 = (Graphics2D) image.getGraphics();
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < 4; i++) {
      String s = randomChar() + "";
      sb.append(s);
      g2.setColor(randomColor());
      g2.setFont(randomFont());
      float x = i * width * 1.0f / 4;
      g2.drawString(s, x, height - 8);
    }
    this.text = sb.toString();
    drawLine(image);
    return image;
  }

  /**
   * 绘制干扰线
   *
   * @param image
   */
  private void drawLine(BufferedImage image) {
    Graphics2D g2 = (Graphics2D) image.getGraphics();
    int num = 5;
    for (int i = 0; i < num; i++) {
      int x1 = random.nextInt(width);
      int y1 = random.nextInt(height);
      int x2 = random.nextInt(width);
      int y2 = random.nextInt(height);
      g2.setColor(randomColor());
      g2.setStroke(new BasicStroke(1.5f));
      g2.drawLine(x1, y1, x2, y2);
    }
  }

  public String getText() {
    return text;
  }

  public static void output(BufferedImage image, OutputStream out) throws IOException {
    ImageIO.write(image, "JPEG", out);
  }
}

处理发送验证码的消息

package top.javahai.subtlechat.mail.receiver;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.impl.AMQImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;

/**
 * 处理发送验证码的消息,保证消息不会重复消费
 * @author Hai
 * @date 2020/10/2 - 23:25
 */
@Component
public class VerifyCodeReceiver {
    @Autowired
    JavaMailSender javaMailSender;
    @Autowired
    StringRedisTemplate redisTemplate;

    private static final Logger LOGGER= LoggerFactory.getLogger(VerifyCodeReceiver.class);

    @RabbitListener(queues = "${mail.queue.verifyCode:mail-queue-verifyCode}")
    public void getMessage(Message message, Channel channel) throws IOException {
        //获取消息内容
        String code = message.getPayload().toString();
        //获取消息头,消息标志tag
        MessageHeaders headers = message.getHeaders();
        Long tag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
        //获取消息ID
        String msgId = (String) headers.get("spring_returned_message_correlation");
        LOGGER.info("【"+msgId+"】-正在处理的消息");
        //查看消息是否已消费
        if (redisTemplate.opsForHash().entries("mail_log").containsKey(msgId)){
            //手动确认消息已消费
            channel.basicAck(tag,false);
            LOGGER.info("【"+msgId+"】消息出现重复消费");
            return;
        }
        //否则进行消息消费
        try{
            SimpleMailMessage msg = new SimpleMailMessage();
            msg.setSubject("-验证码验证");

            msg.setText("本次登录的验证码:"+code);
            msg.setFrom("发送者的邮箱地址");
            msg.setSentDate(new Date());
            msg.setTo("接受者的邮箱地址");
            javaMailSender.send(msg);
            //消息发送成功,将id放到redis中,不能这样put
            //redisTemplate.opsForHash().entries("mail_log").put(msgId,code);
            redisTemplate.opsForHash().put("mail_log",msgId,code);
            //确认消息消费成功
            channel.basicAck(tag,false);
        }catch (Exception e){
            //不批量处理,将消息重新放回到队列中
            channel.basicNack(tag,false,true);
            LOGGER.info("【"+msgId+"】消息重新放回到了队列中");
            e.printStackTrace();
        }
    }
}

controller层

@RestController
public class LoginController {
  /**
   * 获取验证码图片写到响应的输出流中,保存验证码到session
   * @param response
   * @param session
   * @throws IOException
   */
  @GetMapping("/verifyCode")
  public void getVerifyCode(HttpServletResponse response, HttpSession session) throws IOException {
    VerificationCode code = new VerificationCode();
    BufferedImage image = code.getImage();
    String text = code.getText();
    session.setAttribute("verify_code",text);
    VerificationCode.output(image,response.getOutputStream());
  }


  @Autowired
  VerifyCodeService verifyCodeService;
  /**
   * 获取邮箱验证码,并保存到本次会话
   * @param session
   */
  @GetMapping("/admin/mailVerifyCode")
  public RespBean getMailVerifyCode(HttpSession session){
      String code = verifyCodeService.getVerifyCode();
      //保存验证码到本次会话
      session.setAttribute("mail_verify_code",code);
      verifyCodeService.sendVerifyCodeMail(code);
      return RespBean.ok("验证码已发送到邮箱,请注意查看!");
      }
      }
      }

其中sendVerifyCodeMail方法:

  @Override
    public void sendVerifyCodeMail(String code) {
        //添加消息记录
        String msgId = UUID.randomUUID().toString();
        MailSendLog mailSendLog = new MailSendLog();
        mailSendLog.setMsgId(msgId);
        mailSendLog.setContent(code);
        mailSendLog.setContentType(MailConstants.VERIFY_CODE_TYPE);
        mailSendLog.setCount(1);
        mailSendLog.setCreateTime(new Date());
        mailSendLog.setTryTime(new Date(System.currentTimeMillis()+1000*10*MailConstants.MEG_TIMEOUT));
        mailSendLog.setUpdateTime(new Date());
        mailSendLog.setExchange(mailExchange);
        mailSendLog.setRouteKey(mailRouteVerifyCode);
        mailSendLog.setStatus(MailConstants.DELIVERING);
        mailSendLogService.insert(mailSendLog);

        rabbitTemplate.convertAndSend(mailExchange,mailRouteVerifyCode,code,new CorrelationData(msgId));

    }

验证验证码是否正确


/**
 * 拦截登录请求,验证输入的验证码是否正确
 * @author Hai
 * @date 2020/5/28 - 17:31
 */
@Component
public class VerificationCodeFilter extends GenericFilter {

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;
    //如果是登录请求则拦截
    if ("POST".equals(request.getMethod())&&"/doLogin".equals(request.getServletPath())){
      //TODO 不启动验证码
      filterChain.doFilter(request,response);
      //用户输入的验证码
      String code = request.getParameter("code");
      //session中保存的验证码
      String verify_code = (String) request.getSession().getAttribute("verify_code");
      response.setContentType("application/json;charset=utf-8");
      PrintWriter writer = response.getWriter();
      //验证session中保存是否存在
      try {
        //验证是否相同
        if (!code.toLowerCase().equals(verify_code.toLowerCase())){
          //输出json
          writer.write(new ObjectMapper().writeValueAsString( RespBean.error("验证码错误!")));
          return;
        }else {
          filterChain.doFilter(request,response);
        }
      }catch (NullPointerException e){
        writer.write(new ObjectMapper().writeValueAsString(RespBean.error("请求异常,请重新请求!")));
      }finally {
        writer.flush();
        writer.close();
      }
    }
    else {
      filterChain.doFilter(request,response);
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值