React 是一个用于构建用户界面的 JAVASCRIPT 库。
React 主要用于构建 UI,很多人认为 React 是 MVC 中的 V(视图)。
React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。
React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使用它。
声明式设计 −React采用声明范式,可以轻松描述应用。
高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
灵活 −React可以与已知的库或框架很好地配合。
JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。
组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
Spring Cloud Config 用于为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,分为服务端和客户端。 服务端为分布式配置中心,是一个独立的微服务应用;客户端为分布式系统中的基础设置或微服务应用,通过指定配置中心来管理相关的配置。 Spring Cloud Config 构建的配置中心,除了适用于 Spring 构建的应用外,也可以在任何其他语言构建的应用中使用。 Spring Cloud Config 默认采用 Git 存储配置信息,天然支持对配置信息的版本管理。
xml<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lhw.emr</groupId>
<artifactId>config</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>config</name>
<description>微服务统一配置服务</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
阅读3服务器版,桌面端,iOS可用。后端 Kotlin + Spring Boot + Vert.x + Coroutine ;前端 Vue.js + Element。
阅读3服务器版github地址
部署文档地址
需要:
从宝塔面板之后的事情开始说
点击新增模板,并配置 获取最新的配置文件
yml
version: '3.1'
services:
# reader 在线阅读
# 公开服务器(服务器位于日本):[https://reader.nxnow.top](https://reader.nxnow.top) 测试账号/密码分别为guest/guest123,也可自行创建账号添加书源,不定期删除长期未登录账号(2周)
# 书源集合 : [https://legado.aoaostar.com/](https://legado.aoaostar.com/) 点击打开连接,添加远程书源即可
# 公众号汇总 : [https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MjM5MzMyMDgyMA==&action=getalbum&album_id=2397535253763801090#wechat_redirect](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MjM5MzMyMDgyMA==&action=getalbum&album_id=2397535253763801090#wechat_redirect)
# 手动更新方式 : docker-compose pull && docker-compose up -d
reader:
image: hectorqin/reader
#image: hectorqin/reader:openj9-latest #docker镜像,arm64架构或小内存机器优先使用此镜像.启用需删除上一行
container_name: reader #容器名 可自行修改
restart: always
ports:
- 4396:8080 #4396端口映射可自行修改
networks:
- share_net
volumes:
- /home/reader/logs:/logs #log映射目录 /home/reader/logs 映射目录可自行修改
- /home/reader/storage:/storage #数据映射目录 /home/reader/storage 映射目录可自行修改
environment:
- SPRING_PROFILES_ACTIVE=prod
- READER_APP_USERLIMIT=50 #用户上限,默认50
- READER_APP_USERBOOKLIMIT=200 #用户书籍上限,默认200
- READER_APP_CACHECHAPTERCONTENT=true #开启缓存章节内容 V2.0
# 如果启用远程webview,需要取消注释下面的 remote-webview 服务
# - READER_APP_REMOTEWEBVIEWAPI=http://remote-webview:8050 #开启远程webview
# 下面都是多用户模式配置
- READER_APP_SECURE=true #开启登录鉴权,开启后将支持多用户模式
- READER_APP_SECUREKEY=adminpwd #管理员密码 建议修改
- READER_APP_INVITECODE=registercode #注册邀请码 建议修改,如不需要可注释或删除
# remote-webview:
# image: hectorqin/remote-webview
# container_name: remote-webview #容器名 可自行修改
# restart: always
# ports:
# - 8050:8050
# networks:
# - share_net
# 自动更新docker镜像
watchtower:
image: containrrr/watchtower
container_name: watchtower
restart: always
# 环境变量,设置为上海时区
environment:
- TZ=Asia/Shanghai
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: reader watchtower --cleanup --schedule "0 0 4 * * *"
networks:
- share_net
# 仅更新reader与watchtower容器,如需其他自行添加 '容器名' ,如:reader watchtower nginx
# --cleanup 更新后清理旧版本镜像
# --schedule 自动检测更新 crontab定时(限定6位crontab) 此处代表凌晨4点整
networks:
share_net:
driver: bridge
根据自己要求修改配置
由于业务需要,获取多个pdf的时候需要将多个pdf存入zip类型的压缩包中实现下载,导出的过程使用轮询的方式实现进度查询,每次操作将当前进度存储入redis中,获取进度的接口从redis查询信息,下面只详细展开zip下载的代码
这个操作步骤主要分两步
返回查询进度的id,操作完成后将把流信息存储入redis,提供下载使用
javaif (!redisUtil.isPing()) {
throw new BusinessException(ResultCodeEnum.ERR_0x1000.getCode(), "导出失败,Redis服务未连接!");
}
String id = StringUtil.generateId();
redisUtil.set(markKey, id, 3600);
Map<String, Object> map = new HashMap<>();
map.put("current", 0);
map.put("total", list.size());
String mapkey = markKey + id + ":";
redisUtil.set(mapkey, map, 3600);
//单线程线程池
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());
try {
poolExecutor.execute(() -> {
List<byte[]> pdfBytesList = new ArrayList<>();
List<String> filenames=new ArrayList<>();
for (PatientRequest p : list) {
byte[] bytes = null;
try {
bytes = getPdfByte(p);
} catch (Exception e) {
log.error(e.getMessage());
e.printStackTrace();
}
Map<String, Object> map1 = redisUtil.get(mapkey, Map.class);
map1.put("current", (Integer) map1.get("current") + 1);
if (ArrayUtil.isNotEmpty(bytes)) {
filenames.add(String.format("%s_%s_%s_%s.pdf", province, name, p.getPatientId(), DateUtil.format(new Date(), "yyyyMMdd")));
pdfBytesList.add(bytes);
}
if (list.indexOf(p) == list.size() - 1) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos)) {
for (int i = 0; i < pdfBytesList.size(); i++) {
byte[] pdfBytes = pdfBytesList.get(i);
ZipEntry entry = new ZipEntry(filenames.get(i));
zos.putNextEntry(entry);
zos.write(pdfBytes);
zos.closeEntry();
}
zos.flush();
zos.close();
baos.flush();
map1.put("data", Base64.getEncoder().encodeToString(baos.toByteArray()));
} catch (IOException e) {
// 处理可能的异常
e.printStackTrace(); // 实际应用中应使用合适的日志记录方式
map1.put("data", null);
}
}
redisUtil.set(mapkey, map1);
}
});
} catch (Exception e) {
throw new BusinessException(ResultCodeEnum.ERR_0x1000.getCode(), e.getMessage());
} finally {
poolExecutor.shutdown();
}
return id;