业务场景
公司项目,有一个要接受第三方消息得需求,对方会推松大量消息过来,为了防止对方频繁调用我得接受接口
自定义注解方式
代码入侵不高,使用方便,灵活
配置类
package com.bosssoft.op.applets.common.filter;
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;
/**
* @ClassName IntercepterConfig * @Description TODO
* @Author zhair
* @Date 16:42 2022/6/27
* @Version 1.0
**/
@Configuration
public class IntercepterConfig implements WebMvcConfigurer {
@Autowired
private AccessLimtInterceptor accessLimtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(accessLimtInterceptor)
.addPathPatterns("/web/v1/appMessage/saveMessageForTest");
}
}
addPathPatterns方法添加你要限制得接口
自定义注解
package com.bosssoft.op.applets.common.annotation;
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;
}
seconds 时间
maxCount 次数
实现类
package com.bosssoft.op.applets.common.filter;
import com.bosssoft.gp.framework.redis.service.api.IRedisService;
import com.bosssoft.op.applets.common.annotation.AccessLimit;
import com.bosssoft.op.applets.domain.vo.returninfo.ResponseVo;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;
/**
* @ClassName AccessLimtInterceptor * @Description TODO
* @Author zhair
* @Date 16:27 2022/6/27
* @Version 1.0
**/
@Component
public class AccessLimtInterceptor implements HandlerInterceptor {
@Resource
private IRedisService redisService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
if (null == accessLimit) {
return true;
}
int seconds = accessLimit.seconds();
int maxCount = accessLimit.maxCount();
boolean needLogin = accessLimit.needLogin();
if (needLogin) {
//判断是否登录
}
String ipAddress = getIPAddress(request);
String key = request.getContextPath() + ":" + request.getServletPath() + ":" + ipAddress ;
System.out.println(key);
Integer count = (Integer)redisService.get(key);
if (null == count || -1 == count) {
redisService.set(key,1,Integer.toUnsignedLong(seconds), TimeUnit.SECONDS);
return true;
}
if (count < maxCount) {
count++;
Long effectiveDuration = redisService.getEffectiveDuration(key, TimeUnit.SECONDS);
redisService.set(key,count,effectiveDuration, TimeUnit.SECONDS);
return true;
}
if (count >= maxCount) {
// response 返回 json 请求过于频繁请稍后再试
ResponseVo responseVo=new ResponseVo();
responseVo.setCode("500");
responseVo.setMsg("接口调用太频繁!");
responseVo.setData(null);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = null;
try {
out = response.getWriter();
JSONObject responseJSONObject = JSONObject.fromObject(responseVo);
out.write(responseJSONObject.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
return false;
}
}
return true;
}
/**
* 从HTTP请求中获取客户IP地址
*
* @param request http请求
* @return 客户IP地址
*/
public static String getIPAddress( HttpServletRequest request )
{
String ip = request.getHeader( "x-forwarded-for" );
if ( ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase( ip ) )
{
ip = request.getHeader( "Proxy-Client-IP" );
}
if ( ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase( ip ) )
{
ip = request.getHeader( "WL-Proxy-Client-IP" );
}
if ( ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase( ip ) )
{
ip = request.getHeader( "HTTP_CLIENT_IP" );
}
if ( ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase( ip ) )
{
ip = request.getHeader( "HTTP_X_FORWARDED_FOR" );
}
if ( ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase( ip ) )
{
ip = request.getRemoteAddr();
}
return ip;
}
}
Controller类
/**
* 接受第三方推松的数据
*
* @param
* @return 接受第三方推松的数据
*/
@AccessLimit(seconds = 10,maxCount = 3)
@ApiOperation(value = "接受第三方推松的数据")
@RequestMapping(value = "/saveMessage", method = RequestMethod.POST)
public ResponseVo<Object> saveMessage(@RequestBody AppMessageForOtherVo appMessageForOtherVo) throws SQLException, ExecutionException, InterruptedException {
ResponseVo responseVo = appMessageService.saveAppMessageForOther(appMessageForOtherVo);
return responseVo;
}