fzzj 9 месяцев назад
Родитель
Сommit
e610168dae
20 измененных файлов: 295 добавлений и 196 удалений
  1. 4
    1
      RuoYi-Vue/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
  2. 4
    4
      RuoYi-Vue/ruoyi-admin/src/main/resources/application.yml
  3. 4
    4
      RuoYi-Vue/ruoyi-system/pom.xml
  4. 42
    42
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/config/ElasticsearchConfig.java
  5. 34
    33
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/config/ElasticsearchInitializer.java
  6. 21
    6
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/controller/NovelController.java
  7. 11
    11
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/domain/Novel.java
  8. 23
    0
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/domain/User.java
  9. 3
    2
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/mapper/NovelMapper.java
  10. 8
    8
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/repository/elastic/NovelSearchRepository.java
  11. 2
    1
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/repository/jpa/NovelRepository.java
  12. 3
    6
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/repository/jpa/UserRepository.java
  13. 2
    1
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/ChapterRepository.java
  14. 4
    4
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/NovelSearchService.java
  15. 9
    9
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/NovelService.java
  16. 1
    1
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/impl/AuthServiceImpl.java
  17. 100
    57
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/impl/NovelSearchServiceImpl.java
  18. 2
    2
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/impl/NovelServiceImpl.java
  19. 4
    3
      RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/utils/JwtTokenProvider.java
  20. 14
    1
      RuoYi-Vue/ruoyi-system/src/main/resources/mapper/novel/NovelMapper.xml

+ 4
- 1
RuoYi-Vue/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java Просмотреть файл

2
 
2
 
3
 import org.springframework.boot.SpringApplication;
3
 import org.springframework.boot.SpringApplication;
4
 import org.springframework.boot.autoconfigure.SpringBootApplication;
4
 import org.springframework.boot.autoconfigure.SpringBootApplication;
5
+import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration;
5
 import org.springframework.boot.autoconfigure.domain.EntityScan;
6
 import org.springframework.boot.autoconfigure.domain.EntityScan;
7
+import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
6
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
8
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
7
 import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
9
 import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
8
 import org.springframework.context.annotation.ComponentScan;
10
 import org.springframework.context.annotation.ComponentScan;
13
  * 
15
  * 
14
  * @author ruoyi
16
  * @author ruoyi
15
  */
17
  */
16
-@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class},
18
+@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class,
19
+        ElasticsearchRestClientAutoConfiguration.class},
17
         scanBasePackages = {
20
         scanBasePackages = {
18
                 "com.ruoyi",
21
                 "com.ruoyi",
19
                 "com.ruoyi.novel"  // 确保包含 novel 包
22
                 "com.ruoyi.novel"  // 确保包含 novel 包

+ 4
- 4
RuoYi-Vue/ruoyi-admin/src/main/resources/application.yml Просмотреть файл

89
         max-active: 8
89
         max-active: 8
90
         # #连接池最大阻塞等待时间(使用负值表示没有限制)
90
         # #连接池最大阻塞等待时间(使用负值表示没有限制)
91
         max-wait: -1ms
91
         max-wait: -1ms
92
-  elasticsearch:
93
-    uris: http://localhost:9200 # ES地址
94
-    connection-timeout: 3000
95
-    socket-timeout: 5000
92
+#  elasticsearch:
93
+#    uris: http://localhost:9200 # ES地址
94
+#    connection-timeout: 3000
95
+#    socket-timeout: 5000
96
   jpa:
96
   jpa:
97
     show-sql: true
97
     show-sql: true
98
     hibernate:
98
     hibernate:

+ 4
- 4
RuoYi-Vue/ruoyi-system/pom.xml Просмотреть файл

47
             <artifactId>spring-web</artifactId>
47
             <artifactId>spring-web</artifactId>
48
         </dependency>
48
         </dependency>
49
         <!-- Elasticsearch -->
49
         <!-- Elasticsearch -->
50
-        <dependency>
51
-            <groupId>org.springframework.boot</groupId>
52
-            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
53
-        </dependency>
50
+<!--        <dependency>-->
51
+<!--            <groupId>org.springframework.boot</groupId>-->
52
+<!--            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>-->
53
+<!--        </dependency>-->
54
         <!-- MyBatis-Plus 核心依赖 -->
54
         <!-- MyBatis-Plus 核心依赖 -->
55
         <dependency>
55
         <dependency>
56
             <groupId>com.baomidou</groupId>
56
             <groupId>com.baomidou</groupId>

+ 42
- 42
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/config/ElasticsearchConfig.java Просмотреть файл

1
-package com.ruoyi.novel.config;
2
-
3
-import org.elasticsearch.client.RequestOptions;
4
-import org.elasticsearch.client.RestHighLevelClient;
5
-import org.springframework.boot.actuate.health.AbstractHealthIndicator;
6
-import org.springframework.boot.actuate.health.Health;
7
-import org.springframework.boot.actuate.health.HealthIndicator;
8
-import org.springframework.boot.actuate.health.Status;
9
-import org.springframework.context.annotation.Bean;
10
-import org.springframework.context.annotation.Configuration;
11
-import org.springframework.data.elasticsearch.client.ClientConfiguration;
12
-import org.springframework.data.elasticsearch.client.RestClients;
13
-import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
14
-
15
-@Configuration
16
-public class ElasticsearchConfig {
17
-
18
-    @Bean
19
-    public ElasticsearchRestTemplate elasticsearchRestTemplate(RestHighLevelClient client) {
20
-        return new ElasticsearchRestTemplate(client);
21
-    }
22
-
23
-    @Bean
24
-    public RestHighLevelClient elasticsearchClient() {
25
-        return RestClients.create(ClientConfiguration.localhost()).rest();
26
-    }
27
-
28
-    @Bean
29
-    public HealthIndicator elasticsearchHealthIndicator(RestHighLevelClient client) {
30
-        return new AbstractHealthIndicator() {
31
-            @Override
32
-            protected void doHealthCheck(Health.Builder builder) throws Exception {
33
-                try {
34
-                    boolean available = client.ping(RequestOptions.DEFAULT);
35
-                    builder.status(available ? Status.UP : Status.DOWN);
36
-                } catch (Exception e) {
37
-                    builder.down(e);
38
-                }
39
-            }
40
-        };
41
-    }
42
-}
1
+//package com.ruoyi.novel.config;
2
+//
3
+//import org.elasticsearch.client.RequestOptions;
4
+//import org.elasticsearch.client.RestHighLevelClient;
5
+//import org.springframework.boot.actuate.health.AbstractHealthIndicator;
6
+//import org.springframework.boot.actuate.health.Health;
7
+//import org.springframework.boot.actuate.health.HealthIndicator;
8
+//import org.springframework.boot.actuate.health.Status;
9
+//import org.springframework.context.annotation.Bean;
10
+//import org.springframework.context.annotation.Configuration;
11
+//import org.springframework.data.elasticsearch.client.ClientConfiguration;
12
+//import org.springframework.data.elasticsearch.client.RestClients;
13
+//import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
14
+//
15
+//@Configuration
16
+//public class ElasticsearchConfig {
17
+//
18
+////    @Bean
19
+////    public ElasticsearchRestTemplate elasticsearchRestTemplate(RestHighLevelClient client) {
20
+////        return new ElasticsearchRestTemplate(client);
21
+////    }
22
+////
23
+////    @Bean
24
+////    public RestHighLevelClient elasticsearchClient() {
25
+////        return RestClients.create(ClientConfiguration.localhost()).rest();
26
+////    }
27
+//
28
+////    @Bean
29
+////    public HealthIndicator elasticsearchHealthIndicator(RestHighLevelClient client) {
30
+////        return new AbstractHealthIndicator() {
31
+////            @Override
32
+////            protected void doHealthCheck(Health.Builder builder) throws Exception {
33
+////                try {
34
+////                    boolean available = client.ping(RequestOptions.DEFAULT);
35
+////                    builder.status(available ? Status.UP : Status.DOWN);
36
+////                } catch (Exception e) {
37
+////                    builder.down(e);
38
+////                }
39
+////            }
40
+////        };
41
+////    }
42
+//}

+ 34
- 33
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/config/ElasticsearchInitializer.java Просмотреть файл

1
-package com.ruoyi.novel.config;
2
-
3
-import com.ruoyi.novel.domain.Novel;
4
-import com.ruoyi.novel.service.impl.NovelServiceImpl;
5
-import org.slf4j.Logger;
6
-import org.slf4j.LoggerFactory;
7
-import org.springframework.boot.ApplicationArguments;
8
-import org.springframework.boot.ApplicationRunner;
9
-import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
10
-import org.springframework.stereotype.Component;
11
-
12
-@Component
13
-public class ElasticsearchInitializer implements ApplicationRunner {
14
-    private static final Logger logger = LoggerFactory.getLogger(ElasticsearchInitializer.class);
15
-    private final ElasticsearchRestTemplate elasticsearchTemplate;
16
-
17
-    public ElasticsearchInitializer(ElasticsearchRestTemplate elasticsearchTemplate) {
18
-        this.elasticsearchTemplate = elasticsearchTemplate;
19
-    }
20
-
21
-    @Override
22
-    public void run(ApplicationArguments args) {
23
-        try {
24
-            if (!elasticsearchTemplate.indexOps(Novel.class).exists()) {
25
-                elasticsearchTemplate.indexOps(Novel.class).create();
26
-                elasticsearchTemplate.indexOps(Novel.class).putMapping();
27
-                logger.info("Created Elasticsearch index for Novel");
28
-            }
29
-        } catch (Exception e) {
30
-            logger.warn("Failed to create Elasticsearch index", e);
31
-        }
32
-    }
33
-}
1
+//package com.ruoyi.novel.config;
2
+//
3
+//import com.ruoyi.novel.domain.Novel;
4
+//import com.ruoyi.novel.service.impl.NovelServiceImpl;
5
+//import org.slf4j.Logger;
6
+//import org.slf4j.LoggerFactory;
7
+//import org.springframework.boot.ApplicationArguments;
8
+//import org.springframework.boot.ApplicationRunner;
9
+//import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
10
+//import org.springframework.stereotype.Component;
11
+//
12
+//@Component
13
+//public class ElasticsearchInitializer implements ApplicationRunner {
14
+//    private static final Logger logger = LoggerFactory.getLogger(ElasticsearchInitializer.class);
15
+////    private final ElasticsearchRestTemplate elasticsearchTemplate;
16
+////
17
+////    public ElasticsearchInitializer(ElasticsearchRestTemplate elasticsearchTemplate) {
18
+////        this.elasticsearchTemplate = elasticsearchTemplate;
19
+////    }
20
+//
21
+//    @Override
22
+//    public void run(ApplicationArguments args) {
23
+//        logger.info("Created Elasticsearch index for Novel");
24
+////        try {
25
+////            if (!elasticsearchTemplate.indexOps(Novel.class).exists()) {
26
+////                elasticsearchTemplate.indexOps(Novel.class).create();
27
+////                elasticsearchTemplate.indexOps(Novel.class).putMapping();
28
+////                logger.info("Created Elasticsearch index for Novel");
29
+////            }
30
+////        } catch (Exception e) {
31
+////            logger.warn("Failed to create Elasticsearch index", e);
32
+////        }
33
+//    }
34
+//}

+ 21
- 6
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/controller/NovelController.java Просмотреть файл

16
 import com.ruoyi.novel.service.NovelService;
16
 import com.ruoyi.novel.service.NovelService;
17
 import jdk.jfr.Category;
17
 import jdk.jfr.Category;
18
 import org.springframework.beans.factory.annotation.Autowired;
18
 import org.springframework.beans.factory.annotation.Autowired;
19
+import org.springframework.beans.factory.annotation.Qualifier;
20
+import org.springframework.cache.annotation.Cacheable;
19
 import org.springframework.http.ResponseEntity;
21
 import org.springframework.http.ResponseEntity;
22
+import org.springframework.scheduling.annotation.Async;
20
 import org.springframework.web.bind.annotation.*;
23
 import org.springframework.web.bind.annotation.*;
21
 
24
 
22
 import java.util.List;
25
 import java.util.List;
23
 import java.util.Map;
26
 import java.util.Map;
27
+import java.util.concurrent.CompletableFuture;
24
 
28
 
25
 // NovelController.java
29
 // NovelController.java
26
 @RestController
30
 @RestController
31
     @Autowired
35
     @Autowired
32
     private final NovelService novelService;
36
     private final NovelService novelService;
33
 
37
 
38
+    @Qualifier("authServiceImpl")
34
     @Autowired
39
     @Autowired
35
     private final IAuthService authService;
40
     private final IAuthService authService;
36
     @Autowired
41
     @Autowired
38
     @Autowired
43
     @Autowired
39
     private NovelMapper novelMapper;
44
     private NovelMapper novelMapper;
40
     // 构造函数注入
45
     // 构造函数注入
41
-    public NovelController(NovelService novelService, IAuthService authService) {
46
+    public NovelController(NovelService novelService, @Qualifier("authServiceImpl") IAuthService authService) {
42
         this.novelService = novelService;
47
         this.novelService = novelService;
43
         this.authService = authService;
48
         this.authService = authService;
44
     }
49
     }
150
     }
155
     }
151
     // 其他接口...
156
     // 其他接口...
152
     @GetMapping("/search")
157
     @GetMapping("/search")
153
-    public AjaxResult searchNovels(@RequestParam String keyword) {
154
-        List<Novel> novels = searchService.searchNovels(keyword);
158
+    @Cacheable(value = "novelSearch", key = "#keyword + '-' + #categoryId")
159
+    public AjaxResult searchNovels(@RequestParam String keyword, @RequestParam  Long categoryId) {
160
+        List<Novel> novels = searchService.searchNovels(keyword, categoryId);
155
         return AjaxResult.success(novels);
161
         return AjaxResult.success(novels);
156
     }
162
     }
163
+    @Async
164
+    public CompletableFuture<List<Novel>> searchNovelsAsync(String keyword, Long categoryId) {
165
+        return CompletableFuture.completedFuture((List<Novel>) searchNovels(keyword, categoryId));
166
+    }
167
+    @GetMapping("/suggest")
168
+    public List<String> suggestKeywords(@RequestParam String prefix) {
169
+        return novelMapper.suggestKeywords(prefix + "%", 10);
170
+    }
157
 
171
 
172
+    // Mapper中
158
 
173
 
159
     @PostMapping("/create")
174
     @PostMapping("/create")
160
     public AjaxResult addNovel(@RequestBody Novel novel) {
175
     public AjaxResult addNovel(@RequestBody Novel novel) {
161
         novelMapper.insert(novel);
176
         novelMapper.insert(novel);
162
-        searchService.indexNovel(novel); // 创建索引
177
+        //searchService.indexNovel(novel); // 创建索引
163
         return AjaxResult.success();
178
         return AjaxResult.success();
164
     }
179
     }
165
 
180
 
166
     @PutMapping
181
     @PutMapping
167
     public AjaxResult updateNovel(@RequestBody Novel novel) {
182
     public AjaxResult updateNovel(@RequestBody Novel novel) {
168
         novelMapper.updateById(novel);
183
         novelMapper.updateById(novel);
169
-        searchService.updateNovelIndex(novel); // 更新索引
184
+        //searchService.updateNovelIndex(novel); // 更新索引
170
         return AjaxResult.success();
185
         return AjaxResult.success();
171
     }
186
     }
172
 
187
 
173
     @DeleteMapping("/{id}")
188
     @DeleteMapping("/{id}")
174
     public AjaxResult deleteNovel(@PathVariable Long id) {
189
     public AjaxResult deleteNovel(@PathVariable Long id) {
175
         novelMapper.deleteById(id);
190
         novelMapper.deleteById(id);
176
-        searchService.deleteNovelIndex(id); // 删除索引
191
+        //searchService.deleteNovelIndex(id); // 删除索引
177
         return AjaxResult.success();
192
         return AjaxResult.success();
178
     }
193
     }
179
 }
194
 }

+ 11
- 11
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/domain/Novel.java Просмотреть файл

5
 import com.baomidou.mybatisplus.annotation.TableName;
5
 import com.baomidou.mybatisplus.annotation.TableName;
6
 import lombok.Data;
6
 import lombok.Data;
7
 import org.springframework.data.annotation.Id;
7
 import org.springframework.data.annotation.Id;
8
-import org.springframework.data.elasticsearch.annotations.Document;
9
-import org.springframework.data.elasticsearch.annotations.Field;
10
-import org.springframework.data.elasticsearch.annotations.FieldType;
8
+//import org.springframework.data.elasticsearch.annotations.Document;
9
+//import org.springframework.data.elasticsearch.annotations.Field;
10
+//import org.springframework.data.elasticsearch.annotations.FieldType;
11
 
11
 
12
 import javax.persistence.Column;
12
 import javax.persistence.Column;
13
 import javax.persistence.Entity;
13
 import javax.persistence.Entity;
19
 
19
 
20
 @Entity
20
 @Entity
21
 @TableName("novel")
21
 @TableName("novel")
22
-@Document(indexName = "novels")
22
+//@Document(indexName = "novels")
23
 @Data
23
 @Data
24
 public class Novel {
24
 public class Novel {
25
     @javax.persistence.Id
25
     @javax.persistence.Id
27
     @GeneratedValue(strategy = GenerationType.IDENTITY)
27
     @GeneratedValue(strategy = GenerationType.IDENTITY)
28
     @TableId(type = IdType.AUTO)
28
     @TableId(type = IdType.AUTO)
29
     private Long id;
29
     private Long id;
30
-    @Field(type = FieldType.Text, analyzer = "ik_max_word")
30
+    //@Field(type = FieldType.Text, analyzer = "ik_max_word")
31
     private String title;
31
     private String title;
32
-    @Field(type = FieldType.Keyword)
32
+    //@Field(type = FieldType.Keyword)
33
     private String author;
33
     private String author;
34
     private Long authorId;
34
     private Long authorId;
35
     private String cover;
35
     private String cover;
36
     private String coverImg;
36
     private String coverImg;
37
-    @Field(type = FieldType.Long)
37
+    //@Field(type = FieldType.Long)
38
     private Long categoryId;
38
     private Long categoryId;
39
-    @Field(type = FieldType.Keyword)
39
+    //@Field(type = FieldType.Keyword)
40
     private Integer status = 0; // 0: 连载中, 1: 已完结// 连载/完本
40
     private Integer status = 0; // 0: 连载中, 1: 已完结// 连载/完本
41
-    @Field(type = FieldType.Text, analyzer = "ik_smart")
41
+    //@Field(type = FieldType.Text, analyzer = "ik_smart")
42
     private String description;
42
     private String description;
43
     private Long wordCount;
43
     private Long wordCount;
44
-    @Field(type = FieldType.Long)
44
+    //@Field(type = FieldType.Long)
45
     private Long readCount;
45
     private Long readCount;
46
-    @Field(type = FieldType.Date)
46
+    //@Field(type = FieldType.Date)
47
     @Column(name = "create_time")
47
     @Column(name = "create_time")
48
     private Date createTime = new Date();
48
     private Date createTime = new Date();
49
     @Column(name = "update_time")
49
     @Column(name = "update_time")

+ 23
- 0
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/domain/User.java Просмотреть файл

1
+package com.ruoyi.novel.domain;
2
+import javax.persistence.Entity;
3
+import javax.persistence.GeneratedValue;
4
+import javax.persistence.GenerationType;
5
+import javax.persistence.Id;
6
+import javax.persistence.Table;
7
+
8
+@Entity
9
+@Table(name = "sys_user")
10
+public class User {
11
+
12
+    @Id
13
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
14
+    private Long id;
15
+
16
+    private String username;
17
+    private String password;
18
+    private String email;
19
+    private String token;
20
+
21
+    // Getters and setters
22
+    // 构造函数
23
+}

+ 3
- 2
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/mapper/NovelMapper.java Просмотреть файл

12
 @Mapper
12
 @Mapper
13
 // NovelMapper.java
13
 // NovelMapper.java
14
 public interface NovelMapper extends BaseMapper<Novel> {
14
 public interface NovelMapper extends BaseMapper<Novel> {
15
-    List<Novel> selectNovelList(Novel novel);
15
+    List<Novel> selectNovelList(@Param("novel") Novel novel,@Param("keyword") String keyword);
16
     Novel selectNovelById(Long id);
16
     Novel selectNovelById(Long id);
17
     int insertNovel(Novel novel);
17
     int insertNovel(Novel novel);
18
     int updateNovel(Novel novel);
18
     int updateNovel(Novel novel);
37
   //  List<Novel> selectNovelList(Novel novel);
37
   //  List<Novel> selectNovelList(Novel novel);
38
     List<Novel> selectHotNovels(Map<String, Object> params);
38
     List<Novel> selectHotNovels(Map<String, Object> params);
39
 
39
 
40
-
40
+    @Select("SELECT DISTINCT title FROM novel WHERE title LIKE #{prefix} LIMIT #{limit}")
41
+    List<String> suggestKeywords(@Param("prefix") String prefix, @Param("limit") int limit);
41
 }
42
 }
42
 
43
 

+ 8
- 8
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/repository/elastic/NovelSearchRepository.java Просмотреть файл

1
-package com.ruoyi.novel.repository.elastic;
2
-
3
-import com.ruoyi.novel.domain.Novel;
4
-import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
5
-
6
-public interface NovelSearchRepository extends ElasticsearchRepository<Novel, Long> {
7
-    // Elasticsearch 特定查询方法
8
-}
1
+//package com.ruoyi.novel.repository.elastic;
2
+//
3
+//import com.ruoyi.novel.domain.Novel;
4
+//import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
5
+//
6
+//public interface NovelSearchRepository extends ElasticsearchRepository<Novel, Long> {
7
+//    // Elasticsearch 特定查询方法
8
+//}

+ 2
- 1
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/repository/jpa/NovelRepository.java Просмотреть файл

2
 
2
 
3
 import com.ruoyi.novel.domain.Novel;
3
 import com.ruoyi.novel.domain.Novel;
4
 import org.apache.ibatis.annotations.Param;
4
 import org.apache.ibatis.annotations.Param;
5
-import org.springframework.data.elasticsearch.annotations.Query;
5
+//import org.springframework.data.elasticsearch.annotations.Query;
6
 import org.springframework.data.jpa.repository.JpaRepository;
6
 import org.springframework.data.jpa.repository.JpaRepository;
7
+import org.springframework.data.jpa.repository.Query;
7
 import org.springframework.data.repository.NoRepositoryBean;
8
 import org.springframework.data.repository.NoRepositoryBean;
8
 import org.springframework.stereotype.Repository;
9
 import org.springframework.stereotype.Repository;
9
 
10
 

RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/UserRepository.java → RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/repository/jpa/UserRepository.java Просмотреть файл

1
-package com.ruoyi.novel.service;
1
+package com.ruoyi.novel.repository.jpa;
2
 
2
 
3
-import org.elasticsearch.client.security.user.User;
3
+import com.ruoyi.common.core.domain.entity.SysUser;
4
+import com.ruoyi.novel.domain.User;  // 确保导入正确
4
 import org.springframework.data.jpa.repository.JpaRepository;
5
 import org.springframework.data.jpa.repository.JpaRepository;
5
 import org.springframework.stereotype.Repository;
6
 import org.springframework.stereotype.Repository;
6
 
7
 
7
-import java.util.Optional;
8
 @Repository
8
 @Repository
9
-// UserRepository.java
10
 public interface UserRepository extends JpaRepository<User, Long> {
9
 public interface UserRepository extends JpaRepository<User, Long> {
11
-
12
-    //Optional<User> findByUsername(String username);
13
     // 自定义查询方法
10
     // 自定义查询方法
14
     User findByUsername(String username);
11
     User findByUsername(String username);
15
     User findByEmail(String email);
12
     User findByEmail(String email);

+ 2
- 1
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/ChapterRepository.java Просмотреть файл

2
 
2
 
3
 import com.ruoyi.novel.domain.Chapter;
3
 import com.ruoyi.novel.domain.Chapter;
4
 import org.apache.ibatis.annotations.Param;
4
 import org.apache.ibatis.annotations.Param;
5
-import org.springframework.data.elasticsearch.annotations.Query;
5
+//import org.springframework.data.elasticsearch.annotations.Query;
6
 import org.springframework.data.jpa.repository.JpaRepository;
6
 import org.springframework.data.jpa.repository.JpaRepository;
7
+import org.springframework.data.jpa.repository.Query;
7
 
8
 
8
 import java.util.List;
9
 import java.util.List;
9
 
10
 

+ 4
- 4
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/NovelSearchService.java Просмотреть файл

6
 
6
 
7
 // NovelSearchService.java
7
 // NovelSearchService.java
8
 public interface NovelSearchService {
8
 public interface NovelSearchService {
9
-    List<Novel> searchNovels(String keyword);
10
-    void indexNovel(Novel novel);
11
-    void updateNovelIndex(Novel novel);
12
-    void deleteNovelIndex(Long id);
9
+    List<Novel> searchNovels(String keyword, Long categoryId);
10
+//    void indexNovel(Novel novel);
11
+//    void updateNovelIndex(Novel novel);
12
+//    void deleteNovelIndex(Long id);
13
 }
13
 }

+ 9
- 9
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/NovelService.java Просмотреть файл

4
 import com.ruoyi.novel.domain.AuthorApplicationDTO;
4
 import com.ruoyi.novel.domain.AuthorApplicationDTO;
5
 import com.ruoyi.novel.domain.Chapter;
5
 import com.ruoyi.novel.domain.Chapter;
6
 import com.ruoyi.novel.domain.Novel;
6
 import com.ruoyi.novel.domain.Novel;
7
-import com.ruoyi.novel.repository.elastic.NovelSearchRepository;
7
+//import com.ruoyi.novel.repository.elastic.NovelSearchRepository;
8
 import com.ruoyi.novel.repository.jpa.NovelRepository;
8
 import com.ruoyi.novel.repository.jpa.NovelRepository;
9
 import jdk.jfr.Category;
9
 import jdk.jfr.Category;
10
-import org.elasticsearch.client.tasks.ElasticsearchException;
10
+//import org.elasticsearch.client.tasks.ElasticsearchException;
11
 import org.springframework.scheduling.annotation.Async;
11
 import org.springframework.scheduling.annotation.Async;
12
 import org.springframework.stereotype.Service;
12
 import org.springframework.stereotype.Service;
13
 import org.springframework.transaction.annotation.Propagation;
13
 import org.springframework.transaction.annotation.Propagation;
57
 //    String getChapterContent(Long chapterId);
57
 //    String getChapterContent(Long chapterId);
58
 //    void submitAuthorApplication(AuthorApplicationDTO dto, Long userId);
58
 //    void submitAuthorApplication(AuthorApplicationDTO dto, Long userId);
59
 public NovelRepository novelRepository = null; // JPA
59
 public NovelRepository novelRepository = null; // JPA
60
-    public NovelSearchRepository novelSearchRepository = null; // ES
60
+    //public NovelSearchRepository novelSearchRepository = null; // ES
61
     @Transactional(propagation = Propagation.REQUIRED)
61
     @Transactional(propagation = Propagation.REQUIRED)
62
     public default void syncNovelToEs(Long novelId) {
62
     public default void syncNovelToEs(Long novelId) {
63
         Novel novel = novelRepository.findById(novelId).orElseThrow();
63
         Novel novel = novelRepository.findById(novelId).orElseThrow();
64
-        novelSearchRepository.save(novel);
64
+        //novelSearchRepository.save(novel);
65
     }
65
     }
66
 
66
 
67
-    @Async
68
-    public default void asyncIndexToEs(Novel novel) {
69
-        novelSearchRepository.save(novel);
70
-    }
67
+//    @Async
68
+//    public default void asyncIndexToEs(Novel novel) {
69
+//        novelSearchRepository.save(novel);
70
+//    }
71
 //    @Retryable(value = { ElasticsearchException.class }, maxAttempts = 3, backoff = @Backoff(delay = 1000))
71
 //    @Retryable(value = { ElasticsearchException.class }, maxAttempts = 3, backoff = @Backoff(delay = 1000))
72
 //    public void saveToEsWithRetry(Novel novel) {
72
 //    public void saveToEsWithRetry(Novel novel) {
73
 //        novelSearchRepository.save(novel);
73
 //        novelSearchRepository.save(novel);
75
     @PostConstruct
75
     @PostConstruct
76
     public default void checkRepositories() {
76
     public default void checkRepositories() {
77
         assert novelRepository != null : "JPA Repository未注入";
77
         assert novelRepository != null : "JPA Repository未注入";
78
-        assert novelSearchRepository != null : "ES Repository未注入";
78
+        //assert novelSearchRepository != null : "ES Repository未注入";
79
     }
79
     }
80
 }
80
 }

+ 1
- 1
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/impl/AuthServiceImpl.java Просмотреть файл

1
 package com.ruoyi.novel.service.impl;
1
 package com.ruoyi.novel.service.impl;
2
 
2
 
3
 import com.ruoyi.common.core.domain.model.LoginUser;
3
 import com.ruoyi.common.core.domain.model.LoginUser;
4
+import com.ruoyi.novel.repository.jpa.UserRepository;
4
 import com.ruoyi.novel.service.IAuthService;
5
 import com.ruoyi.novel.service.IAuthService;
5
-import com.ruoyi.novel.service.UserRepository;
6
 import com.ruoyi.novel.utils.JwtTokenProvider;
6
 import com.ruoyi.novel.utils.JwtTokenProvider;
7
 import org.springframework.beans.factory.annotation.Autowired;
7
 import org.springframework.beans.factory.annotation.Autowired;
8
 import org.springframework.stereotype.Service;
8
 import org.springframework.stereotype.Service;

+ 100
- 57
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/impl/NovelSearchServiceImpl.java Просмотреть файл

1
 package com.ruoyi.novel.service.impl;
1
 package com.ruoyi.novel.service.impl;
2
 
2
 
3
+import com.ruoyi.common.constant.HttpStatus;
4
+import com.ruoyi.common.core.page.PageDomain;
5
+import com.ruoyi.common.core.page.TableDataInfo;
6
+import com.ruoyi.common.utils.PageUtils;
7
+import com.ruoyi.common.utils.StringUtils;
8
+import com.ruoyi.novel.config.TableSupport;
3
 import com.ruoyi.novel.domain.Novel;
9
 import com.ruoyi.novel.domain.Novel;
4
 import com.ruoyi.novel.mapper.NovelMapper;
10
 import com.ruoyi.novel.mapper.NovelMapper;
5
 import com.ruoyi.novel.service.NovelSearchService;
11
 import com.ruoyi.novel.service.NovelSearchService;
6
-import org.elasticsearch.index.query.QueryBuilders;
12
+//import org.elasticsearch.index.query.QueryBuilders;
7
 import org.slf4j.Logger;
13
 import org.slf4j.Logger;
8
 import org.slf4j.LoggerFactory;
14
 import org.slf4j.LoggerFactory;
9
 import org.springframework.beans.factory.annotation.Autowired;
15
 import org.springframework.beans.factory.annotation.Autowired;
10
-import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
11
-import org.springframework.data.elasticsearch.core.IndexOperations;
12
-import org.springframework.data.elasticsearch.core.SearchHit;
13
-import org.springframework.data.elasticsearch.core.SearchHits;
14
-import org.springframework.data.elasticsearch.core.document.Document;
15
-import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
16
-import org.springframework.data.elasticsearch.core.query.*;
16
+import org.springframework.cache.annotation.Cacheable;
17
+//import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
18
+//import org.springframework.data.elasticsearch.core.IndexOperations;
19
+//import org.springframework.data.elasticsearch.core.SearchHit;
20
+//import org.springframework.data.elasticsearch.core.SearchHits;
21
+//import org.springframework.data.elasticsearch.core.document.Document;
22
+//import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
23
+//import org.springframework.data.elasticsearch.core.query.*;
17
 import org.springframework.scheduling.annotation.Scheduled;
24
 import org.springframework.scheduling.annotation.Scheduled;
18
 import org.springframework.stereotype.Service;
25
 import org.springframework.stereotype.Service;
19
 
26
 
28
 public class NovelSearchServiceImpl implements NovelSearchService {
35
 public class NovelSearchServiceImpl implements NovelSearchService {
29
     private static final Logger logger = LoggerFactory.getLogger(NovelSearchServiceImpl.class);
36
     private static final Logger logger = LoggerFactory.getLogger(NovelSearchServiceImpl.class);
30
 
37
 
31
-    @Autowired
32
-    private ElasticsearchRestTemplate elasticTemplate;
38
+//    @Autowired
39
+//    private ElasticsearchRestTemplate elasticTemplate;
33
     @Autowired
40
     @Autowired
34
     private NovelMapper novelMapper;
41
     private NovelMapper novelMapper;
35
 
42
 
36
     private static final String INDEX_NAME = "novels";
43
     private static final String INDEX_NAME = "novels";
37
 
44
 
38
 //    @PostConstruct
45
 //    @PostConstruct
39
-    public void createIndexIfNotExists() {
40
-        IndexOperations indexOps = elasticTemplate.indexOps(IndexCoordinates.of(INDEX_NAME));
41
-        if (!indexOps.exists()) {
42
-            // 创建索引
43
-            indexOps.create();
44
-
45
-            // 创建映射
46
-            Document mapping = indexOps.createMapping(Novel.class);
47
-            indexOps.putMapping(mapping);
48
-        }
49
-//        if (!elasticTemplate.indexExists(INDEX_NAME)) {
50
-//            elasticTemplate.createIndex(INDEX_NAME);
51
-//            elasticTemplate.putMapping(Novel.class);
46
+//    public void createIndexIfNotExists() {
47
+//        IndexOperations indexOps = elasticTemplate.indexOps(IndexCoordinates.of(INDEX_NAME));
48
+//        if (!indexOps.exists()) {
49
+//            // 创建索引
50
+//            indexOps.create();
51
+//
52
+//            // 创建映射
53
+//            Document mapping = indexOps.createMapping(Novel.class);
54
+//            indexOps.putMapping(mapping);
52
 //        }
55
 //        }
56
+////        if (!elasticTemplate.indexExists(INDEX_NAME)) {
57
+////            elasticTemplate.createIndex(INDEX_NAME);
58
+////            elasticTemplate.putMapping(Novel.class);
59
+////        }
60
+//    }
61
+//    public List<Novel> searchNovels(String keyword) {
62
+//        // 构建查询条件
63
+//        NativeSearchQuery query = new NativeSearchQueryBuilder()
64
+//                .withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "author", "description"))
65
+//                .build();
66
+//        // 执行搜索
67
+//        SearchHits<Novel> hits = elasticTemplate.search(query, Novel.class);
68
+//        return hits.stream()
69
+//                .map(SearchHit::getContent)
70
+//                .collect(Collectors.toList());
71
+//
72
+//        //return elasticTemplate.search(query, Novel.class).getContent();
73
+//    }
74
+@Cacheable(value = "novelSearch", key = "#keyword + '-' + #categoryId")
75
+public List<Novel> searchNovels(String keyword, Long categoryId) {
76
+    startPage();
77
+    PageDomain pageDomain = TableSupport.buildPageRequest();
78
+    if (pageDomain.getPageSize() > 100) {
79
+        pageDomain.setPageSize(100); // 限制最大分页大小
53
     }
80
     }
54
-    public List<Novel> searchNovels(String keyword) {
55
-        // 构建查询条件
56
-        NativeSearchQuery query = new NativeSearchQueryBuilder()
57
-                .withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "author", "description"))
58
-                .build();
59
-        // 执行搜索
60
-        SearchHits<Novel> hits = elasticTemplate.search(query, Novel.class);
61
-        return hits.stream()
62
-                .map(SearchHit::getContent)
63
-                .collect(Collectors.toList());
81
+    Novel novel = new Novel();
64
 
82
 
65
-        //return elasticTemplate.search(query, Novel.class).getContent();
83
+    // 设置分类过滤
84
+    if (categoryId != null && categoryId > 0) {
85
+        novel.setCategoryId(categoryId);
66
     }
86
     }
87
+    // 执行搜索
88
+    List<Novel> list = novelMapper.selectNovelList(novel, keyword);
89
+    return (List<Novel>) getDataTable(list);
90
+
91
+}
67
 
92
 
68
-    @Override
69
-    public void indexNovel(Novel novel) {
70
-        IndexQuery indexQuery = new IndexQueryBuilder()
71
-                .withId(novel.getId().toString())
72
-                .withObject(novel)
73
-                .build();
74
-        elasticTemplate.index(indexQuery, IndexCoordinates.of(INDEX_NAME));
93
+    protected void startPage() {
94
+        PageDomain pageDomain = TableSupport.buildPageRequest();
95
+        Integer pageNum = pageDomain.getPageNum();
96
+        Integer pageSize = pageDomain.getPageSize();
97
+        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) {
98
+            String orderBy = pageDomain.getOrderBy();
99
+            PageUtils.startPage(pageNum, pageSize, orderBy);
100
+        }
75
     }
101
     }
76
-    @Override
77
-    public void updateNovelIndex(Novel novel) {
78
-        UpdateQuery updateQuery = UpdateQuery.builder(novel.getId().toString())
79
-                .withDocument(Document.from(convertNovelToMap(novel)))
80
-                .build();
81
-        elasticTemplate.update(updateQuery, IndexCoordinates.of(INDEX_NAME));
102
+    protected TableDataInfo getDataTable(List<?> list) {
103
+        TableDataInfo rspData = new TableDataInfo();
104
+        rspData.setCode(HttpStatus.SUCCESS);
105
+        rspData.setMsg("查询成功");
106
+        rspData.setRows(list);
107
+        rspData.setTotal(PageUtils.getLocalPage().getTotal());
108
+        return rspData;
82
     }
109
     }
110
+//    @Override
111
+//    public void indexNovel(Novel novel) {
112
+//        IndexQuery indexQuery = new IndexQueryBuilder()
113
+//                .withId(novel.getId().toString())
114
+//                .withObject(novel)
115
+//                .build();
116
+//        elasticTemplate.index(indexQuery, IndexCoordinates.of(INDEX_NAME));
117
+//    }
118
+//    @Override
119
+//    public void updateNovelIndex(Novel novel) {
120
+//        UpdateQuery updateQuery = UpdateQuery.builder(novel.getId().toString())
121
+//                .withDocument(Document.from(convertNovelToMap(novel)))
122
+//                .build();
123
+//        elasticTemplate.update(updateQuery, IndexCoordinates.of(INDEX_NAME));
124
+//    }
83
     private Map<String, Object> convertNovelToMap(Novel novel) {
125
     private Map<String, Object> convertNovelToMap(Novel novel) {
84
         Map<String, Object> map = new HashMap<>();
126
         Map<String, Object> map = new HashMap<>();
85
         map.put("title", novel.getTitle());
127
         map.put("title", novel.getTitle());
89
         map.put("status", novel.getStatus());
131
         map.put("status", novel.getStatus());
90
         return map;
132
         return map;
91
     }
133
     }
92
-    @Override
93
-    public void deleteNovelIndex(Long id) {
94
-        elasticTemplate.delete(id.toString(), IndexCoordinates.of(INDEX_NAME));
95
-    }
134
+
135
+//    @Override
136
+//    public void deleteNovelIndex(Long id) {
137
+//        elasticTemplate.delete(id.toString(), IndexCoordinates.of(INDEX_NAME));
138
+//    }
96
     // 定时同步数据库数据到ES
139
     // 定时同步数据库数据到ES
97
-    @Scheduled(fixedRate = 3600000) // 每小时同步一次
98
-    public void syncDataToEs() {
99
-        List<Novel> novels = novelMapper.selectList(null);
100
-        novels.forEach(this::indexNovel);
101
-        logger.info("同步 {} 条小说数据到ES", novels.size());
102
-    }
140
+//    @Scheduled(fixedRate = 3600000) // 每小时同步一次
141
+//    public void syncDataToEs() {
142
+//        List<Novel> novels = novelMapper.selectList(null);
143
+//        novels.forEach(this::indexNovel);
144
+//        logger.info("同步 {} 条小说数据到ES", novels.size());
145
+//    }
103
 }
146
 }

+ 2
- 2
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/service/impl/NovelServiceImpl.java Просмотреть файл

275
             novel.setCategoryId(categoryId);
275
             novel.setCategoryId(categoryId);
276
         }
276
         }
277
 
277
 
278
-        List<Novel> list = novelMapper.selectNovelList(novel);
278
+        List<Novel> list = novelMapper.selectNovelList(novel,null);
279
         return (List<Novel>) getDataTable(list);
279
         return (List<Novel>) getDataTable(list);
280
     }
280
     }
281
 
281
 
341
     }
341
     }
342
     @Override
342
     @Override
343
     public List<Novel> selectNovelList(Novel novel) {
343
     public List<Novel> selectNovelList(Novel novel) {
344
-        return novelMapper.selectNovelList(novel);
344
+        return novelMapper.selectNovelList(novel,null);
345
     }
345
     }
346
 
346
 
347
     @Override
347
     @Override

+ 4
- 3
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/utils/JwtTokenProvider.java Просмотреть файл

1
 package com.ruoyi.novel.utils;
1
 package com.ruoyi.novel.utils;
2
 
2
 
3
+import com.ruoyi.common.core.domain.entity.SysUser;
3
 import io.jsonwebtoken.Claims;
4
 import io.jsonwebtoken.Claims;
4
 import io.jsonwebtoken.Jwts;
5
 import io.jsonwebtoken.Jwts;
5
 import io.jsonwebtoken.SignatureAlgorithm;
6
 import io.jsonwebtoken.SignatureAlgorithm;
6
-import org.elasticsearch.client.security.user.User;
7
+//import org.elasticsearch.client.security.user.User;
7
 import org.springframework.beans.factory.annotation.Value;
8
 import org.springframework.beans.factory.annotation.Value;
8
 import org.springframework.stereotype.Component;
9
 import org.springframework.stereotype.Component;
9
 
10
 
19
     @Value("${app.jwt.expiration}")
20
     @Value("${app.jwt.expiration}")
20
     private int jwtExpirationInMs;
21
     private int jwtExpirationInMs;
21
 
22
 
22
-    public String generateToken(User user) {
23
+    public String generateToken(SysUser user) {
23
         Date now = new Date();
24
         Date now = new Date();
24
         Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);
25
         Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);
25
 
26
 
26
         return Jwts.builder()
27
         return Jwts.builder()
27
-                .setSubject(user.getUsername())
28
+                .setSubject(user.getUserName())
28
                 .setIssuedAt(now)
29
                 .setIssuedAt(now)
29
                 .setExpiration(expiryDate)
30
                 .setExpiration(expiryDate)
30
                 .signWith(SignatureAlgorithm.HS512, jwtSecret)
31
                 .signWith(SignatureAlgorithm.HS512, jwtSecret)

+ 14
- 1
RuoYi-Vue/ruoyi-system/src/main/resources/mapper/novel/NovelMapper.xml Просмотреть файл

32
         <include refid="selectNovelVo"/>
32
         <include refid="selectNovelVo"/>
33
         <where>
33
         <where>
34
             <if test="title != null and title != ''"> AND title LIKE CONCAT('%', #{title}, '%')</if>
34
             <if test="title != null and title != ''"> AND title LIKE CONCAT('%', #{title}, '%')</if>
35
-            <if test="authorName != null and authorName != ''"> AND author_name LIKE CONCAT('%', #{authorName}, '%')</if>
36
             <if test="categoryId != null"> AND category_id = #{categoryId}</if>
35
             <if test="categoryId != null"> AND category_id = #{categoryId}</if>
36
+            <if test="keyword != null and keyword != ''">
37
+                <!-- 普通模式 -->
38
+                <!-- AND (
39
+                    title LIKE CONCAT('%', #{keyword}, '%')
40
+                    OR author LIKE CONCAT('%', #{keyword}, '%')
41
+                    OR description LIKE CONCAT('%', #{keyword}, '%')
42
+                ) -->
43
+
44
+                <!-- 全文索引模式 -->
45
+                AND MATCH(title, author, description) AGAINST (#{keyword} IN BOOLEAN MODE)
46
+            </if>
47
+            <if test="authorName != null and authorName != ''"> AND author_name LIKE CONCAT('%', #{authorName}, '%')</if>
48
+            <if test="description != null and description != ''"> AND description LIKE CONCAT('%', #{description}, '%')</if>
49
+
37
             <if test="status != null and status != ''"> AND status = #{status}</if>
50
             <if test="status != null and status != ''"> AND status = #{status}</if>
38
         </where>
51
         </where>
39
         ORDER BY update_time DESC
52
         ORDER BY update_time DESC

Загрузка…
Отмена
Сохранить