1
This commit is contained in:
@@ -3,14 +3,17 @@ package com.ruoyi.web.controller.publicapi;
|
|||||||
import com.ruoyi.common.annotation.Anonymous;
|
import com.ruoyi.common.annotation.Anonymous;
|
||||||
import com.ruoyi.common.core.controller.BaseController;
|
import com.ruoyi.common.core.controller.BaseController;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.ruoyi.common.utils.http.HttpUtils;
|
import com.ruoyi.common.utils.http.HttpUtils;
|
||||||
|
import com.ruoyi.jarvis.domain.dto.CommentCallHistory;
|
||||||
import com.ruoyi.jarvis.service.ICommentService;
|
import com.ruoyi.jarvis.service.ICommentService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,9 +69,10 @@ public class CommentPublicController extends BaseController {
|
|||||||
* 入参:productType(型号/类型)
|
* 入参:productType(型号/类型)
|
||||||
*/
|
*/
|
||||||
@PostMapping("/generate")
|
@PostMapping("/generate")
|
||||||
public AjaxResult generate(@RequestBody Map<String, String> body) {
|
public AjaxResult generate(@RequestBody Map<String, String> body, HttpServletRequest request) {
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
String productType = null;
|
String productType = null;
|
||||||
|
String clientIp = getClientIp(request);
|
||||||
try {
|
try {
|
||||||
String url = getJdBase() + "/comment/generate";
|
String url = getJdBase() + "/comment/generate";
|
||||||
JSONObject param = new JSONObject();
|
JSONObject param = new JSONObject();
|
||||||
@@ -84,13 +88,110 @@ public class CommentPublicController extends BaseController {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return AjaxResult.error("generate failed: " + e.getMessage());
|
return AjaxResult.error("generate failed: " + e.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
// 记录接口调用统计
|
// 记录接口调用统计和历史
|
||||||
if (commentService != null && productType != null) {
|
if (commentService != null && productType != null) {
|
||||||
commentService.recordApiCall("jd", productType, success);
|
commentService.recordApiCall("jd", productType, success);
|
||||||
|
commentService.recordApiCallHistory(productType, clientIp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前IP地址
|
||||||
|
*/
|
||||||
|
@GetMapping("/ip")
|
||||||
|
public AjaxResult getIp(HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
String ip = getClientIp(request);
|
||||||
|
Map<String, String> result = new HashMap<>();
|
||||||
|
result.put("ip", ip);
|
||||||
|
return AjaxResult.success(result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("获取IP失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取使用统计(今天/7天/30天/累计)
|
||||||
|
*/
|
||||||
|
@GetMapping("/usage-statistics")
|
||||||
|
public AjaxResult getUsageStatistics() {
|
||||||
|
try {
|
||||||
|
if (commentService != null) {
|
||||||
|
Map<String, Long> statistics = commentService.getUsageStatistics();
|
||||||
|
return AjaxResult.success(statistics);
|
||||||
|
} else {
|
||||||
|
Map<String, Long> statistics = new HashMap<>();
|
||||||
|
statistics.put("today", 0L);
|
||||||
|
statistics.put("last7Days", 0L);
|
||||||
|
statistics.put("last30Days", 0L);
|
||||||
|
statistics.put("total", 0L);
|
||||||
|
return AjaxResult.success(statistics);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("获取使用统计失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取历史记录
|
||||||
|
*/
|
||||||
|
@GetMapping("/history")
|
||||||
|
public TableDataInfo getHistory(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
|
||||||
|
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
|
||||||
|
try {
|
||||||
|
if (commentService != null) {
|
||||||
|
List<CommentCallHistory> historyList = commentService.getApiCallHistory(pageNum, pageSize);
|
||||||
|
TableDataInfo dataTable = new TableDataInfo();
|
||||||
|
dataTable.setCode(200);
|
||||||
|
dataTable.setMsg("查询成功");
|
||||||
|
dataTable.setRows(historyList);
|
||||||
|
dataTable.setTotal(historyList.size()); // 注意:这里返回的是当前页的数量,实际总数可能需要单独查询
|
||||||
|
return dataTable;
|
||||||
|
} else {
|
||||||
|
TableDataInfo dataTable = new TableDataInfo();
|
||||||
|
dataTable.setCode(200);
|
||||||
|
dataTable.setMsg("查询成功");
|
||||||
|
dataTable.setRows(new ArrayList<>());
|
||||||
|
dataTable.setTotal(0);
|
||||||
|
return dataTable;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
TableDataInfo dataTable = new TableDataInfo();
|
||||||
|
dataTable.setCode(500);
|
||||||
|
dataTable.setMsg("获取历史记录失败: " + e.getMessage());
|
||||||
|
return dataTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取客户端真实IP地址
|
||||||
|
* 考虑代理和负载均衡的情况
|
||||||
|
*/
|
||||||
|
private String getClientIp(HttpServletRequest request) {
|
||||||
|
String ip = request.getHeader("X-Forwarded-For");
|
||||||
|
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("Proxy-Client-IP");
|
||||||
|
}
|
||||||
|
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||||
|
}
|
||||||
|
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("HTTP_CLIENT_IP");
|
||||||
|
}
|
||||||
|
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
|
||||||
|
}
|
||||||
|
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
// 对于通过多个代理的情况,第一个IP为客户端真实IP
|
||||||
|
if (ip != null && ip.contains(",")) {
|
||||||
|
ip = ip.substring(0, ip.indexOf(",")).trim();
|
||||||
|
}
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.ruoyi.jarvis.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论接口调用历史记录
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CommentCallHistory {
|
||||||
|
/** 产品类型 */
|
||||||
|
private String productType;
|
||||||
|
|
||||||
|
/** IP地址 */
|
||||||
|
private String ip;
|
||||||
|
|
||||||
|
/** 创建时间 */
|
||||||
|
private Date createTime;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ package com.ruoyi.jarvis.service;
|
|||||||
import com.ruoyi.jarvis.domain.Comment;
|
import com.ruoyi.jarvis.domain.Comment;
|
||||||
import com.ruoyi.jarvis.domain.dto.CommentStatistics;
|
import com.ruoyi.jarvis.domain.dto.CommentStatistics;
|
||||||
import com.ruoyi.jarvis.domain.dto.CommentApiStatistics;
|
import com.ruoyi.jarvis.domain.dto.CommentApiStatistics;
|
||||||
|
import com.ruoyi.jarvis.domain.dto.CommentCallHistory;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -47,6 +48,21 @@ public interface ICommentService {
|
|||||||
*/
|
*/
|
||||||
void recordApiCall(String apiType, String productType, boolean success);
|
void recordApiCall(String apiType, String productType, boolean success);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录接口调用历史(带IP)
|
||||||
|
*/
|
||||||
|
void recordApiCallHistory(String productType, String ip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取接口调用历史记录
|
||||||
|
*/
|
||||||
|
List<CommentCallHistory> getApiCallHistory(int pageNum, int pageSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取使用统计(今天/7天/30天/累计)
|
||||||
|
*/
|
||||||
|
Map<String, Long> getUsageStatistics();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取接口调用统计
|
* 获取接口调用统计
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package com.ruoyi.jarvis.service.impl;
|
|||||||
import com.ruoyi.jarvis.domain.Comment;
|
import com.ruoyi.jarvis.domain.Comment;
|
||||||
import com.ruoyi.jarvis.domain.dto.CommentApiStatistics;
|
import com.ruoyi.jarvis.domain.dto.CommentApiStatistics;
|
||||||
import com.ruoyi.jarvis.domain.dto.CommentStatistics;
|
import com.ruoyi.jarvis.domain.dto.CommentStatistics;
|
||||||
|
import com.ruoyi.jarvis.domain.dto.CommentCallHistory;
|
||||||
import com.ruoyi.jarvis.mapper.CommentMapper;
|
import com.ruoyi.jarvis.mapper.CommentMapper;
|
||||||
import com.ruoyi.jarvis.service.ICommentService;
|
import com.ruoyi.jarvis.service.ICommentService;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -27,6 +29,8 @@ public class CommentServiceImpl implements ICommentService {
|
|||||||
private static final String PRODUCT_TYPE_MAP_PREFIX_TB = "product_type_map_tb";
|
private static final String PRODUCT_TYPE_MAP_PREFIX_TB = "product_type_map_tb";
|
||||||
private static final String API_CALL_STAT_PREFIX = "comment:api:stat:";
|
private static final String API_CALL_STAT_PREFIX = "comment:api:stat:";
|
||||||
private static final String API_CALL_TODAY_PREFIX = "comment:api:today:";
|
private static final String API_CALL_TODAY_PREFIX = "comment:api:today:";
|
||||||
|
private static final String API_CALL_HISTORY_KEY = "comment:api:history:list";
|
||||||
|
private static final int MAX_HISTORY_SIZE = 1000; // 最多保留1000条历史记录
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CommentMapper commentMapper;
|
private CommentMapper commentMapper;
|
||||||
@@ -278,5 +282,153 @@ public class CommentServiceImpl implements ICommentService {
|
|||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
return sdf.format(new Date());
|
return sdf.format(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recordApiCallHistory(String productType, String ip) {
|
||||||
|
if (stringRedisTemplate == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
CommentCallHistory history = new CommentCallHistory();
|
||||||
|
history.setProductType(productType);
|
||||||
|
history.setIp(ip);
|
||||||
|
history.setCreateTime(new Date());
|
||||||
|
|
||||||
|
String historyJson = JSON.toJSONString(history);
|
||||||
|
|
||||||
|
// 使用List存储历史记录,从左侧推入
|
||||||
|
stringRedisTemplate.opsForList().leftPush(API_CALL_HISTORY_KEY, historyJson);
|
||||||
|
|
||||||
|
// 限制列表大小,只保留最近MAX_HISTORY_SIZE条
|
||||||
|
stringRedisTemplate.opsForList().trim(API_CALL_HISTORY_KEY, 0, MAX_HISTORY_SIZE - 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("记录接口调用历史失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CommentCallHistory> getApiCallHistory(int pageNum, int pageSize) {
|
||||||
|
List<CommentCallHistory> historyList = new ArrayList<>();
|
||||||
|
|
||||||
|
if (stringRedisTemplate == null) {
|
||||||
|
return historyList;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
long start = (pageNum - 1) * pageSize;
|
||||||
|
long end = start + pageSize - 1;
|
||||||
|
|
||||||
|
List<String> jsonList = stringRedisTemplate.opsForList().range(API_CALL_HISTORY_KEY, start, end);
|
||||||
|
if (jsonList != null) {
|
||||||
|
for (String json : jsonList) {
|
||||||
|
try {
|
||||||
|
CommentCallHistory history = JSON.parseObject(json, CommentCallHistory.class);
|
||||||
|
historyList.add(history);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("解析历史记录失败: " + json, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取接口调用历史失败", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return historyList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Long> getUsageStatistics() {
|
||||||
|
Map<String, Long> statistics = new HashMap<>();
|
||||||
|
statistics.put("today", 0L);
|
||||||
|
statistics.put("last7Days", 0L);
|
||||||
|
statistics.put("last30Days", 0L);
|
||||||
|
statistics.put("total", 0L);
|
||||||
|
|
||||||
|
if (stringRedisTemplate == null) {
|
||||||
|
return statistics;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String today = getTodayDate();
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
Date todayDate = sdf.parse(today);
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
|
||||||
|
// 统计今天
|
||||||
|
long todayCount = 0;
|
||||||
|
String todayPattern = API_CALL_TODAY_PREFIX + "jd:*:" + today;
|
||||||
|
Set<String> todayKeys = stringRedisTemplate.keys(todayPattern);
|
||||||
|
if (todayKeys != null) {
|
||||||
|
for (String key : todayKeys) {
|
||||||
|
String count = stringRedisTemplate.opsForValue().get(key);
|
||||||
|
if (count != null) {
|
||||||
|
todayCount += Long.parseLong(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statistics.put("today", todayCount);
|
||||||
|
|
||||||
|
// 统计近7天
|
||||||
|
long last7DaysCount = 0;
|
||||||
|
calendar.setTime(todayDate);
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
String dateStr = sdf.format(calendar.getTime());
|
||||||
|
String pattern = API_CALL_TODAY_PREFIX + "jd:*:" + dateStr;
|
||||||
|
Set<String> keys = stringRedisTemplate.keys(pattern);
|
||||||
|
if (keys != null) {
|
||||||
|
for (String key : keys) {
|
||||||
|
String count = stringRedisTemplate.opsForValue().get(key);
|
||||||
|
if (count != null) {
|
||||||
|
last7DaysCount += Long.parseLong(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
calendar.add(Calendar.DAY_OF_MONTH, -1);
|
||||||
|
}
|
||||||
|
statistics.put("last7Days", last7DaysCount);
|
||||||
|
|
||||||
|
// 统计近30天
|
||||||
|
long last30DaysCount = 0;
|
||||||
|
calendar.setTime(todayDate);
|
||||||
|
for (int i = 0; i < 30; i++) {
|
||||||
|
String dateStr = sdf.format(calendar.getTime());
|
||||||
|
String pattern = API_CALL_TODAY_PREFIX + "jd:*:" + dateStr;
|
||||||
|
Set<String> keys = stringRedisTemplate.keys(pattern);
|
||||||
|
if (keys != null) {
|
||||||
|
for (String key : keys) {
|
||||||
|
String count = stringRedisTemplate.opsForValue().get(key);
|
||||||
|
if (count != null) {
|
||||||
|
last30DaysCount += Long.parseLong(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
calendar.add(Calendar.DAY_OF_MONTH, -1);
|
||||||
|
}
|
||||||
|
statistics.put("last30Days", last30DaysCount);
|
||||||
|
|
||||||
|
// 统计累计(从统计key获取)
|
||||||
|
long totalCount = 0;
|
||||||
|
String totalPattern = API_CALL_STAT_PREFIX + "jd:*";
|
||||||
|
Set<String> totalKeys = stringRedisTemplate.keys(totalPattern);
|
||||||
|
if (totalKeys != null) {
|
||||||
|
for (String key : totalKeys) {
|
||||||
|
// 排除success和fail后缀的key
|
||||||
|
if (!key.endsWith(":success") && !key.endsWith(":fail")) {
|
||||||
|
String count = stringRedisTemplate.opsForValue().get(key);
|
||||||
|
if (count != null) {
|
||||||
|
totalCount += Long.parseLong(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statistics.put("total", totalCount);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取使用统计失败", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return statistics;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user