【问题标题】:How can i programmatically upload a file to a website?如何以编程方式将文件上传到网站?
【发布时间】:2012-01-27 06:35:45
【问题描述】:

我必须将文件上传到仅公开带有文件上传按钮(通过 http)的 jsf 网页的服务器。我必须自动化一个进程(作为 java 独立进程完成),它生成一个文件并将文件上传到服务器。遗憾的是,必须上传文件的服务器不提供 FTP 或 SFTP。有没有办法做到这一点?

谢谢, 里奇

【问题讨论】:

  • 你能保留它的工作示例代码吗?

标签: java jsf file-upload


【解决方案1】:

以编程方式提交 JSF 生成的表单时,您需要确保考虑以下 3 件事:

  1. 维护 HTTP 会话(当然,如果网站打开了 JSF 服务器端状态保存)。
  2. 发送javax.faces.ViewState隐藏字段的名称-值对。
  3. 发送虚拟按下按钮的名称-值对。

否则可能根本不会调用该操作。对于残余,它与“常规”形式没有什么不同。流程基本如下:

  • 在带有表单的页面上发送 GET 请求。
  • 提取 JSESSIONID cookie。
  • 从响应中提取 javax.faces.ViewState 隐藏字段的值。如有必要(确定它是否具有动态生成的名称,因此可能会更改每个请求),提取输入文件字段的名称和提交按钮。动态生成的 ID/名称可通过 j_id 前缀识别。
  • 准备一个multipart/form-data POST 请求。
  • 在该请求上设置 JSESSIONID cookie(如果不是 null)。
  • 设置javax.faces.ViewState隐藏字段和按钮的名称-值对。
  • 设置要上传的文件。

您可以使用任何 HTTP 客户端库来执行该任务。标准 Java SE API 为此提供了java.net.URLConnection,即pretty low level。为了减少冗长的代码,您可以使用 Apache HttpClient 执行 HTTP 请求并管理 cookie,并使用 Jsoup 从 HTML 中提取数据。

这是一个启动示例,假设页面只有一个 <form>(否则您需要在 Jsoup 的 CSS 选择器中包含该表单的唯一标识符):

String url = "http://localhost:8088/playground/test.xhtml";
String viewStateName = "javax.faces.ViewState";
String submitButtonValue = "Upload"; // Value of upload submit button.

HttpClient httpClient = new DefaultHttpClient();
HttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute(ClientContext.COOKIE_STORE, new BasicCookieStore());

HttpGet httpGet = new HttpGet(url);
HttpResponse getResponse = httpClient.execute(httpGet, httpContext);
Document document = Jsoup.parse(EntityUtils.toString(getResponse.getEntity()));
String viewStateValue = document.select("input[type=hidden][name=" + viewStateName + "]").val();
String uploadFieldName = document.select("input[type=file]").attr("name");
String submitButtonName = document.select("input[type=submit][value=" + submitButtonValue + "]").attr("name");

File file = new File("/path/to/file/you/want/to/upload.ext");
InputStream fileContent = new FileInputStream(file);
String fileContentType = "application/octet-stream"; // Or whatever specific.
String fileName = file.getName();

HttpPost httpPost = new HttpPost(url);
MultipartEntity entity = new MultipartEntity();
entity.addPart(uploadFieldName, new InputStreamBody(fileContent, fileContentType, fileName));
entity.addPart(viewStateName, new StringBody(viewStateValue));
entity.addPart(submitButtonName, new StringBody(submitButtonValue));
httpPost.setEntity(entity);
HttpResponse postResponse = httpClient.execute(httpPost, httpContext);
// ...

【讨论】:

  • 我试过这个但没有成功。我建立了一个类似的虚拟网站。我在提交 jsf 页面的帖子响应时收到 200 OK 响应。由于某种原因,它没有调用提交方法。我在服务器中为提交方法设置了一个断点,但调用从未到达那里。
  • 目前所提供的信息很难指出真正的问题。您是否了解代码示例中必须进行哪些更改才能使其适用于特定网站?
  • 是的。我更改了 URL 并提交按钮值以匹配我的网页。我还更改了要上传的文件路径
  • 我在实体“%formname%_SUBMIT”中添加了一个字符串值为1的部分,它开始工作了。未在 multipart 中设置的另一个隐藏参数是这个 - 试试我的运气,瞧!感谢一吨的队友,你真的是一个储蓄者。 ;) JSoup 是一个很酷的 api!
  • 哦,那一定是一个旧的 JSF 1.x webapp。抱歉,没想到。很高兴你想通了。是的,确实,Jsoup 非常漂亮:)
【解决方案2】:

尝试使用 HttpClient,here's an article,我认为它描述了您想要的内容,在底部有一个标题为“使用基于 HttpClient 的文件上传”的部分。

希望这会有所帮助。

【讨论】:

  • 感谢朋友的回答。我试过这个,但由于它是一个 jsf 应用程序,我必须设置隐藏参数,正如 BalusC 在他的回答中指出的那样。
【解决方案3】:

可能该网页只是向服务器发送一个带有表单内容的 POST 请求。您可以轻松地从 Java 自己发送这样的 POST 请求,而无需使用该页面。例如this article 显示了从 Java 发送 POST 请求的示例

【讨论】:

    【解决方案4】:

    您需要做的是检查页面上的 HTML 并确定发布表单所需的参数。它可能看起来像这样:

    <form action="/RequestURL">
    <input type=file name=file1>
    <input type=textbox name=value1>
    </form>
    

    基于此,您可以编写一些代码来向 url 发出 POST 请求:

    String data = URLEncoder.encode("value1", "UTF-8") + "=" + URLEncoder.encode("value1", "UTF-8");
    data += "&" + URLEncoder.encode("file1", "UTF-8") + "=" + URLEncoder.encode(FileData, "UTF-8");
    
    // Send data
    URL url = new URL("http://servername.com/RequestURL");
    URLConnection conn = url.openConnection();
    conn.setDoOutput(true);
    OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
    wr.write(data);
    wr.flush();
    wr.close();
    

    请记住,编写页面的人可能会进行一些检查以确保 POST 请求来自同一站点。在这种情况下,您可能会遇到麻烦,您可能需要正确设置用户代理。

    【讨论】:

      【解决方案5】:

      您可以尝试为此使用HtmlUnit。它提供了一个非常简单的 API 来模拟浏览器操作。我已经将这种方法用于类似的要求。这很容易。你应该试一试。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-02-15
        • 1970-01-01
        • 1970-01-01
        • 2014-02-25
        • 1970-01-01
        • 2012-09-10
        • 2015-06-09
        相关资源
        最近更新 更多