背景

假设一台服务器部署了一个 Java 应用程序,需要将本机的数据文件(可能是文本也可能是图像)上传到远端的另外一台服务器,注意这个不是通过前端进行PUT请求来完成的,需要怎么做呢?

实现

需要上传的一方实现一个 FileIOService.java

// 这里把图片的常用后缀采用列举的方式做了设置,可以换个其他更简单的图像判别方法private static final String[] IMAGE_VALUES = new String[]{"jpg", "BMP", "bmp", "JPG", "wbmp", "jpeg", "png", "PNG", "JPEG", "WBMP", "GIF", "gif"};private static final HashSet<String> IMAGE_TYPE = new HashSet<>(Arrays.asList(IMAGE_VALUES));/*** 将文件转换成 byte[]** @param filePath 文件路径* @return buffer*/private byte[] getBytes(String filePath) throws IOException {byte[] buffer = new byte[0];FileInputStream fileInputStream = null;ByteArrayOutputStream byteArrayOutputStream = null;try {File file = new File(filePath);fileInputStream = new FileInputStream(file);byteArrayOutputStream = new ByteArrayOutputStream(1024);byte[] b = new byte[1024];int n;while ((n = fileInputStream.read(b)) != -1) {byteArrayOutputStream.write(b, 0, n);}buffer = byteArrayOutputStream.toByteArray();} catch (Exception e) {log.error(e);} finally {if (fileInputStream != null) fileInputStream.close();if (byteArrayOutputStream != null) byteArrayOutputStream.close();}return buffer;}// 获取文件字节数组private byte[] getFileBytes(File file) throws IOException {String fileName = file.getName();String[] names = fileName.split("\\.");ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();if (names.length > 1) {String fileType = names[names.length - 1];if (IMAGE_TYPE.contains(fileType)) {log.info("The file {} is a picture.", fileName);BufferedImage bi;try {bi = ImageIO.read(file);ImageIO.write(bi, fileType, byteArrayOutputStream);byte[] bytes = byteArrayOutputStream.toByteArray();byteArrayOutputStream.close();return bytes;} catch (IOException e) {log.error(e);}}}return getBytes(file.getAbsolutePath());}/*** 将文件流发送至另外服务器的方法** @param bytes    文件字节* @param fileName  文件路径* @return 从服务器端响应的流 可通过 new String(bytes); 转换*/private void httpPost(byte[] bytes, String fileName) throws IOException {try {URL console = new URL(LOCALIZATION_UPLOAD_URL);HttpURLConnection conn = (HttpURLConnection) console.openConnection();conn.addRequestProperty("fileName", fileName);conn.setConnectTimeout(30000);conn.setReadTimeout(30000);conn.setUseCaches(false);conn.setDoOutput(true);conn.setDoInput(true);conn.setRequestMethod("POST");conn.connect();DataOutputStream out = new DataOutputStream(conn.getOutputStream());log.info(bytes.length);out.write(bytes);out.flush();out.close();InputStream is = conn.getInputStream();if (is != null) {ByteArrayOutputStream outStream = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = is.read(buffer)) != -1) {outStream.write(buffer, 0, len);}is.close();conn.disconnect();byte[] response = outStream.toByteArray();if (response.length > 0) {log.info("Upload response: {}", new String(response));}}conn.disconnect();} catch (Exception e) {log.error("Upload failed: {}", e);}}// 支持多文件上传private void multipleFileUpload(File file) {if (file.isFile()) {log.info("upload file name {}", file.getName());uploadFile(file, file.getName());return;}File[] files = file.listFiles();if (files == null) return;for (File f : files) {multipleFileUpload(f);}}// 上传单文件private void uploadFile(File file) {try {byte[] bytes = getFileBytes(file);log.info("Upload file : {}", file.getName());httpPost(bytes, file.getName());} catch (IOException e) {log.error(e);}}

远端服务器服务接受数据流并持久化到磁盘

// FileIOUtils.java 下面会用到的获取服务器上根目录所在位置的工具类
public class FileIOUtils {private FileIOUtils() {throw new IllegalStateException("Utility class");}public static File getRootPath() throws FileNotFoundException {File path = new File(ResourceUtils.getURL("classpath:").getPath());if(!path.exists()) {path = new File("");}return path;}
}
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;/*** 判断指定文件夹是否存在,不存在则创建* @param path 路径前缀*/private void createDirIfNoExist(String path) {File file = new File(path, FilenameUtils.getName(path));if(!file.exists()) {boolean res = file.mkdirs();log.info("set writable {}", file.setWritable(true, false));log.info("create dir {} : {}", file.getAbsoluteFile(), res);}}@RequestMapping("upload")public void receiveFile(HttpServletRequest request) throws IOException {ServletInputStream in = request.getInputStream();try {String fileName = request.getHeader("fileName");String path = FileIOUtils.getRootPath().getAbsolutePath() + "/static/upload/";String name = FilenameUtils.getName(fileName);String filePath = path + fileName.replace(name, "");createDirIfNoExist(filePath);File file = new File(filePath , FilenameUtils.getName(fileName));if (!file.exists()) {log.info("create file {} : {}", fileName, file.createNewFile());}log.info("set file writable {}", file.setWritable(true, false));FileUtils.copyInputStreamToFile(in, file);} catch (Exception e) {log.error(e);}}

在 SpringBoot 框架下,可能会有异常: request.getInputStream() 获取不到数据(返回空值),这是因为在框架里,HttpServletRequest 已经被框架在接收 HTTP Request 时读取过一遍了,然后我们自己要读取的话,数据流已经被处理过(处理过一次,InputStream的 read index 已经为 -1,再直接读就为空了),这种情况下需要加一个Wrapper类,在第一次读取时对数据进行一次备份
InputStreamHttpServletRequestWrapper.java

public class InputStreamHttpServletRequestWrapper extends HttpServletRequestWrapper {private final byte[] body;private static final int BUFFER_SIZE = 4096;public InputStreamHttpServletRequestWrapper(HttpServletRequest request) throws IOException {super(request);body = inputStream2Byte(request.getInputStream());}private byte[] inputStream2Byte(InputStream inputStream) throws IOException {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();byte[] bytes = new byte[BUFFER_SIZE];int length;while ((length = inputStream.read(bytes, 0, BUFFER_SIZE)) != -1) {outputStream.write(bytes, 0, length);}return outputStream.toByteArray();}@Overridepublic ServletInputStream getInputStream() throws IOException {ByteArrayInputStream inputStream = new ByteArrayInputStream(body);return new ServletInputStream() {@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener readListener) {log.info("set readListener");}@Overridepublic int read() throws IOException {return inputStream.read();}};}@Overridepublic BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(getInputStream()));}
}

利用Java实现后端文件跨服务器传输(上传图片等文件)相关推荐

  1. 文件跨服务器传输_跨桌面设备传输文件的最优选?

    首先问大家一个问题,你们的 U 盘使用频率高吗? 我有很长的时间没有使用过优盘了,最近两次使用优盘分别是给客厅的电视安装 apk 和给卧室的电视安装 apk,在日常工作和学习中,虽然经常会使用跨设备传 ...

  2. Linux SCP跨服务器传输文件

    SCP跨服务器传输文件 注: 1.跨服务器传输文件或文件夹需确保两台服务器之间的22端口是互通的 2.sh脚本自动删除本机原有文件或文件夹然后在从其他服务器上拷贝文件或文件夹到本机 一.sh脚本定时自 ...

  3. FlexPaper不能跨服务器加载远程文件解决办法

    FlexPaper不能跨服务器加载远程文件解决办法 再跨服务器的文件存放 根目录中新建一个xml文件: crossdomain.xml <?xml version="1.0" ...

  4. 怎么传文件到服务器上,怎样传文件到服务器上

    怎样传文件到服务器上 内容精选 换一换 华为云帮助中心,为用户提供产品简介.价格说明.购买指南.用户指南.API参考.最佳实践.常见问题.视频帮助等技术文档,帮助您快速上手使用华为云服务. 安装传输工 ...

  5. pycharm中.ui文件跨包路径转.py文件

    pycharm中.ui文件跨包路径转.py文件 如下图所示报错: 只需要在上面路径后添加.ui文件所在包(我的.ui文件在package里,但我想生成.py文件并放在package包外边),如下图所示 ...

  6. 华为云跨服务器传输文件,云服务器传输文件

    云服务器传输文件 内容精选 换一换 外部镜像文件在从原平台导出前,没有按照"Windows操作系统的镜像文件限制"的要求完成初始化操作,推荐您使用弹性云服务器完成相关配置.流程如图 ...

  7. 华为云跨服务器传输文件,与云服务器传输文件

    与云服务器传输文件 内容精选 换一换 默认部署在VPC下的应用可以调用API.如果域名解析失败,则参考配置内网DNS,在当前终端节点上配置DNS服务器.配置完成后,部署在VPC下的应用可以调用API. ...

  8. 跨服务器移动文件,跨服务器复制文件(示例代码)

    先说下常用的情况: 两台机器IP分别为:A.104.238.161.75,B.43.224.34.73. 在A服务器上操作,将B服务器上/home/lk/目录下所有的文件全部复制到本地的/root目录 ...

  9. 本地文件与服务器传输,云服务器 与本地文件传输

    云服务器 与本地文件传输 内容精选 换一换 登录Windows操作系统的弹性云服务器时,需要使用密码方式登录.此时,用户需要先根据购买弹性云服务器时下载的私钥文件,获取该弹性云服务器初始安装时系统生成 ...

最新文章

  1. 2022-2028年中国高密度聚乙烯(HDPE)行业市场发展调研及投资前景分析报告
  2. 按文件类型获取其图标
  3. SharePoint 2010 使用自定义aspx页面替换列表默认的新建(NewForm.aspx),查看(DispForm.aspx)和编辑(EditForm.aspx)页面...
  4. 内存问题排查手段及相关文件介绍
  5. 电商咄咄逼人的黑色星期五促销横BANNER设计模板
  6. np.where与np.argwhere共同点与区别分析
  7. 格符\b的使用示例:每隔1秒消去1个字符
  8. 高性能迷你React框架anu发布
  9. 如何制作自己的Visio图标
  10. opencv4nodejs安装
  11. 德语区国家的摄影测量与遥感
  12. [linux]scp与服务器互传文件
  13. 计算机所有以太网适配的ip,以太网没有有效的ip配置怎么办
  14. 用代码作图?就是玩!!
  15. 关于JSON.stringify()的用法
  16. 为什么普遍使用Linux做服务器?
  17. 群硕助力vivo智能用户运营,数字化驱动零售销量提升
  18. CAXA CAM数控车2020中文版
  19. keil 用MicroLIB
  20. RGB图像转灰度图像的原理

热门文章

  1. ARM系列CPU对比介绍(未完待续)
  2. [GRE] 填空经典1290题 错题(二)
  3. rundeck上创建project和job
  4. 三星联合独立调研机构调查 Note7事件终水落石出
  5. 如何接入 K8s 持久化存储?K8s CSI 实现机制浅析
  6. 微信支付对接流程及注意事项
  7. 限制页面只能在微信内打开
  8. 安信可A9G-Pudding开发板 ADC功能使用及固件开发
  9. H5开发:调用高德地图api实现H5定位功能
  10. laravel-excel文档翻译笔记详细