FeignClient 跨服务上传文件、导出Excel
分为两个 project,service 提供上传、下载的基础服务。client 作为被外部调用的服务。
本文使用的 spring boot 版本 是 2.2.5.RELEASE。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
service 服务
pom
使用的 lombok 简化 POJO,使用 easyexcel 导出 Excel。
<dependencies>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
FileController
只有两个方法upload()
打印文本文件内容,返回文件名;download()
导出 Excel。
@RestController
public class FileController {
@PostMapping("/upload")
public String upload(@RequestPart("file") MultipartFile file) throws IOException {
InputStream inputStream = file.getInputStream();
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
while (true) {
String s = bufferedReader.readLine();
System.out.println(s);
if (s == null) {
break;
}
}
}
return file.getOriginalFilename();
}
@GetMapping("/download")
public void download(HttpServletResponse response) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
}
private List<DownloadData> data() {
List<DownloadData> list = new ArrayList<DownloadData>();
for (int i = 0; i < 10; i++) {
DownloadData data = new DownloadData();
data.setString("字符串" + 0);
data.setDate(new Date());
data.setDoubleData(0.56);
list.add(data);
}
return list;
}
}
@Data
public class DownloadData {
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
}
client 服务
pom
相比于 service 服务,需要多引入 openfeign 的依赖。spring-cloud 的版本为 Hoxton.SR2。
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR2</spring-cloud.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</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>
启动类 ClientApplication
需要添加@EnableFeignClients
注解
@EnableFeignClients
@SpringBootApplication
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
FileFeignClient
本项目为了简化,没有使用注册中心,而是使用了@FeignClient
的url
属性直接指定了地址。
- 上传文件时必须添加== consumes = “multipart/form-data”==
- 导出文件的返回值必须为
feign.Response
。
@FeignClient(name = "service", url = "127.0.0.1:8081")
public interface FileFeignClient {
@PostMapping(value = "/upload", consumes = "multipart/form-data")
String upload(@RequestPart("file") MultipartFile file);
@GetMapping("download")
Response download();
}
FileController
@Slf4j
@RestController
public class FileController {
private final FileFeignClient fileFeignClient;
public FileController(FileFeignClient fileFeignClient) {
this.fileFeignClient = fileFeignClient;
}
@PostMapping("/upload")
public String upload(@RequestPart("file") MultipartFile file) {
// 直接调用 FileFeignClient
return fileFeignClient.upload(file);
}
@GetMapping("/download")
public void download(HttpServletResponse servletResponse) {
// 先调用 FileFeignClient 获取 feign.Response
// 然后将 feign.Response 的内容写入 HttpServletResponse
Response response = fileFeignClient.download();
Response.Body body = response.body();
for(Object key : response.headers().keySet()){
List<String> kList = (List)response.headers().get(key);
for(String val : kList){
servletResponse.setHeader(key.toString(), val);
}
}
try (InputStream inputStream = body.asInputStream();
OutputStream outputStream = servletResponse.getOutputStream()) {
byte[] b = new byte[inputStream.available()];
inputStream.read(b);
outputStream.write(b);
outputStream.flush();
} catch (IOException e) {
log.error("导出Excel失败", e);
}
}
}
问题:k8s 导出 Excel 报字体相关的错
原因是 Alpine 镜像没有 Excel 需要的字体。
解决办法一行 Run… 安装字体
from ...
RUN apk add --update font-adobe-100dpi ttf-dejavu fontconfig
add ...