2011-04-24 35 views
12

我試圖上傳一個文件和其他表單數據與澤西島使用multipart/form-data客戶端。我正在使用Jersey上傳到REST Web服務。這裏是服務器代碼:嘗試上傳文件到JAX-RS(澤西島)服務器

@POST 
@Consumes(MediaType.MULTIPART_FORM_DATA) 
@Produces(MediaType.APPLICATION_JSON) 
public String create(@FormDataParam("file") InputStream file, 
     @FormDataParam("file") FormDataContentDisposition fileInfo, 
     @FormDataParam("name") String name, 
     @FormDataParam("description") String description) { 
    Ingredient ingredient = new Ingredient(); 
    ingredient.setName(name); 
    ingredient.setDescription(description); 
    ingredient.setImageName(fileInfo.getFileName()); 
    ingredient.setImagePath(context.getRealPath("/resources/uploads/")); 
    // TODO save the file. 
    try { 
     JSONObject json = new JSONObject(); 
     try { 
      ingredientService.create(ingredient); 
     } catch (final InvalidParameterException ex) { 
      logger.log(Level.INFO, ex.getMessage()); 
      json.put("result", false); 
      json.put("error", ex.getMessage()); 
      return json.toString(); 
     } catch (final GoodDrinksException ex) { 
      logger.log(Level.WARNING, null, ex); 
      json.put("result", false); 
      json.put("error", ex.getMessage()); 
      return json.toString(); 
     } 
     json.put("ingredient", JsonUtil.ingredientToJSON(ingredient)); 
     return json.put("result", true).toString(); 
    } catch (JSONException ex) { 
     logger.log(Level.SEVERE, null, ex); 
     return "{\"result\",false}"; 
    } 
} 

我已經測試了服務器代碼,在我的桌面上使用基本的html表單,它工作正常。問題似乎在客戶端。這裏是相關的客戶端代碼。

ClientConfig config = new DefaultClientConfig(); 
client = Client.create(config); 
client.addFilter(new LoggingFilter()); 
webResource = client.resource("http://localhost:8080/webapp/resources").path("ingredient"); 
FormDataMultiPart fdmp = new FormDataMultiPart(); 
if (file != null) { 
    fdmp.bodyPart(new FileDataBodyPart("file", file, MediaType.APPLICATION_OCTET_STREAM_TYPE)); 
} 
fdmp.bodyPart(new FormDataBodyPart("name", ingredient.getName())); 
fdmp.bodyPart(new FormDataBodyPart("description", ingredient.getDescription())); 

ClientResponse response = webResource.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(ClientResponse.class, fdmp); 
String string = response.getEntity(String.class); 
logger.log(Level.INFO, "response: {0}", string); 

我從服務器獲取400響應「客戶端發送的請求是語法不正確」

這裏是吐出記錄器的消息,這個人是沒有文件以保持輸出簡短:

1 > POST http://localhost:8080/webapp/resources/ingredient 
1 > Content-Type: multipart/form-data 
1 > 
--Boundary_5_1545082086_1303666703655 
Content-Type: text/plain 
Content-Disposition: form-data;name="name" 
Adam 
--Boundary_5_1545082086_1303666703655 
Content-Type: text/plain 
Content-Disposition: form-data;name="description" 
Test 
--Boundary_5_1545082086_1303666703655-- 

我在做什麼錯誤的客戶端,以使其正常工作?

+0

樣品:http://puspendu.wordpress.com/2012/08/23/restful-webservice-file-upload-with-jersey/ – 2012-08-22 19:54:25

+0

哪個選項沒有你設置爲顯示請求正文,我啓用了'ServerProperties.TRACING = ALL'和'ServerProperties.TRACING_THRESHOLD = VERBOSE'。但它不顯示請求主體 – 2014-07-21 09:03:02

回答

30

如果要將字符串添加到FormDataMultiPart,則只需使用.field("name", "value")方法,與文件附件使用的方式相同(queryParam不起作用)。

下面是一個工作示例:

首先,它返回讀取文件的內容作爲字符串的服務器部分:

@Path("file") 
public class FileResource { 

    @POST 
    @Consumes(MediaType.MULTIPART_FORM_DATA) 
    public Response handleUpload(@FormDataParam("file") InputStream stream) throws Exception { 
     return Response.ok(IOUtils.toString(stream)).build(); 
    } 
} 

其次,客戶端方法發佈文件:

public void upload(String url, String fileName) { 
    InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName); 
    FormDataMultiPart part = new FormDataMultiPart().field("file", stream, MediaType.TEXT_PLAIN_TYPE); 

    WebResource resource = Client.create().resource(url); 
    String response = resource.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(String.class, part); 
    assertEquals("Hello, World", response); 
} 

三,測試環境:

Server server; 

@Before 
public void before() throws Exception { 
    server = new Server(8080); 
    server.addHandler(new WebAppContext(WEB_INF_DIRECTORY, "/")); 
    server.start(); 
} 

@After 
public void after() throws Exception { 
    server.stop(); 
} 

@Test 
public void upload() { 
    upload("http://localhost:8080/file", "file.txt"); 
} 

最後,行家依賴性:

<dependencies> 
    <dependency> 
     <groupId>junit</groupId> 
     <artifactId>junit</artifactId> 
     <version>4.8.2</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>com.sun.jersey</groupId> 
     <artifactId>jersey-server</artifactId> 
     <version>1.6</version> 
    </dependency> 
    <dependency> 
     <groupId>com.sun.jersey</groupId> 
     <artifactId>jersey-client</artifactId> 
     <version>1.6</version> 
    </dependency> 
    <dependency> 
     <groupId>com.sun.jersey.contribs</groupId> 
     <artifactId>jersey-multipart</artifactId> 
     <version>1.6</version> 
    </dependency> 
    <dependency> 
     <groupId>org.mortbay.jetty</groupId> 
     <artifactId>jetty-embedded</artifactId> 
     <version>6.1.26</version> 
    </dependency> 
    <dependency> 
     <groupId>commons-io</groupId> 
     <artifactId>commons-io</artifactId> 
     <version>2.0.1</version> 
    </dependency> 
</dependencies> 

file.txt是在類路徑的根和含有Hello, World

+0

查詢參數實際上用於獲取操作而不是表單opts。這個問題最終成爲Netbeans 6.9.1中的一個bug。他們不包括必需的罐子。唯一的解決辦法是升級Netbeans 7. – Ruggs 2011-05-03 16:54:13

+0

我不明白Netbeans如何成爲問題的一部分。看到我更新的回覆。 – 2011-05-04 08:55:01

+0

添加jax-rs庫時,我沒有使用maven管理庫和netbeans,因此缺少mimepull.jar。您可以在Netbeans bugzilla中找到與此問題相關的多個門票號碼。 – Ruggs 2011-05-12 15:18:53

-2

或只寫一個新的文件,並上傳:

Writer output = null; 
    File file = null; 
    try { 
     String text = "Rajesh Kumar"; 
     file = new File("write.txt"); 
     output = new BufferedWriter(new FileWriter(file)); 
     output.write(text); 
     output.close(); 
    } catch (IOException e) { 
     System.out.println("IOException e"); 
     e.printStackTrace(); 
    } 

    InputStream is = null; 

    try { 
     is = new FileInputStream(file); 
    } catch (FileNotFoundException e) { 
     System.out.println("FileNotFoundException e"); 
     e.printStackTrace(); 
    } catch (IOException e) { 
     System.out.println("IOException e"); 
     e.printStackTrace(); 
    } 

    FormDataMultiPart part = new FormDataMultiPart().field("file", is, MediaType.TEXT_PLAIN_TYPE); 
    res = service.path("rest").path("tenant").path(tenant1.getTenantId()).path("file").type(MediaType.MULTIPART_FORM_DATA_TYPE).post(ClientResponse.class, part); 
2

伊夫解決方案並沒有爲我的客戶端工作。 我四處張望了一下,發現:

其中非將與我目前的球衣1.18(見下文POM提取物)的工作。 大部分麻煩都在客戶端。我會得到錯誤信息,如:

com.sun.jersey.api.client.ClientHandlerException: javax.ws.rs.WebApplicationException: java.lang.IllegalArgumentException: Missing body part entity of type 'text/plain' 
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:155) 
at com.sun.jersey.api.client.Client.handle(Client.java:652) 
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682) 

服務器端使用此代碼的工作很快(這並不做任何事情與 上傳的InputStream有趣又 - 適合你的需求)

@POST 
@Consumes(MediaType.MULTIPART_FORM_DATA) 
@Produces("text/plain") 
public Response uploadFile(
     @FormDataParam("content") final InputStream uploadedInputStream, 
     @FormDataParam("fileName") String fileName) throws IOException { 
    String uploadContent=IOUtils.toString(uploadedInputStream); 
    return Response.ok(uploadContent).build(); 
} 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.IOException; 
import javax.ws.rs.core.MediaType; 

import com.sun.jersey.api.client.Client; 
import com.sun.jersey.api.client.WebResource; 
import com.sun.jersey.multipart.FormDataBodyPart; 
import com.sun.jersey.multipart.FormDataMultiPart; 
/** 
* upload the given file 
* 
* inspired by 
* http://neopatel.blogspot.de/2011/04/jersey-posting-multipart-data.html 
* 
* @param url 
* @param uploadFile 
* @return the result 
* @throws IOException 
*/ 
public String upload(String url, File uploadFile) throws IOException { 
    WebResource resource = Client.create().resource(url); 
    FormDataMultiPart form = new FormDataMultiPart(); 
    form.field("fileName", uploadFile.getName()); 
    FormDataBodyPart fdp = new FormDataBodyPart("content", 
      new FileInputStream(uploadFile), 
      MediaType.APPLICATION_OCTET_STREAM_TYPE); 
    form.bodyPart(fdp); 
    String response = resource.type(MediaType.MULTIPART_FORM_DATA).post(String.class, form); 
    return response; 
} 

pom.xml中提取:

客戶端將與此代碼的工作
<properties> 
    <jersey.version>1.18</jersey.version> 
</properties> 
<dependency> 
    <groupId>com.sun.jersey</groupId> 
    <artifactId>jersey-server</artifactId> 
    <version>${jersey.version}</version> 
</dependency> 
<dependency> 
    <groupId>com.sun.jersey</groupId> 
    <artifactId>jersey-client</artifactId> 
    <version>${jersey.version}</version> 
</dependency> 
<!-- Multipart support --> 
<dependency> 
    <groupId>com.sun.jersey.contribs</groupId> 
    <artifactId>jersey-multipart</artifactId> 
    <version>${jersey.version}</version> 
</dependency> 
0

public DssResponse callPut(String url, Map<String, String> headers, FileDataBodyPart[] filePath, String boundary, String[] jsonString) throws IOException { 
    Client client = ClientBuilder.newClient().register(MultiPartFeature.class); 
    WebTarget webTarget = client.target(url); 
    Builder builder = webTarget.request(MediaType.MULTIPART_FORM_DATA); 
    FormDataMultiPart multiPart = new FormDataMultiPart(); 
    for (int i = 0; i < filePath.length; i++) { 

     if (!filePath[i].getFileEntity().exists()) { 
      throw new IOException("Invalid Input File - " + filePath[i].getFileEntity().getAbsolutePath()); 
     } 

     multiPart.bodyPart(new FileDataBodyPart(filePath[i].getName(), filePath[i].getFileEntity())); 
    } 

    if (boundary != null) 
     multiPart.type(Boundary.addBoundary(new MediaType("multipart", "form-data", Collections.singletonMap(Boundary.BOUNDARY_PARAMETER, boundary)))); 
    for (String jstr : jsonString) { 
     multiPart.field("Content-Type", jstr, MediaType.APPLICATION_JSON_TYPE); 
    } 
    if (headers != null) { 
     for (Entry<String, String> header : headers.entrySet()) { 
      builder.header(header.getKey(), header.getValue()); 
      System.out.println(header.getKey() + "===============>>" + header.getValue()); 
     } 
    } 

    Response response = builder.accept(MediaType.APPLICATION_JSON).put(Entity.entity(multiPart, multiPart.getMediaType())); 

    multiPart.close(); 

    // Assert.assertNotNull(response); 
    if (response == null) 
     throw new IOException ("Response is NULL"); 

    int status = response.getStatus(); 

    return dssResponse; 
} 
+2

雖然此代碼片段可能解決問題,但[包括解釋](http://meta.stackexchange.com/questions/114762/explaining-entirely-code- based-answers)確實有助於提高您的質量帖子。請記住,您將來會爲讀者回答問題,而這些人可能不知道您的代碼建議的原因。 – NathanOliver 2015-12-23 17:20:20