diff --git a/doc/yml/nacos_config_export_20200602203745.zip b/doc/yml/nacos_config_export_20200602214520.zip
similarity index 65%
rename from doc/yml/nacos_config_export_20200602203745.zip
rename to doc/yml/nacos_config_export_20200602214520.zip
index bdf8b71..036063c 100644
Binary files a/doc/yml/nacos_config_export_20200602203745.zip and b/doc/yml/nacos_config_export_20200602214520.zip differ
diff --git a/novel-book/book-service/pom.xml b/novel-book/book-service/pom.xml
index b0e42f1..a7905d5 100644
--- a/novel-book/book-service/pom.xml
+++ b/novel-book/book-service/pom.xml
@@ -41,9 +41,6 @@
-
-
-
diff --git a/novel-book/book-service/src/main/java/com/java2nb/novel/book/controller/BookController.java b/novel-book/book-service/src/main/java/com/java2nb/novel/book/controller/BookController.java
index f4d137b..b2bc38d 100644
--- a/novel-book/book-service/src/main/java/com/java2nb/novel/book/controller/BookController.java
+++ b/novel-book/book-service/src/main/java/com/java2nb/novel/book/controller/BookController.java
@@ -13,6 +13,7 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
@@ -34,6 +35,8 @@ public class BookController {
private final BookService bookService;
+ private final RabbitTemplate rabbitTemplate;
+
/**
* 小说分类列表查询接口
*/
@@ -67,7 +70,7 @@ public class BookController {
@ApiOperation("点击量新增接口")
@PostMapping("addVisitCount")
public ResultBean addVisitCount(@ApiParam("小说ID") @RequestParam("bookId") Long bookId) {
- bookService.addVisitCount(bookId, 1);
+ rabbitTemplate.convertAndSend("ADD-BOOK-VISIT-EXCHANGE", null, bookId);
return ResultBean.ok();
}
diff --git a/novel-book/book-service/src/main/java/com/java2nb/novel/book/listener/BookVisitAddListener.java b/novel-book/book-service/src/main/java/com/java2nb/novel/book/listener/BookVisitAddListener.java
new file mode 100644
index 0000000..7a0fb8a
--- /dev/null
+++ b/novel-book/book-service/src/main/java/com/java2nb/novel/book/listener/BookVisitAddListener.java
@@ -0,0 +1,70 @@
+package com.java2nb.novel.book.listener;
+import com.java2nb.novel.book.service.BookService;
+import com.java2nb.novel.common.cache.CacheKey;
+import com.java2nb.novel.common.cache.CacheService;
+import com.java2nb.novel.common.utils.Constants;
+import com.rabbitmq.client.Channel;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * @author 11797
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class BookVisitAddListener {
+
+ private final BookService bookService;
+
+ private final CacheService cacheService;
+
+
+ private final RedissonClient redissonClient;
+
+
+
+
+ /**
+ * 更新数据库
+ * 流量削峰,每本小说累积10个点击更新一次
+ */
+ @SneakyThrows
+ @RabbitListener(queues = {"UPDATE-DB-QUEUE"})
+ public void updateDb(Long bookId, Channel channel, Message message) {
+
+ log.debug("收到更新数据库消息:" + bookId);
+ RLock lock = redissonClient.getLock("addVisitCountToDb");
+ lock.lock();
+ try {
+ Integer visitCount = (Integer) cacheService.getObject(CacheKey.BOOK_ADD_VISIT_COUNT + bookId);
+ if (visitCount == null) {
+ visitCount = 0;
+ }
+ cacheService.setObject(CacheKey.BOOK_ADD_VISIT_COUNT + bookId, ++visitCount);
+ if (visitCount >= Constants.ADD_MAX_VISIT_COUNT) {
+ bookService.addVisitCount(bookId, visitCount);
+ cacheService.del(CacheKey.BOOK_ADD_VISIT_COUNT + bookId);
+ }
+ }catch (Exception e){
+ log.error("更新数据库失败"+bookId);
+ }
+
+ lock.unlock();
+
+ Thread.sleep(1000 * 2);
+
+
+
+ }
+
+
+
+}
diff --git a/novel-book/book-service/src/main/resources/bootstrap.yml b/novel-book/book-service/src/main/resources/bootstrap.yml
index 8fae4a1..c57a47c 100644
--- a/novel-book/book-service/src/main/resources/bootstrap.yml
+++ b/novel-book/book-service/src/main/resources/bootstrap.yml
@@ -3,3 +3,15 @@ spring:
name: book-service
profiles:
active: dev
+
+ cloud:
+ nacos:
+ config:
+ ext‐config[0]:
+ data‐id: novel-redis.yml
+ group: novel-common
+ refresh: true
+ ext‐config[1]:
+ data‐id: novel-rabbitmq.yml
+ group: novel-common
+ refresh: true
\ No newline at end of file
diff --git a/novel-common/pom.xml b/novel-common/pom.xml
index 19efa4f..81102e8 100644
--- a/novel-common/pom.xml
+++ b/novel-common/pom.xml
@@ -48,6 +48,12 @@
spring-boot-starter-redis
+
+ org.redisson
+ redisson-spring-boot-starter
+ ${redisson.version}
+
+
mysql
mysql-connector-java
@@ -105,6 +111,11 @@
feign-httpclient
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
+
diff --git a/novel-common/src/main/java/com/java2nb/novel/common/config/RabbitConfig.java b/novel-common/src/main/java/com/java2nb/novel/common/config/RabbitConfig.java
new file mode 100644
index 0000000..d66decd
--- /dev/null
+++ b/novel-common/src/main/java/com/java2nb/novel/common/config/RabbitConfig.java
@@ -0,0 +1,62 @@
+package com.java2nb.novel.common.config;
+
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.FanoutExchange;
+import org.springframework.amqp.core.Queue;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author 11797
+ */
+@Configuration
+@ConditionalOnProperty(prefix = "spring.rabbitmq", name = "host", matchIfMissing = false)
+public class RabbitConfig {
+
+
+ /**
+ * 更新数据库队列
+ */
+ @Bean
+ public Queue updateDbQueue() {
+ return new Queue("UPDATE-DB-QUEUE", true);
+ }
+
+ /**
+ * 更新数据库队列
+ */
+ @Bean
+ public Queue updateEsQueue() {
+ return new Queue("UPDATE-ES-QUEUE", true);
+ }
+
+
+ /**
+ * 增加点击量交换机
+ */
+ @Bean
+ public FanoutExchange addVisitExchange() {
+ return new FanoutExchange("ADD-BOOK-VISIT-EXCHANGE");
+ }
+
+ /**
+ * 更新搜索引擎队列绑定到增加点击量交换机中
+ */
+ @Bean
+ public Binding updateEsBinding() {
+
+ return BindingBuilder.bind(updateEsQueue()).to(addVisitExchange());
+ }
+
+ /**
+ * 更新数据库绑定到增加点击量交换机中
+ */
+ @Bean
+ public Binding updateDbBinding() {
+ return BindingBuilder.bind(updateDbQueue()).to(addVisitExchange());
+ }
+
+
+}
diff --git a/novel-common/src/main/resources/application-common.yml b/novel-common/src/main/resources/application-common.yml
index 7ae9510..53c62fd 100644
--- a/novel-common/src/main/resources/application-common.yml
+++ b/novel-common/src/main/resources/application-common.yml
@@ -19,6 +19,12 @@ feign:
httpclient:
enabled: true
+#关掉mq的健康检查,防止某些没有用到mq的服务启动报错,个别服务如需mq监控,单独开启
+management:
+ health:
+ rabbit:
+ enabled: false
+
diff --git a/novel-search/src/main/java/com/java2nb/novel/search/listener/BookVisitAddListener.java b/novel-search/src/main/java/com/java2nb/novel/search/listener/BookVisitAddListener.java
new file mode 100644
index 0000000..e7b6136
--- /dev/null
+++ b/novel-search/src/main/java/com/java2nb/novel/search/listener/BookVisitAddListener.java
@@ -0,0 +1,67 @@
+package com.java2nb.novel.search.listener;
+
+import com.java2nb.novel.book.entity.Book;
+import com.java2nb.novel.common.cache.CacheKey;
+import com.java2nb.novel.common.cache.CacheService;
+import com.java2nb.novel.search.feign.BookFeignClient;
+import com.java2nb.novel.search.service.SearchService;
+import com.rabbitmq.client.Channel;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * @author 11797
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class BookVisitAddListener {
+
+
+ private final CacheService cacheService;
+
+ private final SearchService searchService;
+
+ private final RedissonClient redissonClient;
+
+ private final BookFeignClient bookFeignClient;
+
+
+
+
+
+ /**
+ * 更新搜索引擎
+ * 流量削峰,每本小说1个小时更新一次
+ */
+ @RabbitListener(queues = {"UPDATE-ES-QUEUE"})
+ public void updateEs(Long bookId, Channel channel, Message message) {
+
+ log.debug("收到更新搜索引擎消息:" + bookId);
+ RLock lock = redissonClient.getLock("addVisitCountToEs");
+ lock.lock();
+ if (cacheService.get(CacheKey.ES_IS_UPDATE_VISIT + bookId) == null) {
+ cacheService.set(CacheKey.ES_IS_UPDATE_VISIT + bookId, "1", 60 * 60);
+ try {
+ Thread.sleep(1000 * 5);
+ Book book = bookFeignClient.queryBookById(bookId);
+ searchService.importToEs(book);
+ }catch (Exception e){
+ cacheService.del(CacheKey.ES_IS_UPDATE_VISIT + bookId);
+ log.error("更新搜索引擎失败"+bookId);
+ }
+
+ }
+ lock.unlock();
+
+
+ }
+
+
+}
diff --git a/novel-search/src/main/java/com/java2nb/novel/search/schedule/BookToEsSchedule.java b/novel-search/src/main/java/com/java2nb/novel/search/schedule/BookToEsSchedule.java
index 8dde727..fb5314e 100644
--- a/novel-search/src/main/java/com/java2nb/novel/search/schedule/BookToEsSchedule.java
+++ b/novel-search/src/main/java/com/java2nb/novel/search/schedule/BookToEsSchedule.java
@@ -7,6 +7,8 @@ import com.java2nb.novel.search.feign.BookFeignClient;
import com.java2nb.novel.search.service.SearchService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@@ -16,6 +18,7 @@ import java.util.List;
/**
* 小说数据导入搜索引擎定时任务
+ *
* @author xiongxiaoyang
* @version 1.0
* @since 2020/5/27
@@ -30,49 +33,47 @@ public class BookToEsSchedule {
private final CacheService cacheService;
-
private final SearchService searchService;
+ private final RedissonClient redissonClient;
+
/**
* 1分钟导入一次
*/
@Scheduled(fixedRate = 1000 * 60)
public void saveToEs() {
- //TODO 引入Redisson框架实现分布式锁
- //可以重复更新,只是效率可能略有降低,所以暂不实现分布式锁
- if (cacheService.get(CacheKey.ES_TRANS_LOCK) == null) {
- cacheService.set(CacheKey.ES_TRANS_LOCK, "1", 60 * 20);
- try {
- //查询需要更新的小说
- Date lastDate = (Date) cacheService.getObject(CacheKey.ES_LAST_UPDATE_TIME);
- if (lastDate == null) {
- lastDate = new SimpleDateFormat("yyyy-MM-dd").parse("2020-01-01");
- }
+ RLock lock = redissonClient.getLock("saveToEs");
+ lock.lock();
-
- List books = bookFeignClient.queryBookByMinUpdateTime(lastDate, 100);
- for (Book book : books) {
- searchService.importToEs(book);
- lastDate = book.getUpdateTime();
- Thread.sleep(5000);
-
- }
-
-
-
- cacheService.setObject(CacheKey.ES_LAST_UPDATE_TIME, lastDate);
-
- } catch (Exception e) {
- log.error(e.getMessage(), e);
+ try {
+ //查询需要更新的小说
+ Date lastDate = (Date) cacheService.getObject(CacheKey.ES_LAST_UPDATE_TIME);
+ if (lastDate == null) {
+ lastDate = new SimpleDateFormat("yyyy-MM-dd").parse("2020-01-01");
}
- cacheService.del(CacheKey.ES_TRANS_LOCK);
+ List books = bookFeignClient.queryBookByMinUpdateTime(lastDate, 100);
+ for (Book book : books) {
+ searchService.importToEs(book);
+ lastDate = book.getUpdateTime();
+ Thread.sleep(5000);
+
+ }
+
+
+ cacheService.setObject(CacheKey.ES_LAST_UPDATE_TIME, lastDate);
+
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
}
+ lock.unlock();
}
+
+
}
diff --git a/novel-search/src/main/resources/bootstrap.yml b/novel-search/src/main/resources/bootstrap.yml
index 735b5e7..2c4cef2 100644
--- a/novel-search/src/main/resources/bootstrap.yml
+++ b/novel-search/src/main/resources/bootstrap.yml
@@ -9,4 +9,8 @@ spring:
ext‐config[0]:
data‐id: novel-redis.yml
group: novel-common
+ refresh: true
+ ext‐config[1]:
+ data‐id: novel-rabbitmq.yml
+ group: novel-common
refresh: true
\ No newline at end of file