全量资讯相关代码

This commit is contained in:
sunflower2014 2025-06-01 23:44:45 +08:00
parent af487fdb48
commit f4e2af107e
18 changed files with 1905 additions and 6 deletions

View File

@ -15,6 +15,8 @@
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<elasticsearch.version>8.12.2</elasticsearch.version>
<jakartajson.version>2.0.1</jakartajson.version>
</properties>
<dependencies>
@ -22,12 +24,32 @@
<groupId>com.jinrui</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</exclusion>
<exclusion>
<artifactId>jakarta.json-api</artifactId>
<groupId>jakarta.json</groupId>
</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>
<version>${elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>${jakartajson.version}</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,201 @@
package com.jinrui.reference.admin.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
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.RequestBody;
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.fasterxml.jackson.databind.ObjectMapper;
import com.jinrui.reference.admin.model.dto.newsinfo.PublishNewsInfoDTO;
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.newsinfo.NewsInfoDetailVO;
import com.jinrui.reference.core.model.vo.newsinfo.NewsInfoVO;
import com.jinrui.reference.core.model.vo.newsinfo.SaveNewsInfoDTO;
import com.jinrui.reference.core.service.NewsInfoService;
@RestController
@RequestMapping("/newsinfo")
public class NewsInfoController {
private static final Logger log = LoggerFactory.getLogger(NewsInfoController.class);
private final NewsInfoService newsInfoService;
private final ObjectMapper objectMapper;
public NewsInfoController(NewsInfoService newsInfoService,
ObjectMapper objectMapper) {
this.newsInfoService = newsInfoService;
this.objectMapper = objectMapper;;
}
@PostMapping("/publish")
public ResultObject<Void> publish(@RequestHeader("auth-token") String token,
@RequestBody PublishNewsInfoDTO 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("当前用户已被封禁!请联系系统管理员!");
}
String id = publishNewsDTO.getId();
if (ObjectUtils.isEmpty(id)) {
return ResultObject.failed("要发布/下架的新闻ID不可为空");
}
log.info("path: /newsinfo/publish, method: POST, request user id: {}, news id: {}", adminUserId, id);
return newsInfoService.publish(id, adminUserId);
} catch (Exception e) {
log.error("解析登陆Token出错!", e);
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
}
}
@GetMapping("/detail")
public ResultObject<NewsInfoDetailVO> detail(@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: /newsinfo/detail, method: GET, request user id: {}, news id: {}", adminUserId, id);
return newsInfoService.detail(id);
} catch (Exception e) {
log.error("解析登陆Tokn出错!", e);
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
}
}
@PostMapping("/delete")
public ResultObject<Void> deleteNews(@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: /newsinfo, method: DELETE, request user id: {}, news id: {}", adminUserId, id);
return newsInfoService.deleteNewsInfo(id);
} catch (Exception e) {
log.error("解析登陆Token出错!", e);
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
}
}
@PostMapping("/save")
public ResultObject<Void> saveDraft(@RequestHeader("auth-token") String token,
@RequestBody SaveNewsInfoDTO saveNewsDTO) {
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有误请联系系统管理员!");
}
if (!adminUser.isActive()) {
log.warn("当前用户已被封禁! id = {}", adminUser.getId());
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
}
log.info("path: /news/save, method: POST, request user id: {}, param: {}",
adminUser.getId(), objectMapper.writeValueAsString(saveNewsDTO));
} catch (Exception e) {
log.error("解析登陆Token出错!", e);
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
}
// 这个接口是保存和编辑那status应该是2
saveNewsDTO.setStatus(2);
return newsInfoService.save(saveNewsDTO);
}
@GetMapping
public PageObject<NewsInfoVO> queryNewsInfo(@RequestHeader("auth-token") String token,
@RequestParam(value = "title", required = false) String title,
@RequestParam(value = "content", required = false) String content,
@RequestParam(value = "stockcode", required = false) String stockcode,
@RequestParam(value = "sourcename", required = false) Long sourcename,
@RequestParam(value = "page", required = false, defaultValue = "1") int page,
@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 = "createTime") String orderBy,
@RequestParam(value = "direction", required = false, defaultValue = "asc") String direction
) {
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有误请联系系统管理员!");
}
if (!adminUser.isActive()) {
log.warn("当前用户已被封禁! id = {}", adminUser.getId());
return PageObject.failedPage("当前用户已被封禁!请联系系统管理员!");
}
log.info("path: /newsinfo, method: GET, request user id: {}, title: {}, content: {}, stockcode: {}, sourcename: {}, " +
"page: {}, size: {}, last: {}, current: {}, orderBy: {}, direction: {}",
adminUser.getId(), title, content, stockcode,sourcename, page, size, last, current, orderBy, direction);
} catch (Exception e) {
log.error("解析登陆Token出错!", e);
return PageObject.failedPage(500, "服务端错误,请联系系统管理员!");
}
return newsInfoService.queryNewsInfo(title, content, stockcode, sourcename, page, size, last, current, orderBy, direction);
}
}

View File

@ -0,0 +1,13 @@
package com.jinrui.reference.admin.model.dto.newsinfo;
public class PublishNewsInfoDTO {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}

View File

@ -32,3 +32,10 @@ redis:
host: 123.60.153.169
port: 6379
password: Xgf_redis
elasticsearch:
scheme: http
host: 10.127.2.194
port: 9200
enable: true
username: elastic
password: Aa123456

View File

@ -17,6 +17,8 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<bouncycastle.version>1.70</bouncycastle.version>
<jwt.version>4.4.0</jwt.version>
<elasticsearch.version>8.12.2</elasticsearch.version>
<jakartajson.version>2.0.1</jakartajson.version>
</properties>
<dependencies>
@ -59,6 +61,31 @@
<artifactId>bcutil-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>${elasticsearch.version}</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</exclusion>
<exclusion>
<artifactId>jakarta.json-api</artifactId>
<groupId>jakarta.json</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>${jakartajson.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,90 @@
package com.jinrui.reference.core;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.message.BasicHeader;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.Header;
import org.elasticsearch.client.RestClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
@Configuration
public class ElasticSearchConfig {
@Value("${elasticsearch.scheme}")
private String scheme;
@Value("${elasticsearch.host}")
private String host;
@Value("${elasticsearch.port}")
private int port;
@Value("${elasticsearch.enable}")
private boolean enable;
@Value("${elasticsearch.username}")
private String username;
@Value("${elasticsearch.password}")
private String password;
@Bean
public ElasticsearchClient elasticsearchClient(){
ElasticsearchClient client = new ElasticsearchClient(null);
if (enable){
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
if (username != null && !username.isEmpty() && password != null && !password.isEmpty()) {
//设置账号密码
credentialsProvider.setCredentials(
AuthScope.ANY, new UsernamePasswordCredentials(username, password));
}
Header[] defaultHeaders = new Header[]{new BasicHeader("header", "value")};
RestClient restClient = RestClient.builder(new HttpHost(host, port, scheme))
.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider))
.setDefaultHeaders(defaultHeaders)
.build();
ElasticsearchTransport transport = new RestClientTransport(restClient,new JacksonJsonpMapper());
client = new ElasticsearchClient(transport);
}
return client;
}
@Bean
public ElasticsearchAsyncClient elasticsearchAsyncClient(){
ElasticsearchAsyncClient syncClient = new ElasticsearchAsyncClient(null);
if (enable){
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
if (username != null && !username.isEmpty() && password != null && !password.isEmpty()) {
//设置账号密码
credentialsProvider.setCredentials(
AuthScope.ANY, new UsernamePasswordCredentials(username, password));
}
Header[] defaultHeaders = new Header[]{new BasicHeader("header", "value")};
RestClient restClient = RestClient.builder(new HttpHost(host, port, scheme))
.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider))
.setDefaultHeaders(defaultHeaders)
.build();
ElasticsearchTransport transport = new RestClientTransport(restClient,new JacksonJsonpMapper());
syncClient = new ElasticsearchAsyncClient(transport);
}
return syncClient;
}
}

View File

@ -4,6 +4,7 @@ import com.jinrui.reference.core.model.entity.News;
import com.jinrui.reference.core.model.entity.NewsDraft;
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.Select;
import org.apache.ibatis.annotations.Update;
@ -45,6 +46,7 @@ public interface NewsMapper {
"content = #{content}," +
"content_text = #{contentText}," +
"status = #{status}," +
"newsinfo_id = #{newsinfoId}," +
"update_time = now() " +
"where id = #{id}")
void updateNews(News news);
@ -63,7 +65,7 @@ public interface NewsMapper {
"where id = #{id}")
void publishNews(News news);
@Select("select id, draft_id as draftId, status from news where id = #{id}")
@Select("select id, draft_id as draftId, status, newsinfo_id as newsinfoId from news where id = #{id}")
News getById(@Param("id") Long id);
@Select("select last_insert_id()")
@ -73,8 +75,9 @@ public interface NewsMapper {
"values (#{title}, #{summary}, #{picture}, #{type}, #{content}, now(), now())")
void saveDraft(NewsDraft newsDraft);
@Insert("insert into news(draft_id, title, summary, picture, type, content, create_time, update_time, status, publish_time, content_text)" +
"values (#{draftId}, #{title}, #{summary}, #{picture}, #{type}, #{content}, now(), now(), #{status}, #{publishTime}, #{contentText})")
@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})")
void saveNews(News news);

View File

@ -26,6 +26,10 @@ public interface TagMapper {
@Select("select * from tag")
List<Tag> queryAll();
@Select("select id, parent_id as parentId, name from tag where id = #{id}")
Tag queryById(@Param("id") Long id);
@Select("select id, draft_id as draftId, tag_id as tagId " +
"from draft_tag_rel where draft_id = #{draftId}")
List<DraftTagRel> getDraftTagRelList(@Param("draftId") Long draftId);

View File

@ -3,6 +3,10 @@ package com.jinrui.reference.core.model.dto.news;
import java.util.Date;
import java.util.List;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import com.jinrui.reference.core.model.entity.NewsInfo;
import com.jinrui.reference.core.model.vo.news.NewsDetailVO;
@SuppressWarnings("unused")
@ -128,4 +132,16 @@ public class SaveNewsDTO {
public void setIndustries(List<Long> industries) {
this.industries = industries;
}
public NewsInfo toNewsInfo() {
NewsInfo newsInfo = new NewsInfo();
newsInfo.setTitle(this.getTitle());
newsInfo.setSummary(this.getSummary());
newsInfo.setStatus(this.getStatus());
newsInfo.setContent(this.getContent());
newsInfo.setCreateTime(new Date());
newsInfo.setUpdateTime(newsInfo.getCreateTime());
newsInfo.setInputDate(newsInfo.getCreateTime());
return newsInfo;
}
}

View File

@ -3,6 +3,7 @@ package com.jinrui.reference.core.model.entity;
import java.util.Date;
import org.apache.ibatis.annotations.Param;
import org.springframework.util.ObjectUtils;
/**
* 行业分类
@ -86,4 +87,11 @@ public class Industry {
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getDisplayName() {
if (ObjectUtils.isEmpty(this.getSecondaryName())) {
return this.getPrimaryName();
}
return this.getSecondaryName();
}
}

View File

@ -71,7 +71,12 @@ public class News {
*/
private Date updateTime;
public News() {}
/**
* 关联的全量资讯es文档ID
*/
private String newsinfoId;
public News() {}
public News(SaveNewsDTO saveNewsDTO) {
this.id = saveNewsDTO.getId();
@ -191,4 +196,12 @@ public class News {
public void setContentText(String contentText) {
this.contentText = contentText;
}
public String getNewsinfoId() {
return newsinfoId;
}
public void setNewsinfoId(String newsinfoId) {
this.newsinfoId = newsinfoId;
}
}

View File

@ -0,0 +1,323 @@
package com.jinrui.reference.core.model.entity;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* 全量资讯
*/
public class NewsInfo {
public static final String INDEX_NAME = "news_info";
public static final String TITLE_ES_NAME = "title_txt";
public static final String SUMMARY_ES_NAME = "abstract";
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";
/**
* 全量资讯ID
*/
private String id;
/**
* 资讯精选ID
*/
@JsonProperty("news_id")
private Long newsId;
/**
* 数据输入时间
*/
@JsonProperty("input_date")
private Date inputDate;
private Integer words;
/**
* 关键词列表(分号分割)
*/
@JsonProperty("key_word")
private String keyword;
/**
* 标题
*/
@JsonProperty(TITLE_ES_NAME)
private String title;
@JsonProperty("title_EN")
private String englishTitle;
/**
* 摘要
*/
@JsonProperty(SUMMARY_ES_NAME)
private String summary;
/**
* 原文链接
*/
@JsonProperty("URL")
private String url;
/**
* 数据来源名称或标识
*/
private String sourcename;
/**
* 语言
*/
private String lang;
/**
* H5富文本
*/
@JsonProperty(CONTENT_ES_NAME)
private String content;
@JsonProperty("EN_content")
private String englishContent;
/**
* 分类信息json格式
*/
@JsonProperty("category")
private String industry;
/**
* 是否删除 0 正常 1 已删除
*/
private Integer deleted = 0;
/**
* 文件日期(取自目录结构)
*/
@JsonProperty("file_date")
private Date fileDate;
/**
* 完整文件名(含扩展名)
*/
@JsonProperty("file_name")
private String fileName;
/**
* 新闻状态 0-草稿 | 1-未发布 | 2-已发布
*/
private Integer status;
/**
* 创建时间
*/
@JsonProperty("create_time")
private Date createTime;
/**
* 发布时间
*/
private Date publishTime;
/**
* 修改时间
*/
@JsonProperty("update_time")
private Date updateTime;
/**
* 编辑ID - 最后一个点击发布的人的ID
*/
private Long editorId;
public NewsInfo() {}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Long getEditorId() {
return editorId;
}
public void setEditorId(Long editorId) {
this.editorId = editorId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getPublishTime() {
return publishTime;
}
public void setPublishTime(Date publishTime) {
this.publishTime = publishTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getSourcename() {
return sourcename;
}
public void setSourcename(String sourcename) {
this.sourcename = sourcename;
}
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang = lang;
}
public Integer getDeleted() {
return deleted;
}
public void setDeleted(Integer deleted) {
this.deleted = deleted;
}
public Long getNewsId() {
return newsId;
}
public void setNewsId(Long newsId) {
this.newsId = newsId;
}
public Date getInputDate() {
return inputDate;
}
public void setInputDate(Date inputDate) {
this.inputDate = inputDate;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public String getEnglishTitle() {
return englishTitle;
}
public void setEnglishTitle(String englishTitle) {
this.englishTitle = englishTitle;
}
public String getEnglishContent() {
return englishContent;
}
public void setEnglishContent(String englishContent) {
this.englishContent = englishContent;
}
public String getIndustry() {
return industry;
}
public void setIndustry(String industry) {
this.industry = industry;
}
public Date getFileDate() {
return fileDate;
}
public void setFileDate(Date fileDate) {
this.fileDate = fileDate;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public Integer getWords() {
return words;
}
public void setWords(Integer words) {
this.words = words;
}
public News toNews() {
News news = new News();
news.setTitle(this.getTitle());
news.setContent(this.getContent());
news.setStatus(this.getStatus());
news.setSummary(this.getSummary());
news.setPublishTime(new Date());
news.setType(1);
news.setNewsinfoId(this.getId());
return news;
}
}

View File

@ -0,0 +1,222 @@
package com.jinrui.reference.core.model.vo.newsinfo;
import java.util.Date;
import java.util.List;
import com.jinrui.reference.core.model.entity.NewsInfo;
import com.jinrui.reference.core.model.vo.news.NewsDetailIndustry;
import com.jinrui.reference.core.model.vo.news.NewsDetailTag;
public class NewsInfoDetailVO {
/**
* 全量资讯ID
*/
private String id;
/**
* 资讯精选ID
*/
private Long newsId;
/**
* 数据输入时间
*/
private Date inputDate;
/**
* 关键词列表(分号分割)
*/
private String keyword;
/**
* 标题
*/
private String title;
/**
* 摘要
*/
private String summary;
/**
* 数据来源名称或标识
*/
private NewsDetailTag sourcename;
/**
* H5富文本
*/
private String content;
/**
* 分类信息json格式
*/
private List<NewsDetailIndustry> industry;
/**
* 文件日期(取自目录结构)
*/
private Date fileDate;
/**
* 新闻状态 0-草稿 | 1-未发布 | 2-已发布
*/
private Integer status;
/**
* 创建时间
*/
private Date createTime;
/**
* 发布时间
*/
private Date publishTime;
/**
* 修改时间
*/
private Date updateTime;
/**
* 编辑ID - 最后一个点击发布的人的ID
*/
private Long editorId;
public NewsInfoDetailVO() {}
public NewsInfoDetailVO(NewsInfo newsInfo) {
this.id = newsInfo.getId();
this.newsId = newsInfo.getNewsId();
this.title = newsInfo.getTitle();
this.summary = newsInfo.getSummary();
this.status = (newsInfo.getStatus() == null ? 1: newsInfo.getStatus());
this.content = newsInfo.getContent();
this.publishTime = newsInfo.getPublishTime();
this.createTime = newsInfo.getCreateTime();
this.updateTime = newsInfo.getUpdateTime();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Long getEditorId() {
return editorId;
}
public void setEditorId(Long editorId) {
this.editorId = editorId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getPublishTime() {
return publishTime;
}
public void setPublishTime(Date publishTime) {
this.publishTime = publishTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public NewsDetailTag getSourcename() {
return sourcename;
}
public void setSourcename(NewsDetailTag sourcename) {
this.sourcename = sourcename;
}
public Long getNewsId() {
return newsId;
}
public void setNewsId(Long newsId) {
this.newsId = newsId;
}
public Date getInputDate() {
return inputDate;
}
public void setInputDate(Date inputDate) {
this.inputDate = inputDate;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public List<NewsDetailIndustry> getIndustry() {
return industry;
}
public void setIndustry(List<NewsDetailIndustry> industry) {
this.industry = industry;
}
public Date getFileDate() {
return fileDate;
}
public void setFileDate(Date fileDate) {
this.fileDate = fileDate;
}
}

View File

@ -0,0 +1,194 @@
package com.jinrui.reference.core.model.vo.newsinfo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.jinrui.reference.core.model.entity.NewsInfo;
public class NewsInfoVO {
/**
* 全量资讯ID
*/
private String id;
/**
* 资讯精选ID
*/
private Long newsId;
/**
* 数据输入时间
*/
private Date inputDate;
/**
* 标题
*/
private String title;
/**
* 摘要
*/
private String summary;
/**
* 正文
*/
private String content;
/**
* 数据来源名称或标识
*/
private String sourcename;
/**
* 文件日期(取自目录结构)
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date fileDate;
/**
* 新闻状态 0-草稿 | 1-未发布 | 2-已发布
*/
private Integer status;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date createTime;
/**
* 发布时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date publishTime;
/**
* 修改时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date updateTime;
/**
* 编辑ID - 最后一个点击发布的人的ID
*/
private Long editorId;
public NewsInfoVO(NewsInfo newsInfo) {
this.id = newsInfo.getId();
this.title = newsInfo.getTitle();
this.summary = newsInfo.getSummary();
this.status = newsInfo.getStatus();
this.sourcename = newsInfo.getSourcename();
this.content = newsInfo.getContent();
this.publishTime = newsInfo.getPublishTime();
this.createTime = newsInfo.getCreateTime();
this.updateTime = newsInfo.getUpdateTime();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Long getEditorId() {
return editorId;
}
public void setEditorId(Long editorId) {
this.editorId = editorId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getPublishTime() {
return publishTime;
}
public void setPublishTime(Date publishTime) {
this.publishTime = publishTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getSourcename() {
return sourcename;
}
public void setSourcename(String sourcename) {
this.sourcename = sourcename;
}
public Long getNewsId() {
return newsId;
}
public void setNewsId(Long newsId) {
this.newsId = newsId;
}
public Date getInputDate() {
return inputDate;
}
public void setInputDate(Date inputDate) {
this.inputDate = inputDate;
}
public Date getFileDate() {
return fileDate;
}
public void setFileDate(Date fileDate) {
this.fileDate = fileDate;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}

View File

@ -0,0 +1,151 @@
package com.jinrui.reference.core.model.vo.newsinfo;
import java.util.Date;
import java.util.List;
import com.jinrui.reference.core.model.dto.news.SaveDraftColumn;
import com.jinrui.reference.core.model.dto.news.SaveDraftTag;
import com.jinrui.reference.core.model.entity.News;
import com.jinrui.reference.core.model.entity.NewsInfo;
import com.jinrui.reference.core.model.vo.news.NewsDetailVO;
@SuppressWarnings("unused")
public class SaveNewsInfoDTO {
private String id;
private String title;
private String summary;
private String picture;
private SaveDraftTag tag;
private SaveDraftColumn column;
private List<Long> industries;
private String content;
// 不含html标签的纯文本
private String contentText;
private Integer status;
private Date publishTime;
public SaveNewsInfoDTO() {}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public SaveDraftTag getTag() {
return tag;
}
public void setTag(SaveDraftTag tag) {
this.tag = tag;
}
public SaveDraftColumn getColumn() {
return column;
}
public void setColumn(SaveDraftColumn column) {
this.column = column;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Date getPublishTime() {
return publishTime;
}
public void setPublishTime(Date publishTime) {
this.publishTime = publishTime;
}
public String getContentText() {
return contentText;
}
public void setContentText(String contentText) {
this.contentText = contentText;
}
public List<Long> getIndustries() {
return industries;
}
public void setIndustries(List<Long> industries) {
this.industries = industries;
}
public NewsInfo toNewsInfo() {
NewsInfo newsInfo = new NewsInfo();
newsInfo.setId(this.getId());
newsInfo.setTitle(this.getTitle());
newsInfo.setSummary(this.getSummary());
newsInfo.setStatus(this.getStatus());
newsInfo.setContent(this.getContent());
newsInfo.setCreateTime(new Date());
newsInfo.setUpdateTime(newsInfo.getCreateTime());
newsInfo.setInputDate(newsInfo.getCreateTime());
return newsInfo;
}
public News toNews() {
News news = new News();
news.setTitle(this.getTitle());
news.setSummary(this.getSummary());
news.setStatus(this.getStatus());
news.setContent(this.getContent());
news.setCreateTime(new Date());
news.setUpdateTime(news.getCreateTime());
news.setType(1);
news.setNewsinfoId(this.getId());
return news;
}
}

View File

@ -0,0 +1,513 @@
package com.jinrui.reference.core.service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
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.ObjectUtils;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jinrui.reference.core.mapper.IndustryMapper;
import com.jinrui.reference.core.mapper.NewsMapper;
import com.jinrui.reference.core.mapper.TagMapper;
import com.jinrui.reference.core.model.dto.news.SaveDraftTag;
import com.jinrui.reference.core.model.entity.Industry;
import com.jinrui.reference.core.model.entity.News;
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.Tag;
import com.jinrui.reference.core.model.vo.PageObject;
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.newsinfo.NewsInfoDetailVO;
import com.jinrui.reference.core.model.vo.newsinfo.NewsInfoVO;
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.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.TermQuery;
import co.elastic.clients.elasticsearch.core.GetResponse;
import co.elastic.clients.elasticsearch.core.IndexResponse;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
@Service
public class NewsInfoService {
private static final Logger log = LoggerFactory.getLogger(NewsInfoService.class);
private final ElasticsearchClient elasticsearchClient;
private final ObjectMapper objectMapper;
private final TagMapper tagMapper;
private final IndustryMapper industryMapper;
private final NewsMapper newsMapper;
public NewsInfoService(ElasticsearchClient elasticsearchClient,
ObjectMapper objectMapper,
TagMapper tagMapper,
IndustryMapper industryMapper,
NewsMapper newsMapper) {
this.elasticsearchClient = elasticsearchClient;
this.objectMapper = objectMapper;
this.tagMapper = tagMapper;
this.industryMapper = industryMapper;
this.newsMapper = newsMapper;
}
public ResultObject<Void> publish(String id, long editorId) {
try {
GetResponse<NewsInfo> newsInfoResp = elasticsearchClient.get(g -> g.index(NewsInfo.INDEX_NAME).id(String.valueOf(id)), NewsInfo.class);
if (!newsInfoResp.found()) {
return ResultObject.success();
}
NewsInfo newsInfo = newsInfoResp.source();
newsInfo.setId(id);
if (newsInfo.getStatus() == null ||newsInfo.getStatus().intValue() == 1) {
newsInfo.setStatus(2);
} else {
newsInfo.setStatus(1);
}
News relateNews = newsMapper.getNewsDetail(newsInfo.getNewsId());
if (relateNews == null||!Objects.equals(relateNews.getTitle(), newsInfo.getTitle())) {
// 插入数据到News表中
News relNews = newsInfo.toNews();
relNews.setEditorId(editorId);
newsMapper.saveNews(relNews);
newsInfo.setNewsId(relNews.getId());
String industry = newsInfo.getIndustry();
if (!ObjectUtils.isEmpty(industry)) {
List<Industry> industries = industryMapper.queryAll();
for (Industry industryItem: industries) {
if (industry.equals(industryItem.getPrimaryName()) || industryItem.equals(industryItem.getSecondaryName())) {
industryMapper.saveNewsIndustryRel(newsInfo.getNewsId(), industryItem.getId());
}
}
}
String sourcename = newsInfo.getSourcename();
if (!ObjectUtils.isEmpty(sourcename)) {
List<Tag> matchedTags = tagMapper.queryTag(1L, sourcename, null, "create_time", null);
for (Tag tag: matchedTags) {
if (tag.getName().equals(sourcename)) {
tagMapper.saveNewsTagRel(newsInfo.getNewsId(), tag.getId());
}
}
}
} else {
if (newsInfo.getStatus().intValue() == 2) {
newsMapper.simplePublish(newsInfo.getNewsId(), editorId);
} else {
newsMapper.simpleUnpublish(newsInfo.getNewsId());
}
}
NewsInfo publishedNewsInfo = new NewsInfo();
publishedNewsInfo.setStatus(newsInfo.getStatus());
publishedNewsInfo.setNewsId(newsInfo.getNewsId());
elasticsearchClient.update(e -> e.index(NewsInfo.INDEX_NAME).refresh(Refresh.True).id(String.valueOf(id)).doc(publishedNewsInfo), NewsInfo.class);
} catch(IOException e) {
log.error("全量资讯发布失败!", e);
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
}
return ResultObject.success();
}
public ResultObject<NewsInfoDetailVO> detail(String id) {
try {
GetResponse<NewsInfo> newsInfoResp = elasticsearchClient.get(g -> g.index(NewsInfo.INDEX_NAME).id(String.valueOf(id)), NewsInfo.class);
if (!newsInfoResp.found()) {
return ResultObject.success();
}
NewsInfo newsInfo = newsInfoResp.source();
newsInfo.setId(id);
NewsInfoDetailVO newsInfoDetailVO = new NewsInfoDetailVO(newsInfo);
List<Tag> allTags = tagMapper.queryAll();
Map<Long, Tag> tagMap = allTags.stream().collect(Collectors.toMap(Tag::getId, Function.identity()));
List<Industry> allIndustrys = industryMapper.queryAll();
if (newsInfo.getStatus() == null ||newsInfo.getStatus() == 1) {
for (Tag tag: allTags) {
if (tag.getName().equals(newsInfo.getSourcename())) {
NewsDetailTag newsDetailTag = new NewsDetailTag();
NewsDetailTagItem sourceTagItem = new NewsDetailTagItem();
newsDetailTag.setSource(sourceTagItem);
sourceTagItem.setId(tag.getId());
sourceTagItem.setName(tag.getName());
newsInfoDetailVO.setSourcename(newsDetailTag);
}
}
String industryStr = newsInfo.getIndustry();
for (Industry industry: allIndustrys) {
if (Objects.equals(industry.getDisplayName(), industryStr)) {
NewsDetailIndustry newsDetailIndustry = new NewsDetailIndustry();
newsDetailIndustry.setId(newsDetailIndustry.getId());
newsDetailIndustry.setPrimaryName(newsDetailIndustry.getPrimaryName());
newsDetailIndustry.setSecondaryName(newsDetailIndustry.getSecondaryName());
newsInfoDetailVO.setIndustry(Arrays.asList(newsDetailIndustry));
}
}
} else {
Map<Long, Industry> industryMap = allIndustrys.stream().collect(Collectors.toMap(Industry::getId, Function.identity()));
List<NewsTagRel> tagRelList = tagMapper.getNewsTagRelList(newsInfo.getNewsId());
NewsDetailTag newsDetailTag = new NewsDetailTag();
newsInfoDetailVO.setSourcename(newsDetailTag);
if (!CollectionUtils.isEmpty(tagRelList)) {
List<NewsDetailTagItem> arr = new ArrayList<>();
for (NewsTagRel rel : tagRelList) {
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) {
newsDetailTag.setSource(tagItem);
} else {
newsDetailTag.setField(tagItem);
arr.add(tagItem);
}
}
newsDetailTag.setFieldArr(arr);
}
List<NewsIndustryRel> industryRelList = industryMapper.getNewsIndustryRelList(newsInfo.getNewsId());
List<NewsDetailIndustry> newsIndustryList = new ArrayList<>();
newsInfoDetailVO.setIndustry(newsIndustryList);
if (!CollectionUtils.isEmpty(industryRelList)) {
for (NewsIndustryRel rel: industryRelList) {
Long industryId = rel.getIndustryId();
Industry industry = industryMap.get(industryId);
NewsDetailIndustry newsDetailIndustry = new NewsDetailIndustry();
newsDetailIndustry.setId(industryId);
newsDetailIndustry.setPrimaryName(industry.getPrimaryName());
newsDetailIndustry.setSecondaryName(industry.getSecondaryName());
newsIndustryList.add(newsDetailIndustry);
}
}
}
return ResultObject.success(newsInfoDetailVO);
} catch(IOException e) {
log.error("获取全量资讯详情异常!", e);
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
}
}
public ResultObject<Void> save(SaveNewsInfoDTO saveNewsDTO) {
String id = saveNewsDTO.getId();
if (ObjectUtils.isEmpty(id)) {
return saveNewsInfo(saveNewsDTO);
}
return updateNewsInfo(saveNewsDTO);
}
private ResultObject<Void> updateNewsInfo(SaveNewsInfoDTO saveNewsInfoDTO) {
String id = saveNewsInfoDTO.getId();
try {
GetResponse<NewsInfo> getResp = elasticsearchClient.get(e -> e.index(NewsInfo.INDEX_NAME).id(String.valueOf(id)), NewsInfo.class);
if (getResp.found()) {
NewsInfo newsInfo = getResp.source();
newsInfo.setId(id);
Long newsId = newsInfo.getNewsId();
News relateNews = newsMapper.getNewsDetail(newsId);
if (relateNews == null ||!Objects.equals(newsInfo.getTitle(), relateNews.getTitle())) {
News news = createRelateNews(saveNewsInfoDTO);
newsId = news.getId();
} else {
updateRelateNews(newsId, saveNewsInfoDTO);
}
NewsInfo updatedNewsInfo = toNewsInfo(newsId, saveNewsInfoDTO);
elasticsearchClient.update(e -> e.index(NewsInfo.INDEX_NAME).id(updatedNewsInfo.getId()).doc(updatedNewsInfo).refresh(Refresh.True), NewsInfo.class);
}
} catch(IOException e) {
log.error("全量资讯更新异常!", e);
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
}
return ResultObject.success();
}
public ResultObject<Void> deleteNewsInfo(String newsInfoId) {
try {
GetResponse<NewsInfo> getResp = elasticsearchClient.get(e -> e.index(NewsInfo.INDEX_NAME).id(String.valueOf(newsInfoId)), NewsInfo.class);
if (getResp.found()) {
NewsInfo newsInfo = getResp.source();
Long newsId = newsInfo.getNewsId();
// 删除资讯精选中关联的数据
deleteNewsRel(newsId);
newsMapper.deleteNews(newsId);
NewsInfo deletedNewsInfo = new NewsInfo();
deletedNewsInfo.setDeleted(1);
elasticsearchClient.update(e -> e.index(NewsInfo.INDEX_NAME).refresh(Refresh.True).id(newsInfoId).doc(deletedNewsInfo), NewsInfo.class);
}
} catch(IOException e) {
log.error("删除全量资讯异常!", e);
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
}
return ResultObject.success();
}
private void deleteNewsRel(Long newsId) {
tagMapper.deleteNews(newsId);
industryMapper.deleteNews(newsId);
}
private ResultObject<Void> saveNewsInfo(SaveNewsInfoDTO saveNewsDTO) {
// 创建关联的资讯精选
News news = createRelateNews(saveNewsDTO);
NewsInfo newsInfo = toNewsInfo(news.getId(), saveNewsDTO);
try {
IndexResponse resp = elasticsearchClient.index(c -> c.index(NewsInfo.INDEX_NAME).document(newsInfo).refresh(Refresh.True));
news.setNewsinfoId(resp.id());
newsMapper.updateNews(news);
} catch(IOException|ElasticsearchException e) {
log.error("新建全量资讯出错!", e);
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
}
return ResultObject.success();
}
private NewsInfo toNewsInfo(Long newsId, SaveNewsInfoDTO saveNewsDTO) {
NewsInfo newsInfo = saveNewsDTO.toNewsInfo();
newsInfo.setNewsId(newsId);
List<Long> industries = saveNewsDTO.getIndustries();
if (!ObjectUtils.isEmpty(industries)) {
List<Industry> allIndustry = industryMapper.queryAll();
Map<Long, Industry> industryMap = allIndustry.stream().collect(Collectors.toMap(Industry::getId, Function.identity()));
String industry = industries.stream().map(e -> industryMap.get(e)).map(Industry::getDisplayName).collect(Collectors.joining(";"));
newsInfo.setIndustry(industry);
}
SaveDraftTag tag = saveNewsDTO.getTag();
if (tag != null) {
if (tag.getSource() != null) {
Tag sourceTag = tagMapper.queryById(tag.getSource());
if (sourceTag != null) {
newsInfo.setSourcename(sourceTag.getName());
}
}
}
return newsInfo;
}
private void updateRelateNews(Long newsId, SaveNewsInfoDTO saveNewsDTO) {
News news = saveNewsDTO.toNews();
news.setId(newsId);
newsMapper.updateNews(news);
tagMapper.deleteNews(newsId);
industryMapper.deleteNews(newsId);
SaveDraftTag saveDraftTag = saveNewsDTO.getTag();
if (saveDraftTag != null) {
Long source = saveDraftTag.getSource();
if (source != null) {
tagMapper.saveNewsTagRel(newsId, source);
}
List<Long> fieldArr = saveDraftTag.getFieldArr();
if (fieldArr != null) {
for (Long field: fieldArr) {
tagMapper.saveNewsTagRel(newsId, field);
}
}
}
List<Long> industries = saveNewsDTO.getIndustries();
if (industries != null) {
for (Long industry: industries) {
tagMapper.saveNewsTagRel(newsId, industry);
}
}
}
private News createRelateNews(SaveNewsInfoDTO saveNewsInfoDTO) {
News news = saveNewsInfoDTO.toNews();
newsMapper.saveNews(news);
// 保存标签关系
try {
SaveDraftTag saveDraftTag = saveNewsInfoDTO.getTag();
if (saveDraftTag != null) {
Long source = saveDraftTag.getSource();
if (source != null) {
tagMapper.saveNewsTagRel(news.getId(), source);
}
// 频道标签多个批量插
List<Long> fieldArr = saveDraftTag.getFieldArr();
if (fieldArr != null) {
for (Long item : fieldArr) {
tagMapper.saveNewsTagRel(news.getId(), item);
}
}
}
} catch (Exception e) {
log.error("保存发布全量资讯关联标签出错!", e);
}
// 保存新闻行业分类关系
try {
List<Long> saveDraftIndustries = saveNewsInfoDTO.getIndustries();
if (!CollectionUtils.isEmpty(saveDraftIndustries)) {
for (Long industryId : saveDraftIndustries) {
industryMapper.saveNewsIndustryRel(news.getId(), industryId);
}
}
} catch (Exception e) {
log.error("保存发布新闻行业分类出错!", e);
}
return news;
}
public PageObject<NewsInfoVO> queryNewsInfo(String title, String content, String stockcode, Long sourcename, int page, int size,
Integer last, Integer current, String orderBy, String direction) {
if (StringUtils.hasText(orderBy)) {
switch (orderBy) {
case "publishTime": {
orderBy = "publish_time";
break;
}
case "updateTime": {
orderBy = "update_time";
break;
}
case "createTime": {
orderBy = "create_time";
break;
}
}
}
final String orderByField = orderBy;
int offset = 0;
if (current != null) {
offset = (Math.max(0, current - 1)) * size;
}
int from = offset;
long total = 0;
List<NewsInfo> newsInfoList = new ArrayList<>();
try {
Query deletedQuery = TermQuery.of(t -> t.field(NewsInfo.DELETED_ES_NAME).value(0L))._toQuery();
// BoolQuery boolQuery = BoolQuery.of(e -> e.filter(deletedQuery)); // QueryBuilders.bool().build()
List<Query> conditions = new ArrayList<>();
List<Query> filters = new ArrayList<>();
filters.add(deletedQuery);
if (!ObjectUtils.isEmpty(title)) {
Query titleQuery = MatchQuery.of(m -> m.field(NewsInfo.TITLE_ES_NAME).query(title))._toQuery(); // .analyzer("ik_max_word")
conditions.add(titleQuery);
}
if (!ObjectUtils.isEmpty(content)) {
Query summaryContentQuery = MultiMatchQuery.of(m -> m.fields(NewsInfo.CONTENT_ES_NAME, NewsInfo.SUMMARY_ES_NAME).query(content).operator(Operator.Or))._toQuery(); // .analyzer("ik_max_word")
conditions.add(summaryContentQuery);
}
if (sourcename != null) {
Tag sourcenameTag = tagMapper.queryById(sourcename);
if (sourcenameTag != null) {
Query sourcenameQuery = TermQuery.of(t -> t.field(NewsInfo.SOURCE_ES_NAME).value(sourcenameTag.getName()))._toQuery();
filters.add(sourcenameQuery);
}
}
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);
SearchResponse<NewsInfo> searchResp = elasticsearchClient.search(s -> s.index(NewsInfo.INDEX_NAME)
.from(from) // 分页参数
.size(size) // 分页参数
.sort(so -> so.field(f -> f.field("_score").order(SortOrder.Desc).field(orderByField).order(sortOrder))) // 排序字段
.query(resultQuery)
.highlight(h -> h.preTags("<font color='red'>")
.postTags("</font>")
.requireFieldMatch(true)
.fields(NewsInfo.SUMMARY_ES_NAME, hf -> hf.numberOfFragments(0))
.fields(NewsInfo.CONTENT_ES_NAME, hf -> hf.numberOfFragments(0))
.fields(NewsInfo.TITLE_ES_NAME, hf -> hf.numberOfFragments(0))), NewsInfo.class);
HitsMetadata<NewsInfo> hits = searchResp.hits();
total = hits.total().value();
for (Hit<NewsInfo> hit: hits.hits()) {
NewsInfo newsInfo = hit.source();
Map<String, List<String>> highlight = hit.highlight();
newsInfo.setTitle(highlight.get(NewsInfo.TITLE_ES_NAME) == null ? newsInfo.getTitle():highlight.get(NewsInfo.TITLE_ES_NAME).get(0));
newsInfo.setSummary(highlight.get(NewsInfo.SUMMARY_ES_NAME) == null ? newsInfo.getSummary():highlight.get(NewsInfo.SUMMARY_ES_NAME).get(0));
newsInfo.setContent(highlight.get(NewsInfo.CONTENT_ES_NAME) == null ? newsInfo.getContent():highlight.get(NewsInfo.CONTENT_ES_NAME).get(0));
newsInfo.setId(hit.id());
newsInfoList.add(newsInfo);
}
} catch (Exception e) {
log.error("搜索新闻异常!", e);
return PageObject.failedPage(500, "服务器错误,请联系系统管理员!");
}
PageObject<NewsInfoVO> pageObject = new PageObject<>();
pageObject.setTotal(Long.valueOf(total).intValue());
pageObject.setCode(200);
pageObject.setCurrent(page);
pageObject.setSize(Math.min(newsInfoList.size(), size));
if (CollectionUtils.isEmpty(newsInfoList)) {
log.info("搜索结果为空!");
pageObject.setData(new ArrayList<>());
return pageObject;
}
List<NewsInfoVO> resultList = new ArrayList<>();
for (NewsInfo newsInfo : newsInfoList) {
NewsInfoVO newsInfoVO = new NewsInfoVO(newsInfo);
resultList.add(newsInfoVO);
}
pageObject.setData(resultList);
return pageObject;
}
}

View File

@ -1,5 +1,6 @@
package com.jinrui.reference.core.service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@ -14,6 +15,7 @@ import org.slf4j.Logger;
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.core.JsonProcessingException;
@ -36,6 +38,7 @@ import com.jinrui.reference.core.model.entity.News;
import com.jinrui.reference.core.model.entity.NewsColumnRel;
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.Tag;
import com.jinrui.reference.core.model.vo.PageObject;
@ -49,6 +52,9 @@ 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.NewsVO;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.Refresh;
@Service
public class NewsService {
@ -59,17 +65,20 @@ public class NewsService {
private final ObjectMapper objectMapper;
private final TagMapper tagMapper;
private final IndustryMapper industryMapper;
private final ElasticsearchClient elasticsearchClient;
public NewsService(NewsMapper newsMapper,
ColumnMapper columnMapper,
ObjectMapper objectMapper,
TagMapper tagMapper,
IndustryMapper industryMapper) {
IndustryMapper industryMapper,
ElasticsearchClient elasticsearchClient) {
this.newsMapper = newsMapper;
this.columnMapper = columnMapper;
this.objectMapper = objectMapper;
this.tagMapper = tagMapper;
this.industryMapper = industryMapper;
this.elasticsearchClient = elasticsearchClient;
}
public ResultObject<Void> publish(long id, long editorId) {
@ -81,12 +90,14 @@ public class NewsService {
Integer status = news.getStatus();
if (status == 2) {
newsMapper.simpleUnpublish(id);
syncStatusToNewsInfo(news.getNewsinfoId(), 1);
return ResultObject.success();
}
Long draftId = news.getDraftId();
if (draftId == null) {
newsMapper.simplePublish(id, editorId);
syncStatusToNewsInfo(news.getNewsinfoId(), 2);
return ResultObject.success();
}
@ -100,6 +111,16 @@ public class NewsService {
return createPublish(editorId, saveNewsDTO);
}
private void syncStatusToNewsInfo(String newsInfoId, Integer status) {
NewsInfo publishedNewsInfo = new NewsInfo();
publishedNewsInfo.setStatus(status);
try {
elasticsearchClient.update(e -> e.index(NewsInfo.INDEX_NAME).refresh(Refresh.True).id(newsInfoId).doc(publishedNewsInfo), NewsInfo.class);
} catch(IOException e) {
log.error("资讯精选状态同步至全量资讯出错!", e);
}
}
public ResultObject<NewsDetailVO> detail(Long id) {
News news = newsMapper.getById(id);
if (news == null) {
@ -415,9 +436,49 @@ public class NewsService {
log.error("保存发布新闻标签出错!", e);
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
}
// 同步更新对应的全量资讯逻辑
try {
syncUpdateNewsInfo(saveNewsDTO);
} catch(IOException e) {
log.error("同步更新对应的全量资讯出错!", e);
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");
}
return ResultObject.success();
}
private void syncUpdateNewsInfo(SaveNewsDTO saveNewsDTO) throws IOException {
Long newsId = saveNewsDTO.getId();
if (newsId == null) {
return;
}
News news = newsMapper.getById(newsId);
String newsInfoId = news.getNewsinfoId();
if (ObjectUtils.isEmpty(newsInfoId)) {
return;
}
NewsInfo newsInfo = saveNewsDTO.toNewsInfo();
newsInfo.setStatus(2);
SaveDraftTag saveDraftTag = saveNewsDTO.getTag();
if (saveDraftTag != null && saveDraftTag.getSource() != null) {
Tag sourceTag = tagMapper.queryById(saveDraftTag.getSource());
if (sourceTag != null) {
newsInfo.setSourcename(sourceTag.getName());
}
}
List<Long> industries = saveNewsDTO.getIndustries();
if (!ObjectUtils.isEmpty(industries)) {
List<Industry> allIndustry = industryMapper.queryAll();
Map<Long, Industry> industryMap = allIndustry.stream().collect(Collectors.toMap(Industry::getId, Function.identity()));
String industry = industries.stream().map(e -> industryMap.get(e)).map(Industry::getDisplayName).collect(Collectors.joining(";"));
newsInfo.setIndustry(industry);
}
elasticsearchClient.update(e -> e.index(NewsInfo.INDEX_NAME).refresh(Refresh.True).id(newsInfoId).doc(newsInfo), NewsInfo.class);
}
public ResultObject<Void> saveDraft(SaveNewsDTO saveNewsDTO) {
Long id = saveNewsDTO.getId();
@ -461,6 +522,15 @@ public class NewsService {
}
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);
}
} catch (Exception e) {
log.error("删除新闻异常!", e);
return ResultObject.failed(500, "服务器错误,请联系系统管理员!");

View File

@ -15,6 +15,8 @@
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<elasticsearch.version>8.12.2</elasticsearch.version>
<jakartajson.version>2.0.1</jakartajson.version>
</properties>
<dependencies>
@ -22,12 +24,32 @@
<groupId>com.jinrui</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</exclusion>
<exclusion>
<artifactId>jakarta.json-api</artifactId>
<groupId>jakarta.json</groupId>
</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>
<version>${elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>${jakartajson.version}</version>
</dependency>
</dependencies>
<build>