diff --git a/kbqa-common/pom.xml b/kbqa-common/pom.xml index 75192aa..c1a2788 100644 --- a/kbqa-common/pom.xml +++ b/kbqa-common/pom.xml @@ -20,8 +20,23 @@ - cn.dev33 - sa-token-spring-boot-starter + org.springframework.boot + spring-boot-starter-data-redis + + + redis.clients + jedis + + + + com.baomidou + lock4j-redis-template-spring-boot-starter + ${lock4j.version} + + + + io.minio + minio diff --git a/kbqa-common/src/main/java/com/supervision/config/JwtInterceptor.java b/kbqa-common/src/main/java/com/supervision/config/JwtInterceptor.java new file mode 100644 index 0000000..70fe253 --- /dev/null +++ b/kbqa-common/src/main/java/com/supervision/config/JwtInterceptor.java @@ -0,0 +1,99 @@ +package com.supervision.config; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import cn.hutool.jwt.JWT; +import cn.hutool.jwt.JWTUtil; +import com.supervision.constant.UserTokenConstant; +import com.supervision.exception.BusinessException; +import com.supervision.util.SpringBeanUtil; +import com.supervision.util.TokenUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.lang.Nullable; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +@Slf4j +public class JwtInterceptor implements HandlerInterceptor { + + private final RedisTemplate redisTemplate; + + public JwtInterceptor(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + //请求消息头获取用户ID + String token = request.getHeader("token"); + if (StrUtil.isBlank(token)) { + // 如果是swagger来的接口,说明这里是测试的,会伪造一个用户 + if (StrUtil.isNotBlank(request.getHeader("Knife4j-Gateway-Code"))) { + cacheAuth(JWTUtil.parseToken(devActiveUser())); + return true; + } else { + throw new BusinessException("当前用户未登录", HttpStatus.UNAUTHORIZED.value()); + } + } + JWT jwt = JWTUtil.parseToken(token); + // 校验token是否过期,如果过期了,需要提示过期重新登录 + checkTokenExpire(jwt); + cacheAuth(jwt); + return true; + } + + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, + @Nullable Exception ex) throws Exception { + // 请求结束,将用户信息从thread中移除 + clearAuth(); + HandlerInterceptor.super.afterCompletion(request, response, handler, ex); + } + + + private void checkTokenExpire(JWT jwt) { + Object expireTime = jwt.getPayload("expireTime"); + long l = Long.parseLong(String.valueOf(expireTime)); + // 校验是否比当前时间大 + long currentTimeMillis = System.currentTimeMillis(); + if (currentTimeMillis > l) { + throw new BusinessException("用户登录已过期,请重新登录", HttpStatus.UNAUTHORIZED.value()); + } + } + + + private void cacheAuth(JWT jwt) { + try { + JSONObject claimsJson = jwt.getPayload().getClaimsJson(); + ThreadCache.USER.set(claimsJson.toString()); + } catch (Exception e) { + log.error("用户信息异常", e); + } + } + + private String devActiveUser() { + Map map = new HashMap<>(); + map.put("id", "1"); + map.put("account", "test"); + map.put("name", "测试账户"); + return TokenUtil.creatToken(JSONUtil.toJsonStr(map)); + } + + private void clearAuth() { + ThreadCache.USER.remove(); + } +} diff --git a/kbqa-common/src/main/java/com/supervision/config/MinioConfig.java b/kbqa-common/src/main/java/com/supervision/config/MinioConfig.java new file mode 100644 index 0000000..92329f1 --- /dev/null +++ b/kbqa-common/src/main/java/com/supervision/config/MinioConfig.java @@ -0,0 +1,24 @@ +package com.supervision.config; + +import io.minio.MinioClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MinioConfig { + + /** + * 创建基于Java端的MinioClient + */ + @Bean + @ConditionalOnProperty(prefix = "minio",name = "url") + public MinioClient minioClient(MinioProperties minioProperties) { + return MinioClient.builder().endpoint(minioProperties.getUrl()) + .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey()) + .build(); + } + + +} diff --git a/kbqa-common/src/main/java/com/supervision/config/MinioProperties.java b/kbqa-common/src/main/java/com/supervision/config/MinioProperties.java new file mode 100644 index 0000000..d846f18 --- /dev/null +++ b/kbqa-common/src/main/java/com/supervision/config/MinioProperties.java @@ -0,0 +1,19 @@ +package com.supervision.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "minio") +public class MinioProperties { + + private String url; + + private String accessKey; + + private String secretKey; + + private String bucketName; +} diff --git a/kbqa-common/src/main/java/com/supervision/config/MybatisMetaHandler.java b/kbqa-common/src/main/java/com/supervision/config/MybatisMetaHandler.java new file mode 100644 index 0000000..3f43623 --- /dev/null +++ b/kbqa-common/src/main/java/com/supervision/config/MybatisMetaHandler.java @@ -0,0 +1,31 @@ +package com.supervision.config; + +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.supervision.util.UserUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.reflection.MetaObject; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.Optional; + +@Component +@Slf4j +public class MybatisMetaHandler implements MetaObjectHandler { + @Override + public void insertFill(MetaObject metaObject) { + log.info("填充创建和开始时间以及新增用户"); + // 填充 + this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); + this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); + Optional.ofNullable(UserUtil.getUser()).ifPresent(user -> this.strictInsertFill(metaObject, "createUserId", String.class, user.getId())); + Optional.ofNullable(UserUtil.getUser()).ifPresent(user -> this.strictInsertFill(metaObject, "updateUserId", String.class, user.getId())); + } + + @Override + public void updateFill(MetaObject metaObject) { + log.info("填充修改时间以及修改用户"); + this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); + Optional.ofNullable(UserUtil.getUser()).ifPresent(user -> this.strictInsertFill(metaObject, "updateUserId", String.class, user.getId())); + } +} diff --git a/kbqa-common/src/main/java/com/supervision/config/SaTokenConfigure.java b/kbqa-common/src/main/java/com/supervision/config/SaTokenConfigure.java deleted file mode 100644 index 62a8d90..0000000 --- a/kbqa-common/src/main/java/com/supervision/config/SaTokenConfigure.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.supervision.config; - -import cn.dev33.satoken.context.SaHolder; -import cn.dev33.satoken.filter.SaServletFilter; -import cn.dev33.satoken.router.SaRouter; -import cn.dev33.satoken.stp.StpUtil; -import cn.dev33.satoken.util.SaResult; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ArrayUtil; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -@Configuration -public class SaTokenConfigure { - - public String[] ignorePathPatterns() { - List paths = new ArrayList<>(); - paths.add("/swagger-resources/**"); - paths.add("/webjars/**"); - paths.add("/v2/**"); - paths.add("/swagger-ui.html/**"); - paths.add("/doc.html/**"); - paths.add("/error"); - paths.add("/favicon.ico"); - paths.add("/user/login"); - return ArrayUtil.toArray(paths,String.class); - } - - /** - * 注册 [Sa-Token全局过滤器] - */ - @Bean - public SaServletFilter getSaServletFilter() { - return new SaServletFilter() - - // 指定 拦截路由 与 放行路由 - .addInclude("/**") - // 排除掉部分不需要登录的路由 - .addExclude(ignorePathPatterns()) - - // 认证函数: 每次请求执行 - .setAuth(obj -> { - System.out.println("---------- 进入Sa-Token全局认证 -----------"); - // 登录认证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录 - SaRouter.match("/**", "/user/doLogin", StpUtil::checkLogin); - - // 更多拦截处理方式,请参考“路由拦截式鉴权”章节 */ - }) - - // 异常处理函数:每次认证函数发生异常时执行此函数 - .setError(e -> { - System.out.println("---------- 进入Sa-Token异常处理 -----------"); - return SaResult.error(e.getMessage()); - }); - } - - -} diff --git a/kbqa-common/src/main/java/com/supervision/config/WebConfig.java b/kbqa-common/src/main/java/com/supervision/config/WebConfig.java index 0621f30..f2bf55e 100644 --- a/kbqa-common/src/main/java/com/supervision/config/WebConfig.java +++ b/kbqa-common/src/main/java/com/supervision/config/WebConfig.java @@ -6,8 +6,10 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -19,6 +21,32 @@ import java.util.List; @Configuration public class WebConfig implements WebMvcConfigurer { + @Autowired + private RedisTemplate redisTemplate; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 添加权限拦截器 + registry.addInterceptor(new JwtInterceptor(redisTemplate)) + .addPathPatterns("/**") + .excludePathPatterns(ignorePathPatterns()); + } + + public List ignorePathPatterns() { + List paths = new ArrayList<>(); + paths.add("/swagger-resources/**"); + paths.add("/webjars/**"); + paths.add("/v2/**"); + paths.add("/swagger-ui.html/**"); + paths.add("/doc.html/**"); + paths.add("/error"); + paths.add("/favicon.ico"); + paths.add("/user/login"); + // 开发环境,放开不校验token.每次修改这里需要重启(热部署不行) +// paths.add("/**"); + return paths; + } + @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); diff --git a/kbqa-common/src/main/java/com/supervision/util/MinioUtil.java b/kbqa-common/src/main/java/com/supervision/util/MinioUtil.java new file mode 100644 index 0000000..8b02abc --- /dev/null +++ b/kbqa-common/src/main/java/com/supervision/util/MinioUtil.java @@ -0,0 +1,95 @@ +package com.supervision.util; + +import com.supervision.config.MinioProperties; +import io.minio.*; +import io.minio.http.Method; +import lombok.extern.slf4j.Slf4j; + +import java.io.InputStream; +import java.util.UUID; + +@Slf4j +public class MinioUtil { + private static final MinioClient minioClient = SpringBeanUtil.getBean(MinioClient.class); + + private static final String bucketName = SpringBeanUtil.getBean(MinioProperties.class).getBucketName(); + + static { + try { + if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) { + + log.info("未找到bucket,自动建立"); + minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + + /** + * 上传一个文件 + */ + public static String uploadFile(InputStream stream) throws Exception { + ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(UUID.randomUUID().toString()) + .stream(stream, stream.available(), -1).build()); + return objectWriteResponse.object(); + } + + /** + * 上传文件 + * @param stream 文件流 + * @param contentType 文件类型 + * @return 文件id + * @throws Exception + */ + public static String uploadFile(InputStream stream,String contentType) throws Exception { + ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(UUID.randomUUID().toString()) + .stream(stream, stream.available(), -1).contentType(contentType).build()); + return objectWriteResponse.object(); + } + + /** + * 下载一个文件 + */ + public static InputStream download(String fileId) throws Exception { + return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileId).build()); + } + + + /** + * 删除一个对象 + */ + public static void deleteObject(String fileId) throws Exception { + minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileId).build()); + } + + + /** + * 获取文件信息 + * + * @Param: [bucket, objectName] + * @return: java.lang.String + * @Author: MrFugui + * @Date: 2021/11/15 + */ + public static String getObjectInfo(String fileId) throws Exception { + return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileId).build()).toString(); + } + + /** + * 生成一个给HTTP GET请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。 + * + * @Param: [bucketName, objectName, expires] + * @return: java.lang.String + * @Author: MrFugui + * @Date: 2021/11/15 + */ + public static String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) throws Exception { + GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs + .builder().bucket(bucketName).object(objectName).expiry(expires).method(Method.GET).build(); + return minioClient.getPresignedObjectUrl(build); + } + + +} diff --git a/kbqa-common/src/main/java/com/supervision/util/UserUtil.java b/kbqa-common/src/main/java/com/supervision/util/UserUtil.java new file mode 100644 index 0000000..f68fe77 --- /dev/null +++ b/kbqa-common/src/main/java/com/supervision/util/UserUtil.java @@ -0,0 +1,39 @@ +package com.supervision.util; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import com.supervision.config.ThreadCache; +import com.supervision.exception.BusinessException; +import lombok.Data; + +public class UserUtil { + + public static UserDTO getUser() { + String userStr = ThreadCache.USER.get(); + UserDTO userDTO = JSONUtil.toBean(userStr, UserDTO.class); + if (ObjectUtil.isEmpty(userDTO)) { + throw new BusinessException("未获取到用户信息"); + } + return userDTO; + } + + public static String getUserToken() { + return ThreadCache.USER.get(); + } + + @Data + public static class UserDTO { + private String id; + + private String userName; + + private String realName; + + private String account; + + private String roleId; + + private String deptId; + + } +} diff --git a/kbqa-report/pom.xml b/kbqa-report/pom.xml index e9870c5..3497a72 100644 --- a/kbqa-report/pom.xml +++ b/kbqa-report/pom.xml @@ -14,6 +14,11 @@ + + com.supervision + kbqa-common + 1.0-SNAPSHOT + org.springframework.boot spring-boot-starter diff --git a/kbqa-report/src/main/java/com/supervision/controller/UserController.java b/kbqa-report/src/main/java/com/supervision/controller/UserController.java new file mode 100644 index 0000000..1e577b7 --- /dev/null +++ b/kbqa-report/src/main/java/com/supervision/controller/UserController.java @@ -0,0 +1,13 @@ +package com.supervision.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping("user") +public class UserController { + + @GetMapping("login") + public void login(){ + + } +} diff --git a/kbqa-report/src/main/resources/application.yml b/kbqa-report/src/main/resources/application.yml index 78c0ea7..3f97a03 100644 --- a/kbqa-report/src/main/resources/application.yml +++ b/kbqa-report/src/main/resources/application.yml @@ -2,14 +2,14 @@ server: port: 9800 servlet: context-path: /knowledge-report - undertow: - # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的 - max-http-post-size: -1 - # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 - # 每块buffer的空间大小,越小的空间被利用越充分 - buffer-size: 512 - # 是否分配的直接内存 - direct-buffers: true + undertow: + # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的 + max-http-post-size: -1 + # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 + # 每块buffer的空间大小,越小的空间被利用越充分 + buffer-size: 512 + # 是否分配的直接内存 + direct-buffers: true spring: profiles: @@ -45,4 +45,18 @@ spring: enabled: true # 是否开启 FilterStat,默认true log-slow-sql: true # 是否开启 慢SQL 记录,默认false slow-sql-millis: 5000 # 慢 SQL 的标准,默认 3000,单位:毫秒 - merge-sql: false # 合并多个连接池的监控数据,默认false \ No newline at end of file + merge-sql: false # 合并多个连接池的监控数据,默认false + redis: + host: 192.168.10.137 + port: 6379 + password: 123456 +minio: + url: http://192.168.10.137:9002 + accessKey: admin + secretKey: 12345678 + bucketName: kbqa-dev + +mybatis-plus: + mapper-locations: classpath*:mapper/**/*.xml + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl \ No newline at end of file diff --git a/kbqa-report/src/test/java/com/supervision/DocumentTest.java b/kbqa-report/src/test/java/com/supervision/DocumentTest.java deleted file mode 100644 index b742604..0000000 --- a/kbqa-report/src/test/java/com/supervision/DocumentTest.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.supervision; - -import com.supervision.entity.Item; -import com.supervision.repository.ItemRepository; -import org.elasticsearch.index.query.MatchQueryBuilder; -import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.search.aggregations.AggregationBuilders; -import org.elasticsearch.search.aggregations.bucket.terms.StringTerms; -import org.elasticsearch.search.aggregations.metrics.InternalAvg; -import org.elasticsearch.search.sort.SortBuilders; -import org.elasticsearch.search.sort.SortOrder; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; -import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage; -import org.springframework.data.elasticsearch.core.query.FetchSourceFilter; -import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; -import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; - -import java.util.List; - -@SpringBootTest -public class DocumentTest { - - @Autowired - private ItemRepository itemRepository; - - @Test - public void testSave() { - //单个添加 - /* Item item = new Item(1L, "小米8", "手机", "小米", 2299.00, "img13.360buyimg.com/12345.jpg"); - itemRepository.save(item); - //批量添加 - List list = new ArrayList<>(); - list.add(new Item(2L, "荣耀V10", "手机", "华为", 2799.00, "img13.360buyimg.com/111.jpg")); - list.add(new Item(3L, "坚果手机R1", "手机", "锤子", 3699.00, "img13.360buyimg.com/222.jpg")); - list.add(new Item(4L, "华为meta10", "手机", "华为", 4499.00, "img13.360buyimg.com/333.jpg")); - list.add(new Item(5L, "小米Mix2S", "手机", "小米", 4299.00, "img13.360buyimg.com/444.jpg")); - itemRepository.saveAll(list);*/ - } - - @Test - public void testFindAll() { - Iterable items = itemRepository.findAll(Sort.by(Sort.Direction.DESC, "price")); - items.forEach(item -> System.out.println(item)); - } - - @Test - public void queryByPriceBetween() { - List items = itemRepository.findByPriceBetween(4000.00, 5000.00); - items.forEach(item -> System.out.println(item)); - } - - - - @Test - public void testNativeQuery() { - // 构建查询条件 - NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); - // 添加基本的分词查询 - queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米")); - // 执行搜索,获取结果 - Page items = itemRepository.search(queryBuilder.build()); - // 打印总条数 - System.out.println(items.getTotalElements()); - // 打印总页数 - System.out.println(items.getTotalPages()); - items.forEach(System.out::println); - } - - @Test - public void testNativePageQuery() { - //设置分页 - int page = 0; - int size = 3; - //构建查询条件 - NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("category", "手机")) - .withPageable(PageRequest.of(page, size)).build(); - //获取结果 - Page items = itemRepository.search(searchQuery); - System.out.println(String.format("总页数:%s", items.getTotalPages())); - System.out.println(String.format("总条数:%s", items.getTotalElements())); - System.out.println(String.format("每页大小:%s", items.getSize())); - System.out.println(String.format("当前页:%s", items.getNumber())); - items.forEach(System.out::println); - } - - @Test - public void testSort() { - // 构建查询条件 - NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("category", "手机")) - .withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC)).build(); - // 执行搜索,获取结果 - Page items = itemRepository.search(searchQuery); - System.out.println(String.format("总条数:%s", items.getTotalElements())); - items.forEach(System.out::println); - } - - @Test - public void testAgg() { - NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() - //不查询任何结果 - .withSourceFilter(new FetchSourceFilter(new String[]{""}, null)) - // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand - .addAggregation(AggregationBuilders.terms("brands").field("brand")) - .build(); - // 2、查询,需要把结果强转为AggregatedPage类型 - AggregatedPage aggPage = (AggregatedPage) itemRepository.search(searchQuery); - //3.解析 - //3.1取出名为brands的聚合 - StringTerms agg = (StringTerms) aggPage.getAggregation("brands"); - //3.2获取桶 - List buckets = agg.getBuckets(); - //3.3遍历 - buckets.forEach(bucket -> - System.out.println(String.format("桶的key:%s,文档数量:%s", bucket.getKeyAsString(), bucket.getDocCount())) - ); - } - - @Test - public void testSubAgg() { - NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withSourceFilter(new FetchSourceFilter(new String[]{}, null)) - .addAggregation( - // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand - AggregationBuilders.terms("brands").field("brand") - // 在品牌聚合桶内进行嵌套聚合,求平均值 - .subAggregation(AggregationBuilders.avg("priceAvg").field("price")) - ).build(); - - // 2、查询,需要把结果强转为AggregatedPage类型 - AggregatedPage aggPage = (AggregatedPage) itemRepository.search(searchQuery); - // 3、解析 - // 3.1、从结果中取出名为brands的那个聚合, - // 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型 - StringTerms agg = (StringTerms) aggPage.getAggregation("brands"); - // 3.2、获取桶 - List buckets = agg.getBuckets(); - // 3.3 遍历 - buckets.forEach(bucket -> { - // 3.4 获取桶中的key和文档数量 - System.out.println(String.format("桶的key:%s,文档数量:%s", bucket.getKeyAsString(), bucket.getDocCount())); - // 3.5 获取子聚合结果 - InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("priceAvg"); - System.out.println("平均售价:" + avg.getValue()); - }); - } -} diff --git a/kbqa-report/src/test/java/com/supervision/KnowledgeReportApplicationTests.java b/kbqa-report/src/test/java/com/supervision/KnowledgeReportApplicationTests.java deleted file mode 100644 index 58b4edd..0000000 --- a/kbqa-report/src/test/java/com/supervision/KnowledgeReportApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.supervision; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class KnowledgeReportApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/kbqa-report/src/test/java/com/supervision/TableModifyTest.java b/kbqa-report/src/test/java/com/supervision/TableModifyTest.java new file mode 100644 index 0000000..9b910b1 --- /dev/null +++ b/kbqa-report/src/test/java/com/supervision/TableModifyTest.java @@ -0,0 +1,15 @@ +package com.supervision; + +import lombok.extern.slf4j.Slf4j; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@Slf4j +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@RunWith(SpringJUnit4ClassRunner.class) +public class TableModifyTest { + + + +} diff --git a/kbqa-report/src/test/java/com/supervision/entity/Item.java b/kbqa-report/src/test/java/com/supervision/entity/Item.java deleted file mode 100644 index 29f4246..0000000 --- a/kbqa-report/src/test/java/com/supervision/entity/Item.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.supervision.entity; - -import org.springframework.data.annotation.Id; -import org.springframework.data.elasticsearch.annotations.Document; -import org.springframework.data.elasticsearch.annotations.Field; -import org.springframework.data.elasticsearch.annotations.FieldType; - -/** - * Spring Data通过注解来声明字段的映射属性,有下面的三个注解: - * - * @Document 作用在类,标记实体类为文档对象,一般有两个属性 - * indexName:对应索引库名称 - * type:对应在索引库中的类型 - * shards:分片数量,默认5 - * replicas:副本数量,默认1 - * @Id 作用在成员变量,标记一个字段作为id主键 - * @Field 作用在成员变量,标记为文档的字段,并指定字段映射属性: - * type:字段类型,取值是枚举:FieldType - * index:是否索引,布尔类型,默认是true - * store:是否存储,布尔类型,默认是false - * analyzer:分词器名称 - */ -@Document(indexName = "item", type = "docs", shards = 1, replicas = 0) -public class Item { - @Id - Long id; - @Field(type = FieldType.Text,analyzer = "ik_max_word") - String title; //标题 - @Field(type = FieldType.Keyword) - String category;// 分类 - @Field(type = FieldType.Keyword) - String brand; // 品牌 - @Field(type = FieldType.Double) - Double price; // 价格 - @Field(index = false,type = FieldType.Keyword) - String images; // 图片地址 - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getCategory() { - return category; - } - - public void setCategory(String category) { - this.category = category; - } - - public String getBrand() { - return brand; - } - - public void setBrand(String brand) { - this.brand = brand; - } - - public Double getPrice() { - return price; - } - - public void setPrice(Double price) { - this.price = price; - } - - public String getImages() { - return images; - } - - public void setImages(String images) { - this.images = images; - } - - public Item() { - } - - public Item(Long id, String title, String category, String brand, Double price, String images) { - this.id = id; - this.title = title; - this.category = category; - this.brand = brand; - this.price = price; - this.images = images; - } - - @Override - public String toString() { - return "Item{" + - "id=" + id + - ", title='" + title + '\'' + - ", category='" + category + '\'' + - ", brand='" + brand + '\'' + - ", price=" + price + - ", images='" + images + '\'' + - '}'; - } -} \ No newline at end of file diff --git a/kbqa-report/src/test/java/com/supervision/repository/ItemRepository.java b/kbqa-report/src/test/java/com/supervision/repository/ItemRepository.java deleted file mode 100644 index 7ff7ec7..0000000 --- a/kbqa-report/src/test/java/com/supervision/repository/ItemRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.supervision.repository; - -import com.supervision.entity.Item; -import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; - -import java.util.List; - -public interface ItemRepository extends ElasticsearchRepository { - /** - * 根据价格区间查询 - */ - List findByPriceBetween(Double price11, Double price2); -} diff --git a/pom.xml b/pom.xml index 47e64a3..8979885 100644 --- a/pom.xml +++ b/pom.xml @@ -29,10 +29,13 @@ 1.8 8.0.26 3.3.1 + 2.3.5.RELEASE 1.1.22 5.8.16 3.0.3 1.37.0 + 2.2.5 + 8.5.7 @@ -58,6 +61,15 @@ ${mybatis-puls-spring-boot.version} + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + com.github.xiaoymin knife4j-spring-boot-starter @@ -77,10 +89,12 @@ - cn.dev33 - sa-token-spring-boot-starter - ${sa-token.version} + io.minio + minio + ${minio.version} + +