服务端A接收到来自于前端的请求后,要使用RestTemplate将请求转发给服务端B,然后将服务端B的返回转发给前端。
根据请求类型的不同,分为:
@RequestMapping("/transmit")
public String transmit(HttpServletRequest request, HttpMethod method, @RequestBody(required = false) String body) {
try {
// 根据request,构造HttpHeaders
HttpHeaders headers = new HttpHeaders();
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
String name = (String)headerNames.nextElement();
String value = request.getHeader(name);
headers.add("Authorization", value);
}
// 复制 request 的参数
Map<String, String[]> parameterMap = request.getParameterMap();
MultiValueMap<String, Object> params = new LinkedMultiValueMap<String, Object>();
// 附加参数值
Set<String> keySet = parameterMap.keySet();
for (String key : keySet) {
String[] value = parameterMap.get(key);
params.add(key, value[0]);
}
// 根据body内容填充requestEntity。对于form-data,body为空但parameterMap有值;对于raw,body不为空。
HttpEntity<Object> requestEntity = (body!=null && !body.isEmpty())? new HttpEntity<>(body, headers): new HttpEntity<>(params, headers);
// 构造URI。必须拼接出String url然后创建URI,否则会出现queryString %符号转%25的问题
String destUrl = "http://192.168.1.98:9098/test";
if (request.getQueryString()!=null && !request.getQueryString().isEmpty()) sUrl += "?" + request.getQueryString();
URI destUri = new URI(destUrl);
// 向服务请求
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.exchange(destUri, method, requestEntity, String.class);
return responseEntity.getBody();
} catch (Exception e) {
e.printStackTrace();
return "转发失败";
}
}
其中:
前端上传的文件需要使用MultipartFile
接收。而RestTemplate发送文件需要使用FileSystemResource
或ByteArrayResource
。
然而两个类都存在限制:
MultipartFile
不能直接转为FileSystemResource
。getFilename()
方法(方法名中name的n是小写),若失败则会认为这是个常规的参数而非文件。ByteArrayResource
并未提供该方法。有两种转发方案:
MultipartFile
后存储在本地,然后将本地File
转为FileSystemResource
。发送FileSystemResource
对象。该方案会在本地生成临时文件,额外调用多次I/O,且生成的临时文件需要进行清理。ByteArrayResource
的派生类并添加getFilename()
方法,服务端A接收MultipartFile
后,转为ByteArrayResource
派生对象。该方案不会生成临时文件,推荐。MultipartFile file; // 接收到的MultipartFile
File tempFile = new File("D://temp/" + file.getOriginalFilename());
file.transferTo(tempFile);
FileSystemResource fileSystemResource = new FileSystemResource(tempFile);
// 放入参数中
MultiValueMap<String, Object> params = new LinkedMultiValueMap<String, Object>();
params.add("file", fileSystemResource);
然后将params作为参数交给RestTemplate发送即可。
创建ByteArrayResource
的派生类:
import org.springframework.core.io.ByteArrayResource;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
public class MultipartFileResource extends ByteArrayResource {
private String filename;
public MultipartFileResource(MultipartFile multipartFile) throws IOException {
super(multipartFile.getBytes());
this.filename = multipartFile.getOriginalFilename();
}
@Override
public String getFilename() {
return this.filename;
}
}
然后使用派生类对MultipartFile
进行转换:
MultipartFile file; // 接收到的MultipartFile
ByteArrayResource byteArrayResource = new MultipartFileResource(file);
// 放入参数中
MultiValueMap<String, Object> params = new LinkedMultiValueMap<String, Object>();
params.add("file", byteArrayResource);
然后将params作为参数交给RestTemplate发送即可。
派生类方案代码实例:
@RequestMapping("/upload")
public String upload(HttpServletRequest request, HttpMethod method, @RequestParam("file") MultipartFile file, @RequestBody(required = false) String body) {
try {
// 复制HttpHeaders
HttpHeaders headers = new HttpHeaders();
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
String name = (String)headerNames.nextElement();
String value = request.getHeader(name);
logger.info(name + " : " + value);
headers.add("Authorization", value);
}
// 复制 request 的参数
MultiValueMap<String, Object> params = new LinkedMultiValueMap<String, Object>();
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> keySet = parameterMap.keySet();
for (String key : keySet) {
String[] value = parameterMap.get(key);
params.add(key, value[0]);
}
// 文件对象单独附加
ByteArrayResource resource = new MultipartFileResource(file);
params.add("file", resource);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);
// 构造URI。必须拼接出String url然后创建URI,否则会出现queryString %符号转%25的问题
String destUrl = "http://192.168.1.98:9098/test";
if (request.getQueryString()!=null && !request.getQueryString().isEmpty()) destUrl += "?" + request.getQueryString();
URI destUri = new URI(destUrl);
// 向服务请求
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.exchange(destUri, method, requestEntity, String.class);
return responseEntity.getBody();
} catch (Exception e) {
e.printStackTrace();
return new Response<String>().setCode(Response.CODE_FAIL).setMessage(Response.MSG_FAIL).toJSONString();
}
}
服务端A收到前端发来的文件下载请求,将该请求转发给服务端B,然后服务端A将服务端B的返回转发给前端。
与前面不同的是下载会返回一个byte[]
。注意需要修改HttpServletResponse
的HttpHeaders
来告知前端浏览器创建下载任务。
@RequestMapping("/download/")
public byte[] download(HttpServletRequest request, HttpServletResponse response, HttpMethod method, @RequestBody(required = false) String body) {
try {
// 复制HttpHeaders
HttpHeaders headers = new HttpHeaders();
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
String name = (String)headerNames.nextElement();
String value = request.getHeader(name);
logger.info(name + " : " + value);
headers.add("Authorization", value);
}
// 复制 request 的参数
MultiValueMap<String, Object> params = new LinkedMultiValueMap<String, Object>();
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> keySet = parameterMap.keySet();
for (String key : keySet) {
String[] value = parameterMap.get(key);
params.add(key, value[0]);
}
// 根据body内容填充requestEntity。对于form-data,body为空但parameterMap有值;对于raw,body不为空。
HttpEntity<Object> requestEntity = (body!=null && !body.isEmpty())? new HttpEntity<>(body, headers): new HttpEntity<>(params, headers);
// 构造URI。必须拼接出String url然后创建URI,否则会出现queryString %符号转%25的问题
String destUrl = "http://192.168.1.98:9098/test";
if (request.getQueryString()!=null && !request.getQueryString().isEmpty()) destUrl += "?" + request.getQueryString();
URI destUri = new URI(destUrl);
// 向服务请求
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<byte[]> responseEntity = restTemplate.exchange(destUri, method, requestEntity, byte[].class);
// 修改HttpServletResponse的HttpHeaders
HttpHeaders responseHeaders = responseEntity.getHeaders();
response.setContentType(responseHeaders.getContentType().toString());
response.addHeader("Content-Disposition", responseHeaders.get("Content-Disposition").get(0));
return responseEntity.getBody();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}