Попытка загрузить файл на сервер JAX-RS (Джерси)
Я пытаюсь загрузить файл и другие данные формы, используя клиент multipart/form-data с Джерси. Я загружаю в веб-сервис REST, также используя Джерси. Вот код сервера:
@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--
что я делаю неправильно в клиенте, чтобы заставить это работать правильно?
4 ответов
если вы хотите добавить строки 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");
}
наконец, maven зависимости:
<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
это в корне classpath и содержит Hello, World
.
решение Yves не работало для меня на стороне клиента. Я немного огляделся и нашел:--6-->
- http://puspendu.wordpress.com/2012/08/23/restful-webservice-file-upload-with-jersey/
- http://neopatel.blogspot.de/2011/04/jersey-posting-multipart-data.html
- http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/
non из которых работал бы с моим текущий Джерси 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;
}
пом.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>
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;
}
или просто напишите новый файл и загрузите его:
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);