King's Studio

文件上传结合SpringCloud的Feign进行服务调用

字数统计: 1.6k阅读时长: 7 min
2020/12/28 Share

工作中一直使用的是SpringCloud,其中的多个组件的使用也已经有一段时间了,包括对组件的配置文件的编写,今天要讲的是SpringCloud中的一个远程服务调用的组件,使用Feign之后,我们调用Eureka注册的其他服务,在代码中就像各个service之间相互调用那么简单。那至于为什么要调用其他服务的接口,就是微服务架构的内容了,今天我讲的是我们项目中独立出来的文件上传模块,我们在项目中将其做成一个通用的接口,使得其他服务中有相同需求时,可以直接调用该服务的接口进行文件上传以及文件管理。

Feign简介

Feign是Netflix开发的声明式,模板化的HTTP客户端,其灵感来自Retrofit,JAXRS-2.0以及WebSocket。

  • Feign可帮助我们更加便捷,优雅的调用HTTP API。
  • 在SpringCloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了
  • Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
  • SpringCloud对Feign进行了增强,使Feign支持了SpringMVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。

文件上传服务

文件上传我们在项目中将其单独作为一个服务使用,这是考虑到系统中有其他不同的模块需要使用到文件上传,因此独立出来,能够避免在各个子模块中重复编写文件上传的代码,也提高了文件上传接口的使用率。创建文件上传服务的过程就不再介绍了,文件上传想必大家做的都非常多了,我们将主要接口暴露出来。

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* @ClassName UploadAppendixCommonController
* @Description 通用附件上传接口
* @Author jinqi
* @Date 2020/7/9 10:51
*/
@Controller
@RequestMapping("/UploadAppendixCommonController")
public class UploadAppendixCommonController extends BaseController {

private Logger logger = LoggerFactory.getLogger(UploadAppendixCommonController.class);

@Autowired
HttpServletRequest request;

@Autowired
HttpServletResponse response;

// 获取Session用户信息
@Autowired
private SessionUtils sessionUtils;

@Autowired
private UploadAppendixCommonService uploadAppendixCommonService;

@Autowired
private UploadAppendixCommonConf uploadAppendixCommonConf;

/**
* 上传附件
* @param
* @param
* @return
* @throws Exception
*/
@RequestMapping("/uploadAppendixToServer4Feign")
@ResponseBody
public String uploadAppendixToServer4Feign(@RequestPart("file") MultipartFile file) throws Exception{

List<String> fileNames = new ArrayList<String>();
String fileName = null;
try {
// 生成uuid作为附件表的查询流水号
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
// String userName = (String) sessionUtils.getLoginUserSession().getString("userName");

SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");//设置日期格式
String time = df.format(new Date());

//创建文件保存的文件夹,以天为分割
File uploadfile = new File(uploadAppendixCommonConf.getPath()+time);
if (!uploadfile.exists()) {
uploadfile.mkdirs();
}

if (file != null) {
fileName = file.getOriginalFilename();
String path = uploadAppendixCommonConf.getPath() + time + "/"
+ uuid + fileName.substring(fileName.length()-5,fileName.length());
File localFile = new File(path);
file.transferTo(localFile);
fileNames.add(fileName);
}
String appendixPath = uploadAppendixCommonConf.getPath()+time+"/";
uploadAppendixCommonService.uploadAppendixToServer(uuid,fileNames,null,appendixPath);

//返回文件的uuid
return uuid;
}catch (Exception e){
logger.error("UploadAppendixCommonController.uploadAppendixToServer抛出了异常: ", e.getMessage() + e);
throw new Exception(e);
}
}

/**
* 根据uuid下载附件
* @param request
* @param response
* @throws Exception
*/
@RequestMapping("/downloadFileByUUID4Feign")
@ResponseBody
public void downloadFileByUUID4Feign(@RequestParam("UUID") String uuid) throws Exception{
Writer out = null;
try {
response.setHeader("Connection", "close");
//自动判断文件下载类型
response.setContentType("multipart/form-data");
//到数据库获取需要下载的文件名
DataModel dataModel = uploadAppendixCommonService.getFileName(uuid);
String fileName = dataModel.get("APPENDIX_NAME").toString();
//获取文件的服务器地址
String filePath = dataModel.get("APPENDIX_PATH").toString();
String tempFileName = "";
try {
tempFileName = ExportUtil2.encodeFileName(request, fileName);
}catch (Exception e){
logger.error("UploadAppendixCommonController.downloadFileByUUID抛出了异常: ", e.getMessage() + e);
}
response.setHeader("Content-Disposition", "attachment;filename=" + tempFileName);

File file = new File(filePath);
//判断服务器上文件是否存在
if (file.exists()){
byte[] buffer = new byte[1024];
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
OutputStream os = response.getOutputStream();
int i = bis.read(buffer);
while (i != -1) {
os.write(buffer, 0, i);
i = bis.read(buffer);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}catch (Exception e){
logger.error("UploadAppendixCommonController.downloadFileByUUID抛出了异常: ", e.getMessage() + e);
throw new Exception(e);
}
}

/**
* 通过UUID删除文件
* @param
* @param
* @return
* @throws Exception
*/
@RequestMapping("/deleteFileByUUID")
@ResponseBody
public String deleteFileByUUID(@RequestParam("UUID")String uuid) throws Exception{
try {
return uploadAppendixCommonService.deleteFileByUUID(uuid);
}catch (Exception e){
logger.error("UploadAppendixCommonController.deleteFileByUUID抛出了异常: ", e.getMessage() + e);
throw new Exception(e);
}
}
}

值得注意的一点是,需要在SpringCloud的启动程序中加入Feign的注解。

1
2
3
4
5
6
7
8
9
10
11
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableSwagger2
public class BusinessFileManageSystemApplication {

public static void main(String[] args) {
SpringApplication.run(BusinessFileManageSystemApplication.class, args);
}

}

对文件上传服务的调用

文件上传服务配置完成之后,我们进行该服务的调用,首先需要在项目中配置接口,用作在整个项目中进行调用。

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

@FeignClient(name = "business-file-manage-system",configuration = FeignMultipartSupportConfig.class)
public interface UploaderServiceFeignClient {

@RequestMapping(value="/UploadAppendixCommonController/uploadAppendixToServer4Feign", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String uploadAppendixToServer(@RequestPart("file") MultipartFile file);

@RequestMapping(value="/UploadAppendixCommonController/downloadFileByUUID4Feign")
public Response downloadFileByUUID4Feign(@RequestParam("UUID") String uuid);

//文件下载
@RequestMapping(value = "/UploadAppendixCommonController/downloadFileByUUID",method = RequestMethod.GET)
Response downloadFileByUUID(@RequestParam("UUID")String uuid);

//文件删除
@RequestMapping(value = "/UploadAppendixCommonController/deleteFileByUUID")
String deleteFileByUUID(@RequestParam("UUID")String uuid);

public class UploaderServiceFallback implements UploaderServiceFeignClient{

public String uploadAppendixToServer(MultipartFile file) {
// TODO Auto-generated method stub
return ResponseEntity.error("上传服务断线,请稍后重试!");
}

public Response downloadFileByUUID4Feign(String uuid) {
// TODO Auto-generated method stub
throw new RuntimeException("上传服务断线,请稍后重试!");
}

@Override
public Response downloadFileByUUID(String uuid) {
throw new RuntimeException("上传服务断线,请稍后重试!");
}

@Override
public String deleteFileByUUID(String uuid) {
return ResponseEntity.error("上传服务断线,请稍后重试!");
}

}
}

编写完interface后,在调用处需要将接口实例注入,然后通过接口实例调用接口中的方法,我们以调用文件上传为例,下面提供代码。

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
/**
* 上传附件
* @param request
* @param response
* @return
* @throws Exception
*/
@RequestMapping("/uploadAppendixToServer")
@ResponseBody
public String uploadAppendixToServer(HttpServletRequest request, HttpServletResponse response) throws Exception{
Writer out = null;
List<String> fileNames = new ArrayList<String>();
String fileName = null;
String id = request.getParameter("id");
String uuid = null;
try {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
request.getSession().getServletContext());
if (multipartResolver.isMultipart(request)) {
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
Iterator<String> iter = multiRequest.getFileNames();
while (iter.hasNext()) {
MultipartFile file = multiRequest.getFile(iter.next());
if (file != null) {
uuid = uploaderServiceFeignClient.uploadAppendixToServer(file);
}
}
}
uploadAppendixCommonService.updateAppendixNameListId(id,uuid);

//返回文件的uuid
return ResponseEntity.success(uuid,"success");
}catch (Exception e){
logger.error("UploadAppendixCommonController.uploadAppendixToServer抛出了异常: ", e.getMessage() + e);
throw new Exception(e);
}
}

其实整个过程并不复杂,可以看到我们在配置完Feign之后,调用接口就像调用普通的service一样,同时通过Feign将模块与模块之间联系起来,后续SpringCloud其他组件我们还会再做介绍.

原文作者:金奇

原文链接:https://www.rossontheway.com/2020/12/28/文件上传结合SpringCloud的Feign进行服务调用/

发表日期:December 28th 2020, 12:00:00 am

更新日期:December 28th 2020, 11:28:26 am

版权声明:本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可,除特别声明外,转载请注明出处!

CATALOG
  1. 1. Feign简介
  2. 2. 文件上传服务
  3. 3. 对文件上传服务的调用