Подтвердить что ты не робот

Загрузка файла вместе с другим объектом на веб-сервисе в Джерси.

Я хочу создать информацию о сотруднике в системе, загрузив изображение вместе с данными сотрудника. Я могу сделать это с различными вызовами отдыха с использованием трикотажа. Но я хочу добиться одного вызова. Я предоставляю ниже структуру. Пожалуйста, помогите мне, как это сделать.

@POST
@Path("/upload2")
@Consumes({MediaType.MULTIPART_FORM_DATA,MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response uploadFileWithData(
        @FormDataParam("file") InputStream fileInputStream,
        @FormDataParam("file") FormDataContentDisposition contentDispositionHeader,
        Employee emp) {

//..... business login

}

Всякий раз, когда я пытаюсь это сделать, я получаю ошибку в почтовом устройстве Chrome. Ниже приведена простая структура моего сотрудника json.

{
    "Name": "John",
    "Age": 23,
    "Email": "[email protected]",
    "Adrs": {
        "DoorNo": "12-A",
        "Street": "Street-11",
        "City": "Bangalore",
        "Country": "Karnataka"
    }
}

Однако я могу сделать это, выполнив два разных вызова, но я хочу добиться одного вызова, чтобы получить файл, а также фактические данные сотрудника.

Попросите вас помочь в этом отношении.

4b9b3361

Ответ 1

У вас не может быть двух Content-Type (хорошо технически, что мы делаем ниже, но они разделены с каждой частью multipart, но основной тип - multipart). Это в основном то, что вы ожидаете от своего метода. Вы ожидаете, что mutlipart и json вместе станут основным типом медиа. Данные Employee должны быть частью мультипартийности. Таким образом, вы можете добавить @FormDataParam("emp") для Employee.

@FormDataParam("emp") Employee emp) { ...

Здесь класс, который я использовал для тестирования

@Path("/multipart")
public class MultipartResource {

    @POST
    @Path("/upload2")
    @Consumes({MediaType.MULTIPART_FORM_DATA})
    public Response uploadFileWithData(
            @FormDataParam("file") InputStream fileInputStream,
            @FormDataParam("file") FormDataContentDisposition cdh,
            @FormDataParam("emp") Employee emp) throws Exception{

        Image img = ImageIO.read(fileInputStream);
        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(img)));
        System.out.println(cdh.getName());
        System.out.println(emp);

        return Response.ok("Cool Tools!").build();
    } 
}

Сначала я просто тестировал API-интерфейс клиента, чтобы убедиться, что он работает

@Test
public void testGetIt() throws Exception {

    final Client client = ClientBuilder.newBuilder()
        .register(MultiPartFeature.class)
        .build();
    WebTarget t = client.target(Main.BASE_URI).path("multipart").path("upload2");

    FileDataBodyPart filePart = new FileDataBodyPart("file", 
                                             new File("stackoverflow.png"));
    // UPDATE: just tested again, and the below code is not needed.
    // It redundant. Using the FileDataBodyPart already sets the
    // Content-Disposition information
    filePart.setContentDisposition(
            FormDataContentDisposition.name("file")
                                    .fileName("stackoverflow.png").build());

    String empPartJson
            = "{\n"
            + "    \"id\": 1234,\n"
            + "    \"name\": \"Peeskillet\"\n"
            + "}\n"
            + "";

    MultiPart multipartEntity = new FormDataMultiPart()
            .field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
            .bodyPart(filePart);

    Response response = t.request().post(
            Entity.entity(multipartEntity, multipartEntity.getMediaType()));
    System.out.println(response.getStatus());
    System.out.println(response.readEntity(String.class));

    response.close();
}

Я просто создал простой класс Employee с полем id и name для тестирования. Это прекрасно работает. Он отображает изображение, распечатывает содержимое и печатает объект Employee.

Я не слишком хорошо знаком с Postman, поэтому я сохранил это тестирование для последнего :-)

enter image description here

Он также отлично работает, так как вы можете увидеть ответ "Cool Tools". Но если мы посмотрим на напечатанные данные Employee, мы увидим, что это null. Что странно, потому что с клиентским API он отлично работал.

Если мы посмотрим на окно предварительного просмотра, мы увидим проблему

enter image description here

Нет заголовка Content-Type для части тела emp. В API-интерфейсе клиента вы можете явно указать его

MultiPart multipartEntity = new FormDataMultiPart()
        .field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
        .bodyPart(filePart);

Поэтому я думаю, что это действительно только часть полного ответа. Как я уже сказал, я не знаком с Postman. Поэтому я не знаю, как установить Content-Type для отдельных частей тела. image/png для изображения было автоматически настроено для меня для части изображения (я думаю, это было просто определено расширением файла). Если вы можете понять это, тогда проблема должна быть решена. Пожалуйста, если вы узнаете, как это сделать, отправьте его как ответ.


И только для полноты...

Основные конфигурации:

Зависимость:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-multipart</artifactId>
    <version>${jersey2.version}</version>
</dependency>

Конфигурация клиента:

final Client client = ClientBuilder.newBuilder()
    .register(MultiPartFeature.class)
    .build();

Конфигурация сервера:

// Create JAX-RS application.
final Application application = new ResourceConfig()
    .packages("org.glassfish.jersey.examples.multipart")
    .register(MultiPartFeature.class);

ОБНОВИТЬ

Таким образом, как вы можете видеть на клиенте Postman, некоторые клиенты не могут установить отдельные элементы Content-Type, включая браузер, в отношении возможностей по умолчанию при использовании FormData (js).

Мы не можем ожидать, что клиент обнаружит это, поэтому, когда мы получаем данные, явным образом устанавливаю Content-Type перед десериализацией. Например

@POST
@Path("upload2")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFileAndJSON(@FormDataParam("emp") FormDataBodyPart jsonPart,
                                  @FormDataParam("file") FormDataBodyPart bodyPart) { 
     jsonPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
     Employee emp = jsonPart.getValueAs(Employee.class);
}

Это небольшая дополнительная работа, чтобы получить POJO, но это лучшее решение, чем заставить клиента попробовать и найти его собственное решение.

Ответ 2

Вы можете получить доступ к файлу изображения и данным из формы, используя MULTIPART FORM DATA. Используя приведенный ниже код.

@POST
@Path("/UpdateProfile")
@Consumes(value={MediaType.APPLICATION_JSON,MediaType.MULTIPART_FORM_DATA})
@Produces(value={MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public Response updateProfile(
    @FormDataParam("file") InputStream fileInputStream,
    @FormDataParam("file") FormDataContentDisposition contentDispositionHeader,
    @FormDataParam("ProfileInfo") String ProfileInfo,
    @FormDataParam("registrationId") String registrationId) {

    String filePath= "/filepath/"+contentDispositionHeader.getFileName();

    OutputStream outputStream = null;
    try {
        int read = 0;
        byte[] bytes = new byte[1024];
        outputStream = new FileOutputStream(new File(filePath));

        while ((read = fileInputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, read);
        }

        outputStream.flush();
        outputStream.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (outputStream != null) { 
            try {
                outputStream.close();
            } catch(Exception ex) {}
        }
    }
}

Ответ 3

Ваш ApplicationConfig должен зарегистрировать MultiPartFeature.class из glassfish.jersey.media.., чтобы разрешить загрузку файла

@javax.ws.rs.ApplicationPath(ResourcePath.API_ROOT)
public class ApplicationConfig extends ResourceConfig {  
public ApplicationConfig() {
        //register the necessary headers files needed from client
        register(CORSConfigurationFilter.class);
        //The jackson feature and provider is used for object serialization
        //between client and server objects in to a json
        register(JacksonFeature.class);
        register(JacksonProvider.class);
        //Glassfish multipart file uploader feature
        register(MultiPartFeature.class);
        //inject and registered all resources class using the package
        //not to be tempered with
        packages("com.flexisaf.safhrms.client.resources");
        register(RESTRequestFilter.class);
    }

Ответ 4

Я хочу добавить комментарий к peeskillet, но не имеет 50 точек репутации, поэтому добавляя в качестве ответа:

Когда я попробовал решение @peeskillet с клиентом-клиентом версии 2.21.1, было 400 ошибок. Он работал, когда я добавил следующее в свой код клиента:

  MediaType contentType = MediaType.MULTIPART_FORM_DATA_TYPE;
  contentType = Boundary.addBoundary(contentType);

  Response response = t.request().post(
        Entity.entity(multipartEntity, contentType));

вместо hardcoded MediaType.MULTIPART_FORM_DATA в вызове после запроса.

Ответ 5

Я использовал пример загрузки файла,

http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/

в моем классе ресурсов я ниже метода

@POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response  attachupload(@FormDataParam("file") byte[] is,
@FormDataParam("file") FormDataContentDisposition fileDetail,
@FormDataParam("fileName") String flename){
attachService.saveAttachment(flename,is);
}

в моем attachService.java у меня есть метод

 public void saveAttachment(String flename,  byte[] is) {
            // TODO Auto-generated method stub
         attachmentDao.saveAttachment(flename,is);

        }

в Дао я

attach.setData(is);
attach.setFileName(flename);

в моем отображении HBM похоже на

<property name="data" type="binary" >
            <column name="data" />
</property>

Это работает для всех типов файлов, таких как .PDF,.TXT,.PNG и т.д.,

Ответ 6

Установите "Content-Type: multipart/form-data" на стороне клиента, и это должно выполнить задание