项目-20-开发社区搜索功能
生活随笔
收集整理的這篇文章主要介紹了
项目-20-开发社区搜索功能
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
開發社區搜索功能
搜索服務:
-
將帖子保存至Elasticsearch服務器。
-
從Elasticsearch服務器刪除帖子。
-
從Elasticsearch服務器搜索帖子。
發布事件:
-
發布帖子時,將帖子異步的提交到Elasticsearch服務器。
-
增加評論時,將帖子異步的提交到Elasticsearch服務器。
-
在消費組件中增加一個方法,消費帖子發布事件。
顯示結果:
- 在控制器中處理搜索請求,在HTML上顯示搜索結果。
1.ElasticsearchService
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; import org.springframework.data.elasticsearch.core.SearchResultMapper; import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage; import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.data.elasticsearch.core.query.SearchQuery; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Date; import java.util.List;@Service public class ElasticsearchService {@Autowiredprivate DiscussPostRepository discussRepository;@Autowiredprivate ElasticsearchTemplate elasticTemplate;// 向Elasticsearch存入帖子public void saveDiscussPost(DiscussPost post) {discussRepository.save(post);}// 刪除Elasticsearch中的帖子public void deleteDiscussPost(int id) {discussRepository.deleteById(id);}// 查詢方法, keyword:檢索關鍵字 current:當前頁 limit:每頁顯示多少public Page<DiscussPost> searchDiscussPost(String keyword, int current, int limit) {SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "content")).withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC)).withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC)).withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC)).withPageable(PageRequest.of(current, limit)).withHighlightFields(new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")).build();return elasticTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {@Overridepublic <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {SearchHits hits = response.getHits();if (hits.getTotalHits() <= 0) {return null;}List<DiscussPost> list = new ArrayList<>();for (SearchHit hit : hits) {DiscussPost post = new DiscussPost();String id = hit.getSourceAsMap().get("id").toString();post.setId(Integer.valueOf(id));String userId = hit.getSourceAsMap().get("userId").toString();post.setUserId(Integer.valueOf(userId));String title = hit.getSourceAsMap().get("title").toString();post.setTitle(title);String content = hit.getSourceAsMap().get("content").toString();post.setContent(content);String status = hit.getSourceAsMap().get("status").toString();post.setStatus(Integer.valueOf(status));String createTime = hit.getSourceAsMap().get("createTime").toString();post.setCreateTime(new Date(Long.valueOf(createTime)));String commentCount = hit.getSourceAsMap().get("commentCount").toString();post.setCommentCount(Integer.valueOf(commentCount));// 處理高亮顯示的結果HighlightField titleField = hit.getHighlightFields().get("title");if (titleField != null) {post.setTitle(titleField.getFragments()[0].toString());}HighlightField contentField = hit.getHighlightFields().get("content");if (contentField != null) {post.setContent(contentField.getFragments()[0].toString());}list.add(post);}return new AggregatedPageImpl(list, pageable,hits.getTotalHits(), response.getAggregations(), response.getScrollId(), hits.getMaxScore());}});} }2.DiscussPostController
帖子發布成功后,觸發發帖時間,向Elasticsearch添加帖子
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import java.util.*;@Controller @RequestMapping("/discuss") public class DiscussPostController implements CommunityConstant {@Autowiredprivate DiscussPostService discussPostService;@Autowiredprivate HostHolder hostHolder;@Autowiredprivate UserService userService;@Autowiredprivate CommentService commentService;@Autowiredprivate LikeService likeService;@Autowiredprivate EventProducer eventProducer;@RequestMapping(path = "/add", method = RequestMethod.POST)@ResponseBodypublic String addDiscussPost(String title, String content) {User user = hostHolder.getUser();if (user == null) {return CommunityUtil.getJSONString(403, "你還沒有登錄哦!");}DiscussPost post = new DiscussPost();post.setUserId(user.getId());post.setTitle(title);post.setContent(content);post.setCreateTime(new Date());discussPostService.addDiscussPost(post);// 觸發發帖事件Event event = new Event().setTopic(TOPIC_PUBLISH).setUserId(user.getId()).setEntityType(ENTITY_TYPE_POST).setEntityId(post.getId());eventProducer.fireEvent(event);// 報錯的情況,將來統一處理.return CommunityUtil.getJSONString(0, "發布成功!");} }3.CommentController
在給帖子增加評論后,觸發事件,存入Elasticsearch
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import java.util.Date;@Controller @RequestMapping("/comment") public class CommentController implements CommunityConstant {@Autowiredprivate CommentService commentService;@Autowiredprivate HostHolder hostHolder;@Autowiredprivate EventProducer eventProducer;@Autowiredprivate DiscussPostService discussPostService;@RequestMapping(path = "/add/{discussPostId}", method = RequestMethod.POST)public String addComment(@PathVariable("discussPostId") int discussPostId, Comment comment) {comment.setUserId(hostHolder.getUser().getId());comment.setStatus(0);comment.setCreateTime(new Date());commentService.addComment(comment);// 觸發評論事件Event event = new Event().setTopic(TOPIC_COMMENT).setUserId(hostHolder.getUser().getId()).setEntityType(comment.getEntityType()).setEntityId(comment.getEntityId()).setData("postId", discussPostId);if (comment.getEntityType() == ENTITY_TYPE_POST) {DiscussPost target = discussPostService.findDiscussPostById(comment.getEntityId());event.setEntityUserId(target.getUserId());} else if (comment.getEntityType() == ENTITY_TYPE_COMMENT) {Comment target = commentService.findCommentById(comment.getEntityId());event.setEntityUserId(target.getUserId());}eventProducer.fireEvent(event);if (comment.getEntityType() == ENTITY_TYPE_POST) {// 觸發發帖事件event = new Event().setTopic(TOPIC_PUBLISH).setUserId(comment.getUserId()).setEntityType(ENTITY_TYPE_POST).setEntityId(discussPostId);eventProducer.fireEvent(event);}return "redirect:/discuss/detail/" + discussPostId;} }4.EventConsumer
消費發帖事件
import org.apache.kafka.clients.consumer.ConsumerRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; import java.util.Date; import java.util.HashMap; import java.util.Map;@Component public class EventConsumer implements CommunityConstant {private static final Logger logger = LoggerFactory.getLogger(EventConsumer.class);@Autowiredprivate MessageService messageService;@Autowiredprivate DiscussPostService discussPostService;@Autowiredprivate ElasticsearchService elasticsearchService;// 消費發帖事件@KafkaListener(topics = {TOPIC_PUBLISH})public void handlePublishMessage(ConsumerRecord record) {if (record == null || record.value() == null) {logger.error("消息的內容為空!");return;}Event event = JSONObject.parseObject(record.value().toString(), Event.class);if (event == null) {logger.error("消息格式錯誤!");return;}DiscussPost post = discussPostService.findDiscussPostById(event.getEntityId());elasticsearchService.saveDiscussPost(post);} }5.SearchController
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;@Controller public class SearchController implements CommunityConstant {@Autowiredprivate ElasticsearchService elasticsearchService;@Autowiredprivate UserService userService; // 展示帖子的作者@Autowiredprivate LikeService likeService; // 展示帖子點贊的數量// search?keyword=xxx@RequestMapping(path = "/search", method = RequestMethod.GET)public String search(String keyword, Page page, Model model) {// 搜索帖子org.springframework.data.domain.Page<DiscussPost> searchResult =elasticsearchService.searchDiscussPost(keyword, page.getCurrent() - 1, page.getLimit());// 聚合數據List<Map<String, Object>> discussPosts = new ArrayList<>();if (searchResult != null) {for (DiscussPost post : searchResult) {Map<String, Object> map = new HashMap<>();// 帖子map.put("post", post);// 作者map.put("user", userService.findUserById(post.getUserId()));// 點贊數量map.put("likeCount", likeService.findEntityLikeCount(ENTITY_TYPE_POST, post.getId()));discussPosts.add(map);}}model.addAttribute("discussPosts", discussPosts);model.addAttribute("keyword", keyword);// 分頁信息page.setPath("/search?keyword=" + keyword);page.setRows(searchResult == null ? 0 : (int) searchResult.getTotalElements());return "/site/search";} }6.search.html
<!-- 帖子列表 --><ul class="list-unstyled mt-4"><li class="media pb-3 pt-3 mb-3 border-bottom" th:each="map:${discussPosts}"><img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" alt="用戶頭像" style="width:50px;height:50px;"><div class="media-body"><h6 class="mt-0 mb-3"><a th:href="@{|/discuss/detail/${map.post.id}|}" th:utext="${map.post.title}">標題</a></h6><div class="mb-3" th:utext="${map.post.content}">內容</div><div class="text-muted font-size-12"><u class="mr-3" th:utext="${map.user.username}">作者</u>發布于 <b th:text="${#dates.format(map.post.createTime,'yyyy-MM-dd HH:mm:ss')}">時間</b><ul class="d-inline float-right"><li class="d-inline ml-2">贊 <i th:text="${map.likeCount}">11</i></li><li class="d-inline ml-2">|</li><li class="d-inline ml-2">回復 <i th:text="${map.post.commentCount}">7</i></li></ul></div></div></li></ul>總結
以上是生活随笔為你收集整理的项目-20-开发社区搜索功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017第二十三届上海国际加工包装展览会
- 下一篇: 机器学习实验(十):基于WiFi fin