利用Java实现后端文件跨服务器传输(上传图片等文件) 您所在的位置:网站首页 ideapost请求带上图片发送图片到另一个服务 利用Java实现后端文件跨服务器传输(上传图片等文件)

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

2023-07-21 06:19| 来源: 网络整理| 查看: 265

背景

假设一台服务器部署了一个 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 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(); } @Override public ServletInputStream getInputStream() throws IOException { ByteArrayInputStream inputStream = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { log.info("set readListener"); } @Override public int read() throws IOException { return inputStream.read(); } }; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有