配置:验证码工具类处理发送验证码的消息controller层验证验证码是否正确
配置: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配置:
@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); } @Bean Queue mailQueueVerifyCode(){ return new Queue(mailQueueVerifyCode,true); } @Bean Binding mailQueueVerifyCodeBinding(){ return BindingBuilder.bind(mailQueueVerifyCode()).to(mailExchange()).with(mailRouteVerifyCode); } } }
自定义rabbitmqtemplate:
@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.set/confirm/iCallback((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;// 记录随机字符串 private Color randomColor() { int red = random.nextInt(150); int green = random.nextInt(150); int blue = random.nextInt(150); return new Color(red, green, blue); } 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); } private char randomChar() { return codes.charAt(random.nextInt(codes.length())); } 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; } 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; @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 { @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; @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)); }验证验证码是否正确
@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); } } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)