仿牛客论坛项目

  • 一、Elasticsearch入门
    • 1.1 elasticsearch安装
    • 1.2 修改config目录下的elasticsearch.yml配置文件
    • 1.3 配置环境变量
    • 1.4 下载ik中文分词器
    • 1.5 下载postman
    • 1.6 启动es
    • 1.7 测试是否正确启动
    • 1.8 操作ES的RESTful语法
    • 1.9 es弹性搜索指南
    • 1.10 es中的数据类型
  • 二、 Spring整合Elasticsearch
    • 2.1 导入依赖
    • 2.2 修改配置文件
    • 2.3 修改主启动类
    • 2.4 实体类添加es注解
    • 2.5 数据操作
      • DiscussPostRepository
    • 2.6 测试
  • 三、开发社区搜索功能
    • 3.1 业务层
      • ElasticSearchService(封装对es的增删改查操作)
    • 3.2 控制层
      • DiscussPostController
      • CommentController
      • SearchController
    • 3.3 新增事件
      • EventConsumer
    • 3.4 静态资源
      • index.html
      • serch.html
    • 3.4 测试

一、Elasticsearch入门

1.1 elasticsearch安装

https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.4.3.zip

  • 下载后直接解压

1.2 修改config目录下的elasticsearch.yml配置文件

1.3 配置环境变量

  • 把对应的bin目录配置到环境变量

1.4 下载ik中文分词器

https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.4.3/elasticsearch-analysis-ik-6.4.3.zip

  • 下载之后解压到es安装目录下的plugins目录下的ik(自己建)目录下
  • 如果需要引入自己建的字典,则自己建一个dic文件,把需要的新词加入进去,然后在下面文件引入即可

1.5 下载postman

https://www.getpostman.com

1.6 启动es

1.7 测试是否正确启动


1.8 操作ES的RESTful语法

1.9 es弹性搜索指南

https://www.elastic.co/guide/en/elasticsearch/reference/6.4/index.html

1.10 es中的数据类型

https://www.elastic.co/guide/en/elasticsearch/reference/6.4/mapping-types.html

二、 Spring整合Elasticsearch

2.1 导入依赖

 <!--整合elasticsearch--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency>

2.2 修改配置文件

# ElasticsearchProperties
# 集群名
spring.data.elasticsearch.cluster-name=nowcoder
# tcp端口:9300, http访问端口:9200
spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300

2.3 修改主启动类

  • 避免es和redis同时依赖netty起冲突
@SpringBootApplication
@MapperScan("com.nowcoder.community.mapper")
public class CommunityApplication {@PostConstructpublic void init() {// 解决netty启动冲突问题// see Netty4Utils.setAvailableProcessors()System.setProperty("es.set.netty.runtime.available.processors", "false");}public static void main(String[] args) {SpringApplication.run(CommunityApplication.class, args);}}

2.4 实体类添加es注解

  • 在程序启动时会自动在es中创建索引
@Data
//index必须为lowercase不然会报错 index:类似mysql中的数据库,type:类似mysql中的表,shards:分片(将数据分成几片),replicas:副本(3份)
@Document(indexName = "discusspost", type = "_doc", shards = 6, replicas = 3)
public class DiscussPost {/*** 自增主键,插入数据后将自增主键设置到对象中*/@TableId(type = IdType.AUTO)@Idprivate Integer id;@Field(type = FieldType.Integer)private Integer userId;//文本类型,将对应的内容拆分成最多的词,搜索时搜索最常见的分词即可@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")private String title;@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")private String content;//0-普通; 1-置顶;@Field(type = FieldType.Integer)private Integer type;//0-正常; 1-精华; 2-拉黑;@Field(type = FieldType.Integer)private Integer status;@Field(type = FieldType.Date)private Date createTime;@Field(type = FieldType.Integer)private Integer commentCount;@Field(type = FieldType.Double)private Double score;}

2.5 数据操作

DiscussPostRepository

@Repository
public interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost, Integer> {}

2.6 测试

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class ElasticsearchTests {@Resourceprivate DiscussPostMapper discussPostMapper;@Resourceprivate DiscussPostService discussPostService;@Resourceprivate DiscussPostRepository discussRepository;@Resourceprivate ElasticsearchTemplate elasticTemplate;/*** 每次添加单条数据*/@Testpublic void testInsert() {discussRepository.save(discussPostMapper.selectById(241));discussRepository.save(discussPostMapper.selectById(242));discussRepository.save(discussPostMapper.selectById(243));}/*** 每次添加多条数据*/@Testpublic void testInsertList() {discussRepository.saveAll(discussPostService.findDiscussPosts(101, 0, 100));discussRepository.saveAll(discussPostService.findDiscussPosts(102, 0, 100));discussRepository.saveAll(discussPostService.findDiscussPosts(103, 0, 100));discussRepository.saveAll(discussPostService.findDiscussPosts(111, 0, 100));discussRepository.saveAll(discussPostService.findDiscussPosts(112, 0, 100));discussRepository.saveAll(discussPostService.findDiscussPosts(131, 0, 100));discussRepository.saveAll(discussPostService.findDiscussPosts(132, 0, 100));discussRepository.saveAll(discussPostService.findDiscussPosts(133, 0, 100));discussRepository.saveAll(discussPostService.findDiscussPosts(134, 0, 100));}/*** 测试更新*/@Testpublic void testUpdate() {DiscussPost post = discussPostMapper.selectById(231);post.setContent("我是新人,使劲灌水.");discussRepository.save(post);}/*** 测试删除*/@Testpublic void testDelete() {// discussRepository.deleteById(231);discussRepository.deleteAll();}/*** 测试查询*/@Testpublic void testSearchByRepository() {SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "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(0, 10)).withHighlightFields(new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")).build();// elasticTemplate.queryForPage(searchQuery, class, SearchResultMapper)// 底层获取得到了高亮显示的值, 但是没有返回.Page<DiscussPost> page = discussRepository.search(searchQuery);System.out.println(page.getTotalElements());System.out.println(page.getTotalPages());System.out.println(page.getNumber());System.out.println(page.getSize());for (DiscussPost post : page) {System.out.println(post);}}@Testpublic void testSearchByTemplate() {SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "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(0, 10)).withHighlightFields(new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")).build();Page<DiscussPost> page = 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());}});System.out.println(page.getTotalElements());System.out.println(page.getTotalPages());System.out.println(page.getNumber());System.out.println(page.getSize());for (DiscussPost post : page) {System.out.println(post);}}}
  • 测试testinsert()方法和testInsertList()方法

  • GET: localhost:9200/discusspost/_search: 查询discusspost索引下的文档

  • 查询指定的文档数据

  • 调用修改方法修改上面这条数据的content

  • 测试删除方法

三、开发社区搜索功能

3.1 业务层

ElasticSearchService(封装对es的增删改查操作)

@Service
public class ElasticsearchService {@Resourceprivate DiscussPostRepository discussRepository;@Resourceprivate ElasticsearchTemplate elasticTemplate;public void saveDiscussPost(DiscussPost post) {discussRepository.save(post);}public void deleteDiscussPost(int id) {discussRepository.deleteById(id);}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());}});}}

3.2 控制层

DiscussPostController

 @PostMapping("/add")@ResponseBodypublic String addDiscussPost(String title, String content) {User user = UserThreadLocal.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());post.setType(0);post.setStatus(0);post.setCommentCount(0);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, "发布成功!");}

CommentController

@PostMapping("/add/{discussPostId}")public String addComment(@PathVariable("discussPostId") int discussPostId, Comment comment) {comment.setUserId(UserThreadLocal.getUser().getId());comment.setStatus(0);comment.setCreateTime(new Date());commentService.addComment(comment);// 触发评论事件Event event = new Event().setTopic(TOPIC_COMMENT).setUserId(UserThreadLocal.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;}

SearchController

@Controller
public class SearchController implements CommunityConstant {@Resourceprivate ElasticsearchService elasticsearchService;@Resourceprivate UserService userService;@Resourceprivate LikeService likeService;// search?keyword=xxx@GetMapping("/search")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";}}

3.3 新增事件

EventConsumer

 // 消费发帖事件@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);}

3.4 静态资源

index.html

<!-- 搜索 --><form class="form-inline my-2 my-lg-0" method="get" th:action="@{/search}"><input class="form-control mr-sm-2" type="search" aria-label="Search" name="keyword" th:value="${keyword}"/><button class="btn btn-outline-light my-2 my-sm-0" type="submit">搜索</button></form>

serch.html

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><link rel="icon" href="https://static.nowcoder.com/images/logo_87_87.png"/><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous"><link rel="stylesheet" th:href="@{/css/global.css}" /><title>牛客网-搜索结果</title>
</head>
<body>
<div class="nk-container"><!-- 头部 --><header class="bg-dark sticky-top" th:replace="index::header"><div class="container"><!-- 导航 --><nav class="navbar navbar-expand-lg navbar-dark"><!-- logo --><a class="navbar-brand" href="#"></a><button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><!-- 功能 --><div class="collapse navbar-collapse" id="navbarSupportedContent"><ul class="navbar-nav mr-auto"><li class="nav-item ml-3 btn-group-vertical"><a class="nav-link" href="../index.html">首页</a></li><li class="nav-item ml-3 btn-group-vertical"><a class="nav-link position-relative" href="letter.html">消息<span class="badge badge-danger">12</span></a></li><li class="nav-item ml-3 btn-group-vertical"><a class="nav-link" href="register.html">注册</a></li><li class="nav-item ml-3 btn-group-vertical"><a class="nav-link" href="login.html">登录</a></li><li class="nav-item ml-3 btn-group-vertical dropdown"><a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><img src="http://images.nowcoder.com/head/1t.png" class="rounded-circle" style="width:30px;"/></a><div class="dropdown-menu" aria-labelledby="navbarDropdown"><a class="dropdown-item text-center" href="profile.html">个人主页</a><a class="dropdown-item text-center" href="setting.html">账号设置</a><a class="dropdown-item text-center" href="login.html">退出登录</a><div class="dropdown-divider"></div><span class="dropdown-item text-center text-secondary">nowcoder</span></div></li></ul><!-- 搜索 --><form class="form-inline my-2 my-lg-0" action="search.html"><input class="form-control mr-sm-2" type="search" aria-label="Search" /><button class="btn btn-outline-light my-2 my-sm-0" type="submit">搜索</button></form></div></nav></div></header><!-- 内容 --><div class="main"><div class="container"><h6><b class="square"></b> 相关帖子</h6><!-- 帖子列表 --><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}">备战<em>春招</em>,面试刷题跟他复习,一个月全搞定!</a></h6><div class="mb-3" th:utext="${map.post.content}">金三银四的金三已经到了,你还沉浸在过年的喜悦中吗? 如果是,那我要让你清醒一下了:目前大部分公司已经开启了内推,正式网申也将在3月份陆续开始,金三银四,<em>春招</em>的求职黄金时期已经来啦!!! 再不准备,作为19应届生的你可能就找不到工作了。。。作为20届实习生的你可能就找不到实习了。。。 现阶段时间紧,任务重,能做到短时间内快速提升的也就只有算法了, 那么算法要怎么复习?重点在哪里?常见笔试面试算法题型和解题思路以及最优代码是怎样的? 跟左程云老师学算法,不仅能解决以上所有问题,还能在短时间内得到最大程度的提升!!!</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')}">2019-04-15 15:32:18</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><!-- 分页 --><nav class="mt-5" th:replace="index::pagination"><ul class="pagination justify-content-center"><li class="page-item"><a class="page-link" href="#">首页</a></li><li class="page-item disabled"><a class="page-link" href="#">上一页</a></li><li class="page-item active"><a class="page-link" href="#">1</a></li><li class="page-item"><a class="page-link" href="#">2</a></li><li class="page-item"><a class="page-link" href="#">3</a></li><li class="page-item"><a class="page-link" href="#">4</a></li><li class="page-item"><a class="page-link" href="#">5</a></li><li class="page-item"><a class="page-link" href="#">下一页</a></li><li class="page-item"><a class="page-link" href="#">末页</a></li></ul></nav></div></div><!-- 尾部 --><footer class="bg-dark" th:replace="index::footer"><div class="container"><div class="row"><!-- 二维码 --><div class="col-4 qrcode"><img src="https://uploadfiles.nowcoder.com/app/app_download.png" class="img-thumbnail" style="width:136px;" /></div><!-- 公司信息 --><div class="col-8 detail-info"><div class="row"><div class="col"><ul class="nav"><li class="nav-item"><a class="nav-link text-light" href="#">关于我们</a></li><li class="nav-item"><a class="nav-link text-light" href="#">加入我们</a></li><li class="nav-item"><a class="nav-link text-light" href="#">意见反馈</a></li><li class="nav-item"><a class="nav-link text-light" href="#">企业服务</a></li><li class="nav-item"><a class="nav-link text-light" href="#">联系我们</a></li><li class="nav-item"><a class="nav-link text-light" href="#">免责声明</a></li><li class="nav-item"><a class="nav-link text-light" href="#">友情链接</a></li></ul></div></div><div class="row"><div class="col"><ul class="nav btn-group-vertical company-info"><li class="nav-item text-white-50">公司地址:北京市朝阳区大屯路东金泉时代3-2708北京牛客科技有限公司</li><li class="nav-item text-white-50">联系方式:010-60728802(电话)&nbsp;&nbsp;&nbsp;&nbsp;admin@nowcoder.com</li><li class="nav-item text-white-50">牛客科技©2018 All rights reserved</li><li class="nav-item text-white-50">京ICP备14055008号-4 &nbsp;&nbsp;&nbsp;&nbsp;<img src="http://static.nowcoder.com/company/images/res/ghs.png" style="width:18px;" />京公网安备 11010502036488号</li></ul></div></div></div></div></div></footer>
</div><script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" crossorigin="anonymous"></script>
<script th:src="@{/js/global.js}"></script>
</body>
</html>

3.4 测试

  • 每次发帖和对帖子评论都会使用kafka异步更新es中对应的数据,我们直接新增一个帖子,然后搜索我们刚创建的帖子


仿牛客论坛项目(4)相关推荐

  1. 仿牛客论坛项目(下)

    代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(上) 仿牛客论坛项目 15.kafka 1.阻塞队列 2.Kafka入门 简介 术语解释 下载 配置 ...

  2. 仿牛客论坛项目(上)

    代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(下) 仿牛客论坛项目上 1. Spring 在测试类中使用Spring环境 @Primary的作用 @ ...

  3. 仿牛客论坛项目(3)

    仿牛客论坛项目 一.阻塞队列 1.1 测试 二.kafka入门 2.1 kafka下载 2.2 测试 三.Spring整合kafka 3.1 引入依赖 3.2 修改配置文件 3.3 测试 四.发布系统 ...

  4. 仿牛客论坛项目(5)

    仿牛客论坛项目 一.SpringSecurity入门案例 1.1 添加依赖 1.2 配置文件 1.3 工具类 CommunityUtil 1.4 配置类 SecurityConfig 1.5 实体类 ...

  5. 仿牛客论坛项目全面大总结

    1.核心功能: - 发帖.评论.私信.转发: - 点赞.关注.通知.搜索: - 权限.统计.调度.监控: 2.核心技术: - Spring Boot.SSM - Redis.Kafka.Elastic ...

  6. 仿牛客论坛项目之修改用户头像

    前言: 在项目最开始的时候,我们默认从牛客网的静态资源库中选择一张照片作为用户的头像,但在实际开发中,我们还要考虑用户可以自己设置头像. 思路: 上传文件(上传到硬盘服务器上 或者 上传到云服务器上, ...

  7. SpringBoot仿牛客论坛项目实战

    Community 论坛项目 转载请附带原文链接: 1. 环境搭建与技术栈说明 1.0 项目架构图 1.1 技术要求 熟悉快速开发框架:SpringBoot2.3.x 整合 SpringMVC + M ...

  8. (仿牛客论坛项目)01 - 开发社区首页

    文章目录 前言 1.做项目的步骤 2.开发社区首页功能分步 2.1 User 类 2.2 UserMapper 接口 2.3 UserMapper 映射文件 2.4 编写测试类 3.开发社区首页,显示 ...

  9. 仿牛客论坛项目部署总结

最新文章

  1. ps制作20种特效文字_ps技巧:给照片制作特效(刀光剑影)
  2. 学python语言用什么软件-Python是什么?学习Python用什么编译器?
  3. Google Guava Cache 移除监听器
  4. show()和exec()的区别
  5. MyEclipse Tomcat 超链接传参中文乱码
  6. 如何解决分布式系统中的“幽灵复现”?
  7. 注释里的诅咒:哪种语言遭受最多的咒骂?
  8. 华为内部存储转sd卡_华为tit al00怎么将手机存储内容转移到sd卡
  9. Android资料之-EditText中的inputType
  10. Ubuntu 第2章 基本命令和文件系统
  11. 同程旅行 IAST 实践
  12. display属性详解
  13. linux下 OOB 炸弹的制作
  14. 前端点击图片将跳出显示框显示图片
  15. 受用一生的高效 PyCharm 使用技巧 !
  16. java报错Error attempting to get column ‘XXX’ from result set. Cause: java.sql.怎么解决
  17. 如何选择数据拆分方法:不同数据拆分方法的优缺点及原因
  18. Linux命令----压缩解压缩
  19. Mac删除键的5种用法
  20. 虚拟机安装Linux系列教材 (二)- 关闭Hiper-V

热门文章

  1. 能忍到第5个不笑的是就是高人
  2. CQUPT Java平时作业02
  3. Java18线程安全
  4. 厉害了 全靠经典之作-Java编程思想,把你教的明明白白
  5. Python实现自动化给视频实时加字幕,软件已打包!
  6. 2023年浙江省职业院校技能大赛大数据技术与应用专业样题
  7. 计算机考试桌贴,Word2010邮件合并一页打印多条记录(考务数据、准考证号、桌贴、考试通知单)...
  8. 【课件制作软件】Focusky教程 | 关于FS字体的部分问题总汇以及解决办法
  9. 捷联惯导-坐标系-观测值补偿-对准-编排-时间更新-测量更新
  10. 曲线曲面的基本理论2之曲线曲面表示方法