From dba5270aaead4eaf5471a8661c272ce2abea788c Mon Sep 17 00:00:00 2001 From: huliyong <2783385703@qq.com> Date: Tue, 28 Oct 2025 00:15:56 +0800 Subject: [PATCH] 1 --- admin-hanhai-vue/.env.production | 4 +- .../api/service/impl/YaoDuApiServiceImpl.java | 161 ++++++++++++++++----- .../modules/api/yaoduapi/YaoDuApiController.java | 1 - .../system/security/IpAccessLimitInterceptor.java | 33 ++--- 4 files changed, 141 insertions(+), 58 deletions(-) diff --git a/admin-hanhai-vue/.env.production b/admin-hanhai-vue/.env.production index 9e94d96..fe8f7cd 100644 --- a/admin-hanhai-vue/.env.production +++ b/admin-hanhai-vue/.env.production @@ -1,4 +1,4 @@ NODE_ENV=production -VUE_APP_API_BASE_URL=http://localhost:8081/api/ -VUE_APP_CAS_BASE_URL=http://localhost:8888/cas +VUE_APP_API_BASE_URL=https://admin.hhlm1688.com/api/ +VUE_APP_CAS_BASE_URL=https://admin.hhlm1688.com/cas VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview \ No newline at end of file diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuApiServiceImpl.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuApiServiceImpl.java index 4a9335a..41e8be9 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuApiServiceImpl.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuApiServiceImpl.java @@ -22,6 +22,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.jeecg.common.api.vo.Result; +import org.jeecg.common.constant.YaoDuCacheConstant; import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.util.RedisUtil; import org.jeecg.config.shiro.ShiroRealm; @@ -93,6 +94,7 @@ import org.jeecg.modules.hanHaiMember.entity.HanHaiMember; import org.jeecg.modules.hanHaiMember.service.IHanHaiMemberService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.Cacheable; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -366,8 +368,9 @@ public class YaoDuApiServiceImpl implements YaoDuApiService { } - //根据分类获取动态帖子列表带分页 + //根据分类获取动态帖子列表带分页 @Override + @Cacheable(value = YaoDuCacheConstant.YAODU_POST_PAGE_CACHE, key = "#classId + '_' + #pageBean.pageNo + '_' + #pageBean.pageSize") public Result getPostPage(String classId,PageBean pageBean){ Page page = new Page(pageBean.getPageNo(), pageBean.getPageSize()); Page page1 = cityTrendsService @@ -376,51 +379,139 @@ public class YaoDuApiServiceImpl implements YaoDuApiService { .orderByDesc(CityTrends::getCreateTime) .page(page); + // 如果没有数据,直接返回 + if (page1.getRecords().isEmpty()) { + return Result.OK(page1); + } - for (CityTrends cityTrends : page1.getRecords()) { - - cityTrends.setIsComment(Math.toIntExact(cityCommentService.lambdaQuery().eq(CityComment::getOrderId, cityTrends.getId()).count())); + // 批量获取所有需要的数据,避免N+1查询问题 + List trendIds = page1.getRecords().stream() + .map(CityTrends::getId) + .collect(java.util.stream.Collectors.toList()); + + List userIds = page1.getRecords().stream() + .map(CityTrends::getUserId) + .filter(StringUtils::isNotBlank) + .distinct() + .collect(java.util.stream.Collectors.toList()); + + List shopIds = page1.getRecords().stream() + .map(CityTrends::getShopId) + .filter(StringUtils::isNotBlank) + .distinct() + .collect(java.util.stream.Collectors.toList()); + + // 批量查询评论数量 + Map commentCountMap = new HashMap<>(); + if (!trendIds.isEmpty()) { + List> commentCounts = cityCommentService.listMaps( + new QueryWrapper() + .select("order_id, COUNT(*) as count") + .in("order_id", trendIds) + .groupBy("order_id") + ); + commentCounts.forEach(map -> + commentCountMap.put((String) map.get("order_id"), ((Number) map.get("count")).longValue()) + ); + } - cityTrends.setIsBrowse(Math.toIntExact(appletBrowseRecordService - .lambdaQuery() - .eq(AppletBrowseRecord::getFormId, cityTrends.getId()) - .eq(AppletBrowseRecord::getType, 0) - .eq(AppletBrowseRecord::getCategory, 0) - .count())); + // 批量查询浏览数量 + Map browseCountMap = new HashMap<>(); + if (!trendIds.isEmpty()) { + List> browseCounts = appletBrowseRecordService.listMaps( + new QueryWrapper() + .select("form_id, COUNT(*) as count") + .in("form_id", trendIds) + .eq("type", 0) + .eq("category", 0) + .groupBy("form_id") + ); + browseCounts.forEach(map -> + browseCountMap.put((String) map.get("form_id"), ((Number) map.get("count")).longValue()) + ); + } - cityTrends.setComments(cityCommentService.lambdaQuery() - .orderByDesc(CityComment::getCreateTime) + // 批量查询评论列表 + Map> commentsMap = new HashMap<>(); + if (!trendIds.isEmpty()) { + List allComments = cityCommentService.lambdaQuery() + .in(CityComment::getOrderId, trendIds) .isNull(CityComment::getPid) - .eq(CityComment::getOrderId, cityTrends.getId()) - .last("limit 3") - .list()); + .orderByDesc(CityComment::getCreateTime) + .list(); + + // 按帖子ID分组评论,每个帖子最多取3条 + commentsMap = allComments.stream() + .collect(java.util.stream.Collectors.groupingBy( + CityComment::getOrderId, + java.util.stream.Collectors.collectingAndThen( + java.util.stream.Collectors.toList(), + list -> list.stream().limit(3).collect(java.util.stream.Collectors.toList()) + ) + )); + } - HanHaiMember one = hanHaiMemberService.lambdaQuery() - .eq(HanHaiMember::getId, cityTrends.getUserId()).one(); + // 批量查询用户信息 + Map memberMap = new HashMap<>(); + if (!userIds.isEmpty()) { + List members = hanHaiMemberService.lambdaQuery() + .in(HanHaiMember::getId, userIds) + .list(); + memberMap = members.stream() + .collect(java.util.stream.Collectors.toMap(HanHaiMember::getId, member -> member)); + } - if(StringUtils.isBlank(one.getName())){ - cityTrends.setUserName(one.getNickName()); - }else{ - cityTrends.setUserName(one.getName()); - } - cityTrends.setUserImage(one.getHeadImage()); + // 批量查询店铺信息 + Map shopMap = new HashMap<>(); + if (!shopIds.isEmpty()) { + List shops = cityShopService.lambdaQuery() + .in(CityShop::getId, shopIds) + .list(); + shopMap = shops.stream() + .collect(java.util.stream.Collectors.toMap(CityShop::getId, shop -> shop)); + } - //获取今年是多少年 - cityTrends.setYearDate(LocalDate.now().getYear() - one.getYearDate()); - cityTrends.setAddId(one.getAddress()); - if (one.getIdCardOpen() == null){ - cityTrends.setIsContent(""); - }else if (one.getIdCardOpen()== 1){ - cityTrends.setIsContent("个人实名"); - } else if (one.getIdCardOpen()== 2){ - cityTrends.setIsContent("店铺实名"); - }else{ - cityTrends.setIsContent(""); + // 设置查询结果 + for (CityTrends cityTrends : page1.getRecords()) { + // 设置评论数量 + cityTrends.setIsComment(commentCountMap.getOrDefault(cityTrends.getId(), 0L).intValue()); + + // 设置浏览数量 + cityTrends.setIsBrowse(browseCountMap.getOrDefault(cityTrends.getId(), 0L).intValue()); + + // 设置评论列表 + cityTrends.setComments(commentsMap.getOrDefault(cityTrends.getId(), new ArrayList<>())); + + // 设置用户信息 + HanHaiMember member = memberMap.get(cityTrends.getUserId()); + if (member != null) { + if(StringUtils.isBlank(member.getName())){ + cityTrends.setUserName(member.getNickName()); + }else{ + cityTrends.setUserName(member.getName()); + } + cityTrends.setUserImage(member.getHeadImage()); + + //获取今年是多少年 + if (member.getYearDate() != null) { + cityTrends.setYearDate(LocalDate.now().getYear() - member.getYearDate()); + } + cityTrends.setAddId(member.getAddress()); + + if (member.getIdCardOpen() == null){ + cityTrends.setIsContent(""); + }else if (member.getIdCardOpen()== 1){ + cityTrends.setIsContent("个人实名"); + } else if (member.getIdCardOpen()== 2){ + cityTrends.setIsContent("店铺实名"); + }else{ + cityTrends.setIsContent(""); + } } //店铺信息 if(StringUtils.isNotBlank(cityTrends.getShopId())){ - cityTrends.setShop(cityShopService.lambdaQuery().eq(CityShop::getId, cityTrends.getShopId()).one()); + cityTrends.setShop(shopMap.get(cityTrends.getShopId())); } } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiController.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiController.java index 8d08f54..ffe7ebc 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiController.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiController.java @@ -70,7 +70,6 @@ public class YaoDuApiController { //根据分类获取动态帖子列表带分页 @ApiOperation(value="根据分类获取动态帖子列表带分页") @GetMapping(value = "/getPostPage") - @Cacheable(value = YaoDuCacheConstant.YAODU_POST_PAGE_CACHE, key = "#classId + '_' + #pageBean.pageNo + '_' + #pageBean.pageSize") public Result getPostPage(String classId,PageBean pageBean) { return yaoDuApiService.getPostPage(classId,pageBean); } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/security/IpAccessLimitInterceptor.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/security/IpAccessLimitInterceptor.java index 43e6864..6817ea8 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/security/IpAccessLimitInterceptor.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/security/IpAccessLimitInterceptor.java @@ -119,37 +119,30 @@ public class IpAccessLimitInterceptor implements HandlerInterceptor { long currentSecond = currentTime / 1000; long currentMinute = currentTime / 60000; - // 检查每秒请求数 String secondKey = IP_ACCESS_COUNT_KEY + ip + ":second:" + currentSecond; - Integer secondCount = (Integer) redisTemplate.opsForValue().get(secondKey); - if (secondCount == null) { - secondCount = 0; - } + String minuteKey = IP_ACCESS_COUNT_KEY + ip + ":minute:" + currentMinute; + + // 先增加计数器 + Long secondCount = redisTemplate.opsForValue().increment(secondKey); + redisTemplate.expire(secondKey, 2, TimeUnit.SECONDS); - if (secondCount >= MAX_REQUESTS_PER_SECOND) { + Long minuteCount = redisTemplate.opsForValue().increment(minuteKey); + redisTemplate.expire(minuteKey, 2, TimeUnit.MINUTES); + + // 检查每秒请求数 + if (secondCount > MAX_REQUESTS_PER_SECOND) { recordViolation(ip); + log.warn("IP {} 每秒请求数超限: {}/{}", ip, secondCount, MAX_REQUESTS_PER_SECOND); return false; } // 检查每分钟请求数 - String minuteKey = IP_ACCESS_COUNT_KEY + ip + ":minute:" + currentMinute; - Integer minuteCount = (Integer) redisTemplate.opsForValue().get(minuteKey); - if (minuteCount == null) { - minuteCount = 0; - } - - if (minuteCount >= MAX_REQUESTS_PER_MINUTE) { + if (minuteCount > MAX_REQUESTS_PER_MINUTE) { recordViolation(ip); + log.warn("IP {} 每分钟请求数超限: {}/{}", ip, minuteCount, MAX_REQUESTS_PER_MINUTE); return false; } - // 更新计数器 - redisTemplate.opsForValue().increment(secondKey); - redisTemplate.expire(secondKey, 2, TimeUnit.SECONDS); - - redisTemplate.opsForValue().increment(minuteKey); - redisTemplate.expire(minuteKey, 2, TimeUnit.MINUTES); - return true; }