资讯精选增加操作日志记录、送审、发布等功能
This commit is contained in:
parent
d291e3be72
commit
4f59c48c1c
|
|
@ -35,11 +35,6 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>${jedis.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-client</artifactId>
|
||||
|
|
@ -50,6 +45,23 @@
|
|||
<artifactId>jakarta.json-api</artifactId>
|
||||
<version>${jakartajson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
<version>3.0.5</version> <!-- 或使用最新版本 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.itextpdf</groupId>
|
||||
<artifactId>itext7-core</artifactId>
|
||||
<version>9.2.0</version> <!-- 或使用最新版本 -->
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
/PDFTextSearcher.java
|
||||
/PDFTextSearcherItext.java
|
||||
|
|
@ -1,14 +1,10 @@
|
|||
package com.jinrui.reference.admin;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = {
|
||||
"com.jinrui.reference.admin",
|
||||
|
|
@ -17,21 +13,11 @@ import redis.clients.jedis.JedisPoolConfig;
|
|||
@MapperScan({
|
||||
"com.jinrui.reference.admin.mapper",
|
||||
"com.jinrui.reference.core.mapper"})
|
||||
@EnableScheduling
|
||||
@EnableAspectJAutoProxy
|
||||
public class AdminApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AdminApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JedisPool jedisPool(@Value("${redis.host}") String host,
|
||||
@Value("${redis.port}") int port,
|
||||
@Value("${redis.timeout:1000}") int timeout,
|
||||
@Value("${redis.password:}") String password) {
|
||||
if (StringUtils.hasText(password)) {
|
||||
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
|
||||
return new JedisPool(jedisPoolConfig, host, port, timeout, password);
|
||||
}
|
||||
return new JedisPool(host, port);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
package com.jinrui.reference.admin;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
public class ApiClient {
|
||||
public final static String ak = "6a91a5070b044eb0b798f9420ccae15d";
|
||||
public final static String sk = "clkky/Ad6d4DXDZ0UzemOKUKroLwSmc5vlIb2Sjh6YM=";
|
||||
public final static String baseUrl = "http://127.0.0.1:13579";
|
||||
|
||||
public ApiClient() {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String path = "/admin/api/news";
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("num", String.valueOf(20));
|
||||
String result = callApi(path, params);
|
||||
System.out.println("+++++++++++++++++++++++++++++++++++++: " + result);
|
||||
}
|
||||
|
||||
public static String callApi(String path, Map<String, String> params) throws Exception {
|
||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
||||
String nonce = UUID.randomUUID().toString();
|
||||
String sortedParams = sortParams(params);
|
||||
String url = baseUrl + path + "?" + sortedParams;
|
||||
|
||||
// 1. 计算签名
|
||||
String data = "GET" + path + sortedParams + timestamp + nonce;
|
||||
String signature = calculateSignature(data, sk);
|
||||
|
||||
// 2. 设置请求头
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("X-Api-Key", ak);
|
||||
conn.setRequestProperty("X-Timestamp", timestamp);
|
||||
conn.setRequestProperty("X-Nonce", nonce);
|
||||
conn.setRequestProperty("X-Signature", signature);
|
||||
|
||||
// 3. 发送请求
|
||||
return IOUtils.toString(conn.getInputStream(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static String calculateSignature(String data, String sk) throws Exception {
|
||||
Mac sha256 = Mac.getInstance("HmacSHA256");
|
||||
sha256.init(new SecretKeySpec(sk.getBytes(), "HmacSHA256"));
|
||||
byte[] signBytes = sha256.doFinal(data.getBytes(StandardCharsets.UTF_8));
|
||||
return Hex.encodeHexString(signBytes);
|
||||
}
|
||||
|
||||
public static String sortParams(Map<String, String> params) {
|
||||
return params.entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.map(e -> e.getKey() + "=" + e.getValue())
|
||||
.collect(Collectors.joining("&"));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.jinrui.reference.admin.annotation;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target({ METHOD, ANNOTATION_TYPE })
|
||||
public @interface OperationInfo {
|
||||
String type() default "";
|
||||
|
||||
String behavior();
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.jinrui.reference.admin.aspect;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.jinrui.reference.admin.annotation.OperationInfo;
|
||||
import com.jinrui.reference.admin.model.dto.news.PublishNewsDTO;
|
||||
import com.jinrui.reference.admin.service.UserOperationLogService;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
|
||||
@Component
|
||||
@Aspect
|
||||
public class UserOperationLogAspect {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(UserOperationLogAspect.class);
|
||||
|
||||
@Autowired
|
||||
private UserOperationLogService userOperationLogService;
|
||||
|
||||
@Pointcut("@annotation(com.jinrui.reference.admin.annotation.OperationInfo)")
|
||||
public void userOperation() {}
|
||||
|
||||
@AfterThrowing(pointcut = "userOperation()", throwing = "e")
|
||||
public void handleThrowing(JoinPoint point, Exception e) {
|
||||
|
||||
}
|
||||
|
||||
@Around("userOperation()")
|
||||
public Object handleSuccess(ProceedingJoinPoint point) throws Throwable {
|
||||
Object result = point.proceed();
|
||||
OperationInfo operationInfo = getOperationInfo(point);
|
||||
String behavior = operationInfo.behavior();
|
||||
String type = operationInfo.type();
|
||||
Object[] args = point.getArgs();
|
||||
|
||||
if (result instanceof ResultObject) {
|
||||
int code = ((ResultObject)result).getCode();
|
||||
if (code != 200) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if ("news".equals(type)) {
|
||||
userOperationLogService.logUserOperation(type, behavior, (String)args[0], ((PublishNewsDTO)args[1]).getId());
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private OperationInfo getOperationInfo(JoinPoint point) {
|
||||
MethodSignature ms = (MethodSignature)point.getSignature();
|
||||
Method method = ms.getMethod();
|
||||
return method.<OperationInfo>getAnnotation(OperationInfo.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.jinrui.reference.admin.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.jinrui.reference.admin.model.entity.AdminUser;
|
||||
import com.jinrui.reference.admin.service.AdminJwtService;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsApiVO;
|
||||
import com.jinrui.reference.core.service.ApiKeyService;
|
||||
import com.jinrui.reference.core.service.NewsService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class ApiController {
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiController.class);
|
||||
|
||||
private final NewsService newsService;
|
||||
private final ApiKeyService apiKeyService;
|
||||
|
||||
public ApiController(NewsService newsService, ApiKeyService apiKeyService) {
|
||||
this.newsService = newsService;
|
||||
this.apiKeyService = apiKeyService;
|
||||
}
|
||||
|
||||
@GetMapping("/news")
|
||||
public ResultObject<List<NewsApiVO>> getNews(@RequestParam(name = "num", required = true, defaultValue = "10") Integer num, @RequestParam(name = "last", required = false) Long last) {
|
||||
return newsService.requestNewsByApi(num, last);
|
||||
}
|
||||
|
||||
@PostMapping("/news")
|
||||
public ResultObject<List<NewsApiVO>> queryNews(@RequestParam(name = "num", required = true, defaultValue = "10") Integer num, @RequestParam(name = "last", required = false) Long last) {
|
||||
return newsService.requestNewsByApi(num, last);
|
||||
}
|
||||
|
||||
@PostMapping("/key")
|
||||
public ResultObject<Map<String, Object>> generateApiKey(@RequestHeader("auth-token") String token,
|
||||
@RequestParam(name = "clientName", required = true) String clientName) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return ResultObject.failed("登陆Token为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return ResultObject.failed("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long adminUserId = adminUser.getId();
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUserId);
|
||||
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
log.info("path: /api/key, method: POST, request user id: {}, clientName: {}", adminUserId, clientName);
|
||||
return apiKeyService.generateApiKey(clientName);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/key")
|
||||
public ResultObject<Map<String, Object>> getApiKey(@RequestHeader("auth-token") String token,
|
||||
@RequestParam(name = "clientName", required = true) String clientName) {
|
||||
return generateApiKey(token, clientName);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,16 @@
|
|||
package com.jinrui.reference.admin.controller;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.aliyuncs.auth.sts.AssumeRoleRequest;
|
||||
import com.aliyuncs.auth.sts.AssumeRoleResponse;
|
||||
import com.aliyuncs.http.MethodType;
|
||||
|
|
@ -7,19 +18,12 @@ import com.aliyuncs.profile.DefaultProfile;
|
|||
import com.aliyuncs.profile.IClientProfile;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jinrui.reference.admin.model.dto.newsinfo.PublishNewsInfoDTO;
|
||||
import com.jinrui.reference.admin.model.dto.oss.CloseableAcsClient;
|
||||
import com.jinrui.reference.admin.model.entity.AdminUser;
|
||||
import com.jinrui.reference.admin.model.vo.oss.OssVO;
|
||||
import com.jinrui.reference.admin.service.AdminJwtService;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
import com.jinrui.reference.core.service.NewsInfoService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/common")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.jinrui.reference.admin.controller;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -8,6 +9,7 @@ import org.springframework.format.annotation.DateTimeFormat;
|
|||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
|
|
@ -16,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jinrui.reference.admin.annotation.OperationInfo;
|
||||
import com.jinrui.reference.admin.model.dto.news.PublishNewsDTO;
|
||||
import com.jinrui.reference.admin.model.entity.AdminUser;
|
||||
import com.jinrui.reference.admin.service.AdminJwtService;
|
||||
|
|
@ -23,10 +26,15 @@ import com.jinrui.reference.core.model.dto.news.SaveNewsDTO;
|
|||
import com.jinrui.reference.core.model.vo.PageObject;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsDetailVO;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsLogVO;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsScoreVO;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsTranslatorVO;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsVO;
|
||||
import com.jinrui.reference.core.service.NewsService;
|
||||
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/news")
|
||||
public class NewsController {
|
||||
|
|
@ -35,15 +43,96 @@ public class NewsController {
|
|||
|
||||
private final NewsService newsService;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final JedisPool jedisPool;
|
||||
|
||||
|
||||
public NewsController(NewsService newsService,
|
||||
ObjectMapper objectMapper) {
|
||||
ObjectMapper objectMapper,
|
||||
JedisPool jedisPool) {
|
||||
this.newsService = newsService;
|
||||
this.objectMapper = objectMapper;;
|
||||
this.objectMapper = objectMapper;
|
||||
this.jedisPool = jedisPool;
|
||||
}
|
||||
|
||||
@PostMapping("/submit")
|
||||
@OperationInfo(behavior = "送审", type = "news")
|
||||
public ResultObject<Void> submit(@RequestHeader("auth-token") String token,
|
||||
@RequestBody PublishNewsDTO publishNewsDTO) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return ResultObject.failed("登陆Token为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return ResultObject.failed("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long adminUserId = adminUser.getId();
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUserId);
|
||||
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long id = publishNewsDTO.getId();
|
||||
if (id == null) {
|
||||
return ResultObject.failed("要送审的新闻ID不可为空!");
|
||||
}
|
||||
boolean isSuccessed = setEditingFlag(id);
|
||||
if (!isSuccessed) {
|
||||
return ResultObject.failed("该资讯正在审核中,请勿重复操作!");
|
||||
}
|
||||
log.info("path: /news/publish, method: POST, request user id: {}, news id: {}", adminUserId, id);
|
||||
return newsService.submit(id, adminUserId);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
} finally {
|
||||
unsetEditingFlag(publishNewsDTO.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/revoke")
|
||||
public ResultObject<Void> revoke(@RequestHeader("auth-token") String token,
|
||||
@RequestBody PublishNewsDTO publishNewsDTO) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return ResultObject.failed("登陆Token为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return ResultObject.failed("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long adminUserId = adminUser.getId();
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUserId);
|
||||
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long id = publishNewsDTO.getId();
|
||||
if (id == null) {
|
||||
return ResultObject.failed("要送审的新闻ID不可为空!");
|
||||
}
|
||||
boolean isSuccessed = setEditingFlag(id);
|
||||
if (!isSuccessed) {
|
||||
return ResultObject.failed("该资讯正在审核中,请勿重复操作!");
|
||||
}
|
||||
log.info("path: /news/publish, method: POST, request user id: {}, news id: {}", adminUserId, id);
|
||||
return newsService.revoke(id, adminUserId, adminUser.isReviewer());
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
} finally {
|
||||
unsetEditingFlag(publishNewsDTO.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/publish")
|
||||
@OperationInfo(behavior = "发布", type = "news")
|
||||
public ResultObject<Void> publish(@RequestHeader("auth-token") String token,
|
||||
@RequestBody PublishNewsDTO publishNewsDTO) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
|
|
@ -67,6 +156,9 @@ public class NewsController {
|
|||
if (id == null) {
|
||||
return ResultObject.failed("要发布/下架的新闻ID不可为空!");
|
||||
}
|
||||
if (!adminUser.isReviewer()) {
|
||||
return ResultObject.failed("当前操作非法,没有审核员权限!");
|
||||
}
|
||||
|
||||
log.info("path: /news/publish, method: POST, request user id: {}, news id: {}", adminUserId, id);
|
||||
return newsService.publish(id, adminUserId);
|
||||
|
|
@ -111,6 +203,39 @@ public class NewsController {
|
|||
return ResultObject.failed("登陆Token为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return ResultObject.failed("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long adminUserId = adminUser.getId();
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUserId);
|
||||
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
boolean isSuccessed = setEditingFlag(id);
|
||||
if (!isSuccessed) {
|
||||
return ResultObject.failed("该资讯正在审核中,请勿重复操作!");
|
||||
}
|
||||
log.info("path: /news, method: DELETE, request user id: {}, news id: {}", adminUserId, id);
|
||||
return newsService.deleteNews(id, adminUserId);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
} finally {
|
||||
unsetEditingFlag(id);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/recover")
|
||||
public ResultObject<Void> recoverNews(@RequestHeader("auth-token") String token,
|
||||
@PathVariable( name = "id", required = true) Long id) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return ResultObject.failed("登陆Token为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
|
|
@ -125,7 +250,7 @@ public class NewsController {
|
|||
}
|
||||
|
||||
log.info("path: /news, method: DELETE, request user id: {}, news id: {}", adminUserId, id);
|
||||
return newsService.deleteNews(id);
|
||||
return newsService.recoverNews(id, adminUserId);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
|
|
@ -151,14 +276,18 @@ public class NewsController {
|
|||
log.warn("当前用户已被封禁! id = {}", adminUserId);
|
||||
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
log.info("path: /news/create/publish, method: POST, request user id: {}, param: {}",
|
||||
adminUserId, objectMapper.writeValueAsString(saveNewsDTO));
|
||||
|
||||
return newsService.createPublish(adminUserId, saveNewsDTO);
|
||||
boolean isSuccessed = setEditingFlag(saveNewsDTO.getId());
|
||||
if (!isSuccessed) {
|
||||
return ResultObject.failed("该资讯正在审核中,请勿重复操作!");
|
||||
}
|
||||
return newsService.createPublish(adminUserId, saveNewsDTO, adminUser.isReviewer());
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
} finally {
|
||||
unsetEditingFlag(saveNewsDTO.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -183,14 +312,12 @@ public class NewsController {
|
|||
|
||||
log.info("path: /news/save, method: POST, request user id: {}, param: {}",
|
||||
adminUser.getId(), objectMapper.writeValueAsString(saveNewsDTO));
|
||||
|
||||
return newsService.saveDraft(saveNewsDTO, adminUser.isReviewer());
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
// 这个接口是保存,那status应该是1,未发布
|
||||
saveNewsDTO.setStatus(1);
|
||||
return newsService.saveDraft(saveNewsDTO);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
|
|
@ -206,10 +333,12 @@ public class NewsController {
|
|||
@RequestParam(value = "size", required = false, defaultValue = "10") int size,
|
||||
@RequestParam(value = "last", required = false) Integer last,
|
||||
@RequestParam(value = "current", required = false) Integer current,
|
||||
@RequestParam(value = "orderBy", required = false, defaultValue = "id$asc") String orderBy,
|
||||
@RequestParam(value = "orderBy", required = false) String orderBy,
|
||||
@RequestParam(value = "mediaId", required = false) Long mediaId,
|
||||
@RequestParam(value = "dateline_from", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date datelineFrom,
|
||||
@RequestParam(value = "dateline_to", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date datelineTo
|
||||
@RequestParam(value = "dateline_to", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date datelineTo,
|
||||
@RequestParam(value = "deleted", required = false) Integer deleted,
|
||||
@RequestParam(value = "rating", required = false) Byte rating
|
||||
) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return PageObject.failedPage("登陆Token为空!");
|
||||
|
|
@ -230,11 +359,11 @@ public class NewsController {
|
|||
log.info("path: /news, method: GET, request user id: {}, keyword: {}, column: {}, status: {}, " +
|
||||
"page: {}, size: {}, last: {}, current: {}, orderBy: {}, tag: {}, industry: {}",
|
||||
adminUser.getId(), keyword, columnList, status, page, size, last, current, orderBy, tag, industry);
|
||||
return newsService.queryNews(keyword, columnList, status, page, size, last, current, orderBy, minScore, maxScore, tag, industry, mediaId, datelineFrom, datelineTo, deleted, rating, adminUser.isReviewer());
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return PageObject.failedPage(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
return newsService.queryNews(keyword, columnList, status, page, size, last, current, orderBy, minScore, maxScore, tag, industry, mediaId, datelineFrom, datelineTo);
|
||||
}
|
||||
|
||||
@GetMapping("/score")
|
||||
|
|
@ -264,4 +393,97 @@ public class NewsController {
|
|||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/translator")
|
||||
public ResultObject<NewsTranslatorVO> getTranslator(@RequestHeader("auth-token") String token,
|
||||
@PathVariable(name = "id", required = true) Long id) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return ResultObject.failed("登陆Token为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return ResultObject.failed("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long adminUserId = adminUser.getId();
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUserId);
|
||||
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
log.info("path: /news/detail, method: GET, request user id: {}, news id: {}", adminUserId, id);
|
||||
return newsService.getTranslator(id);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Tokn出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/log")
|
||||
public PageObject<NewsLogVO> getLog(@RequestHeader("auth-token") String token,
|
||||
@RequestParam("id") Long id,
|
||||
@RequestParam(value = "page", required = false, defaultValue = "1") int page,
|
||||
@RequestParam(value = "size", required = false, defaultValue = "10") int size,
|
||||
@RequestParam(value = "current", required = false) Integer current) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return PageObject.failedPage("登陆Token为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return PageObject.failedPage("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long adminUserId = adminUser.getId();
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUserId);
|
||||
return PageObject.failedPage("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
log.info("path: /news/log, method: GET, request user id: {}, news id: {}, page: {}, size: {}, current: {}", adminUserId, id, page, size, current);
|
||||
return newsService.getLog(id, page, size, current);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Tokn出错!", e);
|
||||
return PageObject.failedPage(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param newsId
|
||||
* @return true:表示不存在其他人在编辑; false表示已经有人在编辑或者操作
|
||||
*/
|
||||
private boolean setEditingFlag(Long newsId) {
|
||||
if (newsId == null) {
|
||||
return true;
|
||||
}
|
||||
String newsIdStr = String.valueOf(newsId);
|
||||
try(Jedis jedis = jedisPool.getResource()) {
|
||||
Long result = jedis.setnx(newsIdStr, "");
|
||||
if (result == null ||result == 0L) {
|
||||
return false;
|
||||
}
|
||||
jedis.expire(newsIdStr, 10*60L);
|
||||
return true;
|
||||
} catch(Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void unsetEditingFlag(Long newsId) {
|
||||
if (newsId == null) {
|
||||
return;
|
||||
}
|
||||
String newsIdStr = String.valueOf(newsId);
|
||||
try(Jedis jedis = jedisPool.getResource()) {
|
||||
jedis.del(newsIdStr);
|
||||
} catch(Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package com.jinrui.reference.admin.controller;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
|
@ -18,6 +21,7 @@ import com.jinrui.reference.admin.model.entity.AdminUser;
|
|||
import com.jinrui.reference.admin.service.AdminJwtService;
|
||||
import com.jinrui.reference.core.model.vo.PageObject;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsScoreVO;
|
||||
import com.jinrui.reference.core.model.vo.newsinfo.NewsInfoDetailVO;
|
||||
import com.jinrui.reference.core.model.vo.newsinfo.NewsInfoVO;
|
||||
import com.jinrui.reference.core.model.vo.newsinfo.SaveNewsInfoDTO;
|
||||
|
|
@ -119,7 +123,7 @@ public class NewsInfoController {
|
|||
}
|
||||
|
||||
log.info("path: /newsinfo, method: DELETE, request user id: {}, news id: {}", adminUserId, id);
|
||||
return newsInfoService.deleteNewsInfo(id);
|
||||
return newsInfoService.deleteNewsInfo(id, adminUserId);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
|
|
@ -168,7 +172,11 @@ public class NewsInfoController {
|
|||
@RequestParam(value = "size", required = false, defaultValue = "10") int size,
|
||||
@RequestParam(value = "current", required = false) Integer current,
|
||||
@RequestParam(value = "orderBy", required = false, defaultValue = "inputDate") String orderBy,
|
||||
@RequestParam(value = "direction", required = false, defaultValue = "asc") String direction
|
||||
@RequestParam(value = "direction", required = false, defaultValue = "desc") String direction,
|
||||
@RequestParam(value = "minScore", required = false) Double minScore,
|
||||
@RequestParam(value = "maxScore", required = false) Double maxScore,
|
||||
@RequestParam(value = "inputDateFrom", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date inputDateFrom,
|
||||
@RequestParam(value = "inputDateTo", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date inputDateTo
|
||||
) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return PageObject.failedPage("登陆Token为空!");
|
||||
|
|
@ -193,8 +201,34 @@ public class NewsInfoController {
|
|||
log.error("解析登陆Token出错!", e);
|
||||
return PageObject.failedPage(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
return newsInfoService.queryNewsInfo(title, content, stockcode, sourcename, page, size, last, current, orderBy, direction);
|
||||
return newsInfoService.queryNewsInfo(title, content, stockcode, sourcename, page, size, last, current, orderBy, direction, minScore, maxScore, inputDateFrom, inputDateTo);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/score")
|
||||
public ResultObject<NewsScoreVO> getScore(@RequestHeader("auth-token") String token,
|
||||
@RequestParam("id") String id) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return ResultObject.failed("登陆Token为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return ResultObject.failed("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long adminUserId = adminUser.getId();
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUserId);
|
||||
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
log.info("path: /news/score, method: GET, request user id: {}, news id: {}", adminUserId, id);
|
||||
return newsInfoService.getScore(id);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Tokn出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
package com.jinrui.reference.admin.job;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.jinrui.reference.core.mapper.NewsMapper;
|
||||
import com.jinrui.reference.core.model.entity.News;
|
||||
import com.jinrui.reference.core.service.NewsService;
|
||||
|
||||
|
||||
@Component
|
||||
public class NewsDeduplicationJob {
|
||||
|
||||
@Autowired
|
||||
private NewsService newsService;
|
||||
@Autowired
|
||||
private NewsMapper newsMapper;
|
||||
|
||||
|
||||
// @Scheduled(fixedDelay=15, initialDelay=0, timeUnit = TimeUnit.MINUTES)
|
||||
public void cleanDuplicatedData() {
|
||||
List<String> clusterIds = newsMapper.getDuplicatedCluster();
|
||||
for (String clusterId: clusterIds) {
|
||||
List<News> duplicatedNews = newsMapper.getDuplicatedNews(clusterId);
|
||||
List<News> toBeDeletedNews = duplicatedNews.stream().filter(e -> e.getDeleted() && e.getEditorId() == null).collect(Collectors.toList());
|
||||
if (duplicatedNews.size() > toBeDeletedNews.size()) {
|
||||
newsService.backupDuplicatedNews(toBeDeletedNews, clusterId);
|
||||
newsService.deletDuplicatedNews(toBeDeletedNews);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
package com.jinrui.reference.admin.job;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.jinrui.reference.core.mapper.NewsTagsMapper;
|
||||
import com.jinrui.reference.core.model.entity.NewsInfo;
|
||||
import com.jinrui.reference.core.model.entity.NewsTags;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
|
||||
import co.elastic.clients.elasticsearch._types.InlineScript;
|
||||
import co.elastic.clients.elasticsearch._types.Refresh;
|
||||
import co.elastic.clients.elasticsearch._types.SortOptions;
|
||||
import co.elastic.clients.elasticsearch._types.SortOrder;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.ExistsQuery;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.ScriptQuery;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.WildcardQuery;
|
||||
import co.elastic.clients.elasticsearch.core.SearchRequest;
|
||||
import co.elastic.clients.elasticsearch.core.SearchResponse;
|
||||
import co.elastic.clients.elasticsearch.core.search.Hit;
|
||||
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
|
||||
|
||||
@Component
|
||||
public class NewsTagsIndustryLabelRepairJob {
|
||||
private static final Logger log = LoggerFactory.getLogger(NewsTagsIndustryLabelRepairJob.class);
|
||||
|
||||
@Autowired
|
||||
private ElasticsearchClient elasticsearchClient;
|
||||
@Autowired
|
||||
private NewsTagsMapper newsTagsMapper;
|
||||
|
||||
// @Scheduled(fixedDelay=15, initialDelay=0, timeUnit = TimeUnit.MINUTES)
|
||||
public void startToRepair() {
|
||||
List<Query> filters = new ArrayList<>();
|
||||
filters.add(ExistsQuery.of(e -> e.field("news_tags.industry_label"))._toQuery());
|
||||
filters.add(WildcardQuery.of(e -> e.field("news_tags.industry_label").value("*"))._toQuery());
|
||||
Query scriptQuery = ScriptQuery.of(e -> e.script(s -> s.inline(InlineScript.of(i -> i.lang("painless").source("doc['news_tags.industry_label.keyword'][0].indexOf('[') == 0")))))._toQuery();
|
||||
filters.add(scriptQuery);
|
||||
|
||||
SortOptions sortOptions = SortOptions.of(e -> e.field(s -> s.field("create_time").order(SortOrder.Desc)));
|
||||
|
||||
Query resultQuery = new Query.Builder().bool(b -> b.filter(filters)).build();
|
||||
|
||||
int pageSize = 1000;
|
||||
SearchRequest request = SearchRequest.of(s ->
|
||||
s.index(NewsInfo.INDEX_NAME).from(0)
|
||||
.size(pageSize) // 分页参数
|
||||
.sort(sortOptions) // 排序字段
|
||||
.query(resultQuery));
|
||||
|
||||
SearchResponse<JsonNode> searchResp;
|
||||
try {
|
||||
searchResp = elasticsearchClient.search(request, JsonNode.class);
|
||||
HitsMetadata<JsonNode> hits = searchResp.hits();
|
||||
if (!ObjectUtils.isEmpty(hits)) {
|
||||
for (Hit<JsonNode> hit: hits.hits()) {
|
||||
String id = hit.id();
|
||||
NewsTags newsTags = newsTagsMapper.getNewsTagsByNewsId(id);
|
||||
if (newsTags == null) {
|
||||
JsonNode newsInfo = hit.source();
|
||||
JsonNode newsTagsNode = newsInfo.get("news_tags");
|
||||
newsTags = new NewsTags();
|
||||
String summary = newsTagsNode.get("abstract").asText();
|
||||
newsTags.setSummary(summary);
|
||||
String title = newsTagsNode.get("title").asText();
|
||||
newsTags.setTitle(title);
|
||||
String rewriteContent = newsTagsNode.get("rewrite_content").asText();
|
||||
newsTags.setRewriteContent(rewriteContent);
|
||||
List<String> industryLabel = getIndustryLabel(newsTagsNode.get("industry_label").asText());
|
||||
newsTags.setIndustryLabel(industryLabel);
|
||||
List<Double> industryConfidence = doubleArrayNodeToList(newsTagsNode.get("industry_confidence"));
|
||||
newsTags.setIndustryConfidence(industryConfidence);
|
||||
List<Double> industryScore = doubleArrayNodeToList(newsTagsNode.get("industry_score"));
|
||||
newsTags.setIndustryScore(industryScore);
|
||||
List<String> conceptLabel = textArrayNodeToList(newsTagsNode.get("concept_label"));
|
||||
newsTags.setConceptLabel(conceptLabel);
|
||||
List<Double> conceptConfidence = doubleArrayNodeToList(newsTagsNode.get("concept_confidence"));
|
||||
newsTags.setConceptConfidence(conceptConfidence);
|
||||
List<Double> conceptScore = doubleArrayNodeToList(newsTagsNode.get("concept_score"));
|
||||
newsTags.setConceptScore(conceptScore);
|
||||
Integer publicOpinionScore = null;
|
||||
if (newsTagsNode.hasNonNull("public_opinion_score")) {
|
||||
publicOpinionScore = newsTagsNode.get("public_opinion_score").asInt();
|
||||
}
|
||||
newsTags.setPublicOpinionScore(publicOpinionScore);
|
||||
Double chinaFactor = null;
|
||||
if (newsTagsNode.hasNonNull("China_factor")) {
|
||||
chinaFactor = newsTagsNode.get("China_factor").asDouble();
|
||||
}
|
||||
newsTags.setChinaFactor(chinaFactor);
|
||||
String source = newsTagsNode.get("source").asText();
|
||||
newsTags.setSource(source);
|
||||
Integer sourceImpact = null;
|
||||
if (newsTagsNode.hasNonNull("source_impact")) {
|
||||
sourceImpact = newsTagsNode.get("source_impact").asInt();
|
||||
}
|
||||
newsTags.setSourceImpact(sourceImpact);
|
||||
Double newsScore = null;
|
||||
if (newsTagsNode.hasNonNull("news_score")) {
|
||||
newsScore = newsTagsNode.get("news_score").asDouble();
|
||||
}
|
||||
newsTags.setNewsScore(newsScore);
|
||||
Long newsId = null;
|
||||
if (newsTagsNode.hasNonNull("news_id")) {
|
||||
newsId = newsTagsNode.get("news_id").asLong();
|
||||
}
|
||||
newsTags.setNewsId(newsId);
|
||||
Integer deleted = newsTagsNode.get("deleted").asInt();
|
||||
newsTags.setDeleted(deleted);
|
||||
Date createTime = getDateNodeValue(newsTagsNode.get("create_time").asText());
|
||||
newsTags.setCreateTime(createTime);
|
||||
Date updateTime = getDateNodeValue(newsTagsNode.get("update_time").asText());
|
||||
newsTags.setUpdateTime(updateTime);
|
||||
newsTagsMapper.save(newsTags);
|
||||
|
||||
NewsInfo newsInfo2 = new NewsInfo();
|
||||
newsInfo2.setNewsTags(new NewsTags());
|
||||
newsInfo2.getNewsTags().setIndustryLabel(industryLabel);
|
||||
|
||||
elasticsearchClient.update(e -> e.index(NewsInfo.INDEX_NAME).refresh(Refresh.True).id(id).doc(newsInfo2), NewsInfo.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ElasticsearchException|IOException e1) {
|
||||
log.error("修复行业分类编码问题失败: ", e1);
|
||||
}
|
||||
}
|
||||
|
||||
private Date getDateNodeValue(String dateStr) {
|
||||
if (ObjectUtils.isEmpty(dateStr)) {
|
||||
return null;
|
||||
}
|
||||
String pattern = "yyyy-MM-dd'T'HH:mm:ss";
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
|
||||
try {
|
||||
return sdf.parse(dateStr);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new Date();
|
||||
}
|
||||
|
||||
private List<Double> doubleArrayNodeToList(JsonNode node) {
|
||||
if (node.isArray()) {
|
||||
int size = ((ArrayNode)node).size();
|
||||
if (size == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Double> nodeValues = new ArrayList<>();
|
||||
Iterator<JsonNode> iterator = ((ArrayNode)node).elements();
|
||||
while (iterator.hasNext()) {
|
||||
nodeValues.add(iterator.next().asDouble());
|
||||
}
|
||||
return nodeValues;
|
||||
}
|
||||
double nodeValue = node.asDouble();
|
||||
if (nodeValue > 0.0d) {
|
||||
return Arrays.asList(nodeValue);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private List<String> textArrayNodeToList(JsonNode node) {
|
||||
if (node.isArray()) {
|
||||
int size = ((ArrayNode)node).size();
|
||||
if (size == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> nodeValues = new ArrayList<>();
|
||||
Iterator<JsonNode> iterator = ((ArrayNode)node).elements();
|
||||
while (iterator.hasNext()) {
|
||||
nodeValues.add(iterator.next().asText());
|
||||
}
|
||||
return nodeValues;
|
||||
}
|
||||
String nodeValue = node.asText();
|
||||
if (!ObjectUtils.isEmpty(nodeValue)) {
|
||||
return Arrays.asList(nodeValue);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private List<String> getIndustryLabel(String unicodeIndustryLabel) {
|
||||
if (ObjectUtils.isEmpty(unicodeIndustryLabel)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
unicodeIndustryLabel = unicodeIndustryLabel.replace("[", "").replace("]", "").replace("\"", "");
|
||||
String industryLabel = unicodeDecode(unicodeIndustryLabel);
|
||||
if (ObjectUtils.isEmpty(industryLabel)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Stream.of(industryLabel.split(",")).map(e -> e.trim()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String unicodeDecode(String unicodeIndustryLabel) {
|
||||
if (!StringUtils.hasLength(unicodeIndustryLabel)) {
|
||||
return null;
|
||||
}
|
||||
Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
|
||||
Matcher matcher = pattern.matcher(unicodeIndustryLabel);
|
||||
char ch;
|
||||
while (matcher.find()) {
|
||||
ch = (char) Integer.parseInt(matcher.group(2), 16);
|
||||
unicodeIndustryLabel = unicodeIndustryLabel.replace(matcher.group(1), ch + "");
|
||||
}
|
||||
return unicodeIndustryLabel;
|
||||
}
|
||||
|
||||
|
||||
// GET /news_info/_search
|
||||
// {
|
||||
// "size": 100,
|
||||
// "query": {
|
||||
// "bool": {
|
||||
// "filter": [
|
||||
// {
|
||||
// "exists": {
|
||||
// "field": "news_tags.industry_label"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "script": {
|
||||
// "script": {
|
||||
// "lang": "painless",
|
||||
// "source": "doc['news_tags.industry_label.keyword'][0].indexOf('[') == 0"
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "wildcard": {
|
||||
// "news_tags.industry_label": "*"
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// },
|
||||
// "sort": [
|
||||
// {
|
||||
// "create_time": {
|
||||
// "order": "desc"
|
||||
// }
|
||||
// }
|
||||
// ],
|
||||
// "track_total_hits": true
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ public interface AdminUserMapper {
|
|||
@Result(column = "phone", property = "phone"),
|
||||
@Result(column = "name", property = "name"),
|
||||
@Result(column = "active", property = "active"),
|
||||
@Result(column = "user_type", property = "userType"),
|
||||
@Result(column = "create_time", property = "createTime", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP),
|
||||
@Result(column = "update_time", property = "updateTime", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP)
|
||||
})
|
||||
|
|
@ -31,6 +32,7 @@ public interface AdminUserMapper {
|
|||
@Result(column = "phone", property = "phone"),
|
||||
@Result(column = "name", property = "name"),
|
||||
@Result(column = "active", property = "active"),
|
||||
@Result(column = "user_type", property = "userType"),
|
||||
@Result(column = "create_time", property = "createTime", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP),
|
||||
@Result(column = "update_time", property = "updateTime", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.auth0.jwt.interfaces.DecodedJWT;
|
|||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 管理后台用户
|
||||
|
|
@ -33,6 +34,11 @@ public class AdminUser {
|
|||
*/
|
||||
private boolean active;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 用户创建时间
|
||||
*/
|
||||
|
|
@ -62,6 +68,10 @@ public class AdminUser {
|
|||
this.name = value.asString();
|
||||
break;
|
||||
}
|
||||
case "userType": {
|
||||
this.userType = value.asString();
|
||||
break;
|
||||
}
|
||||
case "createTime": {
|
||||
this.createTime = new Date(value.asLong());
|
||||
break;
|
||||
|
|
@ -122,4 +132,16 @@ public class AdminUser {
|
|||
public void setUpdateTime(Date updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public void setUserType(String userType) {
|
||||
this.userType = userType;
|
||||
}
|
||||
|
||||
public String getUserType() {
|
||||
return userType;
|
||||
}
|
||||
|
||||
public boolean isReviewer() {
|
||||
return Objects.equals(userType, "01");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ public class LoginVO {
|
|||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 用户创建时间
|
||||
*/
|
||||
|
|
@ -49,6 +54,7 @@ public class LoginVO {
|
|||
this.phone = adminUser.getPhone();
|
||||
this.name = adminUser.getName();
|
||||
this.token = AdminJwtService.generateToken(adminUser);
|
||||
this.userType = adminUser.getUserType();
|
||||
this.createTime = adminUser.getCreateTime();
|
||||
this.updateTime = adminUser.getUpdateTime();
|
||||
}
|
||||
|
|
@ -100,4 +106,12 @@ public class LoginVO {
|
|||
public void setUpdateTime(Date updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public String getUserType() {
|
||||
return userType;
|
||||
}
|
||||
|
||||
public void setUserType(String userType) {
|
||||
this.userType = userType;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,12 +27,14 @@ public final class AdminJwtService {
|
|||
Long id = adminUser.getId();
|
||||
String phone = adminUser.getPhone();
|
||||
String name = adminUser.getName();
|
||||
String userType = adminUser.getUserType();
|
||||
long createTime = adminUser.getCreateTime().getTime();
|
||||
long updateTime = adminUser.getUpdateTime().getTime();
|
||||
JWTCreator.Builder jwtBuilder = JWT.create();
|
||||
jwtBuilder.withClaim("id", id);
|
||||
jwtBuilder.withClaim("phone", phone);
|
||||
jwtBuilder.withClaim("name", name);
|
||||
jwtBuilder.withClaim("userType", userType);
|
||||
jwtBuilder.withClaim("createTime", createTime);
|
||||
jwtBuilder.withClaim("updateTime", updateTime);
|
||||
jwtBuilder.withClaim("timestamp", System.currentTimeMillis());
|
||||
|
|
@ -47,6 +49,7 @@ public final class AdminJwtService {
|
|||
.withClaimPresence("id")
|
||||
.withClaimPresence("phone")
|
||||
.withClaimPresence("name")
|
||||
.withClaimPresence("userType")
|
||||
.withClaimPresence("createTime")
|
||||
.withClaimPresence("updateTime")
|
||||
.withClaimPresence("timestamp")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,15 @@
|
|||
package com.jinrui.reference.admin.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jinrui.reference.admin.mapper.AdminUserMapper;
|
||||
|
|
@ -9,19 +19,10 @@ import com.jinrui.reference.admin.model.vo.admin.user.AdminUserVO;
|
|||
import com.jinrui.reference.admin.model.vo.login.LoginVO;
|
||||
import com.jinrui.reference.core.model.vo.PageObject;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class AdminUserService {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.jinrui.reference.admin.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.jinrui.reference.admin.model.entity.AdminUser;
|
||||
import com.jinrui.reference.core.mapper.UserOperationLogMapper;
|
||||
|
||||
@Service
|
||||
public class UserOperationLogService {
|
||||
|
||||
private final UserOperationLogMapper userOperationLogMapper;
|
||||
|
||||
public UserOperationLogService(UserOperationLogMapper userOperationLogMapper) {
|
||||
this.userOperationLogMapper = userOperationLogMapper;
|
||||
}
|
||||
|
||||
public void logUserOperation(String type, String behavior, String token, Long dataId) {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
userOperationLogMapper.save(adminUser.getId(), adminUser.getName(), adminUser.getUserType(), dataId, type, behavior);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
/application-prod.yml
|
||||
|
|
@ -1,13 +1,50 @@
|
|||
logging:
|
||||
level:
|
||||
root: DEBUG
|
||||
server:
|
||||
port: 13579
|
||||
compression:
|
||||
enabled: true
|
||||
servlet:
|
||||
context-path: /admin
|
||||
oss:
|
||||
ak: LTAI5t8z9QNdCG6b54mDgx8p
|
||||
sk: F3M41hTgH8g99ZgVWyelj42825YbZM
|
||||
roleArn: acs:ram::1647420045565932:role/ramoss
|
||||
endPoint: oss-cn-hangzhou.aliyuncs.com
|
||||
region: oss-cn-hangzhou
|
||||
bucketName: lengfeng-test
|
||||
baseUrl: https://lengfeng-test.oss-cn-hangzhou.aliyuncs.com
|
||||
sts:
|
||||
endPoint: sts.cn-hangzhou.aliyuncs.com
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3306/reference?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&allowMultiQueries=true
|
||||
# url: jdbc:mysql://192.168.0.142:3306/reference?autoReconnect=true&useUnicode=true&useSSL=false&allowMultiQueries=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
||||
# username: financial_prod
|
||||
# password: mmTFncqmDal5HLRGY0BV
|
||||
url: jdbc:mysql://121.37.185.246:3306/reference?autoReconnect=true&useUnicode=true&useSSL=false&allowMultiQueries=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
||||
username: root
|
||||
password: Aa123456@
|
||||
password: Xgf_8000
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
# host: 192.168.0.172
|
||||
# port: 6379
|
||||
# password: Xgf_redis
|
||||
host: 123.60.153.169
|
||||
port: 6379
|
||||
password: Xgf_redis
|
||||
elasticsearch:
|
||||
scheme: http
|
||||
# 111.13.176.3 部署地址
|
||||
# 10.127.2.194 本地测试地址
|
||||
host: 111.13.176.3
|
||||
port: 9200
|
||||
enable: true
|
||||
username: elastic
|
||||
password: ZxE,3VM@Thk0
|
||||
mybatis:
|
||||
type-handlers-package:com.jinrui.reference.core.typehandler
|
||||
api:
|
||||
key: WBysu6N1z26AbA12l
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
logging:
|
||||
level:
|
||||
root: DEBUG
|
||||
server:
|
||||
port: 13579
|
||||
compression:
|
||||
|
|
@ -36,7 +39,7 @@ elasticsearch:
|
|||
scheme: http
|
||||
# 111.13.176.3 部署地址
|
||||
# 10.127.2.194 本地测试地址
|
||||
host: 10.127.2.194
|
||||
host: 111.13.176.3
|
||||
port: 9200
|
||||
enable: true
|
||||
username: elastic
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE `reference`.`news`
|
||||
ADD COLUMN `revision` TEXT NULL AFTER `rating`;
|
||||
|
||||
ALTER TABLE `reference`.`admin_user`
|
||||
ADD COLUMN `user_type` CHAR(2) NULL DEFAULT '00' AFTER `active`;
|
||||
|
|
@ -39,6 +39,10 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
|
|
@ -86,6 +90,11 @@
|
|||
<artifactId>jakarta.json-api</artifactId>
|
||||
<version>${jakartajson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>${jedis.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
package com.jinrui.reference.core;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
@Value("${redis.host}")
|
||||
private String host;
|
||||
|
||||
@Value("${redis.port}")
|
||||
private int port;
|
||||
|
||||
@Value("${redis.timeout:1000}")
|
||||
private int timeout;
|
||||
|
||||
@Value("${redis.password:}")
|
||||
private String password;
|
||||
|
||||
@Bean
|
||||
public JedisPool jedisPool() {
|
||||
if (StringUtils.hasText(password)) {
|
||||
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
|
||||
return new JedisPool(jedisPoolConfig, host, port, timeout, password);
|
||||
}
|
||||
return new JedisPool(host, port);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,15 @@
|
|||
package com.jinrui.reference.core;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import com.jinrui.reference.core.interceptor.ApiAuthInterceptor;
|
||||
|
||||
|
||||
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
|
|
@ -18,4 +24,15 @@ public class WebConfig implements WebMvcConfigurer {
|
|||
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH")
|
||||
.maxAge(3600);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApiAuthInterceptor apiAuthInterceptor() {
|
||||
return new ApiAuthInterceptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(apiAuthInterceptor())
|
||||
.addPathPatterns("/api/**").excludePathPatterns("/api/key"); // 拦截API路径
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.jinrui.reference.core.api;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ApiKeyGenerator {
|
||||
public static String generateAK() {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
|
||||
public static String generateSK() {
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte[] bytes = new byte[32]; // 256位密钥
|
||||
random.nextBytes(bytes);
|
||||
return Base64.getEncoder().encodeToString(bytes);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.jinrui.reference.core.api;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
|
||||
public enum ApiReturnCode {
|
||||
ILLEGAL_HEADER("10001", "缺失API相关的请求头参数!"),
|
||||
REPLAY_ERROR("10002", "请求超时或重复请求!"),
|
||||
KEY_ERROR("10003", "请求的KEY非法!"),
|
||||
ARGUMENT_ERROR("10004", "参数签名错误!");
|
||||
|
||||
private final String code;
|
||||
private final String msg;
|
||||
|
||||
private ApiReturnCode(String code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
package com.jinrui.reference.core.interceptor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jinrui.reference.core.api.ApiReturnCode;
|
||||
import com.jinrui.reference.core.service.ApiKeyService;
|
||||
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.params.SetParams;
|
||||
|
||||
public class ApiAuthInterceptor implements HandlerInterceptor {
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(ApiAuthInterceptor.class);
|
||||
public static final Long REQUEST_TIMEOUT = 300L;
|
||||
|
||||
@Autowired
|
||||
private ApiKeyService apiKeyService; // 从数据库查询SK
|
||||
@Autowired
|
||||
private JedisPool jedisPool;
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws InvalidKeyException, NoSuchAlgorithmException {
|
||||
String ak = request.getHeader("X-Api-Key");
|
||||
String timestamp = request.getHeader("X-Timestamp");
|
||||
String nonce = request.getHeader("X-Nonce");
|
||||
String clientSign = request.getHeader("X-Signature");
|
||||
|
||||
// 1. 校验基础参数
|
||||
if (!StringUtils.hasLength(ak) || !StringUtils.hasLength(timestamp)
|
||||
|| !StringUtils.hasLength(nonce) || !StringUtils.hasLength(clientSign)) {
|
||||
responseToFailed(response, ApiReturnCode.ILLEGAL_HEADER);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 防重放:时间戳有效期5分钟
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (Math.abs(currentTime - Long.parseLong(timestamp)) > REQUEST_TIMEOUT * 1000) {
|
||||
responseToFailed(response, ApiReturnCode.REPLAY_ERROR);
|
||||
return false;
|
||||
}
|
||||
// 3. 校验nonce唯一性(Redis实现)
|
||||
try(Jedis jedis = jedisPool.getResource()) {
|
||||
if (jedis.exists(nonce)) {
|
||||
responseToFailed(response, ApiReturnCode.REPLAY_ERROR);
|
||||
return false;
|
||||
}
|
||||
jedis.set(nonce, "", SetParams.setParams().ex(REQUEST_TIMEOUT));
|
||||
} catch(Exception e) {
|
||||
LOGGER.error("获取redis对象失败", e);
|
||||
}
|
||||
|
||||
// 4. 获取SK并计算服务端签名
|
||||
String sk = apiKeyService.getSecretKeyByAk(ak);
|
||||
if (ObjectUtils.isEmpty(sk)) {
|
||||
responseToFailed(response, ApiReturnCode.KEY_ERROR);
|
||||
return false;
|
||||
}
|
||||
String serverSign = calculateSignature(request, sk, timestamp, nonce);
|
||||
|
||||
// 5. 比对签名
|
||||
if (!serverSign.equals(clientSign)) {
|
||||
responseToFailed(response, ApiReturnCode.ARGUMENT_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String calculateSignature(HttpServletRequest request, String sk, String timestamp, String nonce) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
// 拼接请求数据:方法+路径+排序后的参数
|
||||
String method = request.getMethod();
|
||||
String path = request.getRequestURI();
|
||||
|
||||
String params = getSortedParams(request);
|
||||
String data = method + path + params + timestamp + nonce;
|
||||
|
||||
// HMAC-SHA256签名
|
||||
Mac sha256 = Mac.getInstance("HmacSHA256");
|
||||
sha256.init(new SecretKeySpec(sk.getBytes(), "HmacSHA256"));
|
||||
byte[] signBytes = sha256.doFinal(data.getBytes(StandardCharsets.UTF_8));
|
||||
return Hex.encodeHexString(signBytes);
|
||||
}
|
||||
|
||||
private String getSortedParams(HttpServletRequest request) {
|
||||
// 获取请求参数(目前只考虑query string类型的参数,暂不支持application/json格式参数
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
String sortedQueryString = parameterMap.entrySet().stream().filter(e -> !ObjectUtils.isEmpty(e.getValue())).sorted(Map.Entry.comparingByKey())
|
||||
.map(e -> e.getKey() + "=" + String.join(",", e.getValue())).collect(Collectors.joining("&"));
|
||||
return sortedQueryString;
|
||||
}
|
||||
|
||||
private void responseToFailed(HttpServletResponse response, ApiReturnCode apiReturnCode) {
|
||||
try {
|
||||
response.setStatus(200);
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
response.getWriter().print(objectMapper.writeValueAsString(apiReturnCode));
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.jinrui.reference.core.mapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
public interface ApiUserMapper {
|
||||
@Select("select secret_key from api_user where access_key = #{ak} and disabled = 0")
|
||||
String getClientSecretkey(@Param("ak") String ak);
|
||||
|
||||
@Select("select access_key, secret_key from api_user where client_name = #{clientName} and disabled = 0")
|
||||
Map<String, Object> getClientKey(@Param("clientName") String clientName);
|
||||
|
||||
@Insert("insert into api_user(client_name, access_key, secret_key)" +
|
||||
"values (#{clientName}, #{accessKey}, #{secretKey})")
|
||||
void save(@Param("clientName") String clientName, @Param("accessKey") String accessKey, @Param("secretKey") String secretKey);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.jinrui.reference.core.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
|
||||
import com.jinrui.reference.core.model.entity.NewsDeleted;
|
||||
|
||||
public interface NewsDeletedMapper {
|
||||
@Insert("insert into news_deleted(news_id, newsinfo_id, cluster_id, deleted_time)" +
|
||||
"values (#{newsId}, #{newsinfoId}, #{clusterId}, now())")
|
||||
void save(NewsDeleted newsDeleted);
|
||||
|
||||
}
|
||||
|
|
@ -7,16 +7,23 @@ import org.apache.ibatis.annotations.Delete;
|
|||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Options;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Result;
|
||||
import org.apache.ibatis.annotations.Results;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import com.jinrui.reference.core.model.entity.News;
|
||||
import com.jinrui.reference.core.model.entity.NewsDraft;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsApiVO;
|
||||
import com.jinrui.reference.core.typehandler.JsonArrayTypeHandler;
|
||||
|
||||
public interface NewsMapper {
|
||||
|
||||
@Delete("delete from news where id = #{newsId}")
|
||||
void deleteNews(@Param("newsId") Long newsId);
|
||||
@Delete("update news set is_delete = 1, update_time = now(), editor_id = #{editorId} where id = #{newsId} and status = 1")
|
||||
int deleteNews(@Param("newsId") Long newsId, @Param("editorId") Long editorId);
|
||||
|
||||
@Delete("update news set is_delete = 0, update_time = now(), editor_id = #{editorId} where id = #{newsId}")
|
||||
void recoverNews(@Param("newsId") Long newsId, @Param("editorId") Long editorId);
|
||||
|
||||
@Delete("delete from news_draft where id = #{draftId}")
|
||||
void deleteDraft(@Param("draftId") Long draftId);
|
||||
|
|
@ -27,75 +34,60 @@ public interface NewsMapper {
|
|||
"from news_draft where id = #{id}")
|
||||
NewsDraft getDraftDetail(@Param("id") Long id);
|
||||
|
||||
@Select("select id, title, summary, picture, content, " +
|
||||
@Select("select id, llm_title as title, summary, picture, llm_content as content, " +
|
||||
"create_time as createTime, " +
|
||||
"update_time as updateTime " +
|
||||
"update_time as updateTime, " +
|
||||
"is_delete as deleted, " +
|
||||
"rating, " +
|
||||
"revision, " +
|
||||
"newsinfo_id as newsinfoId " +
|
||||
"from news where id = #{id}")
|
||||
News getNewsDetail(@Param("id") Long id);
|
||||
|
||||
@Update("update news set status = 1, update_time = now() where id = #{id}")
|
||||
void simpleUnpublish(@Param("id") long id);
|
||||
|
||||
@Update("update news set status = 2, update_time = now(), editor_id = #{editorId} where id = #{id}")
|
||||
void simplePublish(@Param("id") long id, @Param("editorId") long editorId);
|
||||
@Update("update news set status = #{newStatus}, update_time = now(), editor_id = #{editorId} where id = #{id} and status = #{oldStatus}")
|
||||
int changeFrom(@Param("id") long id, @Param("oldStatus") int oldStatus, @Param("newStatus") int newStatus, @Param("editorId") long editorId);
|
||||
|
||||
@Update("update news " +
|
||||
"set draft_id = #{draftId}," +
|
||||
"editor_id = #{editorId}," +
|
||||
"title = #{title}," +
|
||||
"summary = #{summary}," +
|
||||
"picture = #{picture}," +
|
||||
"content = #{content}," +
|
||||
"content_text = #{contentText}," +
|
||||
"status = #{status}," +
|
||||
"newsinfo_id = #{newsinfoId}," +
|
||||
"set editor_id = #{news.editorId}," +
|
||||
"draft_id = #{news.draftId}, " +
|
||||
"llm_title = #{news.title}," +
|
||||
"summary = #{news.summary}," +
|
||||
"picture = #{news.picture}," +
|
||||
"llm_content = #{news.content}," +
|
||||
"content_text = #{news.contentText}," +
|
||||
"status = #{news.status}," +
|
||||
"newsinfo_id = #{news.newsinfoId}," +
|
||||
"rating = #{news.rating}," +
|
||||
"revision = #{news.revision}," +
|
||||
"update_time = now()" +
|
||||
"where id = #{id}")
|
||||
void updateNews(News news);
|
||||
"where id = #{news.id} and status = #{oldStatus}")
|
||||
int updateNews(News news, Integer oldStatus);
|
||||
|
||||
@Update("update news " +
|
||||
"set editor_id = #{editorId}," +
|
||||
"draft_id = NULL, " +
|
||||
"title = #{title}," +
|
||||
"summary = #{summary}," +
|
||||
"picture = #{picture}," +
|
||||
"content = #{content}," +
|
||||
"content_text = #{contentText}," +
|
||||
"status = #{status}," +
|
||||
"update_time = now()" +
|
||||
"where id = #{id}")
|
||||
void publishNews(News news);
|
||||
|
||||
@Select("select id, draft_id as draftId, status, newsinfo_id as newsinfoId from news where id = #{id}")
|
||||
@Select("select id, draft_id as draftId, status, newsinfo_id as newsinfoId, is_delete as deleted, rating, revision from news where id = #{id}")
|
||||
News getById(@Param("id") Long id);
|
||||
|
||||
@Select("select last_insert_id()")
|
||||
Long getLastInsertId();
|
||||
|
||||
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
|
||||
@Insert("insert into news_draft(title, summary, picture, type, content, create_time, update_time)" +
|
||||
"values (#{title}, #{summary}, #{picture}, #{type}, #{content}, now(), now())")
|
||||
void saveDraft(NewsDraft newsDraft);
|
||||
|
||||
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
|
||||
@Insert("insert into news(draft_id, title, summary, picture, type, content, create_time, update_time, status, publish_time, content_text, newsinfo_id)" +
|
||||
"values (#{draftId}, #{title}, #{summary}, #{picture}, #{type}, #{content}, now(), now(), #{status}, #{publishTime}, #{contentText}, #{newsinfoId})")
|
||||
@Insert("insert into news(draft_id, title, summary, picture, type, content, create_time, update_time, status, publish_time, content_text, newsinfo_id, llm_title, llm_content, rating)" +
|
||||
"values (#{draftId}, #{title}, #{summary}, #{picture}, #{type}, #{content}, now(), now(), #{status}, #{publishTime}, #{contentText}, #{newsinfoId}, #{llmTitle}, #{llmContent}, #{rating})")
|
||||
void saveNews(News news);
|
||||
|
||||
|
||||
@Select("SELECT MAX(id) AS max_id FROM news")
|
||||
Long getNewsLastInsertId();
|
||||
|
||||
@Select("<script>" +
|
||||
"select distinct " +
|
||||
"news.id as id," +
|
||||
"news.draft_id as draftId," +
|
||||
"news.title as title," +
|
||||
"news.llm_title as title," +
|
||||
"news.status as status," +
|
||||
"news.create_time as createTime," +
|
||||
"news.publish_time as publishTime," +
|
||||
"news.update_time as updateTime, " +
|
||||
"news.newsinfo_id as newsinfoId, " +
|
||||
"news.is_delete as deleted, " +
|
||||
"news.rating as rating, " +
|
||||
"news_tags.news_score as score " +
|
||||
"from news " +
|
||||
"<if test=\"column != null and !column.isEmpty()\">" +
|
||||
|
|
@ -121,7 +113,7 @@ public interface NewsMapper {
|
|||
"<if test=\"keywords != null and !keywords.isEmpty()\">" +
|
||||
" and " +
|
||||
"<foreach collection=\"keywords\" item=\"keyword\" open=\"(\" close=\")\" separator=\"or\">\n" +
|
||||
" (news.title like concat('%', #{keyword}, '%') or news.content like concat('%', #{keyword}, '%')) " +
|
||||
" (news.llm_title like concat('%', #{keyword}, '%') or news.llm_content like concat('%', #{keyword}, '%')) " +
|
||||
"</foreach>" +
|
||||
"</if>" +
|
||||
"<if test=\"datelineFrom != null\">" +
|
||||
|
|
@ -142,9 +134,18 @@ public interface NewsMapper {
|
|||
"<if test=\"status != null\">" +
|
||||
"and news.status = #{status} " +
|
||||
"</if>" +
|
||||
"<if test=\"deleted != null\">" +
|
||||
"and news.is_delete = #{deleted} " +
|
||||
"</if>" +
|
||||
"<if test=\"rating != null\">" +
|
||||
"and news.rating = #{rating} " +
|
||||
"</if>" +
|
||||
"<if test=\"last != null\">" +
|
||||
"and news.id > #{last}" +
|
||||
"</if>" +
|
||||
"<if test=\"isReviewer == true\">" +
|
||||
"and news.status in (2, 3) " +
|
||||
"</if>" +
|
||||
"</where>" +
|
||||
"<if test=\"orderBy != null\">" +
|
||||
"order by ${orderBy} " +
|
||||
|
|
@ -163,7 +164,10 @@ public interface NewsMapper {
|
|||
@Param("tags") List<Long> tags,
|
||||
@Param("industries") List<Long> industries,
|
||||
@Param("datelineFrom") Date datelineFrom,
|
||||
@Param("datelineTo") Date datelineTo);
|
||||
@Param("datelineTo") Date datelineTo,
|
||||
@Param("deleted") Integer deleted,
|
||||
@Param("rating") Byte rating,
|
||||
@Param("isReviewer") boolean isReviewer);
|
||||
|
||||
@Select("<script>" +
|
||||
"select count(*) from (select distinct news.* from news " +
|
||||
|
|
@ -192,7 +196,7 @@ public interface NewsMapper {
|
|||
"<if test=\"keywords != null and !keywords.isEmpty()\">" +
|
||||
" and " +
|
||||
"<foreach collection=\"keywords\" item=\"keyword\" open=\"(\" close=\")\" separator=\"or\">\n" +
|
||||
" (news.title like concat('%', #{keyword}, '%') or news.content like concat('%', #{keyword}, '%')) " +
|
||||
" (news.llm_title like concat('%', #{keyword}, '%') or news.llm_content like concat('%', #{keyword}, '%')) " +
|
||||
"</foreach>" +
|
||||
"</if>" +
|
||||
"<if test=\"datelineFrom != null\">" +
|
||||
|
|
@ -213,6 +217,15 @@ public interface NewsMapper {
|
|||
"<if test=\"status != null\">" +
|
||||
"and news.status = #{status} " +
|
||||
"</if>" +
|
||||
"<if test=\"deleted != null\">" +
|
||||
"and news.is_delete = #{deleted} " +
|
||||
"</if>" +
|
||||
"<if test=\"rating != null\">" +
|
||||
"and news.rating = #{rating} " +
|
||||
"</if>" +
|
||||
"<if test=\"isReviewer == true\">" +
|
||||
"and news.status in (2, 3) " +
|
||||
"</if>" +
|
||||
"</where>) tmp" +
|
||||
"</script>")
|
||||
int queryTotal(@Param("keywords") List<String> keywords,
|
||||
|
|
@ -223,12 +236,74 @@ public interface NewsMapper {
|
|||
@Param("tags") List<Long> tags,
|
||||
@Param("industries") List<Long> industries,
|
||||
@Param("datelineFrom") Date datelineFrom,
|
||||
@Param("datelineTo") Date datelineTo);
|
||||
@Param("datelineTo") Date datelineTo,
|
||||
@Param("deleted") Integer deleted,
|
||||
@Param("rating") Byte rating,
|
||||
@Param("isReviewer") boolean isReviewer);
|
||||
|
||||
@Select("select id, title, summary, picture, content, status, " +
|
||||
@Select("select id, llm_title as title, summary, picture, llm_content as content, status, " +
|
||||
"create_time as createTime, " +
|
||||
"publish_time as publishTime, " +
|
||||
"update_time as updateTime " +
|
||||
"from news where newsinfo_id = #{newsinfoId}")
|
||||
News getNewsDetailByNewsInfoId(@Param("newsinfoId") String newsinfoId);
|
||||
|
||||
@Select("SELECT cluster_id FROM news WHERE newsinfo_id IS NOT NULL AND cluster_id IS NOT NULL GROUP BY cluster_id HAVING COUNT(*) > 1")
|
||||
List<String> getDuplicatedCluster();
|
||||
|
||||
@Select("select id, draft_id as draftId, newsinfo_id as newsinfoId, is_delete as deleted, editor_id as editorId from news where cluster_id = #{clusterId} and newsinfo_id IS NOT NULL")
|
||||
List<News> getDuplicatedNews(@Param("clusterId") String clusterId);
|
||||
|
||||
@Delete("delete from news where id = #{id}")
|
||||
void deleteById(@Param("id") Long id);
|
||||
|
||||
|
||||
@Results({
|
||||
@Result(column = "id", property = "id", id = true),
|
||||
@Result(column = "llm_title", property = "title"),
|
||||
@Result(column = "llm_content", property = "content"),
|
||||
@Result(column = "summary", property = "summary"),
|
||||
@Result(column = "publish_time", property = "publishTime"),
|
||||
@Result(column = "industry_label", property = "industryLabel", typeHandler = JsonArrayTypeHandler.class),
|
||||
@Result(column = "industry_confidence", property = "industryConfidence", typeHandler = JsonArrayTypeHandler.class),
|
||||
@Result(column = "industry_score", property = "industryScore", typeHandler = JsonArrayTypeHandler.class),
|
||||
@Result(column = "concept_label", property = "conceptLabel", typeHandler = JsonArrayTypeHandler.class),
|
||||
@Result(column = "concept_confidence", property = "conceptConfidence", typeHandler = JsonArrayTypeHandler.class),
|
||||
@Result(column = "concept_score", property = "conceptScore", typeHandler = JsonArrayTypeHandler.class),
|
||||
@Result(column = "source", property = "source"),
|
||||
@Result(column = "source_impact", property = "sourceImpact"),
|
||||
@Result(column = "China_factor", property = "chinaFactor"),
|
||||
@Result(column = "public_opinion_score", property = "publicOpinionScore"),
|
||||
@Result(column = "news_score", property = "newsScore"),
|
||||
})
|
||||
@Select("<script>" +
|
||||
"select " +
|
||||
"news.id as id," +
|
||||
"news.llm_title," +
|
||||
"news.llm_content," +
|
||||
"news.summary, " +
|
||||
"news.publish_time," +
|
||||
"news_tags.news_score, " +
|
||||
"news_tags.source, " +
|
||||
"news_tags.industry_label, " +
|
||||
"news_tags.industry_confidence," +
|
||||
"news_tags.industry_score," +
|
||||
"news_tags.concept_label," +
|
||||
"news_tags.concept_confidence," +
|
||||
"news_tags.concept_score," +
|
||||
"news_tags.source_impact," +
|
||||
"news_tags.China_factor," +
|
||||
"news_tags.public_opinion_score" +
|
||||
"from news " +
|
||||
" left join news_tags on news.newsinfo_id = news_tags.newsinfo_id " +
|
||||
"<where>" +
|
||||
" news.status = 2 and news.is_delete = 0 and news.publish_time >= adddate(date(now()), -2) " +
|
||||
"<if test=\"last != null\">" +
|
||||
"and news.id > #{last}" +
|
||||
"</if>" +
|
||||
"</where>" +
|
||||
"order by id desc " +
|
||||
"limit ${limit}" +
|
||||
"</script>")
|
||||
List<NewsApiVO> queryNewsByApi(@Param("last") Long last, @Param("limit") int limit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.jinrui.reference.core.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Result;
|
||||
import org.apache.ibatis.annotations.Results;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import com.jinrui.reference.core.model.entity.News;
|
||||
import com.jinrui.reference.core.model.entity.NewsTags;
|
||||
import com.jinrui.reference.core.typehandler.JsonArrayTypeHandler;
|
||||
|
||||
|
|
@ -32,4 +34,8 @@ public interface NewsTagsMapper {
|
|||
})
|
||||
@Select("select * from news_tags where newsinfo_id = #{newsId}")
|
||||
NewsTags getNewsTagsByNewsId(@Param("newsId") String newsId);
|
||||
|
||||
@Insert("insert into news_tags(abstract, title, rewrite_content, industry_label, industry_confidence, industry_score, concept_label, concept_confidence, concept_score, source, source_impact, China_factor, public_opinion_score, news_score, news_id, deleted, create_time, update_time)" +
|
||||
"values (#{summary}, #{title}, #{rewriteContent}, #{industryLabel, jdbcType=VARCHAR,typeHandler=com.jinrui.reference.core.typehandler.JsonArrayTypeHandler}, #{industryConfidence,jdbcType=VARCHAR,typeHandler=com.jinrui.reference.core.typehandler.JsonArrayTypeHandler}, #{industryScore,jdbcType=VARCHAR,typeHandler=com.jinrui.reference.core.typehandler.JsonArrayTypeHandler}, #{conceptLabel,jdbcType=VARCHAR,typeHandler=com.jinrui.reference.core.typehandler.JsonArrayTypeHandler}, #{conceptConfidence,jdbcType=VARCHAR,typeHandler=com.jinrui.reference.core.typehandler.JsonArrayTypeHandler}, #{conceptScore,jdbcType=VARCHAR,typeHandler=com.jinrui.reference.core.typehandler.JsonArrayTypeHandler}, #{source}, #{sourceImpact}, #{chinaFactor}, #{publicOpinionScore}, #{newsScore}, #{newsId}, #{deleted},#{createTime}, #{updateTime})")
|
||||
void save(NewsTags newsTags);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package com.jinrui.reference.core.mapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Result;
|
||||
import org.apache.ibatis.annotations.Results;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import com.jinrui.reference.core.model.entity.UserOperationLog;
|
||||
|
||||
public interface UserOperationLogMapper {
|
||||
@Insert("insert into user_operation_log(user_id, username, user_type, data_id, type, behavior)" +
|
||||
"values (#{userId},#{username},#{userType}, #{dataId}, #{type}, #{behavior})")
|
||||
void save(@Param("userId") Long userId,@Param("username") String username,@Param("userType") String userType,@Param("dataId") Long dataId, @Param("type") String type, @Param("behavior") String behavior);
|
||||
|
||||
@Results({
|
||||
@Result(column = "id", property = "id", id = true),
|
||||
@Result(column = "data_id", property = "dataId"),
|
||||
@Result(column = "user_id", property = "userId"),
|
||||
@Result(column = "username", property = "username"),
|
||||
@Result(column = "user_type", property = "userType"),
|
||||
@Result(column = "type", property = "type"),
|
||||
@Result(column = "behavior", property = "behavior"),
|
||||
@Result(column = "create_time", property = "createTime", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP),
|
||||
})
|
||||
@Select("select * from user_operation_log where data_id = #{dataId} and type = #{type} order by create_time desc limit ${limit} offset ${offset}")
|
||||
List<UserOperationLog> selectByDataIdAndType(@Param("dataId") Long dataId, @Param("type") String type, @Param("limit") int limit, @Param("offset") int offset);
|
||||
|
||||
@Select("select count(*) from user_operation_log where data_id = #{dataId} and type = #{type}")
|
||||
int queryTotal(@Param("dataId") Long dataId, @Param("type") String type);
|
||||
}
|
||||
|
|
@ -33,6 +33,10 @@ public class SaveNewsDTO {
|
|||
private Integer status;
|
||||
private Date publishTime;
|
||||
|
||||
private Byte rating;
|
||||
|
||||
private String revision;
|
||||
|
||||
public SaveNewsDTO() {}
|
||||
|
||||
public SaveNewsDTO(NewsDetailVO newsDetailVO) {
|
||||
|
|
@ -144,4 +148,20 @@ public class SaveNewsDTO {
|
|||
newsInfo.setInputDate(newsInfo.getCreateTime());
|
||||
return newsInfo;
|
||||
}
|
||||
|
||||
public Byte getRating() {
|
||||
return rating;
|
||||
}
|
||||
|
||||
public void setRating(Byte rating) {
|
||||
this.rating = rating;
|
||||
}
|
||||
|
||||
public String getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
public void setRevision(String revision) {
|
||||
this.revision = revision;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class News {
|
|||
private String contentText;
|
||||
|
||||
/**
|
||||
* 新闻状态 0-草稿 | 1-未发布 | 2-已发布
|
||||
* 新闻状态 0-草稿 | 1-未发布 | 2-已发布 | 3-送审
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
|
|
@ -78,6 +78,16 @@ public class News {
|
|||
|
||||
private Double score;
|
||||
|
||||
private String llmTitle;
|
||||
|
||||
private String llmContent;
|
||||
|
||||
private Boolean deleted;
|
||||
|
||||
private Byte rating;
|
||||
|
||||
private String revision;
|
||||
|
||||
public News() {}
|
||||
|
||||
public News(SaveNewsDTO saveNewsDTO) {
|
||||
|
|
@ -90,7 +100,10 @@ public class News {
|
|||
this.content = saveNewsDTO.getContent();
|
||||
this.contentText = saveNewsDTO.getContentText();
|
||||
this.publishTime = saveNewsDTO.getPublishTime();
|
||||
// this.status = 0;
|
||||
this.llmTitle = saveNewsDTO.getTitle();
|
||||
this.llmContent = saveNewsDTO.getContent();
|
||||
this.rating = saveNewsDTO.getRating();
|
||||
this.revision = saveNewsDTO.getRevision();
|
||||
this.createTime = new Date();
|
||||
this.updateTime = new Date();
|
||||
}
|
||||
|
|
@ -214,4 +227,44 @@ public class News {
|
|||
public void setScore(Double score) {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
public String getLlmTitle() {
|
||||
return llmTitle;
|
||||
}
|
||||
|
||||
public void setLlmTitle(String llmTitle) {
|
||||
this.llmTitle = llmTitle;
|
||||
}
|
||||
|
||||
public String getLlmContent() {
|
||||
return llmContent;
|
||||
}
|
||||
|
||||
public void setLlmContent(String llmContent) {
|
||||
this.llmContent = llmContent;
|
||||
}
|
||||
|
||||
public Boolean getDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(Boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public Byte getRating() {
|
||||
return rating;
|
||||
}
|
||||
|
||||
public void setRating(Byte rating) {
|
||||
this.rating = rating;
|
||||
}
|
||||
|
||||
public void setRevision(String revision) {
|
||||
this.revision = revision;
|
||||
}
|
||||
|
||||
public String getRevision() {
|
||||
return revision;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
package com.jinrui.reference.core.model.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class NewsDeleted {
|
||||
|
||||
private Long id;
|
||||
|
||||
private Long newsId;
|
||||
|
||||
private String newsinfoId;
|
||||
|
||||
private String clusterId;
|
||||
|
||||
private Date deletedTime;
|
||||
|
||||
public NewsDeleted() {
|
||||
|
||||
}
|
||||
|
||||
public NewsDeleted(News news, String clusterId) {
|
||||
this.newsId = news.getId();
|
||||
this.newsinfoId = news.getNewsinfoId();
|
||||
this.clusterId = clusterId;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getNewsId() {
|
||||
return newsId;
|
||||
}
|
||||
|
||||
public void setNewsId(Long newsId) {
|
||||
this.newsId = newsId;
|
||||
}
|
||||
|
||||
public String getNewsinfoId() {
|
||||
return newsinfoId;
|
||||
}
|
||||
|
||||
public void setNewsinfoId(String newsinfoId) {
|
||||
this.newsinfoId = newsinfoId;
|
||||
}
|
||||
|
||||
public String getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
public void setClusterId(String clusterId) {
|
||||
this.clusterId = clusterId;
|
||||
}
|
||||
|
||||
public Date getDeletedTime() {
|
||||
return deletedTime;
|
||||
}
|
||||
|
||||
public void setDeletedTime(Date deletedTime) {
|
||||
this.deletedTime = deletedTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ public class NewsInfo {
|
|||
public static final String CONTENT_ES_NAME = "CN_content";
|
||||
public static final String SOURCE_ES_NAME = "sourcename.keyword";
|
||||
public static final String DELETED_ES_NAME = "deleted.keyword";
|
||||
public static final String SCORE_ES_NAME = "news_tags.news_score";
|
||||
public static final String INPUT_DATE_ES_NAME = "input_date";
|
||||
|
||||
/**
|
||||
* 全量资讯ID
|
||||
|
|
@ -33,7 +35,7 @@ public class NewsInfo {
|
|||
/**
|
||||
* 数据输入时间
|
||||
*/
|
||||
@JsonProperty("input_date")
|
||||
@JsonProperty(INPUT_DATE_ES_NAME)
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Shanghai")
|
||||
private Date inputDate;
|
||||
|
||||
|
|
@ -137,6 +139,8 @@ public class NewsInfo {
|
|||
*/
|
||||
private Long editorId;
|
||||
|
||||
@JsonProperty("news_tags")
|
||||
private NewsTags newsTags;
|
||||
|
||||
public NewsInfo() {}
|
||||
|
||||
|
|
@ -316,11 +320,21 @@ public class NewsInfo {
|
|||
this.words = words;
|
||||
}
|
||||
|
||||
public NewsTags getNewsTags() {
|
||||
return newsTags;
|
||||
}
|
||||
|
||||
public void setNewsTags(NewsTags newsTags) {
|
||||
this.newsTags = newsTags;
|
||||
}
|
||||
|
||||
|
||||
public News toNews() {
|
||||
News news = new News();
|
||||
news.setTitle(this.getTitle());
|
||||
news.setContent(this.getContent());
|
||||
news.setLlmTitle(this.getTitle());
|
||||
news.setLlmContent(this.getContent());
|
||||
news.setStatus(this.getStatus());
|
||||
news.setSummary(this.getSummary());
|
||||
news.setPublishTime(this.getInputDate());
|
||||
|
|
|
|||
|
|
@ -3,43 +3,67 @@ package com.jinrui.reference.core.model.entity;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class NewsTags {
|
||||
@JsonProperty("id")
|
||||
private Long id;
|
||||
|
||||
@JsonProperty("abstract")
|
||||
private String summary;
|
||||
|
||||
@JsonProperty("title")
|
||||
private String title;
|
||||
|
||||
@JsonProperty("rewrite_content")
|
||||
private String rewriteContent;
|
||||
|
||||
@JsonProperty("industry_label")
|
||||
private List<String> industryLabel;
|
||||
|
||||
@JsonProperty("industry_confidence")
|
||||
private List<Double> industryConfidence;
|
||||
|
||||
@JsonProperty("industry_score")
|
||||
private List<Double> industryScore;
|
||||
|
||||
@JsonProperty("concept_label")
|
||||
private List<String> conceptLabel;
|
||||
|
||||
@JsonProperty("concept_confidence")
|
||||
private List<Double> conceptConfidence;
|
||||
|
||||
@JsonProperty("concept_score")
|
||||
private List<Double> conceptScore;
|
||||
|
||||
@JsonProperty("source")
|
||||
private String source;
|
||||
|
||||
@JsonProperty("source_impact")
|
||||
private Integer sourceImpact;
|
||||
|
||||
@JsonProperty("China_factor")
|
||||
private Double chinaFactor;
|
||||
|
||||
@JsonProperty("public_opinion_score")
|
||||
private Integer publicOpinionScore;
|
||||
|
||||
@JsonProperty("news_score")
|
||||
private Double newsScore;
|
||||
|
||||
@JsonProperty("news_id")
|
||||
private Long newsId;
|
||||
|
||||
private Boolean deleted;
|
||||
@JsonProperty("deleted")
|
||||
private Integer deleted;
|
||||
|
||||
@JsonProperty("create_time")
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Shanghai")
|
||||
private Date createTime;
|
||||
|
||||
@JsonProperty("update_time")
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Shanghai")
|
||||
private Date updateTime;
|
||||
|
||||
public List<Double> getIndustryScore() {
|
||||
|
|
@ -170,11 +194,11 @@ public class NewsTags {
|
|||
this.newsId = newsId;
|
||||
}
|
||||
|
||||
public Boolean getDeleted() {
|
||||
public Integer getDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(Boolean deleted) {
|
||||
public void setDeleted(Integer deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
package com.jinrui.reference.core.model.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class UserOperationLog {
|
||||
private Long id;
|
||||
private Long dataId;
|
||||
private String type;
|
||||
private String behavior;
|
||||
private Long userId;
|
||||
private String username;
|
||||
private String userType;
|
||||
private Date createTime;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
public Long getDataId() {
|
||||
return dataId;
|
||||
}
|
||||
public void setDataId(Long dataId) {
|
||||
this.dataId = dataId;
|
||||
}
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
public String getBehavior() {
|
||||
return behavior;
|
||||
}
|
||||
public void setBehavior(String behavior) {
|
||||
this.behavior = behavior;
|
||||
}
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
public String getUserType() {
|
||||
return userType;
|
||||
}
|
||||
public void setUserType(String userType) {
|
||||
this.userType = userType;
|
||||
}
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
package com.jinrui.reference.core.model.vo.news;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
public class NewsApiVO {
|
||||
/**
|
||||
* 资讯ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 资讯标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 资讯内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 报道时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
|
||||
private Date publishTime;
|
||||
|
||||
/**
|
||||
* 资讯摘要
|
||||
*/
|
||||
private String summary;
|
||||
|
||||
/**
|
||||
* 资讯评分
|
||||
*/
|
||||
private Double newsScore;
|
||||
|
||||
/**
|
||||
* 资讯来源
|
||||
*/
|
||||
private String source;
|
||||
|
||||
/**
|
||||
* 行业分类标签
|
||||
*/
|
||||
private List<String> industryLabel;
|
||||
|
||||
/**
|
||||
* 行业分类置信度
|
||||
*/
|
||||
private List<Number> industryConfidence;
|
||||
|
||||
/**
|
||||
* 行业分类评分
|
||||
*/
|
||||
private List<Number> industryScore;
|
||||
|
||||
|
||||
/**
|
||||
* 概念标签
|
||||
* @return
|
||||
*/
|
||||
private List<String> conceptLabel;
|
||||
|
||||
/**
|
||||
* 概念标签置信度
|
||||
*/
|
||||
private List<Number> conceptConfidence;
|
||||
|
||||
/**
|
||||
* 概念标签评分
|
||||
*/
|
||||
private List<Number> conceptScore;
|
||||
|
||||
/**
|
||||
* 媒体影响力
|
||||
*/
|
||||
private Integer sourceImpact;
|
||||
|
||||
/**
|
||||
* 中国股市相关性
|
||||
*/
|
||||
private Double chinaFactor;
|
||||
|
||||
/**
|
||||
* 资讯质量
|
||||
*/
|
||||
private Integer publicOpinionScore;
|
||||
|
||||
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Date getPublishTime() {
|
||||
return publishTime;
|
||||
}
|
||||
|
||||
public void setPublishTime(Date publishTime) {
|
||||
this.publishTime = publishTime;
|
||||
}
|
||||
|
||||
public String getSummary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
public void setSummary(String summary) {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public List<String> getIndustryLabel() {
|
||||
return industryLabel;
|
||||
}
|
||||
|
||||
public void setIndustryLabel(List<String> industryLabel) {
|
||||
this.industryLabel = industryLabel;
|
||||
}
|
||||
|
||||
public List<String> getConceptLabel() {
|
||||
return conceptLabel;
|
||||
}
|
||||
|
||||
public void setConceptLabel(List<String> conceptLabel) {
|
||||
this.conceptLabel = conceptLabel;
|
||||
}
|
||||
|
||||
public Double getNewsScore() {
|
||||
return newsScore;
|
||||
}
|
||||
|
||||
public void setNewsScore(Double newsScore) {
|
||||
this.newsScore = newsScore;
|
||||
}
|
||||
|
||||
public List<Number> getIndustryConfidence() {
|
||||
return industryConfidence;
|
||||
}
|
||||
|
||||
public void setIndustryConfidence(List<Number> industryConfidence) {
|
||||
this.industryConfidence = industryConfidence;
|
||||
}
|
||||
|
||||
public List<Number> getIndustryScore() {
|
||||
return industryScore;
|
||||
}
|
||||
|
||||
public void setIndustryScore(List<Number> industryScore) {
|
||||
this.industryScore = industryScore;
|
||||
}
|
||||
|
||||
public List<Number> getConceptConfidence() {
|
||||
return conceptConfidence;
|
||||
}
|
||||
|
||||
public void setConceptConfidence(List<Number> conceptConfidence) {
|
||||
this.conceptConfidence = conceptConfidence;
|
||||
}
|
||||
|
||||
public List<Number> getConceptScore() {
|
||||
return conceptScore;
|
||||
}
|
||||
|
||||
public void setConceptScore(List<Number> conceptScore) {
|
||||
this.conceptScore = conceptScore;
|
||||
}
|
||||
|
||||
public Integer getSourceImpact() {
|
||||
return sourceImpact;
|
||||
}
|
||||
|
||||
public void setSourceImpact(Integer sourceImpact) {
|
||||
this.sourceImpact = sourceImpact;
|
||||
}
|
||||
|
||||
public Double getChinaFactor() {
|
||||
return chinaFactor;
|
||||
}
|
||||
|
||||
public void setChinaFactor(Double chinaFactor) {
|
||||
this.chinaFactor = chinaFactor;
|
||||
}
|
||||
|
||||
public Integer getPublicOpinionScore() {
|
||||
return publicOpinionScore;
|
||||
}
|
||||
|
||||
public void setPublicOpinionScore(Integer publicOpinionScore) {
|
||||
this.publicOpinionScore = publicOpinionScore;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,9 +9,13 @@ import com.jinrui.reference.core.model.entity.NewsDraft;
|
|||
@SuppressWarnings("unused")
|
||||
public class NewsDetailVO {
|
||||
|
||||
public static final String AI_TITLE_FLAG = "title";
|
||||
public static final String AI_CONENT_FLAG = "content";
|
||||
public static final String AI_TITLE_CONTENT_FLAG = "title&content";
|
||||
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
private String title; // 标题
|
||||
|
||||
private String summary;
|
||||
|
||||
|
|
@ -23,10 +27,22 @@ public class NewsDetailVO {
|
|||
|
||||
private List<NewsDetailIndustry> industry;
|
||||
|
||||
private String content;
|
||||
private String content; // 正文
|
||||
|
||||
private Date publishTime;
|
||||
|
||||
private Boolean titleTranslated; // 大模型翻译标识
|
||||
|
||||
private Boolean contentTranslated; // 大模型翻译标识
|
||||
|
||||
private Boolean deleted; // 删除标识
|
||||
|
||||
private String newsInfoId; // 获取原文和参考译文的字段
|
||||
|
||||
private Byte rating; // 打分
|
||||
|
||||
private String revision; // 修订说明
|
||||
|
||||
public NewsDetailVO() {
|
||||
}
|
||||
|
||||
|
|
@ -37,6 +53,10 @@ public class NewsDetailVO {
|
|||
this.picture = news.getPicture();
|
||||
this.content = news.getContent();
|
||||
this.publishTime = news.getPublishTime();
|
||||
this.deleted = news.getDeleted();
|
||||
this.newsInfoId = news.getNewsinfoId();
|
||||
this.rating = news.getRating();
|
||||
this.revision = news.getRevision();
|
||||
}
|
||||
|
||||
public NewsDetailVO(NewsDraft newsDraft) {
|
||||
|
|
@ -118,4 +138,67 @@ public class NewsDetailVO {
|
|||
this.publishTime = publishTime;
|
||||
}
|
||||
|
||||
public Boolean getTitleTranslated() {
|
||||
return titleTranslated;
|
||||
}
|
||||
|
||||
public void setTitleTranslated(Boolean titleTranslated) {
|
||||
this.titleTranslated = titleTranslated;
|
||||
}
|
||||
|
||||
public Boolean getContentTranslated() {
|
||||
return contentTranslated;
|
||||
}
|
||||
|
||||
public void setContentTranslated(Boolean contentTranslated) {
|
||||
this.contentTranslated = contentTranslated;
|
||||
}
|
||||
|
||||
public Boolean getDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(Boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public String getNewsInfoId() {
|
||||
return newsInfoId;
|
||||
}
|
||||
|
||||
public void setNewsInfoId(String newsInfoId) {
|
||||
this.newsInfoId = newsInfoId;
|
||||
}
|
||||
|
||||
public void markTranslatedFlag(String aiFlag) {
|
||||
if (AI_TITLE_FLAG.equals(aiFlag)) {
|
||||
this.setTitleTranslated(true);
|
||||
this.setContentTranslated(false);
|
||||
} else if (AI_CONENT_FLAG.equals(aiFlag)) {
|
||||
this.setTitleTranslated(false);
|
||||
this.setContentTranslated(true);
|
||||
} else if (AI_TITLE_CONTENT_FLAG.equals(aiFlag)) {
|
||||
this.setTitleTranslated(true);
|
||||
this.setContentTranslated(true);
|
||||
} else {
|
||||
this.setTitleTranslated(false);
|
||||
this.setContentTranslated(false);
|
||||
}
|
||||
}
|
||||
|
||||
public Byte getRating() {
|
||||
return rating;
|
||||
}
|
||||
|
||||
public void setRating(Byte rating) {
|
||||
this.rating = rating;
|
||||
}
|
||||
|
||||
public String getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
public void setRevision(String revision) {
|
||||
this.revision = revision;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
package com.jinrui.reference.core.model.vo.news;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.jinrui.reference.core.model.entity.UserOperationLog;
|
||||
|
||||
public class NewsLogVO {
|
||||
private String username;
|
||||
private String userType;
|
||||
private String behavior;
|
||||
private Date createTime;
|
||||
|
||||
public NewsLogVO(UserOperationLog userOperationLog) {
|
||||
this.username = userOperationLog.getUsername();
|
||||
this.userType = userOperationLog.getUserType();
|
||||
this.behavior = userOperationLog.getBehavior();
|
||||
this.createTime = userOperationLog.getCreateTime();
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
public String getUserType() {
|
||||
return userType;
|
||||
}
|
||||
public void setUserType(String userType) {
|
||||
this.userType = userType;
|
||||
}
|
||||
public String getBehavior() {
|
||||
return behavior;
|
||||
}
|
||||
public void setBehavior(String behavior) {
|
||||
this.behavior = behavior;
|
||||
}
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.jinrui.reference.core.model.vo.news;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.jinrui.reference.core.model.entity.News;
|
||||
import com.jinrui.reference.core.model.entity.NewsDraft;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class NewsTranslatorVO {
|
||||
private String titleEN; // 原文标题
|
||||
|
||||
private String contentEN; // 原文正文
|
||||
|
||||
private String titleCN; // 参考翻译标题
|
||||
|
||||
private String contentCN; // 参考翻译正文
|
||||
|
||||
public String getTitleEN() {
|
||||
return titleEN;
|
||||
}
|
||||
|
||||
public void setTitleEN(String titleEN) {
|
||||
this.titleEN = titleEN;
|
||||
}
|
||||
|
||||
public String getContentEN() {
|
||||
return contentEN;
|
||||
}
|
||||
|
||||
public void setContentEN(String contentEN) {
|
||||
this.contentEN = contentEN;
|
||||
}
|
||||
|
||||
public String getTitleCN() {
|
||||
return titleCN;
|
||||
}
|
||||
|
||||
public void setTitleCN(String titleCN) {
|
||||
this.titleCN = titleCN;
|
||||
}
|
||||
|
||||
public String getContentCN() {
|
||||
return contentCN;
|
||||
}
|
||||
|
||||
public void setContentCN(String contentCN) {
|
||||
this.contentCN = contentCN;
|
||||
}
|
||||
}
|
||||
|
|
@ -54,6 +54,18 @@ public class NewsVO {
|
|||
|
||||
private Double score;
|
||||
|
||||
public Boolean getDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(Boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
private Boolean deleted; // 删除标识
|
||||
|
||||
private Byte rating; // 打分
|
||||
|
||||
public NewsVO(News news) {
|
||||
this.id = news.getId();
|
||||
this.title = news.getTitle();
|
||||
|
|
@ -62,6 +74,8 @@ public class NewsVO {
|
|||
this.publishTime = news.getPublishTime();
|
||||
this.updateTime = news.getUpdateTime();
|
||||
this.score = news.getScore();
|
||||
this.deleted = news.getDeleted();
|
||||
this.rating = news.getRating();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
|
|
@ -123,4 +137,12 @@ public class NewsVO {
|
|||
public void setScore(Double score) {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
public Byte getRating() {
|
||||
return rating;
|
||||
}
|
||||
|
||||
public void setRating(Byte rating) {
|
||||
this.rating = rating;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,11 @@ public class NewsInfoVO {
|
|||
*/
|
||||
private Long editorId;
|
||||
|
||||
/**
|
||||
* 资讯评分
|
||||
*/
|
||||
private Double score;
|
||||
|
||||
public NewsInfoVO(NewsInfo newsInfo) {
|
||||
this.id = newsInfo.getId();
|
||||
this.title = newsInfo.getTitle();
|
||||
|
|
@ -86,6 +91,9 @@ public class NewsInfoVO {
|
|||
this.createTime = newsInfo.getCreateTime();
|
||||
this.updateTime = newsInfo.getUpdateTime();
|
||||
this.inputDate = newsInfo.getInputDate();
|
||||
if (newsInfo.getNewsTags() != null) {
|
||||
this.score = newsInfo.getNewsTags().getNewsScore();
|
||||
}
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
|
@ -191,4 +199,12 @@ public class NewsInfoVO {
|
|||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Double getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
public void setScore(Double score) {
|
||||
this.score = score;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,12 +140,20 @@ public class SaveNewsInfoDTO {
|
|||
News news = new News();
|
||||
news.setTitle(this.getTitle());
|
||||
news.setSummary(this.getSummary());
|
||||
news.setLlmTitle(this.getTitle());
|
||||
news.setLlmContent(this.getContent());
|
||||
news.setStatus(this.getStatus());
|
||||
news.setContent(this.getContent());
|
||||
news.setCreateTime(new Date());
|
||||
news.setUpdateTime(news.getCreateTime());
|
||||
news.setType(1);
|
||||
news.setNewsinfoId(this.getId());
|
||||
// 报道时间
|
||||
if (this.getPublishTime() != null) {
|
||||
news.setPublishTime(this.getPublishTime());
|
||||
} else {
|
||||
news.setPublishTime(news.getCreateTime());
|
||||
}
|
||||
return news;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
package com.jinrui.reference.core.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.jinrui.reference.core.api.ApiKeyGenerator;
|
||||
import com.jinrui.reference.core.mapper.ApiUserMapper;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
|
||||
@Service
|
||||
public class ApiKeyService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ApiKeyService.class);
|
||||
|
||||
private final ApiUserMapper apiUserMapper;
|
||||
|
||||
public ApiKeyService(ApiUserMapper apiUserMapper) {
|
||||
this.apiUserMapper = apiUserMapper;
|
||||
}
|
||||
|
||||
public String getSecretKeyByAk(String ak) {
|
||||
String secretKey = apiUserMapper.getClientSecretkey(ak);
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public ResultObject<Map<String, Object>> generateApiKey(String clientName) {
|
||||
Map<String, Object> clientKeyMap = apiUserMapper.getClientKey(clientName);
|
||||
if (ObjectUtils.isEmpty(clientKeyMap)) {
|
||||
String accessKey = ApiKeyGenerator.generateAK();
|
||||
String secretKey = ApiKeyGenerator.generateSK();
|
||||
try {
|
||||
apiUserMapper.save(clientName, accessKey, secretKey);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("产生客户API密钥对失败", e);
|
||||
ResultObject.failed("客户已存在!");
|
||||
}
|
||||
clientKeyMap = new HashMap<>();
|
||||
clientKeyMap.put("access_key", accessKey);
|
||||
clientKeyMap.put("secret_key", secretKey);
|
||||
}
|
||||
|
||||
return ResultObject.success(clientKeyMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
package com.jinrui.reference.core.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -13,7 +17,6 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jinrui.reference.core.mapper.IndustryMapper;
|
||||
|
|
@ -33,6 +36,7 @@ import com.jinrui.reference.core.model.vo.ResultObject;
|
|||
import com.jinrui.reference.core.model.vo.news.NewsDetailIndustry;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsDetailTag;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsDetailTagItem;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsScoreVO;
|
||||
import com.jinrui.reference.core.model.vo.newsinfo.NewsInfoDetailVO;
|
||||
import com.jinrui.reference.core.model.vo.newsinfo.NewsInfoVO;
|
||||
import com.jinrui.reference.core.model.vo.newsinfo.SaveNewsInfoDTO;
|
||||
|
|
@ -40,12 +44,14 @@ import com.jinrui.reference.core.model.vo.newsinfo.SaveNewsInfoDTO;
|
|||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
|
||||
import co.elastic.clients.elasticsearch._types.Refresh;
|
||||
import co.elastic.clients.elasticsearch._types.SortOptions;
|
||||
import co.elastic.clients.elasticsearch._types.SortOrder;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.MultiMatchQuery;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.Operator;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.TermQuery;
|
||||
import co.elastic.clients.elasticsearch.core.GetResponse;
|
||||
import co.elastic.clients.elasticsearch.core.IndexResponse;
|
||||
|
|
@ -53,8 +59,7 @@ import co.elastic.clients.elasticsearch.core.SearchRequest;
|
|||
import co.elastic.clients.elasticsearch.core.SearchResponse;
|
||||
import co.elastic.clients.elasticsearch.core.search.Hit;
|
||||
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
|
||||
import co.elastic.clients.json.JsonpUtils;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.json.JsonData;
|
||||
|
||||
@Service
|
||||
public class NewsInfoService {
|
||||
|
|
@ -104,6 +109,14 @@ public class NewsInfoService {
|
|||
News relNews = newsInfo.toNews();
|
||||
relNews.setStatus(1);
|
||||
relNews.setEditorId(editorId);
|
||||
|
||||
NewsTags newsTags = newsTagsMapper.getNewsTagsByNewsId(id);
|
||||
if (newsTags != null) {
|
||||
String llmTitle = Optional.ofNullable(newsTags.getTitle()).filter(s -> !s.isEmpty()).orElse(relNews.getTitle());
|
||||
relNews.setLlmTitle(llmTitle);
|
||||
String llmContent = Optional.ofNullable(newsTags.getRewriteContent()).filter(s -> !s.isEmpty()).orElse(relNews.getContent());
|
||||
relNews.setLlmContent(llmContent);
|
||||
}
|
||||
newsMapper.saveNews(relNews);
|
||||
saveNewsRel(id, relNews.getId());
|
||||
}
|
||||
|
|
@ -336,6 +349,7 @@ public class NewsInfoService {
|
|||
News relateNews = newsMapper.getNewsDetailByNewsInfoId(id);
|
||||
|
||||
if (relateNews == null) {
|
||||
saveNewsInfoDTO.setPublishTime(newsInfo.getInputDate()); // 报道时间
|
||||
relateNews = createRelateNews(saveNewsInfoDTO);
|
||||
NewsInfo updatedNewsInfo = toNewsInfo(relateNews.getId(), saveNewsInfoDTO);
|
||||
elasticsearchClient.update(e -> e.index(NewsInfo.INDEX_NAME).id(updatedNewsInfo.getId()).doc(updatedNewsInfo).refresh(Refresh.True), NewsInfo.class);
|
||||
|
|
@ -351,7 +365,7 @@ public class NewsInfoService {
|
|||
return ResultObject.success();
|
||||
}
|
||||
|
||||
public ResultObject<Void> deleteNewsInfo(String newsInfoId) {
|
||||
public ResultObject<Void> deleteNewsInfo(String newsInfoId, Long editorId) {
|
||||
try {
|
||||
GetResponse<NewsInfo> getResp = elasticsearchClient.get(e -> e.index(NewsInfo.INDEX_NAME).id(String.valueOf(newsInfoId)), NewsInfo.class);
|
||||
if (getResp.found()) {
|
||||
|
|
@ -359,7 +373,7 @@ public class NewsInfoService {
|
|||
Long newsId = newsInfo.getNewsId();
|
||||
// 删除资讯精选中关联的数据
|
||||
deleteNewsRel(newsId);
|
||||
newsMapper.deleteNews(newsId);
|
||||
newsMapper.deleteNews(newsId, editorId);
|
||||
|
||||
NewsInfo deletedNewsInfo = new NewsInfo();
|
||||
deletedNewsInfo.setDeleted(1);
|
||||
|
|
@ -385,7 +399,7 @@ public class NewsInfoService {
|
|||
try {
|
||||
IndexResponse resp = elasticsearchClient.index(c -> c.index(NewsInfo.INDEX_NAME).document(newsInfo).refresh(Refresh.True));
|
||||
news.setNewsinfoId(resp.id());
|
||||
newsMapper.updateNews(news);
|
||||
newsMapper.updateNews(news, news.getStatus());
|
||||
} catch(IOException|ElasticsearchException e) {
|
||||
log.error("新建全量资讯出错!", e);
|
||||
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
|
||||
|
|
@ -419,7 +433,7 @@ public class NewsInfoService {
|
|||
private void updateRelateNews(Long newsId, SaveNewsInfoDTO saveNewsDTO) {
|
||||
News news = saveNewsDTO.toNews();
|
||||
news.setId(newsId);
|
||||
newsMapper.updateNews(news);
|
||||
newsMapper.updateNews(news, news.getStatus());
|
||||
|
||||
tagMapper.deleteNews(newsId);
|
||||
industryMapper.deleteNews(newsId);
|
||||
|
|
@ -489,30 +503,10 @@ public class NewsInfoService {
|
|||
}
|
||||
|
||||
public PageObject<NewsInfoVO> queryNewsInfo(String title, String content, String stockcode, Long sourcename, int page, int size,
|
||||
String last, Integer current, String orderBy, String direction) {
|
||||
String last, Integer current, String orderBy, String direction, Double minScore, Double maxScore,
|
||||
Date inputDateFrom, Date inputDateTo) {
|
||||
|
||||
if (StringUtils.hasText(orderBy)) {
|
||||
switch (orderBy) {
|
||||
case "publishTime": {
|
||||
orderBy = "publish_time";
|
||||
break;
|
||||
}
|
||||
case "updateTime": {
|
||||
orderBy = "update_time";
|
||||
break;
|
||||
}
|
||||
case "createTime": {
|
||||
orderBy = "create_time";
|
||||
break;
|
||||
}
|
||||
case "inputDate": {
|
||||
orderBy = "input_date";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String orderByField = orderBy;
|
||||
final String orderByField = mappingToEsFieldName(orderBy);
|
||||
int offset = 0;
|
||||
if (current != null) {
|
||||
offset = (Math.max(0, current - 1)) * size;
|
||||
|
|
@ -542,18 +536,34 @@ public class NewsInfoService {
|
|||
filters.add(sourcenameQuery);
|
||||
}
|
||||
}
|
||||
|
||||
if (conditions.size() == 0) {
|
||||
conditions.add(QueryBuilders.matchAll().build()._toQuery());
|
||||
// 评分范围查询
|
||||
Query scoreRangeQuery = buildRangeQuery(NewsInfo.SCORE_ES_NAME, minScore, maxScore);
|
||||
if (scoreRangeQuery != null) {
|
||||
filters.add(scoreRangeQuery);
|
||||
}
|
||||
// 报道时间范围查询
|
||||
Query inputDateRangeQuery = buildRangeQuery(NewsInfo.INPUT_DATE_ES_NAME, inputDateFrom, inputDateTo);
|
||||
if (inputDateRangeQuery != null) {
|
||||
filters.add(inputDateRangeQuery);
|
||||
}
|
||||
|
||||
List<SortOptions> sortOptions = new ArrayList<>();
|
||||
if (conditions.size() > 0) {
|
||||
sortOptions.add(SortOptions.of(e -> e.score(x -> x.order(SortOrder.Desc))));
|
||||
}
|
||||
|
||||
// if (conditions.size() == 0) {
|
||||
// conditions.add(QueryBuilders.matchAll().build()._toQuery());
|
||||
// }
|
||||
Query resultQuery = new Query.Builder().bool(b -> b.must(conditions).filter(filters)).build();
|
||||
SortOrder sortOrder = (Objects.equals(direction, SortOrder.Asc.jsonValue()) ?SortOrder.Asc:SortOrder.Desc);
|
||||
sortOptions.add(SortOptions.of(e -> e.field(f -> f.field(orderByField).order(sortOrder))));
|
||||
|
||||
SearchRequest request = SearchRequest.of(s ->
|
||||
s.from(from)
|
||||
s.index(NewsInfo.INDEX_NAME).from(from)
|
||||
.size(size) // 分页参数
|
||||
.trackTotalHits(e -> e.enabled(true))
|
||||
.sort(so -> so.field(f -> f.field(orderByField).order(sortOrder))) // 排序字段
|
||||
.sort(sortOptions) // 排序字段
|
||||
.query(resultQuery).trackScores(true)
|
||||
.highlight(h -> h.preTags("<font color='red'>")
|
||||
.postTags("</font>")
|
||||
|
|
@ -592,4 +602,73 @@ public class NewsInfoService {
|
|||
pageObject.setData(newsInfoList);
|
||||
return pageObject;
|
||||
}
|
||||
|
||||
private Query buildRangeQuery(String fieldName, Object fromValue, Object toValue) {
|
||||
if (fromValue == null && toValue == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
RangeQuery.Builder rangeBuilder = QueryBuilders.range().field(fieldName);
|
||||
if (fromValue != null) {
|
||||
if (fromValue instanceof Date) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
rangeBuilder = rangeBuilder.gte(JsonData.of(sdf.format(fromValue)));
|
||||
} else {
|
||||
rangeBuilder = rangeBuilder.gte(JsonData.of(fromValue));
|
||||
}
|
||||
|
||||
}
|
||||
if (toValue != null) {
|
||||
if (toValue instanceof Date) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime((Date)toValue);
|
||||
calendar.add(Calendar.DATE, 1);
|
||||
Date expireDate = calendar.getTime();
|
||||
rangeBuilder = rangeBuilder.lt(JsonData.of(sdf.format(expireDate)));
|
||||
} else {
|
||||
rangeBuilder = rangeBuilder.lte(JsonData.of(toValue));
|
||||
}
|
||||
|
||||
}
|
||||
return rangeBuilder.build()._toQuery();
|
||||
}
|
||||
|
||||
private String mappingToEsFieldName(String orderBy) {
|
||||
String esFieldName = "";
|
||||
switch (orderBy) {
|
||||
case "publishTime": {
|
||||
esFieldName = "publish_time";
|
||||
break;
|
||||
}
|
||||
case "updateTime": {
|
||||
esFieldName = "update_time";
|
||||
break;
|
||||
}
|
||||
case "createTime": {
|
||||
esFieldName = "create_time";
|
||||
break;
|
||||
}
|
||||
case "inputDate": {
|
||||
esFieldName = "input_date";
|
||||
break;
|
||||
}
|
||||
case "score": {
|
||||
esFieldName = "news_tags.news_score";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
esFieldName = "input_date";
|
||||
}
|
||||
return esFieldName;
|
||||
}
|
||||
|
||||
public ResultObject<NewsScoreVO> getScore(String id) {
|
||||
NewsTags newsTags = newsTagsMapper.getNewsTagsByNewsId(id);
|
||||
if (newsTags == null) {
|
||||
return ResultObject.success();
|
||||
}
|
||||
NewsScoreVO newsScoreVO = new NewsScoreVO(newsTags);
|
||||
return ResultObject.success(newsScoreVO);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -22,15 +23,18 @@ import org.springframework.util.CollectionUtils;
|
|||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.aliyun.oss.common.utils.DateUtil;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.jinrui.reference.core.mapper.ColumnMapper;
|
||||
import com.jinrui.reference.core.mapper.IndustryMapper;
|
||||
import com.jinrui.reference.core.mapper.NewsDeletedMapper;
|
||||
import com.jinrui.reference.core.mapper.NewsMapper;
|
||||
import com.jinrui.reference.core.mapper.NewsTagsMapper;
|
||||
import com.jinrui.reference.core.mapper.TagMapper;
|
||||
import com.jinrui.reference.core.mapper.UserOperationLogMapper;
|
||||
import com.jinrui.reference.core.model.dto.news.SaveDraftColumn;
|
||||
import com.jinrui.reference.core.model.dto.news.SaveDraftColumnItem;
|
||||
import com.jinrui.reference.core.model.dto.news.SaveDraftColumnVip;
|
||||
|
|
@ -43,26 +47,32 @@ import com.jinrui.reference.core.model.entity.DraftTagRel;
|
|||
import com.jinrui.reference.core.model.entity.Industry;
|
||||
import com.jinrui.reference.core.model.entity.News;
|
||||
import com.jinrui.reference.core.model.entity.NewsColumnRel;
|
||||
import com.jinrui.reference.core.model.entity.NewsDeleted;
|
||||
import com.jinrui.reference.core.model.entity.NewsDraft;
|
||||
import com.jinrui.reference.core.model.entity.NewsIndustryRel;
|
||||
import com.jinrui.reference.core.model.entity.NewsInfo;
|
||||
import com.jinrui.reference.core.model.entity.NewsTagRel;
|
||||
import com.jinrui.reference.core.model.entity.NewsTags;
|
||||
import com.jinrui.reference.core.model.entity.Tag;
|
||||
import com.jinrui.reference.core.model.entity.UserOperationLog;
|
||||
import com.jinrui.reference.core.model.vo.PageObject;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
import com.jinrui.reference.core.model.vo.column.ColumnVO;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsApiVO;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsDetailColumn;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsDetailColumnVip;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsDetailIndustry;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsDetailTag;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsDetailTagItem;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsDetailVO;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsLogVO;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsScoreVO;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsTranslatorVO;
|
||||
import com.jinrui.reference.core.model.vo.news.NewsVO;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.elasticsearch._types.Refresh;
|
||||
import co.elastic.clients.elasticsearch.core.GetResponse;
|
||||
|
||||
@Service
|
||||
public class NewsService {
|
||||
|
|
@ -76,6 +86,8 @@ public class NewsService {
|
|||
private final IndustryMapper industryMapper;
|
||||
private final ElasticsearchClient elasticsearchClient;
|
||||
private final NewsTagsMapper newsTagsMapper;
|
||||
private final NewsDeletedMapper newsDeletedMapper;
|
||||
private final UserOperationLogMapper userOperationLogMapper;
|
||||
|
||||
public NewsService(NewsMapper newsMapper,
|
||||
ColumnMapper columnMapper,
|
||||
|
|
@ -83,7 +95,9 @@ public class NewsService {
|
|||
TagMapper tagMapper,
|
||||
IndustryMapper industryMapper,
|
||||
ElasticsearchClient elasticsearchClient,
|
||||
NewsTagsMapper newsTagsMapper) {
|
||||
NewsTagsMapper newsTagsMapper,
|
||||
NewsDeletedMapper newsDeletedMapper,
|
||||
UserOperationLogMapper userOperationLogMapper) {
|
||||
this.newsMapper = newsMapper;
|
||||
this.columnMapper = columnMapper;
|
||||
this.objectMapper = objectMapper;
|
||||
|
|
@ -91,6 +105,8 @@ public class NewsService {
|
|||
this.industryMapper = industryMapper;
|
||||
this.elasticsearchClient = elasticsearchClient;
|
||||
this.newsTagsMapper = newsTagsMapper;
|
||||
this.newsDeletedMapper = newsDeletedMapper;
|
||||
this.userOperationLogMapper = userOperationLogMapper;
|
||||
}
|
||||
|
||||
public ResultObject<Void> publish(long id, long editorId) {
|
||||
|
|
@ -99,18 +115,20 @@ public class NewsService {
|
|||
log.warn("找不到ID为{}的新闻!", id);
|
||||
return ResultObject.failed("找不到ID为" + id + "的新闻!");
|
||||
}
|
||||
Integer status = news.getStatus();
|
||||
if (status == 2) {
|
||||
newsMapper.simpleUnpublish(id);
|
||||
Integer oldStatus = news.getStatus();
|
||||
if (oldStatus == 1) {
|
||||
return ResultObject.failed("资讯已被撤稿,请刷新列表页面!");
|
||||
}
|
||||
if (oldStatus == 2) {
|
||||
newsMapper.changeFrom(id, oldStatus, 3, editorId);
|
||||
return ResultObject.success();
|
||||
}
|
||||
|
||||
Long draftId = news.getDraftId();
|
||||
if (draftId == null) {
|
||||
newsMapper.simplePublish(id, editorId);
|
||||
newsMapper.changeFrom(id, oldStatus, 2, editorId);
|
||||
return ResultObject.success();
|
||||
}
|
||||
|
||||
ResultObject<NewsDetailVO> resultObject = detail(id);
|
||||
int code = resultObject.getCode();
|
||||
NewsDetailVO newsDetailVO = resultObject.getData();
|
||||
|
|
@ -118,7 +136,7 @@ public class NewsService {
|
|||
return ResultObject.failed(resultObject.getCode(), resultObject.getMsg());
|
||||
}
|
||||
SaveNewsDTO saveNewsDTO = new SaveNewsDTO(newsDetailVO);
|
||||
return createPublish(editorId, saveNewsDTO);
|
||||
return createPublish(editorId, saveNewsDTO, true);
|
||||
}
|
||||
|
||||
public ResultObject<NewsDetailVO> detail(Long id) {
|
||||
|
|
@ -139,6 +157,10 @@ public class NewsService {
|
|||
NewsDraft newsDraft = newsMapper.getDraftDetail(draftId);
|
||||
NewsDetailVO newsDetailVO = new NewsDetailVO(newsDraft);
|
||||
newsDetailVO.setId(id);
|
||||
newsDetailVO.setDeleted(news.getDeleted());
|
||||
newsDetailVO.setNewsInfoId(news.getNewsinfoId());
|
||||
newsDetailVO.setRating(news.getRating());
|
||||
newsDetailVO.setRevision(news.getRevision());
|
||||
|
||||
Set<Long> set = new HashSet<>();
|
||||
set.add(draftId);
|
||||
|
|
@ -221,33 +243,13 @@ public class NewsService {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// List<NewsTagRel> tagRelListNews = tagMapper.getNewsTagRelList(id);
|
||||
// NewsDetailTag newsDetailTag2 = new NewsDetailTag();
|
||||
// newsDetailVO.setTag(newsDetailTag2);
|
||||
// List<NewsDetailTagItem> arr = new ArrayList<>();
|
||||
// if (!CollectionUtils.isEmpty(tagRelListNews)) {
|
||||
// for (NewsTagRel rel : tagRelListNews) {
|
||||
// Long tagId = rel.getTagId();
|
||||
// Tag tag = tagMap.get(tagId);
|
||||
// Long parentId = tag.getParentId();
|
||||
// NewsDetailTagItem tagItem = new NewsDetailTagItem();
|
||||
// tagItem.setId(tagId);
|
||||
// tagItem.setName(tag.getName());
|
||||
// if (parentId != null && parentId == 1) {
|
||||
// newsDetailTag2.setSource(tagItem);
|
||||
// } else {
|
||||
//// newsDetailTag2.setField(tagItem);
|
||||
// arr.add(tagItem);
|
||||
// }
|
||||
// }
|
||||
// newsDetailTag2.setFieldArr(arr);
|
||||
// }
|
||||
processLLMFlag(newsDetailVO);
|
||||
return ResultObject.success(newsDetailVO);
|
||||
}
|
||||
|
||||
news = newsMapper.getNewsDetail(id);
|
||||
NewsDetailVO newsDetailVO = new NewsDetailVO(news);
|
||||
processLLMFlag(newsDetailVO);
|
||||
|
||||
Set<Long> set = new HashSet<>();
|
||||
set.add(id);
|
||||
|
|
@ -339,14 +341,48 @@ public class NewsService {
|
|||
return ResultObject.success(newsDetailVO);
|
||||
}
|
||||
|
||||
public ResultObject<Void> createPublish(Long editorId, SaveNewsDTO saveNewsDTO) {
|
||||
private void processLLMFlag(NewsDetailVO newsDetailVO) {
|
||||
String newsInfoId = newsDetailVO.getNewsInfoId();
|
||||
String llmFlag = null;
|
||||
if (ObjectUtils.isEmpty(newsInfoId)) {
|
||||
newsDetailVO.markTranslatedFlag(llmFlag);
|
||||
return;
|
||||
}
|
||||
|
||||
NewsTags newsTags = newsTagsMapper.getNewsTagsByNewsId(newsInfoId);
|
||||
if (newsTags == null) {
|
||||
newsDetailVO.markTranslatedFlag(llmFlag);
|
||||
return;
|
||||
}
|
||||
llmFlag = checkNewsLLMFlag(newsTags);
|
||||
newsDetailVO.markTranslatedFlag(llmFlag);
|
||||
}
|
||||
|
||||
private String checkNewsLLMFlag(NewsTags newsTags) {
|
||||
String llmFlag = null;
|
||||
if (!ObjectUtils.isEmpty(newsTags.getTitle()) && !ObjectUtils.isEmpty(newsTags.getRewriteContent())) {
|
||||
llmFlag = NewsDetailVO.AI_TITLE_CONTENT_FLAG;
|
||||
} else if (!ObjectUtils.isEmpty(newsTags.getTitle())) {
|
||||
llmFlag = NewsDetailVO.AI_TITLE_FLAG;
|
||||
} else if (!ObjectUtils.isEmpty(newsTags.getRewriteContent())) {
|
||||
llmFlag = NewsDetailVO.AI_CONENT_FLAG;
|
||||
}
|
||||
return llmFlag;
|
||||
}
|
||||
|
||||
public ResultObject<Void> createPublish(Long editorId, SaveNewsDTO saveNewsDTO, boolean isReviewer) {
|
||||
Long id = saveNewsDTO.getId();
|
||||
Long newsId = saveNewsDTO.getId();
|
||||
Integer newStatus = (isReviewer ? 2: 3);
|
||||
Integer oldStatus = (isReviewer ? 3: 1);
|
||||
News news;
|
||||
Long draftId = null;
|
||||
String newsInfoId = null;
|
||||
if (id != null) {
|
||||
news = newsMapper.getById(id);
|
||||
Long draftId = news.getDraftId();
|
||||
if (draftId != null) {
|
||||
draftId = news.getDraftId();
|
||||
newsInfoId = news.getNewsinfoId();
|
||||
if (draftId != null && newStatus.intValue() == 2) {
|
||||
deleteDraft(draftId);
|
||||
}
|
||||
}
|
||||
|
|
@ -356,14 +392,20 @@ public class NewsService {
|
|||
// 已发布
|
||||
saveNewsDTO.setStatus(2);
|
||||
saveNewsDTO.setPublishTime(new Date());
|
||||
saveNewDraft(saveNewsDTO, null);
|
||||
saveNewDraft(saveNewsDTO, null, isReviewer);
|
||||
}
|
||||
|
||||
Long newIdRl = saveNewsDTO.getId();
|
||||
news = new News(saveNewsDTO);
|
||||
news.setStatus(2);
|
||||
news.setStatus(newStatus);
|
||||
news.setEditorId(editorId);
|
||||
newsMapper.publishNews(news);
|
||||
news.setNewsinfoId(newsInfoId);
|
||||
news.setDraftId(isReviewer ? null: draftId);
|
||||
|
||||
int count = newsMapper.updateNews(news, oldStatus);
|
||||
if (count == 0) {
|
||||
return ResultObject.failed("该资讯正在审核中,请勿重复操作");
|
||||
}
|
||||
// zzp
|
||||
deleteNewsRel(newsId);
|
||||
try {
|
||||
|
|
@ -477,57 +519,37 @@ public class NewsService {
|
|||
elasticsearchClient.update(e -> e.index(NewsInfo.INDEX_NAME).refresh(Refresh.True).id(newsInfoId).doc(newsInfo), NewsInfo.class);
|
||||
}
|
||||
|
||||
public ResultObject<Void> saveDraft(SaveNewsDTO saveNewsDTO) {
|
||||
public ResultObject<Void> saveDraft(SaveNewsDTO saveNewsDTO, boolean isReviewer) {
|
||||
Long id = saveNewsDTO.getId();
|
||||
|
||||
if (id == null) {
|
||||
return saveNewDraft(saveNewsDTO, null);
|
||||
saveNewsDTO.setStatus(1);
|
||||
return saveNewDraft(saveNewsDTO, null, isReviewer);
|
||||
}
|
||||
return updateDraft(saveNewsDTO);
|
||||
return updateDraft(saveNewsDTO, isReviewer);
|
||||
}
|
||||
|
||||
private ResultObject<Void> updateDraft(SaveNewsDTO saveNewsDTO) {
|
||||
private ResultObject<Void> updateDraft(SaveNewsDTO saveNewsDTO, boolean isReviewer) {
|
||||
Long id = saveNewsDTO.getId();
|
||||
News news = newsMapper.getById(id);
|
||||
Long draftId = news.getDraftId();
|
||||
if (draftId != null) {
|
||||
deleteDraft(draftId);
|
||||
}
|
||||
return saveNewDraft(saveNewsDTO, news);
|
||||
return saveNewDraft(saveNewsDTO, news, isReviewer);
|
||||
}
|
||||
|
||||
public ResultObject<Void> deleteNews(Long newsId) {
|
||||
public ResultObject<Void> deleteNews(Long newsId, Long editorId) {
|
||||
News news = newsMapper.getById(newsId);
|
||||
Integer status = news.getStatus();
|
||||
if (status == 2) {
|
||||
return ResultObject.failed("请先手动下架新闻然后进行删除!");
|
||||
}
|
||||
|
||||
Long draftId = news.getDraftId();
|
||||
if (draftId != null) {
|
||||
try {
|
||||
deleteDraft(draftId);
|
||||
} catch (Exception e) {
|
||||
log.error("删除新闻草稿异常!", e);
|
||||
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
|
||||
}
|
||||
}
|
||||
try {
|
||||
deleteNewsRel(newsId);
|
||||
} catch (Exception e) {
|
||||
log.error("删除新闻栏目标签异常!", e);
|
||||
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
|
||||
}
|
||||
try {
|
||||
newsMapper.deleteNews(newsId);
|
||||
String newsInfoId = news.getNewsinfoId();
|
||||
if (!ObjectUtils.isEmpty(newsInfoId)) {
|
||||
NewsInfo deletedNewsInfo = new NewsInfo();
|
||||
deletedNewsInfo.setDeleted(1);
|
||||
elasticsearchClient.update(e -> e.index(NewsInfo.INDEX_NAME)
|
||||
.refresh(Refresh.True)
|
||||
.id(newsInfoId)
|
||||
.doc(deletedNewsInfo), NewsInfo.class);
|
||||
int count = newsMapper.deleteNews(newsId, editorId);
|
||||
if (count == 0) {
|
||||
return ResultObject.failed("该资讯正在审核中,请勿重复操作");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("删除新闻异常!", e);
|
||||
|
|
@ -549,7 +571,7 @@ public class NewsService {
|
|||
industryMapper.deleteDraft(draftId);
|
||||
}
|
||||
|
||||
private ResultObject<Void> saveNewDraft(SaveNewsDTO saveNewsDTO, News news) {
|
||||
private ResultObject<Void> saveNewDraft(SaveNewsDTO saveNewsDTO, News news, boolean isReviewer) {
|
||||
NewsDraft newsDraft = new NewsDraft(saveNewsDTO);
|
||||
try {
|
||||
newsMapper.saveDraft(newsDraft);
|
||||
|
|
@ -558,6 +580,7 @@ public class NewsService {
|
|||
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
Integer oldStatus = (isReviewer ? 3: 1);
|
||||
Long draftId = newsDraft.getId();
|
||||
if (news == null) {
|
||||
news = new News(saveNewsDTO);
|
||||
|
|
@ -570,30 +593,20 @@ public class NewsService {
|
|||
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
|
||||
}
|
||||
} else {
|
||||
Integer status = news.getStatus();
|
||||
String newsInfoId = news.getNewsinfoId();
|
||||
if (status < 2) {
|
||||
news = new News(saveNewsDTO);
|
||||
news.setStatus(status);
|
||||
news.setStatus(oldStatus);
|
||||
news.setDraftId(draftId);
|
||||
news.setNewsinfoId(newsInfoId);
|
||||
try {
|
||||
newsMapper.updateNews(news);
|
||||
int count = newsMapper.updateNews(news, oldStatus);
|
||||
if (count == 0) {
|
||||
return ResultObject.failed("该资讯正在审核中,请勿重复操作");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("更新新闻报错!", e);
|
||||
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
|
||||
}
|
||||
} else {
|
||||
news = new News(saveNewsDTO);
|
||||
news.setDraftId(draftId);
|
||||
news.setNewsinfoId(newsInfoId);
|
||||
try {
|
||||
newsMapper.updateNews(news);
|
||||
} catch (Exception e) {
|
||||
log.error("更新新闻报错!", e);
|
||||
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
|
||||
}
|
||||
}
|
||||
}
|
||||
Long newsId = news.getId();
|
||||
// 保存新闻标签关系
|
||||
|
|
@ -781,7 +794,7 @@ public class NewsService {
|
|||
public PageObject<NewsVO> queryNews(String keyword, String columnParam, Integer status, int page, int size,
|
||||
Integer last, Integer current, String orderBy, Double minScore, Double maxScore,
|
||||
String tag, String industry, Long mediaId,
|
||||
Date datelineFrom, Date datelineTo) {
|
||||
Date datelineFrom, Date datelineTo, Integer deleted, Byte rating,boolean isReviewer) {
|
||||
String orderByClause = null;
|
||||
if (StringUtils.hasText(orderBy)) {
|
||||
String orderByStr = orderBy;
|
||||
|
|
@ -800,6 +813,8 @@ public class NewsService {
|
|||
orderByClause = orderByClause.replace("news.score", "news_tags.news_score");
|
||||
orderByClause = " IF(ISNULL(news_tags.news_score), 1, 0) asc, " + orderByClause;
|
||||
}
|
||||
} else {
|
||||
orderByClause = (deleted != null && (deleted.intValue() == 1))? "news.update_time desc":"news.publish_time desc";
|
||||
}
|
||||
int offset = 0;
|
||||
if (current != null) {
|
||||
|
|
@ -844,7 +859,7 @@ public class NewsService {
|
|||
|
||||
List<News> newsList;
|
||||
try {
|
||||
newsList = newsMapper.queryNews(keywords, minScore, maxScore, columnParam, status, last, orderByClause, size, offset, tags, industries, datelineFrom, datelineTo);
|
||||
newsList = newsMapper.queryNews(keywords, minScore, maxScore, columnParam, status, last, orderByClause, size, offset, tags, industries, datelineFrom, datelineTo, deleted, rating, isReviewer);
|
||||
} catch (Exception e) {
|
||||
log.error("搜索新闻异常!", e);
|
||||
return PageObject.failedPage(500, "服务器错误,请联系系统管理员!");
|
||||
|
|
@ -853,7 +868,7 @@ public class NewsService {
|
|||
PageObject<NewsVO> pageObject = new PageObject<>();
|
||||
if (page == 1) {
|
||||
try {
|
||||
int total = newsMapper.queryTotal(keywords,minScore, maxScore, columnParam, status, tags, industries, datelineFrom, datelineTo);
|
||||
int total = newsMapper.queryTotal(keywords,minScore, maxScore, columnParam, status, tags, industries, datelineFrom, datelineTo, deleted, rating, isReviewer);
|
||||
pageObject.setTotal(total);
|
||||
} catch (Exception e) {
|
||||
log.error("获取新闻总数异常!", e);
|
||||
|
|
@ -959,10 +974,171 @@ public class NewsService {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String keyword = "中国 美国 俄罗斯";
|
||||
keyword = keyword.replaceAll("\\s+", "%");
|
||||
System.out.println(keyword);
|
||||
public ResultObject<NewsTranslatorVO> getTranslator(Long id) {
|
||||
News news = newsMapper.getNewsDetail(id);
|
||||
String newsInfoId = news.getNewsinfoId();
|
||||
if (ObjectUtils.isEmpty(newsInfoId)) {
|
||||
return ResultObject.success();
|
||||
}
|
||||
NewsTranslatorVO newsTranslatorVO = new NewsTranslatorVO();
|
||||
try {
|
||||
GetResponse<ObjectNode> newsInfoResp = elasticsearchClient.get(g -> g.index(NewsInfo.INDEX_NAME).id(newsInfoId), ObjectNode.class);
|
||||
if (!newsInfoResp.found()) {
|
||||
return ResultObject.success();
|
||||
}
|
||||
ObjectNode newsInfo = newsInfoResp.source();
|
||||
String titleEN = Optional.ofNullable(newsInfo.get("title_EN")).filter(JsonNode::isTextual).map(JsonNode::asText).orElse(null);
|
||||
String contentEN = Optional.ofNullable(newsInfo.get("EN_content")).filter(JsonNode::isTextual).map(JsonNode::asText).orElse(null);
|
||||
|
||||
//大模型翻译
|
||||
String title = Optional.ofNullable(newsInfo.at("/news_tags/title")).filter(JsonNode::isTextual).map(JsonNode::asText).orElse(null);
|
||||
String rewriteContent = Optional.ofNullable(newsInfo.at("/news_tags/rewrite_content")).filter(JsonNode::isTextual).map(JsonNode::asText).orElse(null);
|
||||
|
||||
newsTranslatorVO.setTitleEN(titleEN);
|
||||
newsTranslatorVO.setContentEN(contentEN);
|
||||
if (!ObjectUtils.isEmpty(title)) {
|
||||
newsTranslatorVO.setTitleCN(news.getTitle());
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(rewriteContent)) {
|
||||
newsTranslatorVO.setContentCN(news.getContent());
|
||||
}
|
||||
return ResultObject.success(newsTranslatorVO);
|
||||
} catch(IOException e) {
|
||||
log.error("获取全量资讯详情异常!", e);
|
||||
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
|
||||
}
|
||||
}
|
||||
|
||||
public void backupDuplicatedNews(List<News> newsList, String clusterId) {
|
||||
for (News news: newsList) {
|
||||
NewsDeleted newsDeleted = new NewsDeleted(news, clusterId);
|
||||
newsDeletedMapper.save(newsDeleted);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 挪到service层
|
||||
* @param newsList
|
||||
*/
|
||||
public void deletDuplicatedNews(List<News> newsList) {
|
||||
for (News news: newsList) {
|
||||
Long draftId = news.getDraftId();
|
||||
if (draftId != null) {
|
||||
newsMapper.deleteDraft(draftId);
|
||||
columnMapper.deleteDraft(draftId);
|
||||
tagMapper.deleteDraft(draftId);
|
||||
industryMapper.deleteDraft(draftId);
|
||||
}
|
||||
Long newsId = news.getId();
|
||||
columnMapper.deleteNews(newsId);
|
||||
tagMapper.deleteNews(newsId);
|
||||
industryMapper.deleteNews(newsId);
|
||||
newsMapper.deleteById(newsId);
|
||||
}
|
||||
}
|
||||
|
||||
public ResultObject<Void> recoverNews(Long id, Long adminUserId) {
|
||||
News news = newsMapper.getById(id);
|
||||
if (news == null) {
|
||||
return ResultObject.failed("要恢复的数据不存在,请联系系统管理员!");
|
||||
}
|
||||
|
||||
try {
|
||||
newsMapper.recoverNews(id, adminUserId);
|
||||
} catch (Exception e) {
|
||||
log.error("恢复新闻异常!", e);
|
||||
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
|
||||
}
|
||||
return ResultObject.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回最近两天的数据
|
||||
* @param num
|
||||
* @param last
|
||||
* @return
|
||||
*/
|
||||
public ResultObject<List<NewsApiVO>> requestNewsByApi(Integer num, Long last) {
|
||||
List<NewsApiVO> result = newsMapper.queryNewsByApi(last, Integer.min(num, 1000));
|
||||
|
||||
Map<Long, Industry> industryMap = industryMapper.queryAll().stream().collect(Collectors.toMap(Industry::getId, Function.identity()));
|
||||
result.stream().forEach( e -> {
|
||||
List<Tag> newsTagRels = tagMapper.getNewsTagRelList(e.getId()).stream().map(x -> tagMapper.queryById(x.getTagId())).collect(Collectors.toList());
|
||||
|
||||
if (ObjectUtils.isEmpty(e.getSource())) {
|
||||
Optional<Tag> sourceTag = newsTagRels.stream().filter(x -> x != null && (x.getParentId() == 1L)).findFirst();
|
||||
if (sourceTag.isPresent()) {
|
||||
e.setSource(sourceTag.get().getName());
|
||||
}
|
||||
}
|
||||
List<String> conceptLabel = newsTagRels.stream().filter(t -> t != null).map(Tag::getDisplayName).collect(Collectors.toList());
|
||||
e.setConceptLabel(conceptLabel);
|
||||
|
||||
List<String> industryLabel = industryMapper.getNewsIndustryRelList(e.getId()).stream().map(x -> industryMap.get(x.getIndustryId())).filter(i -> i != null).map(n -> n.getDisplayName()).collect(Collectors.toList());
|
||||
e.setIndustryLabel(industryLabel);
|
||||
});
|
||||
return ResultObject.success(result);
|
||||
}
|
||||
|
||||
public ResultObject<Void> submit(long id, long editorId) {
|
||||
News news = newsMapper.getById(id);
|
||||
if (news == null) {
|
||||
log.warn("找不到ID为{}的新闻!", id);
|
||||
return ResultObject.failed("找不到ID为" + id + "的新闻!");
|
||||
}
|
||||
Integer oldStatus = news.getStatus();
|
||||
if (oldStatus != 1) {
|
||||
return ResultObject.failed("该资讯正在审核中,请勿重复操作");
|
||||
}
|
||||
|
||||
newsMapper.changeFrom(id, oldStatus, 3, editorId);
|
||||
return ResultObject.success();
|
||||
}
|
||||
|
||||
public ResultObject<Void> revoke(Long id, Long editorId, boolean isReviewer) {
|
||||
News news = newsMapper.getById(id);
|
||||
if (news == null) {
|
||||
log.warn("找不到ID为{}的新闻!", id);
|
||||
return ResultObject.failed("找不到ID为" + id + "的新闻!");
|
||||
}
|
||||
Integer oldStatus = news.getStatus();
|
||||
if (isReviewer) {
|
||||
if (oldStatus != 2) {
|
||||
return ResultObject.failed("该资讯正在审核中,请勿重复操作");
|
||||
}
|
||||
newsMapper.changeFrom(id, oldStatus, 3, editorId);
|
||||
return ResultObject.success();
|
||||
}
|
||||
|
||||
if (oldStatus != 3) {
|
||||
return ResultObject.failed("该资讯正在审核中,请勿重复操作");
|
||||
}
|
||||
|
||||
newsMapper.changeFrom(id, oldStatus, 1, editorId);
|
||||
return ResultObject.success();
|
||||
}
|
||||
|
||||
public PageObject<NewsLogVO> getLog(Long id, int page, int size, Integer current) {
|
||||
int offset = 0;
|
||||
if (current != null) {
|
||||
offset = (Math.max(0, current - 1)) * size;
|
||||
}
|
||||
List<UserOperationLog> dataOperationLogs = userOperationLogMapper.selectByDataIdAndType(id, "news", size, offset);
|
||||
List<NewsLogVO> newsLogList = dataOperationLogs.stream().map(e -> new NewsLogVO(e)).collect(Collectors.toList());
|
||||
|
||||
PageObject<NewsLogVO> pageObject = new PageObject<>();
|
||||
pageObject.setData(newsLogList);
|
||||
pageObject.setCode(200);
|
||||
pageObject.setCurrent(page);
|
||||
size = Math.min(newsLogList.size(), size);
|
||||
pageObject.setSize(size);
|
||||
try {
|
||||
int total = userOperationLogMapper.queryTotal(id, "news");
|
||||
pageObject.setTotal(total);
|
||||
} catch (Exception e) {
|
||||
log.error("获取新闻总数异常!", e);
|
||||
return PageObject.failedPage(500, "服务器错误,请联系系统管理员!");
|
||||
}
|
||||
return pageObject;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,11 +35,11 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- <dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>${jedis.version}</version>
|
||||
</dependency>
|
||||
</dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-client</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
package com.jinrui.reference.mini;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = {
|
||||
"com.jinrui.reference.mini",
|
||||
|
|
@ -23,17 +19,17 @@ public class MiniApplication {
|
|||
SpringApplication.run(MiniApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JedisPool jedisPool(@Value("${redis.host}") String host,
|
||||
@Value("${redis.port}") int port,
|
||||
@Value("${redis.timeout:1000}") int timeout,
|
||||
@Value("${redis.password:}") String password) {
|
||||
if (StringUtils.hasText(password)) {
|
||||
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
|
||||
return new JedisPool(jedisPoolConfig, host, port, timeout, password);
|
||||
}
|
||||
return new JedisPool(host, port);
|
||||
}
|
||||
// @Bean
|
||||
// public JedisPool jedisPool(@Value("${redis.host}") String host,
|
||||
// @Value("${redis.port}") int port,
|
||||
// @Value("${redis.timeout:1000}") int timeout,
|
||||
// @Value("${redis.password:}") String password) {
|
||||
// if (StringUtils.hasText(password)) {
|
||||
// JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
|
||||
// return new JedisPool(jedisPoolConfig, host, port, timeout, password);
|
||||
// }
|
||||
// return new JedisPool(host, port);
|
||||
// }
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue