媒体查询做响应式网站娱乐建网站
news/
2025/9/23 19:40:49/
文章来源:
媒体查询做响应式网站,娱乐建网站,怎么向搜索引擎提交网站,门户网站广告的特点有导航一、方法计时器二、valid 参数校验的通用返回三、接口访问频次拦截#xff08;幂等#xff09;一、方法计时器
注解类#xff1a;MethodTimer
Target({ElementType.METHOD})
Retention(RetentionPolicy.RUNTIME)
public interface MethodTimer {
}处理器#xff08;需…
导航一、方法计时器二、valid 参数校验的通用返回三、接口访问频次拦截幂等一、方法计时器
注解类MethodTimer
Target({ElementType.METHOD})
Retention(RetentionPolicy.RUNTIME)
public interface MethodTimer {
}处理器需要AOP和spring的支持MethodTimerProcessor
Slf4j
Component
Aspect
public class MethodTimerProcessor {/*** 处理 MethodTimer 注解*/Around(annotation(methodTimer))public Object timerAround(ProceedingJoinPoint point, MethodTimer methodTimer) throws Throwable {long beginMills System.currentTimeMillis();// process the methodObject result point.proceed();log.info({} 耗时 : {} ms, point.getSignature(), System.currentTimeMillis() - beginMills);return result;}
}使用方法直接标记在 Controller 的方法上。
二、valid 参数校验的通用返回
注解类ValidCommonResp
Target(ElementType.METHOD)
Retention(RetentionPolicy.RUNTIME)
public interface ValidCommonResp {
}处理器aopspringValidCommonRespProcessor
Slf4j
Aspect
Component
public class ValidCommonRespProcessor {/*** 处理 ValidCommonResp 注解.* 注意BindingResult是Spring validation的校验结果* 当参数传入 BindingResult后,Spring MVC就不再控制校验* 结果的返回如果不希望使用 ValidCommonResp的校验结果* 封装请在方法中实现校验结果的处理二者任选其一。** author mouhaotian*/Around(annotation(validCommonResp))public Object aroundAdvice(ProceedingJoinPoint point, ValidCommonResp validCommonResp) throws Throwable {Object[] args point.getArgs();for (Object arg : args) {if (arg instanceof BindingResult) {BindingResult bindingResult (BindingResult) arg;if (bindingResult.hasErrors()) {FieldError fieldError bindingResult.getFieldError();CommonResp commonResp new CommonResp(CommonCode.FAIL,fieldError.getField() fieldError.getDefaultMessage());return R.data(commonResp);}break;}}Object result point.proceed(args);return result;}
}使用方法搭配 validation 注解、BindingResult 一起使用 PostMapping(/xxxx)ValidCommonResppublic R submit(Valid RequestBody DoorzoneInfo doorzoneInfo, BindingResult result) {log.info(请求{}, doorzoneInfo);R commonResp doorzoneInfoService.insertOrUpdDoorzoneInfo(doorzoneInfo);log.info(响应{}, commonResp);return commonResp;}好处可以替代代码块中处理 BindingResult 的逻辑。
三、接口访问频次拦截幂等
实现一个注解当controller中的方法收到请求后在一定时间之内如10s内拒绝接收相同参数的请求。即对后台接口的访问增加了频次限制可以理解为一种不是特别标准的幂等。
注解 Ide
/*** 幂等校验注解类*/
Target(ElementType.METHOD)
Retention(RetentionPolicy.RUNTIME)
Documented
public interface Ide {/*** 关键key* key是本次请求中参数的键* 重复请求的key取自header中的rid* 用来标识这个请求的唯一性* 拦截器中会使用key从请求参数中获取value** return String*/String key() default ;/*** 自定义key的前缀用来区分业务*/String perFix();/*** 自定义key的超时时间(基于接口)*/String expireTime();/*** 禁止重复提交的模式* 默认是全部使用*/IdeTypeEnum ideTypeEnum() default IdeTypeEnum.ALL;
}AOP 横切处理逻辑
/*** 注解执行器 处理重复请求 和串行指定条件的请求* p* 两种模式的拦截* 1.rid 是针对每一次请求的* 2.keyval 是针对相同参数请求* /p* p* 另根据谢新的建议对所有参数进行加密检验提供思路可以自行扩展* DigestUtils.md5Hex(userId - request.getRequestURL().toString()- JSON.toJSONString(request.getParameterMap()));* 或 DigestUtils.md5Hex(ip - request.getRequestURL().toString()- JSON.toJSONString(request.getParameterMap()));* /p*/
Slf4j
Aspect
Component
RequiredArgsConstructor
ConditionalOnClass(RedisService.class)
public class IdeAspect extends BaseAspect {private final ThreadLocalString PER_FIX_KEY new ThreadLocalString();/*** 配置注解后 默认开启*/private final boolean enable true;/*** request请求头中的key*/private final static String HEADER_RID_KEY RID;/*** redis中锁的key前缀*/private static final String REDIS_KEY_PREFIX RID:;/*** 锁等待时长*/private static int LOCK_WAIT_TIME 10;private final RedisService redisService;AutowiredIdeAspectConfig ideAspectConfig;Pointcut(annotation(cn.com.bmac.wolf.core.ide.annotation.Ide))public void watchIde() {}Before(watchIde())public void doBefore(JoinPoint joinPoint) {Ide ide getAnnotation(joinPoint, Ide.class);if (enable null ! ide) {ServletRequestAttributes attributes (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (null attributes) {throw new IdeException(请求数据为空);}HttpServletRequest request attributes.getRequest();//根据配置文件中的超时时间赋值if (Func.isNotBlank(ideAspectConfig.getExpireTime())) {if(Func.isNumeric(ideAspectConfig.getExpireTime())){LOCK_WAIT_TIME Integer.parseInt(ideAspectConfig.getExpireTime());}}//根据注解传参赋值if(Func.isNotBlank(ide.expireTime())){LOCK_WAIT_TIME Integer.parseInt(ide.expireTime());}//1.判断模式if (ide.ideTypeEnum() IdeTypeEnum.ALL || ide.ideTypeEnum() IdeTypeEnum.RID) {//2.1.通过rid模式判断是否属于重复提交String rid request.getHeader(HEADER_RID_KEY);if (Func.isNotBlank(rid)) {Boolean result redisService.tryLock(REDIS_KEY_PREFIX rid, LOCK_WAIT_TIME);if (!result) {throw new IdeException(命中RID重复请求);}log.debug(msg1当前请求已成功记录,且标记为0未处理,,{}{}, HEADER_RID_KEY, rid);} else {log.warn(msg1header没有rid,防重复提交功能失效,,remoteHost{} request.getRemoteHost());}}boolean isApiExpireTime false;if (ide.ideTypeEnum() IdeTypeEnum.ALL|| ide.ideTypeEnum() IdeTypeEnum.KEY) {//2.2.通过自定义key模式判断是否属于重复提交String key ide.key();if (Func.isNotBlank(key)) {String val ;Object[] paramValues joinPoint.getArgs();String[] paramNames ((CodeSignature) joinPoint.getSignature()).getParameterNames();//获取自定义key的valueString[] keys key.split(\\|);for(int i 0; i keys.length; i){for (int j 0; j paramNames.length; j) {//BindingResult 不能转json会导致线程报错终止if (paramValues[j] instanceof BindingResult) {continue;}String params JSON.toJSONString(paramValues[j]);if (params.startsWith({)) {//如果是对象//通过key获取valueJSONObject jsonObject JSON.parseObject(params);val val jsonObject.getString(keys[i]);} else if (keys[i].equals(paramNames[j])) {//如果是单个kvval val params;} else {//如果自定义的key,在请求参数中没有此参数,说明非法请求log.warn(自定义的key,在请求参数中没有此参数,防重复提交功能失效);}}}//判断重复提交的条件String perFix ;if (Func.isNotBlank(val)) {String[] perFixs ide.perFix().split(\\|);int perFixsLength perFixs.length;for(int i 0; i perFixs.length; i){if(Func.isNotBlank(perFix)){perFix perFix : perFixs[i];}else{perFix perFixs[i];}}perFix perFix : val;Boolean result true;try {result redisService.tryLock(perFix, LOCK_WAIT_TIME);} catch (Exception e) {log.error(获取redis锁发生异常, e);throw e;}if (!result) {String targetName joinPoint.getTarget().getClass().getName();String methodName joinPoint.getSignature().getName();log.error(msg1不允许重复执行,,key{},,targetName{},,methodName{}, perFix, targetName, methodName);throw new IdeException(不允许重复提交);}//存储在当前线程PER_FIX_KEY.set(perFix);log.info(msg1当前请求已成功锁定:{}, perFix);} else {log.warn(自定义的key,在请求参数中value为空,防重复提交功能失效);}}}}}After(watchIde())public void doAfter(JoinPoint joinPoint) throws Throwable {try {Ide ide getAnnotation(joinPoint, Ide.class);if (enable null ! ide) {if (ide.ideTypeEnum() IdeTypeEnum.ALL|| ide.ideTypeEnum() IdeTypeEnum.RID) {ServletRequestAttributes attributes (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request attributes.getRequest();String rid request.getHeader(HEADER_RID_KEY);if (Func.isNotBlank(rid)) {try {log.info(msg1当前请求已成功处理,,rid{}, rid);} catch (Exception e) {log.error(释放redis锁异常, e);}}PER_FIX_KEY.remove();}if (ide.ideTypeEnum() IdeTypeEnum.ALL|| ide.ideTypeEnum() IdeTypeEnum.KEY) {// 自定义keyString key ide.key();if (Func.isNotBlank(key) Func.isNotBlank(PER_FIX_KEY.get())) {try {log.info(msg1当前请求已成功释放,,key{}, PER_FIX_KEY.get());PER_FIX_KEY.set(null);PER_FIX_KEY.remove();} catch (Exception e) {log.error(释放redis锁异常, e);}}}}} catch (Exception e) {log.error(e.getMessage(), e);}}
}其他相关类
Data
Component
ConfigurationProperties(prefix ide)
public class IdeAspectConfig {/*** 过期时间 秒*/private String expireTime;}Getter
AllArgsConstructor
public enum IdeTypeEnum {/*** 01*/ALL(0, ALL),/*** ruid 是针对每一次请求的*/RID(1, RID),/*** keyval 是针对相同参数请求*/KEY(2, KEY);private final Integer index;private final String title;
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/913659.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!