openfeign的几种调用方式

一、介绍

先上openfeignmaven依赖,这边注册中心用的是nacos,具体版本看自己的需求

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>

二、示例代码

1)客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.banmoon.client1.controller;

import com.banmoon.client1.service.TestService;
import com.banmoon.common.ResultData;
import com.banmoon.common.dto.UploadDTO;
import com.banmoon.common.dto.UserDTO;
import com.banmoon.common.entities.UserEntity;
import com.banmoon.common.utils.MyFileUtil;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {

@Autowired(required = false)
private TestService testService;

@GetMapping("/simpleGet")
public ResultData<UserEntity> simpleGet(@RequestParam Integer id) {
return testService.simpleGet(id);
}

@GetMapping("/pathGet/{id}")
public ResultData<UserEntity> pathGet(@PathVariable Integer id) {
return testService.pathGet(id);
}

@PostMapping("/mapPost")
public ResultData<List<UserEntity>> mapPost(@RequestBody Map<String, Object> params) {
return testService.mapPost(params);
}

@PostMapping("/dtoPost")
public ResultData<List<UserEntity>> dtoPost(@RequestBody UserDTO userDTO) {
return testService.dtoPost(userDTO);
}

@DeleteMapping("/delete")
public ResultData delete(@RequestBody Long[] ids) {
return testService.delete(ids);
}

@PutMapping("/put")
public ResultData put(@RequestBody UserDTO userDTO) {
return testService.put(userDTO);
}

/**
* 导出,下载
* @param userDTO
* @param response
*/
@PostMapping("/export")
public void export(@RequestBody UserDTO userDTO, HttpServletResponse response) {
try {
Response feignResponse = testService.export(userDTO);
InputStream inputStream = feignResponse.body().asInputStream();
MyFileUtil.downloadFile(response, inputStream, "测试.jpg");
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* 上传
* @param dto
* @return
*/
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResultData upload(UploadDTO dto) {
return testService.upload(dto);
}

}

openfeign的使用,可以使用springMVC中的注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.banmoon.client1.service;

import com.banmoon.common.ResultData;
import com.banmoon.common.constant.ServerNameConstant;
import com.banmoon.common.dto.UploadDTO;
import com.banmoon.common.dto.UserDTO;
import com.banmoon.common.entities.UserEntity;
import feign.Response;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@FeignClient(name = ServerNameConstant.SERVER_ONE)
public interface TestService {

@RequestMapping(value = "/test/simpleGet", method = RequestMethod.GET)
ResultData<UserEntity> simpleGet(@RequestParam("id") Integer id);

@RequestMapping(value = "/test/pathGet/{id}", method = RequestMethod.GET)
ResultData<UserEntity> pathGet(@PathVariable("id") Integer id);

@RequestMapping(value = "/test/mapPost", method = RequestMethod.POST)
ResultData<List<UserEntity>> mapPost(@RequestBody Map<String, Object> params);

@RequestMapping(value = "/test/dtoPost", method = RequestMethod.POST)
ResultData<List<UserEntity>> dtoPost(@RequestBody UserDTO userDTO);

@RequestMapping(value = "/test/delete", method = RequestMethod.DELETE)
ResultData delete(@RequestBody Long[] ids);

@RequestMapping(value = "/test/put", method = RequestMethod.PUT)
ResultData put(@RequestBody UserDTO userDTO);

@RequestMapping(value = "/test/export", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
Response export(@RequestBody UserDTO userDTO);

@PostMapping(value = "/test/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
ResultData upload(UploadDTO dto);
}

2)服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package com.banmoon.server.controller;

import cn.hutool.core.io.IoUtil;
import com.banmoon.common.ResultData;
import com.banmoon.common.dto.UploadDTO;
import com.banmoon.common.dto.UserDTO;
import com.banmoon.common.entities.UserEntity;
import com.banmoon.common.utils.MyFileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@CrossOrigin(exposedHeaders = {"Content-Disposition", "Access-Control-Allow-Origin"})
@RestController
@RequestMapping("/test")
public class TestController {

public static final List<UserEntity> userList = new ArrayList<UserEntity>() {{
add(new UserEntity(1, "banmoon", 18, "男"));
add(new UserEntity(2, "hh", 22, "男"));
add(new UserEntity(3, "xiao", 18, "女"));
add(new UserEntity(4, "kun", 22, "女"));
}};

@GetMapping("/simpleGet")
public ResultData<UserEntity> simpleGet(@RequestParam Integer id) {
UserEntity userEntity = userList.stream().filter(user -> user.getId().equals(id)).findFirst().orElse(null);
return ResultData.success(userEntity);
}

@GetMapping("/pathGet/{id}")
public ResultData<UserEntity> pathGet(@PathVariable Integer id) {
UserEntity userEntity = userList.stream().filter(user -> user.getId().equals(id)).findFirst().orElse(null);
return ResultData.success(userEntity);
}

@PostMapping("/mapPost")
public ResultData<List<UserEntity>> mapPost(@RequestBody Map<String, Object> params) {
log.info("入参:{}", params);
return ResultData.success(userList);
}

@PostMapping("/dtoPost")
public ResultData<List<UserEntity>> dtoPost(@RequestBody UserDTO userDTO) {
log.info("入参:{}", userDTO);
return ResultData.success(userList);
}

@DeleteMapping("/delete")
public ResultData delete(@RequestBody Long[] ids) {
log.info("入参:{}", ids);
return ResultData.success();
}

@PutMapping("/put")
public ResultData put(@RequestBody UserDTO userDTO) {
log.info("入参:{}", userDTO);
return ResultData.success();
}

@PostMapping(value = "/export", produces = MediaType.APPLICATION_JSON_VALUE)
public void export(@RequestBody UserDTO userDTO, HttpServletResponse response) throws Exception {
log.info("入参:{}", userDTO);
String str = "E:\\downFile\\fireFox\\Cyberpunk-edgerunners-lucy-edgerunners-anime-girls-Cyberpunk-2077-cyberpunk-Netflix-TV-Series-2179331-wallhere.com.jpg";
File file = new File(str);
MyFileUtil.downloadFile(response, file, "测试.jpg");
}

@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResultData upload(UploadDTO dto) {
try {
MultipartFile file = dto.getFile();
String fileName = dto.getFileName();
String path = System.getProperty("java.io.tmpdir") + fileName;
File targetFile = new File(path);
FileOutputStream outputStream = new FileOutputStream(targetFile);
InputStream inputStream = file.getInputStream();
IoUtil.copy(inputStream, outputStream);
IoUtil.close(outputStream);
IoUtil.close(inputStream);
return ResultData.success();
} catch (IOException e) {
e.printStackTrace();
return ResultData.fail("上传失败");
}
}

}

其他的都好说,主要是这个下载,有遇到流在openfeign中流转需求时,

需要将服务端的返回值设置为void

openfeign的调用服务,他的返回值需要设置为feign.Response

然后再从其中取到输出流转输入流,再从客户端的selvet输出流进行输出

3)其他代码

如果微服务众多的话,可以将其进行统一常量管理

1
2
3
4
5
6
7
package com.banmoon.common.constant;

public class ServerNameConstant {

public static final String SERVER_ONE = "server1";

}

两个传输使用的DTO

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.banmoon.common.dto;

import lombok.Data;
import org.springframework.web.multipart.MultipartFile;

@Data
public class UploadDTO {

private MultipartFile file;

private String fileName;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.banmoon.common.dto;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class UserDTO {

private Integer id;

private String username;

private Integer age;

private String sex;

}

一个统一的返回类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.banmoon.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResultData<T> {

private Integer errCode;

private String errMsg;

private T data;

public static ResultData success(){
return new ResultData(0, "成功", null);
}

public static ResultData fail(String errMsg){
return new ResultData(-1, errMsg, null);
}

public static <T> ResultData success(T t) {
return new ResultData(0, "成功", t);
}
}

一个实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.banmoon.common.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity {

private Integer id;

private String username;

private Integer age;

private String sex;

}

重点的文件工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.banmoon.common.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelWriter;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;

@Slf4j
public class MyFileUtil {

public static void downloadFile(HttpServletResponse response, ExcelWriter writer, String filename){
ServletOutputStream out = null;
try {
out = response.getOutputStream();
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));

writer.flush(out, true);
} catch (IOException e) {
log.error("io异常", e);
} finally {
writer.close();
IoUtil.close(out);
}
}

public static void downloadFile(HttpServletResponse response, File file, String filename){
OutputStream out = null;
try {
out = response.getOutputStream();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
response.setHeader("Content-Length", String.valueOf(FileUtil.size(file)));

BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file.getPath()));
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
IoUtil.copy(fis, toClient);
out.flush();
} catch (Exception e) {
log.error("io异常", e);
} finally {
IoUtil.close(out);
}
}

public static void downloadFile(HttpServletResponse response, InputStream inputStream, String filename) {
try {
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
ServletOutputStream outputStream = response.getOutputStream();
IoUtil.copy(inputStream, outputStream);
} catch (Exception e) {
log.error("io异常", e);
}
}

}

三、最后

注意跨域,在测试进行下载时,时长遇到跨域问题,请格外注意!

我是半月,祝你幸福!!!