当前位置: 首页 > news >正文

环球资源外贸平台怎么样seo优化操作

环球资源外贸平台怎么样,seo优化操作,哈尔滨专业做网站公司,做水果网站首页的图片素材目录 介绍 限流的思路 代码示例 必需pom依赖 自定义注解 redis工具类 redis配置类 主拦截器 注册拦截器 介绍 限流的需求出现在许多常见的场景中: 秒杀活动,有人使用软件恶意刷单抢货,需要限流防止机器参与活动 某 api 被各式各样…

目录

介绍

限流的思路

代码示例

必需pom依赖

自定义注解

redis工具类

redis配置类

主拦截器

注册拦截器


介绍

限流的需求出现在许多常见的场景中:
秒杀活动,有人使用软件恶意刷单抢货,需要限流防止机器参与活动
api 被各式各样系统广泛调用,严重消耗网络、内存等资源,需要合理限流
淘宝获取 ip 所在城市接口、微信公众号识别微信用户等开发接口,免费提供给用户时需要限流,更
具有实时性和准确性的接口需要付费。

限流的思路

通过 ip:api 路径 的作为 key ,访问次数为 value 的方式对某一用户的某一请求进行唯一标识
每次访问的时候判断 key 是否存在,是否 count 超过了限制的访问次数
若访问超出限制,则应 response 返回 msg: 请求过于频繁 给前端予以展示

代码示例

准备一个springboot项目

必需pom依赖

 <dependencies>
<!--        web开发场景启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
<!--        redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.3</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;//运行时执行
@Retention(RetentionPolicy.RUNTIME)
//指定注解的适用目标 表示该注解适用于方法上。
@Target(ElementType.METHOD)
public @interface AccessLimit {/*** 限制时长 秒*/int seconds();/*** 最大访问次数*/int maxCount();/*** 是否需要登录*/boolean needLogin() default true;
}

redis工具类


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Protocol;
import redis.clients.util.SafeEncoder;import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;@Component
public class RedisUtil {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// =============================common============================/*** 指定缓存失效时间* @param key 键* @param time 时间(秒)* @return*/public boolean expire(String key, long time) {try {if (time > 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 根据key 获取过期时间* @param key 键 不能为null* @return 时间(秒) 返回0代表为永久有效*/public long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/*** 判断key是否存在* @param key 键* @return true 存在 false不存在*/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除缓存* @param key 可以传一个值 或多个*/@SuppressWarnings("unchecked")public void del(String... key) {if (key != null && key.length > 0) {if (key.length == 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));}}}/*** 删除缓存* @param keys 可以传一个值 或多个*/public void del(Collection<String> keys) {if (CollectionUtils.isEmpty(keys)) {redisTemplate.delete(keys);}}// ============================String=============================/*** 普通缓存获取* @param key 键* @return 值*/public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);}/*** 普通缓存放入* @param key 键* @param value 值* @return true成功 false失败*/public boolean set(String key, Object value) {try {redisTemplate.opsForValue().set(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 普通缓存放入并设置时间* @param key 键* @param value 值* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期* @return true成功 false 失败*/public boolean set(String key, Object value, long time) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 递增* @param key 键* @param delta 要增加几(大于0)* @return*/public long incr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递增因子必须大于0");}return redisTemplate.opsForValue().increment(key, delta);}/*** 递减* @param key 键* @param delta 要减少几(小于0)* @return*/public long decr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递减因子必须大于0");}return redisTemplate.opsForValue().increment(key, -delta);}// ================================Map=================================/*** HashGet* @param key 键 不能为null* @param item 项 不能为null* @return 值*/public Object hget(String key, String item) {return redisTemplate.opsForHash().get(key, item);}/*** 获取hashKey对应的所有键值* @param key 键* @return 对应的多个键值*/public Map<Object, Object> hmget(String key) {return redisTemplate.opsForHash().entries(key);}/*** HashSet* @param key 键* @param map 对应多个键值* @return true 成功 false 失败*/public boolean hmset(String key, Map<String, Object> map) {try {redisTemplate.opsForHash().putAll(key, map);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** HashSet 并设置时间* @param key 键* @param map 对应多个键值* @param time 时间(秒)* @return true成功 false失败*/public boolean hmset(String key, Map<String, Object> map, long time) {try {redisTemplate.opsForHash().putAll(key, map);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建* @param key 键* @param item 项* @param value 值* @return true 成功 false失败*/public boolean hset(String key, String item, Object value) {try {redisTemplate.opsForHash().put(key, item, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建* @param key 键* @param item 项* @param value 值* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间* @return true 成功 false失败*/public boolean hset(String key, String item, Object value, long time) {try {redisTemplate.opsForHash().put(key, item, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除hash表中的值* @param key 键 不能为null* @param item 项 可以使多个 不能为null*/public void hdel(String key, Object... item) {redisTemplate.opsForHash().delete(key, item);}/*** 删除hash表中的值* @param key 键 不能为null* @param items 项 可以使多个 不能为null*/public void hdel(String key, Collection items) {redisTemplate.opsForHash().delete(key, items.toArray());}/*** 判断hash表中是否有该项的值* @param key 键 不能为null* @param item 项 不能为null* @return true 存在 false不存在*/public boolean hHasKey(String key, String item) {return redisTemplate.opsForHash().hasKey(key, item);}/*** hash递增 如果不存在,就会创建一个 并把新增后的值返回* @param key 键* @param item 项* @param delta 要增加几(大于0)* @return*/public double hincr(String key, String item, double delta) {if (delta < 0) {throw new RuntimeException("递增因子必须大于0");}return redisTemplate.opsForHash().increment(key, item, delta);}/*** hash递减* @param key 键* @param item 项* @param delta 要减少记(小于0)* @return*/public double hdecr(String key, String item, double delta) {if (delta < 0) {throw new RuntimeException("递减因子必须大于0");}return redisTemplate.opsForHash().increment(key, item, -delta);}// ============================set=============================/*** 根据key获取Set中的所有值* @param key 键* @return*/public Set<Object> sGet(String key) {try {return redisTemplate.opsForSet().members(key);} catch (Exception e) {e.printStackTrace();return null;}}/*** 根据value从一个set中查询,是否存在* @param key 键* @param value 值* @return true 存在 false不存在*/public boolean sHasKey(String key, Object value) {try {return redisTemplate.opsForSet().isMember(key, value);} catch (Exception e) {e.printStackTrace();return false;}}/*** 将数据放入set缓存* @param key 键* @param values 值 可以是多个* @return 成功个数*/public long sSet(String key, Object... values) {try {return redisTemplate.opsForSet().add(key, values);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 将数据放入set缓存* @param key 键* @param values 值 可以是多个* @return 成功个数*/public long sSet(String key, Collection values) {try {return redisTemplate.opsForSet().add(key, values.toArray());} catch (Exception e) {e.printStackTrace();return 0;}}/*** 将set数据放入缓存* @param key 键* @param time 时间(秒)* @param values 值 可以是多个* @return 成功个数*/public long sSetAndTime(String key, long time, Object... values) {try {Long count = redisTemplate.opsForSet().add(key, values);if (time > 0)expire(key, time);return count;} catch (Exception e) {e.printStackTrace();return 0;}}/*** 获取set缓存的长度* @param key 键* @return*/public long sGetSetSize(String key) {try {return redisTemplate.opsForSet().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 移除值为value的* @param key 键* @param values 值 可以是多个* @return 移除的个数*/public long setRemove(String key, Object... values) {try {Long count = redisTemplate.opsForSet().remove(key, values);return count;} catch (Exception e) {e.printStackTrace();return 0;}}// ===============================list=================================/*** 获取list缓存的内容* @param key 键* @param start 开始* @param end 结束 0 到 -1代表所有值* @return*/public List<Object> lGet(String key, long start, long end) {try {return redisTemplate.opsForList().range(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}/*** 获取list缓存的长度* @param key 键* @return*/public long lGetListSize(String key) {try {return redisTemplate.opsForList().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 通过索引 获取list中的值* @param key 键* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推* @return*/public Object lGetIndex(String key, long index) {try {return redisTemplate.opsForList().index(key, index);} catch (Exception e) {e.printStackTrace();return null;}}/*** 将list放入缓存* @param key 键* @param value 值* @return*/public boolean lSet(String key, Object value) {try {redisTemplate.opsForList().rightPush(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存* @param key 键* @param value 值* @param time 时间(秒)* @return*/public boolean lSet(String key, Object value, long time) {try {redisTemplate.opsForList().rightPush(key, value);if (time > 0)expire(key, time);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存* @param key 键* @param value 值* @return*/public boolean lSet(String key, List<Object> value) {try {redisTemplate.opsForList().rightPushAll(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存** @param key 键* @param value 值* @param time 时间(秒)* @return*/public boolean lSet(String key, List<Object> value, long time) {try {redisTemplate.opsForList().rightPushAll(key, value);if (time > 0)expire(key, time);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 根据索引修改list中的某条数据* @param key 键* @param index 索引* @param value 值* @return*/public boolean lUpdateIndex(String key, long index, Object value) {try {redisTemplate.opsForList().set(key, index, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 移除N个值为value* @param key 键* @param count 移除多少个* @param value 值* @return 移除的个数*/public long lRemove(String key, long count, Object value) {try {Long remove = redisTemplate.opsForList().remove(key, count, value);return remove;} catch (Exception e) {e.printStackTrace();return 0;}}/*** RedisTemplate 实现 setnx exptime (扩展 redisTemplate.setIfAbsent)** 之前用 redisTemplate 实现setnx exptime 时 是分两步的* 1. redisTemplate.setIfAbsent* 2. redisTemplate.expire* 这样的不是原子性的 可能在第一步与第二步之间 重新发布了或者服务器重启了* 这个key就永远不会消失了 可以采用以下的方法** @param key* @param value* @param exptime* @return*/public boolean setIfAbsent(final String key, final Serializable value, final long exptime) {Boolean b = (Boolean) redisTemplate.execute(new RedisCallback<Boolean>() {@Overridepublic Boolean doInRedis(RedisConnection connection) throws DataAccessException {RedisSerializer valueSerializer = redisTemplate.getValueSerializer();RedisSerializer keySerializer = redisTemplate.getKeySerializer();Object obj = connection.execute("set", keySerializer.serialize(key),valueSerializer.serialize(value),SafeEncoder.encode("NX"),//EX 秒,PX 毫秒SafeEncoder.encode("EX"),Protocol.toByteArray(exptime));return obj != null;}});return b;}
}

redis配置类


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {/*** retemplate相关配置* @param factory* @return*/@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();// 配置连接工厂template.setConnectionFactory(factory);//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
//        jacksonSeial.setObjectMapper(om);// 值采用json序列化template.setValueSerializer(jacksonSeial);//使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());// 设置hash key 和value序列化模式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(jacksonSeial);template.afterPropertiesSet();return template;}/*** 对hash类型的数据操作** @param redisTemplate* @return*/@Beanpublic HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForHash();}/*** 对redis字符串类型数据操作** @param redisTemplate* @return*/@Beanpublic ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForValue();}/*** 对链表类型的数据操作** @param redisTemplate* @return*/@Beanpublic ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForList();}/*** 对无序集合类型的数据操作** @param redisTemplate* @return*/@Beanpublic SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForSet();}/*** 对有序集合类型的数据操作** @param redisTemplate* @return*/@Beanpublic ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForZSet();}
}

主拦截器


import com.example.demo.service.AccessLimit;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;@Component
public class AccessLimitInterceptor implements HandlerInterceptor {@Resourceprivate RedisUtil redisUtil;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;//拿到限流注解类的参数AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);if(accessLimit==null){return true;}//时间int seconds = accessLimit.seconds();//最大次数int maxCount = accessLimit.maxCount();boolean needLogin = accessLimit.needLogin();if(needLogin){//判断是否登录}//获取访问ip和路径String ip=request.getRemoteAddr();String key=ip+":"+request.getServletPath();Integer count = (Integer)redisUtil.get(key);//首次进入if(count==null||-1==count){redisUtil.set(key,1);//设置过期时间redisUtil.expire(key,seconds);return true;}//如果访问次数<最大次数,则做加1操作if(count<maxCount){redisUtil.incr(key,1);return true;}//此时访问次数大于等于最大次数if(count>=maxCount){System.out.println("已经达到该接口限制最大次数========"+count);response.setContentType("text/html;charset=utf-8");response.getWriter().write("请求过于频繁,请稍后再试!");return false;}}return true;}
}

注册拦截器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class InteceptorConfig implements WebMvcConfigurer {@Autowiredprivate AccessLimitInterceptor accessLimitInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(accessLimitInterceptor)//添加限流拦截的接口路径.addPathPatterns("/access/accessLimit").addPathPatterns("/main/hello")//添加不限流拦截的路径.excludePathPatterns("/access/login");}
}

控制层

import com.example.demo.service.AccessLimit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("access")
public class AccessController {@ResponseBody@GetMapping("accessLimit")@AccessLimit(seconds = 60,maxCount = 5)public String accessLimit(){return "Hellp world!";}
}
@RestController
@RequestMapping("/main")
@Slf4j
public class MainCOntroller {@AutowiredStringRedisTemplate redisTemplate;@GetMapping("/hello")@AccessLimit(seconds = 10,maxCount = 2)public String helloo(){return "你好啊";}
}

启动测试:

 可以看到,两个接口都在限制的时间内有一定数量的访问限制,在redis里也能找到响应的key,从而实现了简单的接口限流

http://www.shuangfujiaoyu.com/news/40944.html

相关文章:

  • 网站开发岗位说明书描述建设一个网站的具体步骤
  • 网站开发模块全国人大常委会副委员长
  • 欧美做电影 迅雷下载网站百度地图推广怎么做的
  • 网站建设价类型seo是对网站进行什么优化
  • 北京企业做网站镇江网站建设
  • 网站建设制作细节重庆广告公司
  • 网站内容与功能设计新手做销售怎么开发客户
  • 驻马店网站建设熊掌号十大跨境电商erp排名
  • 济南建站联系企汇优百度百科搜索入口
  • 建筑网站夜里几点维护2023年中国进入一级战备状态了吗
  • 珠海网站建设多少钱搜索引擎优化的主要工作有
  • 网站做代码图像显示不出来百度快速排名案例
  • 福清哪有做网站的地方域名购买
  • 文化传媒可以做网站吗免费发布推广的平台有哪些
  • 广告设计接单网站媒体平台推广
  • 自己做外贸网站百度安装app
  • 网站登录模板下载厦门网络推广公司
  • jimdo做的网站企业网络推广计划书
  • 江苏响应式网站建设哪里有抖音自动推广引流app
  • 做分析图很好用的网站推广类软文案例
  • 苏州做企业网站的公司重庆seo和网络推广
  • 购物网站详细设计seo排名优化的方法
  • 四川网站建设制作网络竞价推广托管公司
  • 杭州做公司网站四年级小新闻50字左右
  • 聊城医院网站建设中文搜索引擎排行榜
  • 长沙网站建设优化免费的网页制作软件
  • 城口自助建站网络软文推广网站
  • 做起点说网站的服务器多少钱宜昌seo
  • 网站语音转写怎么做中央人民政府网
  • aspcms网站源码已矣seo排名点击软件