From 8a7f6a25ac6a97d7c889bad42e1458ba73d43fa2 Mon Sep 17 00:00:00 2001 From: 00fly <00fly@noreply.gitcode.com> Date: Sat, 26 Oct 2024 20:57:10 +0800 Subject: [PATCH] =?UTF-8?q?add=20CSDN=E5=8D=9A=E5=AE=A2=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../.gitignore" | 7 + .../Dockerfile" | 16 ++ .../README.md" | 19 ++ .../docker/docker-compose.yml" | 21 ++ .../docker/restart.sh" | 2 + .../docker/stop.sh" | 2 + .../pom.xml" | 181 ++++++++++++++++++ .../main/java/com/fly/SimpleApplication.java" | 15 ++ .../com/fly/core/config/Knife4jConfig.java" | 62 ++++++ .../com/fly/core/config/WebClientConfig.java" | 18 ++ .../com/fly/core/config/WebMvcConfig.java" | 85 ++++++++ .../fly/core/runner/WebStartedRunner.java" | 33 ++++ .../com/fly/core/utils/JsonBeanUtils.java" | 107 +++++++++++ .../fly/core/utils/SpringContextUtils.java" | 103 ++++++++++ .../java/com/fly/demo/entity/Article.java" | 13 ++ .../java/com/fly/demo/entity/BlogData.java" | 9 + .../java/com/fly/demo/entity/Record.java" | 11 ++ .../com/fly/demo/service/DataService.java" | 43 +++++ .../java/com/fly/demo/sse/SSEServer.java" | 102 ++++++++++ .../com/fly/demo/web/DataPushController.java" | 73 +++++++ .../src/main/resources/application-dev.yml" | 6 + .../src/main/resources/application.yml" | 22 +++ .../src/main/resources/static/error/404.html" | 31 +++ .../src/main/resources/static/index.html" | 80 ++++++++ .../src/test/java/com/fly/AlgorithmTest.java" | 106 ++++++++++ .../java/com/fly/http/WebClientTest.java" | 69 +++++++ .../src/test/resources/log4j2.xml" | 28 +++ 27 files changed, 1264 insertions(+) create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/.gitignore" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/Dockerfile" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/README.md" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/docker-compose.yml" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/restart.sh" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/stop.sh" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/pom.xml" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/SimpleApplication.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/Knife4jConfig.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/WebClientConfig.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/WebMvcConfig.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/runner/WebStartedRunner.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/utils/JsonBeanUtils.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/utils/SpringContextUtils.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/Article.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/BlogData.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/Record.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/service/DataService.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/sse/SSEServer.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/web/DataPushController.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/application-dev.yml" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/application.yml" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/static/error/404.html" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/static/index.html" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/java/com/fly/AlgorithmTest.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/java/com/fly/http/WebClientTest.java" create mode 100644 "CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/resources/log4j2.xml" diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/.gitignore" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/.gitignore" new file mode 100644 index 0000000..9ac5367 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/.gitignore" @@ -0,0 +1,7 @@ +target/ +logs/ +.classpath +.project +.settings +.factorypath +upload/ \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/Dockerfile" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/Dockerfile" new file mode 100644 index 0000000..7022708 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/Dockerfile" @@ -0,0 +1,16 @@ +#基础镜像 +FROM adoptopenjdk/openjdk8-openj9:alpine-slim + +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ + echo 'Asia/Shanghai' >/etc/timezone + +#引入运行包 +COPY target/*.jar /app.jar + +#指定交互端口 +EXPOSE 8081 + +CMD ["--server.port=8081"] + +#项目的启动方式 +ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-Xshareclasses", "-Xquickstart", "-jar", "/app.jar"] diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/README.md" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/README.md" new file mode 100644 index 0000000..29df1a1 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/README.md" @@ -0,0 +1,19 @@ +# csdn-reader + +csdn博客文章阅读器web版本 + +镜像已经上传到公开镜像仓库 + +# 一、使用技术 +| 技术 | 说明 | +|--|--| +| SSE |服务端向客户端推送数据 | +| json | 数据解析 | +| WebClient | 访问http接口 | +|cache注解 | 缓存url数据| +|openj9| IBM高性能企业级虚拟机,大幅减少容器运行内存| + + +# 二、功能展示 + +点击链接 [http://124.71.129.204:8081](http://124.71.129.204:8081) 访问。 \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/docker-compose.yml" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/docker-compose.yml" new file mode 100644 index 0000000..7f86e74 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/docker-compose.yml" @@ -0,0 +1,21 @@ +version: '3.7' +services: + csdn-reader: + image: registry.cn-shanghai.aliyuncs.com/00fly/csdn-reader:1.0.0 + container_name: csdn-reader + deploy: + resources: + limits: + cpus: '1.0' + memory: 200M + reservations: + cpus: '0.05' + memory: 200M + ports: + - 8081:8081 + restart: on-failure + logging: + driver: json-file + options: + max-size: '5m' + max-file: '1' \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/restart.sh" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/restart.sh" new file mode 100644 index 0000000..fd0d951 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/restart.sh" @@ -0,0 +1,2 @@ +#!/bin/bash +docker-compose down && docker-compose up -d && docker stats \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/stop.sh" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/stop.sh" new file mode 100644 index 0000000..28bdde6 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/docker/stop.sh" @@ -0,0 +1,2 @@ +#!/bin/bash +docker-compose down \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/pom.xml" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/pom.xml" new file mode 100644 index 0000000..b6bed33 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/pom.xml" @@ -0,0 +1,181 @@ + + + 4.0.0 + com.fly + csdn-reader + 1.0.0 + jar + + + org.springframework.boot + spring-boot-starter-parent + 2.2.4.RELEASE + + + + + UTF-8 + registry.cn-shanghai.aliyuncs.com + 1.8 + true + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-starter-jetty + + + com.github.xiaoymin + knife4j-spring-boot-starter + 2.0.8 + + + + + com.lmax + disruptor + 3.4.2 + + + + commons-io + commons-io + 2.5 + + + org.apache.commons + commons-lang3 + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + org.projectlombok + lombok + provided + + + org.springframework.boot + spring-boot-devtools + true + + + + + + + public + aliyun nexus + https://maven.aliyun.com/repository/public/ + + true + + + + + + public + aliyun nexus + https://maven.aliyun.com/repository/public/ + + true + + + false + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + + io.fabric8 + docker-maven-plugin + 0.40.3 + + + package + + build + push + + + + + + + + + + ${docker.hub} + + + ${docker.hub}/00fly/${project.artifactId}:${project.version} + + ${project.basedir} + + + + + + + + + src/main/java + + **/*.java + + + + src/main/resources + + **/** + + false + + + + diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/SimpleApplication.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/SimpleApplication.java" new file mode 100644 index 0000000..5a450a3 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/SimpleApplication.java" @@ -0,0 +1,15 @@ +package com.fly; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; + +@EnableCaching +@SpringBootApplication +public class SimpleApplication +{ + public static void main(String[] args) + { + SpringApplication.run(SimpleApplication.class, args); + } +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/Knife4jConfig.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/Knife4jConfig.java" new file mode 100644 index 0000000..0b01668 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/Knife4jConfig.java" @@ -0,0 +1,62 @@ +package com.fly.core.config; + +import java.util.Collections; +import java.util.List; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; + +import io.swagger.annotations.ApiOperation; +import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.ApiKey; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; + +/** + * Knife4jConfig + * + */ +@EnableKnife4j +@Configuration +@EnableSwagger2WebMvc +@ConditionalOnWebApplication +@Import(BeanValidatorPluginsConfiguration.class) +public class Knife4jConfig +{ + /** + * 开发、测试环境接口文档打开 + * + * @return + * @see [类、类#方法、类#成员] + */ + @Bean + Docket createRestApi() + { + return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()) + .enable(true) + .select() + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) + .paths(PathSelectors.any()) // 包下的类,生成接口文档 + .build() + .securitySchemes(security()); + } + + private ApiInfo apiInfo() + { + return new ApiInfoBuilder().title("数据接口API").description("接口文档").termsOfServiceUrl("http://00fly.online/").version("1.0.0").build(); + } + + private List security() + { + return Collections.singletonList(new ApiKey("token", "token", "header")); + } +} \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/WebClientConfig.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/WebClientConfig.java" new file mode 100644 index 0000000..67e10d6 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/WebClientConfig.java" @@ -0,0 +1,18 @@ +package com.fly.core.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +/** + * 配置WebClient + */ +@Configuration +public class WebClientConfig +{ + @Bean + WebClient webClient() + { + return WebClient.builder().codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(-1)).build(); + } +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/WebMvcConfig.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/WebMvcConfig.java" new file mode 100644 index 0000000..126c662 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/config/WebMvcConfig.java" @@ -0,0 +1,85 @@ +package com.fly.core.config; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * + * mvc配置 + * + * @author 00fly + * @version [版本号, 2021年4月23日] + * @see [相关类/方法] + * @since [产品/模块版本] + */ +@Configuration +@ConditionalOnWebApplication +public class WebMvcConfig implements WebMvcConfigurer +{ + @Override + public void configureMessageConverters(final List> converters) + { + converters.add(stringHttpMessageConverter()); + converters.add(mappingJackson2HttpMessageConverter()); + } + + @Override + public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) + { + configurer.defaultContentType(MediaType.APPLICATION_JSON); + configurer.ignoreUnknownPathExtensions(false); + configurer.favorPathExtension(true); + configurer.favorParameter(false); + final Map mediaTypes = new ConcurrentHashMap<>(3); + mediaTypes.put("atom", MediaType.APPLICATION_ATOM_XML); + mediaTypes.put("html", MediaType.TEXT_HTML); + mediaTypes.put("json", MediaType.APPLICATION_JSON); + configurer.mediaTypes(mediaTypes); + } + + @Bean + StringHttpMessageConverter stringHttpMessageConverter() + { + return new StringHttpMessageConverter(); + } + + @Bean + MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() + { + final MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(); + final List list = new ArrayList<>(); + list.add(MediaType.APPLICATION_JSON); + list.add(MediaType.APPLICATION_XML); + list.add(MediaType.TEXT_PLAIN); + list.add(MediaType.TEXT_HTML); + list.add(MediaType.TEXT_XML); + messageConverter.setSupportedMediaTypes(list); + return messageConverter; + } + + /** + * 等价于mvc中
+ * 等价于mvc中 + * + * @param registry + */ + @Override + public void addViewControllers(final ViewControllerRegistry registry) + { + registry.addViewController("/").setViewName("redirect:index"); + registry.addViewController("/index").setViewName("index.html"); + } +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/runner/WebStartedRunner.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/runner/WebStartedRunner.java" new file mode 100644 index 0000000..2ef0561 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/runner/WebStartedRunner.java" @@ -0,0 +1,33 @@ +package com.fly.core.runner; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import com.fly.core.utils.SpringContextUtils; + +@Component +@Configuration +@ConditionalOnWebApplication +public class WebStartedRunner +{ + @Bean + @ConditionalOnWebApplication + CommandLineRunner init() + { + return args -> { + if (SystemUtils.IS_OS_WINDOWS)// 防止非windows系统报错,启动失败 + { + String url = SpringContextUtils.getServerBaseURL(); + if (StringUtils.containsNone(url, "-")) // junit port:-1 + { + Runtime.getRuntime().exec("cmd /c start /min " + url); + } + } + }; + } +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/utils/JsonBeanUtils.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/utils/JsonBeanUtils.java" new file mode 100644 index 0000000..2a0e169 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/utils/JsonBeanUtils.java" @@ -0,0 +1,107 @@ +package com.fly.core.utils; + +import java.io.IOException; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * JsonBean转换工具 + * + * @author 00fly + * + */ +public class JsonBeanUtils +{ + private static ObjectMapper objectMapper = new ObjectMapper(); + + /** + * bean转json字符串 + * + * @param bean + * @return + * @throws IOException + */ + public static String beanToJson(Object bean) + throws IOException + { + return beanToJson(bean, false); + } + + /** + * bean转json字符串 + * + * @param bean + * @param pretty 是否格式美化 + * @return + * @throws IOException + */ + public static String beanToJson(Object bean, boolean pretty) + throws IOException + { + String jsonText = objectMapper.writeValueAsString(bean); + if (pretty) + { + return objectMapper.readTree(jsonText).toPrettyString(); + } + return objectMapper.readTree(jsonText).toString(); + } + + /** + * json字符串转bean + * + * @param jsonText + * @return + * @throws IOException + */ + public static T jsonToBean(String jsonText, Class clazz) + throws IOException + { + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true); + return objectMapper.readValue(jsonText, clazz); + } + + /** + * json字符串转bean + * + * @param jsonText + * @param clazz + * @param ingoreError 是否忽略无法识别字段 + * @return + * @throws IOException + */ + public static T jsonToBean(String jsonText, Class clazz, boolean ingoreError) + throws IOException + { + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, !ingoreError); + return objectMapper.readValue(jsonText, clazz); + } + + /** + * json字符串转bean + * + * @param jsonText + * @return + * @throws IOException + */ + public static T jsonToBean(String jsonText, JavaType javaType) + throws IOException + { + return objectMapper.readValue(jsonText, javaType); + } + + /** + * json字符串转bean + * + * @param jsonText + * @return + * @throws IOException + */ + public static T jsonToBean(String jsonText, TypeReference typeRef) + throws IOException + { + return objectMapper.readValue(jsonText, typeRef); + } +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/utils/SpringContextUtils.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/utils/SpringContextUtils.java" new file mode 100644 index 0000000..6601c01 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/core/utils/SpringContextUtils.java" @@ -0,0 +1,103 @@ +package com.fly.core.utils; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import javax.servlet.ServletContext; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import lombok.extern.slf4j.Slf4j; + +/** + * Spring Context 工具类 + */ +@Slf4j +@Component +public class SpringContextUtils implements ApplicationContextAware +{ + private static ApplicationContext applicationContext; + + private static String SERVER_BASE_URL = null; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException + { + log.info("###### execute setApplicationContext ######"); + SpringContextUtils.applicationContext = applicationContext; + } + + public static ApplicationContext getApplicationContext() + { + return applicationContext; + } + + public static T getBean(Class clazz) + { + Assert.notNull(applicationContext, "applicationContext is null"); + return applicationContext.getBean(clazz); + } + + /** + * execute @PostConstruct May be SpringContextUtils not inited, throw NullPointerException + * + * @return + */ + public static String getActiveProfile() + { + Assert.notNull(applicationContext, "applicationContext is null"); + String[] profiles = applicationContext.getEnvironment().getActiveProfiles(); + return StringUtils.join(profiles, ","); + } + + /** + * can use in @PostConstruct + * + * @param context + * @return + */ + public static String getActiveProfile(ApplicationContext context) + { + Assert.notNull(context, "context is null"); + String[] profiles = context.getEnvironment().getActiveProfiles(); + return StringUtils.join(profiles, ","); + } + + /** + * get web服务基准地址,一般为 http://${ip}:${port}/${contentPath} + * + * @return + * @throws UnknownHostException + * @see [类、类#方法、类#成员] + */ + public static String getServerBaseURL() + throws UnknownHostException + { + ServletContext servletContext = getBean(ServletContext.class); + Assert.notNull(servletContext, "servletContext is null"); + if (SERVER_BASE_URL == null) + { + String ip = InetAddress.getLocalHost().getHostAddress(); + SERVER_BASE_URL = "http://" + ip + ":" + getProperty("server.port") + servletContext.getContextPath(); + } + return SERVER_BASE_URL; + } + + /** + * getProperty + * + * @param key eg:server.port + * @return + * @see [类、类#方法、类#成员] + */ + public static String getProperty(String key) + { + return applicationContext.getEnvironment().getProperty(key, ""); + } +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/Article.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/Article.java" new file mode 100644 index 0000000..cea2116 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/Article.java" @@ -0,0 +1,13 @@ +package com.fly.demo.entity; + +import lombok.Data; + +@Data +public class Article +{ + String title; + + String url; + + Long viewCount; +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/BlogData.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/BlogData.java" new file mode 100644 index 0000000..4d6123f --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/BlogData.java" @@ -0,0 +1,9 @@ +package com.fly.demo.entity; + +import lombok.Data; + +@Data +public class BlogData +{ + private Record data; +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/Record.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/Record.java" new file mode 100644 index 0000000..4cf98d3 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/entity/Record.java" @@ -0,0 +1,11 @@ +package com.fly.demo.entity; + +import java.util.List; + +import lombok.Data; + +@Data +public class Record +{ + private List
list; +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/service/DataService.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/service/DataService.java" new file mode 100644 index 0000000..aaa8fb9 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/service/DataService.java" @@ -0,0 +1,43 @@ +package com.fly.demo.service; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; + +import com.fly.core.utils.JsonBeanUtils; +import com.fly.demo.entity.Article; +import com.fly.demo.entity.BlogData; + +import lombok.extern.slf4j.Slf4j; + +/** + * DataService + */ +@Slf4j +@Service +public class DataService +{ + @Autowired + private WebClient webClient; + + /** + * 获取url数据列表 + * + * @return + * @throws IOException + */ + @Cacheable(cacheNames = "data", key = "'articles'", sync = true) + public List
getArticles() + throws IOException + { + log.info("★★★★★★★★ getData from webApi ★★★★★★★★"); + String resp = webClient.get().uri("https://00fly.online/upload/data.json").acceptCharset(StandardCharsets.UTF_8).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(String.class).block(); + return JsonBeanUtils.jsonToBean(resp, BlogData.class, true).getData().getList(); + } +} \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/sse/SSEServer.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/sse/SSEServer.java" new file mode 100644 index 0000000..ac714b7 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/sse/SSEServer.java" @@ -0,0 +1,102 @@ +package com.fly.demo.sse; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; + +import org.springframework.http.MediaType; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +import lombok.extern.slf4j.Slf4j; + +/** + * Server-Sent Events
+ * https://blog.csdn.net/hhl18730252820/article/details/126244274 + */ +@Slf4j +public class SSEServer +{ + private static List sseEmitters = new CopyOnWriteArrayList<>(); + + public static SseEmitter connect() + { + SseEmitter sseEmitter = new SseEmitter(0L); // 设置超时时间,0表示不过期,默认是30秒,超过时间未完成会抛出异常 + + // 注册回调 + sseEmitter.onCompletion(completionCallBack(sseEmitter)); + sseEmitter.onError(errorCallBack(sseEmitter)); + sseEmitter.onTimeout(timeOutCallBack(sseEmitter)); + sseEmitters.add(sseEmitter); + log.info("###### create new sse connect, count: {}", sseEmitters.size()); + return sseEmitter; + } + + public static void batchSendMessage(Number message) + { + sseEmitters.forEach(it -> { + try + { + it.send(message, MediaType.APPLICATION_JSON); + } + catch (IOException e) + { + log.error("send message error: {}", e.getMessage()); + remove(it); + } + }); + } + + /** + * 指定name,发送message + * @param name + * @param message 普通字符串或json数据 + */ + public static void batchSendMessage(String name, String message) + { + sseEmitters.forEach(it -> { + try + { + it.send(SseEmitter.event().name(name).data(message)); + } + catch (IOException e) + { + log.error("send message error: {}", e.getMessage()); + remove(it); + } + }); + } + + public static void remove(SseEmitter s) + { + if (sseEmitters.contains(s)) + { + sseEmitters.remove(s); + log.info("###### remove SseEmitter, count: {}", sseEmitters.size()); + } + } + + private static Runnable completionCallBack(SseEmitter s) + { + return () -> { + log.info("结束连接"); + remove(s); + }; + } + + private static Runnable timeOutCallBack(SseEmitter s) + { + return () -> { + log.info("连接超时"); + remove(s); + }; + } + + private static Consumer errorCallBack(SseEmitter s) + { + return throwable -> { + log.error("连接异常"); + remove(s); + }; + } +} \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/web/DataPushController.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/web/DataPushController.java" new file mode 100644 index 0000000..0b59f11 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/java/com/fly/demo/web/DataPushController.java" @@ -0,0 +1,73 @@ +package com.fly.demo.web; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.RandomUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +import com.fly.core.utils.JsonBeanUtils; +import com.fly.demo.entity.Article; +import com.fly.demo.service.DataService; +import com.fly.demo.sse.SSEServer; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Controller +@Api(tags = "DataPush接口") +public class DataPushController +{ + long i = 0L; + + @Autowired + DataService dataService; + + @CrossOrigin + @ApiOperation("SSE初始化") + @GetMapping("/sse/connect/{userId}") + public SseEmitter connect(@PathVariable String userId) + { + return SSEServer.connect(); + } + + /** + * 初始化触发 + */ + @PostConstruct + private void init() + { + log.info("Server-Sent Events start"); + new ScheduledThreadPoolExecutor(2).scheduleAtFixedRate(() -> { + i = (i + 1) % 21; + SSEServer.batchSendMessage(i * 5); + if (i < 1) + { + try + { + // 随机选择2个,返回访问量小的 + List
articles = dataService.getArticles(); + int length = articles.size(); + Article article001 = articles.get(RandomUtils.nextInt(0, length)); + Article article002 = articles.get(RandomUtils.nextInt(0, length)); + Article article = article001.getViewCount() < article002.getViewCount() ? article001 : article002; + SSEServer.batchSendMessage("json", JsonBeanUtils.beanToJson(article, false)); + } + catch (IOException e) + { + } + } + }, 2000, 1000, TimeUnit.MILLISECONDS); + } +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/application-dev.yml" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/application-dev.yml" new file mode 100644 index 0000000..f2430ae --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/application-dev.yml" @@ -0,0 +1,6 @@ +#设置日志级别 +logging: + level: + org: + springframework: + web: INFO \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/application.yml" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/application.yml" new file mode 100644 index 0000000..da81d84 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/application.yml" @@ -0,0 +1,22 @@ +server: + port: 8080 + servlet: + context-path: / + session: + timeout: 1800 +spring: + cache: + type: simple + + servlet: + multipart: + max-file-size: 10MB + max-request-size: 100MB + profiles: + active: + - dev + +#设置日志级别 +logging: + level: + root: INFO diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/static/error/404.html" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/static/error/404.html" new file mode 100644 index 0000000..a099b7c --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/static/error/404.html" @@ -0,0 +1,31 @@ + + + + + + + 404(找不到页面) + + + + + + + + + + +
+
+

404!

+

很抱歉,没有找到这个页面!

+

+ 返回首页 +
+
+ + + \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/static/index.html" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/static/index.html" new file mode 100644 index 0000000..3049d3c --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/main/resources/static/index.html" @@ -0,0 +1,80 @@ + + + + + + + + + +CSDN-Reader + + + +
+ + +
+ + + +
+ +
+ + + \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/java/com/fly/AlgorithmTest.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/java/com/fly/AlgorithmTest.java" new file mode 100644 index 0000000..6c3f425 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/java/com/fly/AlgorithmTest.java" @@ -0,0 +1,106 @@ +package com.fly; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; +import java.util.stream.LongStream; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.RandomUtils; +import org.junit.jupiter.api.Test; +import org.springframework.util.StopWatch; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/** + * 模拟测试访问量算法具有补偿功能 + */ +@Slf4j +public class AlgorithmTest +{ + @Test + public void test001() + { + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + int length = 50; + List list = new ArrayList<>(length); + IntStream.range(0, length).forEach(n -> list.add(new Visit(RandomStringUtils.randomAlphanumeric(10), RandomUtils.nextLong(0, 1000)))); + AtomicInteger count1 = new AtomicInteger(0); + + // 写法1 + Collections.sort(list, Comparator.comparing(Visit::getCount)); + list.stream().forEach(v -> log.info("{}. {}", count1.incrementAndGet(), v)); + + // 写法2,与追加后的数据输出比较,注意细微区别 + // list.stream().sorted(Comparator.comparing(Visit::getCount)).forEach(v -> log.info("{}. {}", count1.incrementAndGet(), v)); + + long sum1 = list.stream().mapToLong(Visit::getCount).sum(); + + log.info("******随机选择2条,对count较小的执行追加******"); + LongStream.range(0, 30000).forEach(n -> { + List randomList = new ArrayList<>(2); + IntStream.range(0, 2).forEach(i -> randomList.add(list.get(RandomUtils.nextInt(0, length)))); + Visit visit = randomList.stream().sorted(Comparator.comparing(Visit::getCount)).findFirst().get(); + visit.setCount(visit.getCount() + 1); + }); + AtomicInteger count2 = new AtomicInteger(0); + list.stream().forEach(v -> log.info("{}. {}", count2.incrementAndGet(), v)); + long sum2 = list.stream().mapToLong(Visit::getCount).sum(); + stopWatch.stop(); + log.info("SUM: {} ---> {}, COST {} ms", sum1, sum2, stopWatch.getLastTaskTimeMillis()); + } + + @Test + public void test002() + { + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + int length = 50; + List list = new ArrayList<>(length); + IntStream.range(0, length).forEach(n -> list.add(new Visit(RandomStringUtils.randomAlphanumeric(10), RandomUtils.nextLong(0, 1000)))); + AtomicInteger count1 = new AtomicInteger(0); + + // 写法1 + Collections.sort(list, Comparator.comparing(Visit::getCount)); + list.stream().forEach(v -> log.info("{}. {}", count1.incrementAndGet(), v)); + + // 写法2,与追加后的数据输出比较,注意细微区别 + // list.stream().sorted(Comparator.comparing(Visit::getCount)).forEach(v -> log.info("{}. {}", count1.incrementAndGet(), v)); + + long sum1 = list.stream().mapToLong(Visit::getCount).sum(); + + log.info("******随机选择2条,对count较小的执行追加******"); + LongStream.range(0, 30000).forEach(n -> { + Visit visit001 = list.get(RandomUtils.nextInt(0, 50)); + Visit visit002 = list.get(RandomUtils.nextInt(0, 50)); + Visit visit = (visit001.getCount() > visit002.getCount() ? visit002 : visit001); + visit.setCount(visit.getCount() + 1); + }); + AtomicInteger count2 = new AtomicInteger(0); + list.stream().forEach(v -> log.info("{}. {}", count2.incrementAndGet(), v)); + long sum2 = list.stream().mapToLong(Visit::getCount).sum(); + stopWatch.stop(); + log.info("SUM: {} ---> {}, COST {} ms", sum1, sum2, stopWatch.getLastTaskTimeMillis()); + } +} + +@Data +@AllArgsConstructor +class Visit +{ + /** + * 链接地址 + */ + private String url; + + /** + * 访问量 + */ + private Long count; +} \ No newline at end of file diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/java/com/fly/http/WebClientTest.java" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/java/com/fly/http/WebClientTest.java" new file mode 100644 index 0000000..7e03083 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/java/com/fly/http/WebClientTest.java" @@ -0,0 +1,69 @@ +package com.fly.http; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.client.WebClient; + +import com.fly.core.utils.JsonBeanUtils; +import com.fly.demo.entity.Article; +import com.fly.demo.entity.BlogData; + +import lombok.extern.slf4j.Slf4j; + +/** + * https://blog.csdn.net/zzhongcy/article/details/105412842 + * + */ +@Slf4j +@DisplayName("WebClient测试") +public class WebClientTest +{ + private static WebClient webClient; + + @BeforeAll + public static void init() + { + // 默认底层使用Netty + log.info("--- init ---"); + webClient = WebClient.builder().codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(-1)).build(); + + // 内置支持Jetty反应性HttpClient实现,手工编码指定 + // webClient = WebClient.builder().baseUrl("https://blog.csdn.net").clientConnector(new JettyClientHttpConnector()).build(); + } + + @Test + @DisplayName("getUrls请求") + public void testGetUrls() + throws InterruptedException, IOException + { + AtomicInteger count = new AtomicInteger(0); + getBlogData().getData() + .getList() + .stream() + .map(Article::getUrl) + .forEach(url -> webClient.get() + .uri(url) + .acceptCharset(StandardCharsets.UTF_8) + .accept(MediaType.TEXT_HTML) + .retrieve() + .bodyToMono(String.class) + .subscribe(r -> log.info("process complted: {}. {}", count.incrementAndGet(), url), e -> log.error("{}. ====> {}", count.incrementAndGet(), e.getMessage()))); + log.info("异步请求已提交..."); + TimeUnit.SECONDS.sleep(10); // 重要,等待异步调用完成 + } + + private BlogData getBlogData() + throws IOException + { + log.info("★★★★★★★★ getData from webApi ★★★★★★★★"); + String resp = webClient.get().uri("https://00fly.online/upload/data.json").acceptCharset(StandardCharsets.UTF_8).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(String.class).block(); + return JsonBeanUtils.jsonToBean(resp, BlogData.class, true); + } +} diff --git "a/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/resources/log4j2.xml" "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/resources/log4j2.xml" new file mode 100644 index 0000000..3c510f8 --- /dev/null +++ "b/CSDN\345\215\232\345\256\242\350\207\252\345\212\250\351\230\205\350\257\273\345\231\250/src/test/resources/log4j2.xml" @@ -0,0 +1,28 @@ + + + + %xwEx + %5p + yyyy-MM-dd HH:mm:ss.SSS + %clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} + %d{${LOG_DATEFORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} %pid --- [%t] %-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} + + + + + + + + + + + + + + + + + + + + -- Gitee