SpringBoot 如何优雅的实现跨服务器上传文件的示例

项目完整代码链接:代码链接

跨服务上传文件示意图

一、创建项目

  • springboot:2.2.6
  • JDK:1.8

由于资源有限,就用不同端口表示不同服务器了。

1.1 上传文件的项目

首先idea快速搭建工具创建一个springboot项目,名字为fileupload,作为上传文件的服务端。

选择spring web模块即可

配置相关参数

spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=30MB
spring.servlet.multipart.max-request-size=30MB
#文件保存的url,末尾的 / 别漏了
file.upload.path=http://localhost:8888/fileuploadserver/uploads/

添加坐标依赖

跨服器上传所需要的jar包坐标

<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-core</artifactId>
  <version>1.18.1</version>
</dependency>
<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-client</artifactId>
  <version>1.18.1</version>
</dependency>

1.2 创建fileuploadserver 保存文件服务器

创建一个jeex项目,项目名字为fileuploadserver,什么都不需要配置。然后再webapp目录下创建一个uploads文件夹,与上面项目设置的文件保存地址一直,然后配置好tomcat环境启动即可。记得把web.xml文件里面的配置信息删掉

如下图所示

记得改下Http和JMX的端口,免得和其他项目冲突了。

二、编写服务器接收文件上传代码

编写一个controller类,用与处理文件上传
MultipartFile类用来保存上传的文件数据

package cn.jxj4869.fileupload.controller;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.UUID;

@Controller

public class FileController {
  @Value("${file.upload.path}")
  private String path;

  @RequestMapping("/fileupload/method1")
  @ResponseBody
  private String method1(@RequestParam("upload") MultipartFile upload) throws IOException {
    System.out.println("跨服务器上传文件上传");

    String filename = upload.getOriginalFilename();
    // 把文件的名称设置唯一值,uuid
    String uuid = UUID.randomUUID().toString().replace("-", "");
    filename = uuid + "_" + filename;
    // 创建客户端的对象

    Client client = Client.create();

    // 和图片服务器进行连接
    WebResource webResource = client.resource(path + filename);

    webResource.put(upload.getBytes());
    return "success";
  }
}

前端代码

放在/resources/static/目录下

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>fileupload</title>
</head>
<body>
<h3>method1</h3>
<form method="post" enctype="multipart/form-data" action="fileupload/method1">
  <input type="file" name="upload">
  <br>
  <input type="submit">
</form>
</body>
</html>

上传效果如下

三、分析存在问题以及解决办法

3.1 问题分析

正如上面写的,只要我们关联了服务器地址之后就可以直接通过put方法把文件上传上去,这无疑是非常危险的行为。因为在上传过程中并没有进行用户校验,那么如果被人知道了服务器保存图片的路径,甚至不需要知道准确路径,只要知道服务器ip地址就够了,那么他就可以通过put方法无限量的进行服务器上传。

根据apache官方在2017公布的一个漏洞,如果开启了put方法,那么就可以任意写写入文件到服务器。但是如果禁用了put方法,那么又有导致一些需要put方法的业务无法使用。

一个解决办法就是修改tomcat的配置。修改在tomcat的/conf目录下的web.xml。找到下面这段

readonly设置成true。这样就无法通过put往服务器中写入文件了。

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
      <param-name>readonly</param-name>
      <param-value>true</param-value>
    </init-param>
  </servlet>

但是这样一来,我们就无法通过上述方法来进行跨服务器上传了,因为文件服务器已经禁止了通过put方法写入文件。那么这种情况应该怎么办呢?

有一种思路就是把服务器接收到的文件上传请求,通过HttpPost再把上传的文件信息发送到文件服务器。由文件服务器自己处理是否接收保存文件。

3.2 修改项目fileupload的配置

添加HttpPost的相关坐标依赖

  <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.3.6</version>
    </dependency>
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpmime</artifactId>
      <version>4.5</version>
    </dependency>
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpcore</artifactId>
      <version>4.4.1</version>
    </dependency>

添加配置:

application.properties

file.upload.path1=http://localhost:8888/fileupload/

3.3 创建fileuploadserver1 项目

创建一个springboot项目,选择如**fileload**项目一样。

创建好之后在/resources/目录下创建一个uploads文件夹,用作保存上传文件的位置。(也可以根据自己实际需要,更改文件保存的位置)

配置相关参数

# 文件上传位置 这里是路径是相对于项目而言,可以根据实际情况更改
file.upload.save-path=/uploads/
#文件访问路径
file.upload.url=/uploads/**

server.port=8888

#文件大小设置
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=30MB
spring.servlet.multipart.max-request-size=100MB

3.4 编写服务器接收文件上传代码

用数组的形式接收MultipartFile参数,实现多文件上传。

把上传的文件用MultipartEntityBuilder打包好之后,再用HttpPost发送到文件服务器。这里最好需要了解一些HttpPost用法。

package cn.jxj4869.fileupload.controller;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.UUID;

@Controller

public class FileController {

  @Value("${file.upload.path1}")
  private String path1;

  @RequestMapping("/fileupload/method2")
  @ResponseBody
  private String method2(@RequestParam("upload") MultipartFile[] uploads) throws IOException {
    System.out.println("跨服务器上传文件上传");
    CloseableHttpClient httpClient = HttpClients.createDefault();
    HttpPost httpPost = new HttpPost(path1);
    MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    for (MultipartFile upload : uploads) {
      String filename = upload.getOriginalFilename();
      builder.addBinaryBody("upload", upload.getBytes(), ContentType.MULTIPART_FORM_DATA, filename);
    }
    try {

      HttpEntity entity = builder.build();
      httpPost.setEntity(entity);
      CloseableHttpResponse response = httpClient.execute(httpPost);
      System.out.println(response.getStatusLine().getStatusCode());
      String s = response.getEntity().toString();
      System.out.println(s);
    } catch (Exception e) {

    } finally {
      httpClient.close();
    }
    return "success";
  }
}

前端部分的代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>fileupload</title>
</head>
<body>
<h3>method2</h3>
<form method="post" enctype="multipart/form-data" action="fileupload/method2">
  <input type="file" name="upload"><br><br>
  <input type="file" name="upload"><br><br>
  <input type="file" name="upload">
  <br><br>
  <input type="submit">
</form>
</body>
</html>

3.5 编写文件服务器接收代码

接收的Controller

ResourceUtils.getURL("classpath:") 获取当前项目所在的路径,最好别存在中文,可能会出错

package cn.jxj4869.fileuploadserver1.controller;

import com.sun.javafx.scene.shape.PathUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;

import java.util.UUID;

@Controller
public class FileController {

  @Value("${file.upload.save-path}")
  private String savePath;

  @PostMapping("/fileupload")
  @ResponseBody
  private String fileupload(HttpServletRequest request, @RequestParam("upload")MultipartFile[] uploads) throws IOException {
    System.out.println("文件上传");

    String path= ResourceUtils.getURL("classpath:").getPath()+savePath;

    File file = new File(path);
    if (!file.exists()) {
      file.mkdir();
    }
    for (MultipartFile upload : uploads) {
      String filename = upload.getOriginalFilename();
      String uuid = UUID.randomUUID().toString().replace("-", "");
      filename=uuid+"_"+filename;
      upload.transferTo(new File(path,filename));
    }
    return "success";

  }
}

编写配置类

package cn.jxj4869.fileuploadserver1.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cglib.core.WeakCacheKey;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MySpringMvcConfig implements WebMvcConfigurer {

  @Value("${file.upload.save-path}")
  private String savePath;
  @Value("${file.upload.url}")
  private String url;
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler(url).addResourceLocations("classpath:"+savePath);
  }
}

3.6 效果展示

到此这篇关于SpringBoot 如何优雅的实现跨服务器上传文件的示例的文章就介绍到这了,更多相关SpringBoot 跨服务器上传文件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot上传文件到本服务器 目录与jar包同级问题

    前言 看标题好像很简单的样子,但是针对使用jar包发布SpringBoot项目就不一样了. 当你使用tomcat发布项目的时候,上传文件存放会变得非常简单,因为你可以随意操作项目路径下的资源.但是当你使用SpringBoot的jar包发布项目的时候,你会发现,你不能像以前一样操作文件了.当你使用File file = new File()的时候根本不知道这个路径怎么办.而且总不能很小的项目也给它构建一个文件服务器吧.所以这次就来解决这样的问题. 不想知道细节的,可以直接跳转到最后封装的部分,里面

  • SpringBoot中的五种对静态资源的映射规则的实现

    SpringBoot中的SpringMVC配置功能都是在WebMvcAutoConfiguration类中,xxxxAutoConfiguration就是帮我们给容器中自动配置组件的:idea全局搜索的快捷键是两次shift,查看webMvcAutoConfiguration 查看webMvc自动配置类 WebMvcAutoConfiguration类的原理以后至少还要稍微掌握,而这里文章只是来看它的具体的关键代码,这里只例举部分关键代码,多了看着也头疼,看不懂没关系哈哈哈可跳过源码阶段,何必徒

  • SpringBoot上传文件并配置本地资源映射来访问文件的实例代码

    1.准备工作 1.新建一个SpringBoot项目加上web依赖, 所有依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.thymeleaf</groupId&

  • springboot以FTP方式上传文件到远程服务器

    一.html代码   <div class="layui-form-item"> <label class="layui-form-label">上传附件:</label> <div class="layui-input-block doc-litpic"> <button type="button" name="avatar" class="

  • springboot上传文件过大的500异常解决

    修改appliaction.properties # 单个文件最大20m spring.servlet.multipart.max-file-size=20MB #一次请求最大100M spring.servlet.multipart.max-request-size=100MB 如果配置文件为appliaction.yml的这样配置文件: spring: servlet: multipart: maxFileSize: 20MB maxRequestSize: 100MB 500代码异常,在启

  • SpringBoot 如何优雅的实现跨服务器上传文件的示例

    项目完整代码链接:代码链接 跨服务上传文件示意图 一.创建项目 springboot:2.2.6 JDK:1.8 由于资源有限,就用不同端口表示不同服务器了. 1.1 上传文件的项目 首先idea快速搭建工具创建一个springboot项目,名字为fileupload,作为上传文件的服务端. 选择spring web模块即可 配置相关参数 spring.servlet.multipart.enabled=true spring.servlet.multipart.max-file-size=30

  • SpringMVC跨服务器上传文件中出现405错误的解决

    目录 SpringMVC跨服务器上传文件中出现405错误 重点来了~ SpringMVC跨服务器上传文件中出现405错误 下面是 应用服务器 的代码 package com.itheima.controller; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.WebResource; import org.apache.commons.fileupload.FileItem; import or

  • Java实现跨服务器上传文件功能

    前几天做个项目,本身客户端和管理员端是写在一起的,共用一台服务器,客户上传的文件都是存在服务器的硬盘上的.老龙提出要把客户端和管理员端分离,这时候用户上传的附件的存储就出现问题了.显然,把大到几百M的apk文件存到数据库不现实,查了半天,在两端建立ftp服务器传文件是最快的方法. 具体流程是,用户登录外网客户端,上传文件到外网的服务器硬盘上,在此同时,文件通过外网服务器访问内网管理员服务器的ftp服务器,传到内网服务器的硬盘上.这样内网服务器可以对上传的文件进行加密签名工作,之后也通过ftp的方

  • SpringMVC图片文件跨服务器上传

    图片文件跨服务器上传(我使用的公司云桌面作为上传服务器,自己的笔记本作为存储服务器测试的) 一.上传服务器: 1.pom文件(使用jersey插件) <!-- 上传组件包 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version&g

  • form+iframe解决跨域上传文件的方法

    (1)  jsp代码: <form id="form" name="form" enctype="multipart/form-data" method="post" target="hidden_frame"> <table style="border:0;width:100%;text-align:middle;"> <tr style="bo

  • Java实现ftp上传下载、删除文件及在ftp服务器上传文件夹的方法

    一个JAVA 实现FTP功能的代码,包括了服务器的设置模块,并包括有上传文件至FTP的通用方法.下载文件的通用方法以及删除文件.在ftp服务器上传文件夹.检测文件夹是否存在等,里面的有些代码对编写JAVA文件上传或许有参考价值,Java FTP主文件代码: package ftpDemo; import java.io.DataOutputStream; import java.io.InputStream; import java.io.OutputStream; import sun.net

  • java模拟客户端向服务器上传文件

    本文实例为大家分享了java客户端向服务器上传文件的具体代码,供大家参考,具体内容如下 先来了解一下客户端与服务器Tcp通信的基本步骤: 服务器端先启动,然后启动客户端向服务器端发送数据. 服务器端收到客户端发送的数据,服务器端会响应应客户端,向客户端发送响应结果. 客户端读取服务器发送的数据 文件上传步骤: 客户端使用本地字节输入流,指定上传数据的数据源. 客户端使用网络字节输出流,把读取的本地文件上传到服务器. 服务器使用网络字节输入流,读取客户端上传的文件. 服务器使用本地字节输出流,把读

  • Python调用scp向服务器上传文件示例

    最近做的项目中有一个小功能:在python中调用scp命令 使用ssh登录,然后将指定目录中的图片上传到服务器指定目录 网上搜了很多方法都没用,最后终于碰到一个可以成功上传的,特此记录 import paramiko # 用于调用scp命令 from scp import SCPClient # 将指定目录的图片文件上传到服务器指定目录 # remote_path远程服务器目录 # file_path本地文件夹路径 # img_name是file_path本地文件夹路径下面的文件名称 def u

  • Android FTP服务器上传文件攻略(代码详解)

    1.前言 在开发中,会遇到向FTP服务器上传文件的需求,首先要导入 commons-net-3.3.jar 然后利用api进行相关操作,具体功能如下: Ftp相关代码 import android.util.Log; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; import java.i

  • React实现阿里云OSS上传文件的示例

    简介 阿里云 OSS 是 阿里云提供的海量.安全.低成本.高可靠的云存储服务,提供 99.9999999999%的数据可靠性(号称).能够使用 RESTful API 可以在互联网任何位置存储和访问,支持容量和处理能力弹性扩展. 基本术语 1.bucket :类似本地的一个文件夹 2.object : oss 存储数据的基本单元,类似本地的一个文件. 3.region:oss 存储的数据中心所在区域 4.Endpoint:oss 对外服务的访问域名,oss 以 http api 提供服务,不同

随机推荐