Java 实现短信发送请求限制1分钟1次,不借助redis等额外插件,最简教程

版权声明:本文为作者原创文章,转载请附上原文出处链接和本声明。
本文链接:http://doc.shulijp.com/jdetail/1586921627006

实体类——用于接收ip和手机号

import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class SmsEntity{
  private String mobile;
  private String ip;
}

SmsFilter——拦截接口

public interface SmsFilter{
	/**
	   * 初始化该过滤器
	   */
	  void init() throws Exception;

	  /**
	   * 判断短信是否可以发送.
	   * @param smsEntity 将要发送的短信内容
	   * @return 可以发送则返回true, 否则返回false
	   */
	  boolean filter(SmsEntity smsEntity);

	  /**
	   * 销毁该过滤器
	   */
	  void destroy();
}

FrequencyFilter——SmsFilter的实现类

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.bitrade.notice.api.bean.SmsEntity;
import org.bitrade.notice.api.service.SmsFilter;
import org.bitrade.notice.api.utils.LogUtil;
import org.springframework.stereotype.Service;

@Service
public class FrequencyFilter implements SmsFilter {
	  /**
	   * 发送间隔, 单位: 毫秒
	   */
	  private long sendInterval = 60000;
	  private ConcurrentMap<String, Long> sendAddressMap = new ConcurrentHashMap<>();
	  
	  private long cleanMapInterval;
	  private Timer timer = new Timer("sms_frequency_filter_clear_data_thread");

	  @Override
	  public void init() {
	    timer.schedule(new TimerTask() {
	      @Override
	      public void run() {
	        cleanSendAddressMap();
	      }
	    }, cleanMapInterval, cleanMapInterval);
	  }

	  /**
	   * 将sendAddressMap中的所有过期数据删除
	   */
	  private void cleanSendAddressMap() {
	    long currentTime = System.currentTimeMillis();
	    long expireSendTime = currentTime - sendInterval;

	    for(String key : sendAddressMap.keySet()) {
	      Long sendTime = sendAddressMap.get(key);
	      if(sendTime < expireSendTime) {
	        sendAddressMap.remove(key, sendTime);
	      }
	    }
	  }

	  @Override
	  public void destroy() {
	    timer.cancel();
	  }
	  // 省略了部分无用代码

	  @Override
	  public boolean filter(SmsEntity smsEntity) {
	    if(setSendTime(smsEntity.getMobile()) && setSendTime(smsEntity.getIp())){
	      return true;
	    }
	    return false;
	  }

	  /**
	   * 将发送时间修改为当前时间.
	   * 如果距离上次发送的时间间隔大于{@link #sendInterval}则设置发送时间为当前时间. 否则不修改任何内容.
	   *
	   * @param id 发送手机号 或 ip
	   * @return 如果成功将发送时间修改为当前时间, 则返回true. 否则返回false
	   */
	  private boolean setSendTime(String id) {
	    long currentTime = System.currentTimeMillis();
	    Long sendTime = sendAddressMap.putIfAbsent(id, currentTime);
	    if(sendTime == null) {
	      return true;
	    }

	    long nextCanSendTime = sendTime + sendInterval;
	    LogUtil.log("当前时间:"+currentTime+"可以发送的时间:"+nextCanSendTime);
	    if(currentTime < nextCanSendTime) {
	      return false;
	    }

	    if(sendAddressMap.replace(id, sendTime, currentTime)) {
	        return true;
	      }
	    return sendAddressMap.putIfAbsent(id, currentTime) == null;
	  }

	}

action层调用

    @Autowired
	protected HttpServletRequest request;
	@Autowired
	private SmsFilter filters;

	@RequestMapping("/messageNotice")
	public R messageNotice(String mobile,String content){
		// 查询是超过短信发送限制 查询上次发送时间
		boolean filter=filters.filter(new SmsEntity(IpUtil.getIpAddr(request),mobile));
//		LogUtil.log(filter);
		if(!filter){
			return R.fail("验证码发送的太快了,请稍后重试");
		}
		具体业务逻辑。。。。。
		return R.ok();
	}

有问题请留言!

还能输入1000个字符
  • 今天在使用springboot删除文件的时候无法进行正常删除,经过一段时间的排查,发现是在进行文件读取后没有关闭数据流导致的,再此进行记录。1、查找原因文件无法删除一般都是文件被某个程序进程占用,在代

  • @Data@ApiModelpublicclassPageVo{@ApiModelProperty(value="当前页",example="1",dataType="Integer")publicI

  • <code>一、校验数字的表达式  1 数字:^[0-9]*$  2 n位的数字:^\d{n}$  3 至少n位的数字:^\d{n,}$  4 m-n位的数字:^\d{m,n}$  5 零和非零开头的数字:^(0|[1-9][0-9]*)$  6 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$  7 带1-2位小数的正数或负数:^(\-)?\d+(\

  • &!--数组转字符串--&vara,b;a=newArray(0,1,2,3,4);b=a.join("-");&!--字符串转数组--&vars="abc,abcd,aaa";ss=s.split(

  • 需要在之间加上红色代码response.reset();out=response.getOutputStream();response.reset();while((len=br.read(buf))

  • js图片截取

    阅读数 13

    /***js图片截取*@paramval*@paramtop*@paramright*@parambottom*@paramleft*用例:imgSplit(this,0,0,-30,0)*/func

  • &!--定义--&在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的

  • 方法一:对移动端兼容不好$(".copy")[0].onclick=function(){vartxt=$('#wxContent').text();Copy(txt);}//复制微信号函数funct

  •     cmd命令大全(第一部分)  winver---------检查Windows版本   wmimgmt.msc----打开windows管理体系结构(WMI)   wupdmgr-------

  • centos系统中,如果/sbin目录下没有service这个命令,就会出现-bash:service:commandnotfound的错误。解决步骤如下:1、输入:[plain]viewplainc