diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/annotation/limiter/Limiter.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/annotation/Limiter.java similarity index 90% rename from opsli-base-support/opsli-common/src/main/java/org/opsli/common/annotation/limiter/Limiter.java rename to opsli-base-support/opsli-common/src/main/java/org/opsli/common/annotation/Limiter.java index c11fc09..411a83f 100644 --- a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/annotation/limiter/Limiter.java +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/annotation/Limiter.java @@ -1,4 +1,4 @@ -package org.opsli.common.annotation.limiter; +package org.opsli.common.annotation; import org.opsli.common.enums.AlertType; diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/annotation/SearchHis.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/annotation/SearchHis.java new file mode 100644 index 0000000..b87e4bf --- /dev/null +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/annotation/SearchHis.java @@ -0,0 +1,29 @@ +package org.opsli.common.annotation; + +import java.lang.annotation.*; + +/** + * 搜索历史注解 + * + * 默认按照当前用户 key, 搜索记录排行最高 + * + * @author Parker + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface SearchHis { + + /** + * 搜索 key,即 url 参数key + * + * http://127.0.0.1/opsli-boot?username=123 + * + * username 就是 key + * + * 如果使用条件构造器, 比如 username_EQ key需要一致 + * + */ + String[] keys(); + +} diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/OrderConstants.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/OrderConstants.java index 7188b60..4586f15 100644 --- a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/OrderConstants.java +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/OrderConstants.java @@ -37,6 +37,9 @@ public interface OrderConstants { /** 参数非法验证顺序 */ int PARAM_VALIDATE_AOP_SORT = 185; + /** 搜索历史 */ + int SEARCH_HIS_AOP_SORT = 186; + /** SQL 切面执行顺序 */ int SQL_ORDER = 190; diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/RateLimiterUtil.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/RateLimiterUtil.java index d0eb6cd..43b3b28 100644 --- a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/RateLimiterUtil.java +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/RateLimiterUtil.java @@ -95,7 +95,7 @@ public final class RateLimiterUtil { */ public static boolean enter(String clientIpAddress, String resource, Double dfQps) { // 计时器 - TimeInterval timer = DateUtil.timer(); + long t1 = System.currentTimeMillis(); Map rateLimiterInnerMap; try { @@ -141,15 +141,11 @@ public final class RateLimiterUtil { //非阻塞 if (!rateLimiter.tryAcquire(Duration.ofMillis(DEFAULT_WAIT))) { - // 花费毫秒数 - long timerCount = timer.interval(); //限速中,提示用户 - log.error("限流器 - 访问频繁 耗时: "+ timerCount + "ms, IP地址: " + clientIpAddress + ", URI: " + resource); + log.error("限流器 - 访问频繁 耗时: "+ (System.currentTimeMillis() - t1) + "ms, IP地址: " + clientIpAddress + ", URI: " + resource); return false; } else { // 正常访问 - // 花费毫秒数 - long timerCount = timer.interval(); return true; } } diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/aspect/LimiterAop.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/aspect/LimiterAop.java index 8831c75..edf4aea 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/aspect/LimiterAop.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/aspect/LimiterAop.java @@ -22,7 +22,7 @@ import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; -import org.opsli.common.annotation.limiter.Limiter; +import org.opsli.common.annotation.Limiter; import org.opsli.common.enums.AlertType; import org.opsli.common.exception.ServiceException; import org.opsli.common.utils.OutputStreamUtil; @@ -52,7 +52,7 @@ import static org.opsli.common.constants.OrderConstants.LIMITER_AOP_SORT; public class LimiterAop { - @Pointcut("@annotation(org.opsli.common.annotation.limiter.Limiter)") + @Pointcut("@annotation(org.opsli.common.annotation.Limiter)") public void requestMapping() { } diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/aspect/SearchHisAop.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/aspect/SearchHisAop.java new file mode 100644 index 0000000..5c7f7c3 --- /dev/null +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/aspect/SearchHisAop.java @@ -0,0 +1,81 @@ +/** + * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.opsli.core.aspect; + +import cn.hutool.core.convert.Convert; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.opsli.common.annotation.SearchHis; +import org.opsli.core.utils.SearchHisUtil; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; + +import static org.opsli.common.constants.OrderConstants.SEARCH_HIS_AOP_SORT; + +/** + * 搜索历史 AOP + * + * @author 周鹏程 + * @date 2020-09-16 + */ +@Slf4j +@Order(SEARCH_HIS_AOP_SORT) +@Aspect +@Component +public class SearchHisAop { + + + @Pointcut("@annotation(org.opsli.common.annotation.SearchHis)") + public void requestMapping() { + } + + /** + * 限流 + * @param point + */ + @Before("requestMapping()") + public void limiterHandle(JoinPoint point){ + try { + RequestAttributes ra = RequestContextHolder.getRequestAttributes(); + ServletRequestAttributes sra = (ServletRequestAttributes) ra; + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + if(sra != null) { + HttpServletRequest request = sra.getRequest(); + SearchHis searchHis = method.getAnnotation(SearchHis.class); + if(searchHis != null){ + String[] keys = searchHis.keys(); + + // 存入缓存 + SearchHisUtil.putSearchHis(request, Convert.toList(String.class, keys)); + } + } + }catch (Exception e){ + log.error(e.getMessage(),e); + } + } + +} diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java index 91e42a0..0109bc9 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/CaptchaUtil.java @@ -17,12 +17,10 @@ package org.opsli.core.utils; import com.google.code.kaptcha.Producer; import org.apache.commons.lang3.StringUtils; -import org.opsli.api.web.system.dict.DictDetailApi; import org.opsli.common.constants.CacheConstants; import org.opsli.common.exception.TokenException; import org.opsli.common.utils.Props; import org.opsli.core.msg.TokenMsg; -import org.opsli.plugins.redis.RedisLockPlugins; import org.opsli.plugins.redis.RedisPlugin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/DictUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/DictUtil.java index 29089f8..e442e87 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/DictUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/DictUtil.java @@ -23,9 +23,8 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.opsli.api.base.result.ResultVo; import org.opsli.api.web.system.dict.DictDetailApi; -import org.opsli.api.web.system.menu.MenuApi; -import org.opsli.api.wrapper.system.dict.DictWrapper; import org.opsli.api.wrapper.system.dict.DictDetailModel; +import org.opsli.api.wrapper.system.dict.DictWrapper; import org.opsli.common.constants.CacheConstants; import org.opsli.common.constants.DictConstants; import org.opsli.core.cache.local.CacheUtil; diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/MenuUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/MenuUtil.java index f956059..b9f67c0 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/MenuUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/MenuUtil.java @@ -19,11 +19,9 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.opsli.api.base.result.ResultVo; import org.opsli.api.web.system.menu.MenuApi; -import org.opsli.api.web.system.user.UserApi; import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.core.cache.local.CacheUtil; import org.opsli.core.cache.pushsub.msgs.MenuMsgFactory; -import org.opsli.core.cache.pushsub.msgs.OrgMsgFactory; import org.opsli.plugins.redis.RedisLockPlugins; import org.opsli.plugins.redis.RedisPlugin; import org.opsli.plugins.redis.lock.RedisLock; diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java index f7bb9f2..0d24952 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java @@ -18,12 +18,9 @@ package org.opsli.core.utils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.opsli.api.base.result.ResultVo; -import org.opsli.api.web.system.menu.MenuApi; import org.opsli.api.web.system.user.UserApi; -import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.api.wrapper.system.user.UserOrgRefModel; import org.opsli.core.cache.local.CacheUtil; -import org.opsli.core.cache.pushsub.msgs.MenuMsgFactory; import org.opsli.core.cache.pushsub.msgs.OrgMsgFactory; import org.opsli.plugins.redis.RedisLockPlugins; import org.opsli.plugins.redis.RedisPlugin; diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SearchHisUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SearchHisUtil.java new file mode 100644 index 0000000..1ee8ade --- /dev/null +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/SearchHisUtil.java @@ -0,0 +1,129 @@ +/** + * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.opsli.core.utils; + +import cn.hutool.core.collection.CollUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.opsli.api.wrapper.system.user.UserModel; +import org.opsli.common.constants.CacheConstants; +import org.opsli.common.utils.Props; +import org.opsli.plugins.redis.RedisLockPlugins; +import org.opsli.plugins.redis.RedisPlugin; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.opsli.common.constants.OrderConstants.UTIL_ORDER; + +/** + * @Author: 周鹏程 + * @CreateTime: 2020-09-22 11:17 + * @Description: 搜索历史工具类 + */ +@Slf4j +@Order(UTIL_ORDER) +@Component +@Lazy(false) +@AutoConfigureAfter({RedisPlugin.class , RedisLockPlugins.class}) +public class SearchHisUtil { + + + /** 搜索历史缓存数据KEY */ + private static final int DEFAULT_COUNT = 10; + + /** + * 热点数据前缀 + */ + public static final String PREFIX_NAME; + private static final String CACHE_PREFIX = "his:username:"; + + /** Redis插件 */ + private static RedisPlugin redisPlugin; + + static { + Props props = new Props("application.yaml"); + PREFIX_NAME = props.getStr("spring.cache-conf.prefix", CacheConstants.PREFIX_NAME) + ":"; + } + + + /** + * 获得搜索历史记录 + * @param key 类型 + * @param count 获取数量 + */ + public static Set getSearchHis(HttpServletRequest request, String key, Integer count) { + if(request == null || StringUtils.isEmpty(key)){ + return null; + } + + if(count == null){ + count = DEFAULT_COUNT; + } + + // 获得当前用户 + UserModel user = UserUtil.getUser(); + + String cacheKey = PREFIX_NAME + CACHE_PREFIX + user.getUsername() + ":" + key; + + return redisPlugin.zReverseRange(cacheKey, 0, count - 1); + } + + /** + * 存放搜索历史记录 + * @param request + * @param keys 搜索key + */ + public static void putSearchHis(HttpServletRequest request, List keys) { + if(request == null || CollUtil.isEmpty(keys)){ + return; + } + + // 获得当前用户 + UserModel user = UserUtil.getUser(); + + Map parameterMap = request.getParameterMap(); + for (String key : keys) { + String[] values = parameterMap.get(key); + if(values == null || values.length == 0){ + continue; + } + + + String cacheKey = PREFIX_NAME + CACHE_PREFIX + user.getUsername() + ":" + key; + String val = values[0]; + + // 记录 + redisPlugin.zIncrementScore(cacheKey, val, 1); + } + } + + + // =================================== + + @Autowired + public void setRedisPlugin(RedisPlugin redisPlugin) { + SearchHisUtil.redisPlugin = redisPlugin; + } + +} diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/TenantUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/TenantUtil.java index 9cd3cf3..eac5268 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/TenantUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/TenantUtil.java @@ -20,13 +20,8 @@ import org.apache.commons.lang3.StringUtils; import org.opsli.api.base.result.ResultVo; import org.opsli.api.web.system.tenant.TenantApi; import org.opsli.api.wrapper.system.tenant.TenantModel; -import org.opsli.api.wrapper.system.user.UserOrgRefModel; -import org.opsli.common.exception.TokenException; import org.opsli.core.cache.local.CacheUtil; -import org.opsli.core.cache.pushsub.msgs.OrgMsgFactory; import org.opsli.core.cache.pushsub.msgs.TenantMsgFactory; -import org.opsli.core.msg.TokenMsg; -import org.opsli.core.persistence.querybuilder.GenQueryBuilder; import org.opsli.plugins.redis.RedisLockPlugins; import org.opsli.plugins.redis.RedisPlugin; import org.opsli.plugins.redis.lock.RedisLock; @@ -36,8 +31,6 @@ import org.springframework.context.annotation.Lazy; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.util.List; - import static org.opsli.common.constants.OrderConstants.UTIL_ORDER; /** diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java index 4537ce0..29c74dd 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java @@ -30,13 +30,11 @@ import org.opsli.common.constants.CacheConstants; import org.opsli.common.constants.SignConstants; import org.opsli.common.constants.TokenConstants; import org.opsli.common.constants.TokenTypeConstants; -import org.opsli.common.exception.ServiceException; import org.opsli.common.exception.TokenException; import org.opsli.common.utils.Props; import org.opsli.core.msg.TokenMsg; import org.opsli.plugins.redis.RedisPlugin; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Lazy; import org.springframework.core.annotation.Order; diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java index 2ef44c7..49de8db 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java @@ -29,7 +29,6 @@ import org.opsli.common.api.TokenThreadLocal; import org.opsli.common.exception.TokenException; import org.opsli.common.utils.Props; import org.opsli.core.cache.local.CacheUtil; -import org.opsli.core.cache.pushsub.msgs.MenuMsgFactory; import org.opsli.core.cache.pushsub.msgs.UserMsgFactory; import org.opsli.core.msg.TokenMsg; import org.opsli.plugins.redis.RedisLockPlugins; diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java index 1061aa6..648ec01 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java @@ -23,7 +23,7 @@ import org.apache.tomcat.util.http.fileupload.IOUtils; import org.opsli.api.base.result.ResultVo; import org.opsli.api.wrapper.system.tenant.TenantModel; import org.opsli.api.wrapper.system.user.UserModel; -import org.opsli.common.annotation.limiter.Limiter; +import org.opsli.common.annotation.Limiter; import org.opsli.common.api.TokenThreadLocal; import org.opsli.common.enums.AlertType; import org.opsli.common.exception.TokenException; diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/tools/searchhis/web/SearchHisRestController.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/tools/searchhis/web/SearchHisRestController.java new file mode 100644 index 0000000..9117976 --- /dev/null +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/tools/searchhis/web/SearchHisRestController.java @@ -0,0 +1,66 @@ +/** + * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.opsli.modulars.tools.searchhis.web; + +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.opsli.api.base.result.ResultVo; +import org.opsli.common.annotation.ApiRestController; +import org.opsli.common.annotation.Limiter; +import org.opsli.common.annotation.SearchHis; +import org.opsli.core.utils.SearchHisUtil; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.util.Set; + +/** + * 搜索历史记录 + * + * @author parker + * @date 2020-05-23 13:30 + ** + */ +@Slf4j +@RestController +@ApiRestController("/searchhis") +public class SearchHisRestController { + + /** + * 获得搜索历史记录 + */ + @Limiter + @ApiOperation(value = "获得搜索历史记录", notes = "获得搜索历史记录") + @PostMapping("/getSearchHis") + public ResultVo getSearchHis(String key, Integer count, HttpServletRequest request){ + + Set searchHis = SearchHisUtil.getSearchHis(request, key, count); + + return ResultVo.success(searchHis); + } + + /** + * 获得搜索历史记录 + */ + @Limiter + @SearchHis(keys = {"test"}) + @ApiOperation(value = "测试存入搜索历史记录", notes = "测试存入搜索历史记录") + @PostMapping("/testPutSearchHis") + public void getSearchHis(String test, HttpServletRequest request){ + } + +}