首先来一个注解
package co.yiiu.module.bountyHunter.pay.wxpay.core;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import java.lang.annotation.*;
/**
* Created date on 2018/12/10
* Author Zy
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {
/**
* 允许访问的次数,默认值MAX_VALUE
*/
int count() default Integer.MAX_VALUE;
/**
* 时间段,单位为毫秒,默认值一分钟
*/
long time() default 60000;
}
利用AOP前置增强做逻辑处理
package co.yiiu.module.bountyHunter.pay.wxpay.core;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
@Aspect
public class RequestLimitAop {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Before("within(@org.springframework.stereotype.Controller *) && @annotation(limit)")
public void requestLimit(JoinPoint joinPoint, RequestLimit limit) throws RequestLimitException {
try {
Object[] args = joinPoint.getArgs();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String ip = getIpAddress(request);
String url = request.getRequestURL().toString();
String key = "req_limit_".concat(url).concat("_").concat(ip);
boolean checkResult = checkWithRedis(limit, key);
if (!checkResult) {
log.debug("requestLimited," + "[用户ip:{}],[访问地址:{}]超过了限定的次数[{}]次", ip, url, limit.count());
throw new RequestLimitException("请求过于频繁,超出限制!");
}
} catch (RequestLimitException e) {
throw e;
} catch (Exception e) {
log.error("RequestLimitAop.requestLimit has some exceptions: ", e);
}
}
/**
* 以redis实现请求记录
*
* @param limit
* @param key
* @return
*/
private boolean checkWithRedis(RequestLimit limit, String key) {
long count = stringRedisTemplate.opsForValue().increment(key, 1);
if (count == 1) {
stringRedisTemplate.expire(key, limit.time(), TimeUnit.MILLISECONDS);
}
if (count > limit.count()) {
return false;
}
return true;
}
/**
* 获取用户真实IP地址,不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址,
* 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值
*
* @return ip
*/
private String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
log.info("x-forwarded-for ip: " + ip);
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
if( ip.indexOf(",")!=-1 ){
ip = ip.split(",")[0];
}
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
log.info("Proxy-Client-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
log.info("WL-Proxy-Client-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
log.info("HTTP_CLIENT_IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
log.info("HTTP_X_FORWARDED_FOR ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
log.info("X-Real-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
log.info("getRemoteAddr ip: " + ip);
}
log.info("获取客户端ip: " + ip);
return ip;
}
}
利用AOP后置捕获web请求的异常
**
package co.yiiu.core.exception;
import co.yiiu.core.base.BaseController;
import co.yiiu.core.bean.Result;
import co.yiiu.module.user.pojo.User;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Slf4j
@Aspect
@Component
public class WebExceptionAspect extends BaseController{
private Exception e;
//切入点
@Pointcut("execution(* co.yiiu.web.bountyHunter..*.*(..))")
private void bountyHunterPointcut() {
}
/**
* 拦截web层异常,记录异常日志,并返回友好信息到前端
*
* @param e
* 异常对象
*/
@AfterThrowing(pointcut = "bountyHunterPointcut()", throwing = "e")
public void handleThrowing(JoinPoint joinPoint,Exception e) {
User user = getUserFromSession();
this.e = e;
//e.printStackTrace();
if (null != user){
log.error("发现异常!操作用户手机号:"+user.getMobile());
}
log.error("发现异常!方法:"+ joinPoint.getSignature().getName()+"--->异常",e);
//这里输入友好性信息
if (!StringUtils.isEmpty(e.getMessage())){
log.error("异常",e.getMessage());
writeContent(500,e.getMessage());
}else {
writeContent(500,"十分抱歉,出现异常!程序猿小哥正在紧急抢修...");
}
}
/**
* 将内容输出到浏览器
*
* @param content
* 输出内容
*/
public static void writeContent(Integer code,String content) {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getResponse();
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "text/json;charset=UTF-8");
response.setHeader("icop-content-type", "exception");
PrintWriter writer = null;
JsonGenerator jsonGenerator = null;
try {
writer = response.getWriter();
jsonGenerator = (new ObjectMapper()).getFactory().createGenerator(writer);
jsonGenerator.writeObject(Result.error(code,content));
} catch (IOException e1) {
e1.printStackTrace();
}finally {
writer.flush();
writer.close();
}
}
}
现在我们进行简单的测试
@PostMapping("/test")
@RequestLimit(count = 2)
@ResponseBody
public Result test(){
return Result.success();
}
postman测试
控制台打印信息
---------------------
作者:IT界的奇葩
来源:CSDN
原文:https://blog.csdn.net/a309220728/article/details/84937630
版权声明:本文为博主原创文章,转载请附上博文链接!