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

Как загружать/передавать большие изображения с помощью Spring 3.2 spring -mvc в спокойном виде

Я пытаюсь загрузить/передать большое изображение контроллеру REST, который берет файл и сохраняет его в базе данных.

@Controller
@RequestMapping("/api/member/picture")
public class MemberPictureResourceController {

  @RequestMapping(value = "", method = RequestMethod.POST)
  @ResponseStatus(HttpStatus.NO_CONTENT)
  public void addMemberPictureResource(@RequestBody InputStream image) {
    // Process and Store image in database
  }
}

Это неработающий пример того, что я пытаюсь достичь (конечно, или я предполагаю, что InputStream не работает). Я хочу передать/прочитать изображение через @RequestBody.

Я искал везде, но не могу найти хороший пример того, как этого добиться. Большинство людей, похоже, спрашивают только, как загружать изображения поверх форм, но не используйте REST/RestTemplate для этого. Есть ли кто-нибудь, кто может мне помочь?

Я благодарен за любой намек в правильном направлении.

С уважением, Крис

Решения

Ниже я попытаюсь опубликовать решения, которые работали для меня после ввода от Dirk и Gigadot. На данный момент я думаю, что оба решения стоит посмотреть. Сначала я пытаюсь опубликовать рабочий пример с помощью, которую я получил от Dirk, а затем попытаюсь создать его с помощью Gigadot. Я буду отмечать ответ Dirks как правильный, поскольку я просил явным образом загрузить файл через @RequestBody. Но мне также интересно проверить решение от Gigadot, поскольку это, возможно, проще и более распространено в использовании.

В приведенных ниже примерах я храню файлы в MongoDB GridFS.

Решение 1 - Пример после рекомендации Dirks

Контроллер (с командой curl для тестирования в комментарии):

/**
*
* @author charms
* curl -v -H "Content-Type:image/jpeg" -X PUT --data-binary @star.jpg http://localhost:8080/api/cardprovider/logo/12345
*/
@Controller
@RequestMapping("/api/cardprovider/logo/{cardprovider_id}")
public class CardproviderLogoResourceController {

  @Resource(name = "cardproviderLogoService")
  private CardproviderLogoService cardproviderLogoService;

  @RequestMapping(value = "", method = RequestMethod.PUT)
  @ResponseStatus(HttpStatus.NO_CONTENT)
  public void addCardproviderLogo(@PathVariable("cardprovider_id") String cardprovider_id,
      HttpEntity<byte[]> requestEntity) {
    byte[] payload = requestEntity.getBody();
    InputStream logo = new ByteArrayInputStream(payload);
    HttpHeaders headers = requestEntity.getHeaders();

    BasicDBObject metadata = new BasicDBObject();
    metadata.put("cardproviderId", cardprovider_id);
    metadata.put("contentType", headers.getContentType().toString());
    metadata.put("dirShortcut", "cardproviderLogo");
    metadata.put("filePath", "/resources/images/cardproviders/logos/"); 

    cardproviderLogoService.create1(logo, metadata);
  }
}

Сервис (незавершенный, но работающий как тест):

@Service
public class CardproviderLogoService {

  @Autowired
  GridFsOperations gridOperation;

  public Boolean create1(InputStream content, BasicDBObject metadata) {
    Boolean save_state = false;
    try {
      gridOperation.store(content, "demo.jpg", metadata);
      save_state = true;
    } catch (Exception ex) {
      Logger.getLogger(CardproviderLogoService.class.getName())
          .log(Level.SEVERE, "Storage of Logo failed!", ex);
    }
    return save_state;    
  }
}

Решение 2 - Пример после рекомендации Гигадота

Это описано в руководстве Spring: http://static.springsource.org/spring/docs/3.2.1.RELEASE/spring-framework-reference/html/mvc.html#mvc-multipart

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

Спасибо всем за сообщение и за ваши ответы. Это очень ценится.

4b9b3361

Ответ 1

Как вам кажется, вы используете spring, вы можете использовать HttpEntity (http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/http/HttpEntity.html).

Используя его, вы получите что-то вроде этого (посмотрите на "полезную нагрузку" ):

@Controller
public class ImageServerEndpoint extends AbstractEndpoint {

@Autowired private ImageMetadataFactory metaDataFactory;
@Autowired private FileService fileService;

@RequestMapping(value="/product/{spn}/image", method=RequestMethod.PUT) 
public ModelAndView handleImageUpload(
        @PathVariable("spn") String spn,
        HttpEntity<byte[]> requestEntity, 
        HttpServletResponse response) throws IOException {
    byte[] payload = requestEntity.getBody();
    HttpHeaders headers = requestEntity.getHeaders();

    try {
        ProductImageMetadata metaData = metaDataFactory.newSpnInstance(spn, headers);
        fileService.store(metaData, payload);
        response.setStatus(HttpStatus.NO_CONTENT.value());
        return null;
    } catch (IOException ex) {
        return internalServerError(response);
    } catch (IllegalArgumentException ex) {
        return badRequest(response, "Content-Type missing or unknown.");
    }
}

Мы используем PUT здесь, потому что RESTfull "помещает изображение в продукт". 'spn' - номер продукта, созданный файлом fileService.store(). Конечно, вы могли бы также ПОСТИТЬ изображение для создания ресурса изображения.

Ответ 2

При отправке запроса POST существует два типа кодировки, которые вы можете использовать для отправки формы/параметров/файлов на сервер, т.е. application/x-www-form-urlencoded и multipart/form-data. Вот для более чтения.

Использование application/x-www-form-urlencoded не является хорошей идеей, если у вас есть большой контент в вашем POST-запросе, потому что он обычно сбой веб-браузера (из моего опыта). Таким образом, multipart/form-data.

Spring может обрабатывать контент multipart/form-data автоматически, если вы добавите многочастный преобразователь в диспетчер. Spring реализация для обработки выполняется с помощью apache-commons-fileupload, поэтому вам нужно будет добавить эту библиотеку в свой проект.

Теперь для основного ответа о том, как на самом деле это сделать, уже сейчас написано здесь http://viralpatel.net/blogs/spring-mvc-multiple-file-upload-example/

Я надеюсь, что это поможет вам найти решение. Вы можете прочитать о том, что такое REST. Похоже, вы немного смущены. В основном, почти все HTTP-запросы RESTful, даже если URL-адреса уродливы.

Ответ 3

Я сделал это недавно, см. подробности здесь.

В браузере мы можем использовать API-интерфейс файла для загрузки файла, затем кодировать его содержимое с использованием кодировки Base64 и, наконец, назначить кодированное содержимое объекту javascript перед его отправкой.

На сервере у нас есть контроллер Spring, который будет обрабатывать запрос. Как часть json unmarshalling, которая преобразует тело запроса в объект java, значение, закодированное base64 для байтов изображения, будет преобразовано в стандартный байт Java [] и сохранено как LOB в базе данных.

Чтобы получить изображение, другой способ Spring Controller может предоставить изображение путем потоковой передачи байтов напрямую.

Сообщение в блоге, с которым я связан выше, предполагает, что вы хотите использовать изображение как часть другого объекта, но принцип должен быть таким же, если вы хотите работать только с изображением напрямую. Дайте мне знать, если что-то нуждается в разъяснении.