700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 利用Java实现后端文件跨服务器传输(上传图片等文件)

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

时间:2021-01-15 21:20:03

相关推荐

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

背景

假设一台服务器部署了一个 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 mons.io.FileUtils;import mons.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()));}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。