Загрузка многостраничного файла на Google Appengine с использованием jersey-1.7

Я написал приложение в Google Appengine с Джерси для обработки простой загрузки файлов. Это прекрасно работает, когда он был на майке 1.2. В более поздних версиях (текущий 1.7) вводится @FormDataParam для обработки входов multipart / form. Я использую jersey-multipart и зависимость mimepull. Кажется, что новый способ сделать это – создать временные файлы в appengine, которые все мы знаем, является незаконным …

Я что-то упустил или сделал что-то не так, потому что Джерси теперь якобы совместим с AppEngine?

@POST @Path("upload") @Consumes(MediaType.MULTIPART_FORM_DATA) public void upload(@FormDataParam("file") InputStream in) { .... } 

Вышеупомянутое не будет выполнено, если вызвано с этими исключениями …

 /upload java.lang.SecurityException: Unable to create temporary file at java.io.File.checkAndCreate(File.java:1778) at java.io.File.createTempFile(File.java:1870) at java.io.File.createTempFile(File.java:1907) at org.jvnet.mimepull.MemoryData.createNext(MemoryData.java:87) at org.jvnet.mimepull.Chunk.createNext(Chunk.java:59) at org.jvnet.mimepull.DataHead.addBody(DataHead.java:82) at org.jvnet.mimepull.MIMEPart.addBody(MIMEPart.java:192) at org.jvnet.mimepull.MIMEMessage.makeProgress(MIMEMessage.java:235) at org.jvnet.mimepull.MIMEMessage.parseAll(MIMEMessage.java:176) at org.jvnet.mimepull.MIMEMessage.getAttachments(MIMEMessage.java:101) at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readMultiPart(MultiPartReaderClientSide.java:177) at com.sun.jersey.multipart.impl.MultiPartReaderServerSide.readMultiPart(MultiPartReaderServerSide.java:80) at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:139) at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:77) at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:474) at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:538) 

Кто-нибудь знает? Есть ли способ сделать что-то, не позволяя mimepull создавать временный файл?

Для файлов, размер которых превышает размер по умолчанию, multipart создаст временный файл. Чтобы этого избежать – создание файла невозможно на gae – вы можете создать файл jersey-multipart-config.properties в папке ресурсов проекта и добавить к нему эту строку:

 bufferThreshold = -1 

Тогда код – тот, который вы дали:

 @POST @Consumes(MediaType.MULTIPART_FORM_DATA) public Response post(@FormDataParam("file") InputStream stream, @FormDataParam("file") FormDataContentDisposition disposition) throws IOException { post(file, disposition.getFileName()); return Response.ok().build(); } 

В интересах тех, кто борется при использовании Eclipse с GPE (плагин Google для Eclipse), я даю это слегка измененное решение, полученное из ответа @yves.

Я тестировал его с помощью App Engine SDK 1.9.10 и Jersey 2.12 . Он не будет работать с App Engine SDK 1.9.6 -> 1.9.9 среди других из-за другой проблемы.

В папке \war\WEB-INF\classes создайте новый файл с именем jersey-multipart-config.properties . Отредактируйте файл, чтобы он содержал строку jersey.config.multipart.bufferThreshold = -1 .

Обратите внимание, что папка \classes скрыта в Eclipse, поэтому найдите папку в проводнике файлов вашей операционной системы (например, проводник Windows).

Теперь, когда функция multipart получает инициализацию (при инициализации сервлета Джерси), и когда выполняется загрузка файла (на запрос сообщения сержанта сервлета), временный файл больше не будет создан, и GAE не будет жаловаться.

Очень важно поместить файл jersey-multipart-config.properties под WEB-INF/classes внутри WAR.

Обычно в файловой структуре WAR вы помещаете файлы конфигурации ( web.xml , appengine-web.xml ) в WEB-INF/ , но здесь вам нужно поместить в WEB-INF/classes .

Пример конфигурации Maven:

   org.apache.maven.plugins maven-war-plugin 2.4  true   ${basedir}/src/main/webapp/WEB-INF true WEB-INF   ${basedir}/src/main/resources WEB-INF/classes     -   org.apache.maven.plugins maven-war-plugin 2.4  true   ${basedir}/src/main/webapp/WEB-INF true WEB-INF   ${basedir}/src/main/resources WEB-INF/classes     

И ваша структура проекта может выглядеть так:

Структура проекта

Содержание jersey-multipart-config.properties с Jersey 2.x:

 jersey.config.multipart.bufferThreshold = -1 

я нашел решение программным образом избежать использования временного создания файлов (очень полезно для реализации GAE)

Мое решение состоит в создании нового провайдера MultiPartReader … ниже моего кода


  @Provider @Consumes("multipart/*") public class GaeMultiPartReader implements MessageBodyReader { final Log logger = org.apache.commons.logging.LogFactory.getLog(getClass()); private final Providers providers; private final CloseableService closeableService; private final MIMEConfig mimeConfig; private String getFixedHeaderValue(Header h) { String result = h.getValue(); if (h.getName().equals("Content-Disposition") && (result.indexOf("filename=") != -1)) { try { result = new String(result.getBytes(), "utf8"); } catch (UnsupportedEncodingException e) { final String msg = "Can't convert header \"Content-Disposition\" to UTF8 format."; logger.error(msg,e); throw new RuntimeException(msg); } } return result; } public GaeMultiPartReader(@Context Providers providers, @Context MultiPartConfig config, @Context CloseableService closeableService) { this.providers = providers; if (config == null) { final String msg = "The MultiPartConfig instance we expected is not present. " + "Have you registered the MultiPartConfigProvider class?"; logger.error( msg ); throw new IllegalArgumentException(msg); } this.closeableService = closeableService; mimeConfig = new MIMEConfig(); //mimeConfig.setMemoryThreshold(config.getBufferThreshold()); mimeConfig.setMemoryThreshold(-1L); // GAE FIX } @Override public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return MultiPart.class.isAssignableFrom(type); } @Override public MultiPart readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap headers, InputStream stream) throws IOException, WebApplicationException { try { MIMEMessage mm = new MIMEMessage(stream, mediaType.getParameters().get("boundary"), mimeConfig); boolean formData = false; MultiPart multiPart = null; if (MediaTypes.typeEquals(mediaType, MediaType.MULTIPART_FORM_DATA_TYPE)) { multiPart = new FormDataMultiPart(); formData = true; } else { multiPart = new MultiPart(); } multiPart.setProviders(providers); if (!formData) { multiPart.setMediaType(mediaType); } for (MIMEPart mp : mm.getAttachments()) { BodyPart bodyPart = null; if (formData) { bodyPart = new FormDataBodyPart(); } else { bodyPart = new BodyPart(); } bodyPart.setProviders(providers); for (Header h : mp.getAllHeaders()) { bodyPart.getHeaders().add(h.getName(), getFixedHeaderValue(h)); } try { String contentType = bodyPart.getHeaders().getFirst("Content-Type"); if (contentType != null) { bodyPart.setMediaType(MediaType.valueOf(contentType)); } bodyPart.getContentDisposition(); } catch (IllegalArgumentException ex) { logger.error( "readFrom error", ex ); throw new WebApplicationException(ex, 400); } bodyPart.setEntity(new BodyPartEntity(mp)); multiPart.getBodyParts().add(bodyPart); } if (closeableService != null) { closeableService.add(multiPart); } return multiPart; } catch (MIMEParsingException ex) { logger.error( "readFrom error", ex ); throw new WebApplicationException(ex, 400); } } } 

У нас возникла аналогичная проблема, Jetty не позволил нам загружать файлы более 9194 байт (внезапно – один день), после чего мы поняли, что кто-то взял наш пользовательский доступ из / tmp, что соответствует java.io. tmpdir в некоторых версиях Linux, поэтому Jetty не смог сохранить загруженный файл, и мы получили ошибку 400.

  • Удалить class = атрибут
  • Как поддерживать несколько версий Android в коде?
  • Как я могу использовать пользовательский растровый рисунок для точки «вы здесь» в MyLocationOverlay?
  • Изменение библиотеки OpenSSL в приложении Android для HttpClient
  • Что делает оператор «+ =» в Java?
  • Предпочтения в списке Android: есть сводка в качестве выбранного значения?
  • Пользовательский макет для DialogFragment OnCreateView и OnCreateDialog
  • Android: изменение фонового цвета активности (основной вид)
  • NoClassDefFoundError для проекта внешней библиотеки для Android
  • Как передать строку из одной активности в другую?
  • Код для загрузки видео с Youtube на Java, Android
  • Interesting Posts

    Можно ли удалить системный раздел системы Windows 7 без проблем?

    Сжатые папки NTFS: можно ли настроить коэффициент сжатия?

    Loop / отражать все свойства во всех моделях EF для установки типа столбца

    Отключить стрелки страницы поиска Google, кроме результатов при прокрутке вверх / вниз с помощью клавиатуры

    Проще говоря, что такое фабрика?

    Где GOTO: EOF возвращается?

    Сколько символов можно сопоставить с Unicode?

    Фатальный сигнал 11 (SIGSEGV) при 0x00000000 (код = 1) – PhoneGap

    Как я могу запускать скрипт всякий раз, когда подключаю внешний монитор?

    Гарантирован ли заказ для возврата ключей и значений из объекта LinkedHashMap?

    Как удалить пунктирную схему Firefox на BUTTONS, а также ссылки?

    Как остановить публикацию файлов Office в Internet Explorer?

    Целочисленные объекты-оболочки имеют одни и те же экземпляры только в пределах значения 127?

    std :: вектор и непрерывная память многомерных массивов

    Хороший инструмент для поиска дубликатов фотографий на основе данных изображения

    Давайте будем гением компьютера.