2010-03-18 8 views
4

Я пытаюсь использовать Panda с моим приложением GWT. Я могу загружать видео непосредственно на мою панде сервер с помощьюJava Proxy Servlet для отправки файлов

POST MY_PANDA_SERVER/videos/MY_VIDEO_ID/upload 

Однако я хотел бы скрыть панду сервер позади моего сервера (GlassFish) J2EE. Я хотел бы добиться этого:

  1. Start загрузить какой-то сервлет на моем J2EE сервере
  2. Аутентифицировать пользователь
  3. POST файл на мою панде сервер в то же время загрузки на сервлет

В идеале I хотел бы никогда не хранить файл на сервере J2EE, а просто использовать его в качестве прокси для доступа к серверу panda.

ответ

6

Commons FileUpload приятный, но недостаточный в вашем случае. Он будет анализировать весь объект в памяти перед предоставлением файлов (и потоков). Вас не интересуют отдельные предметы. В основном вы просто хотите прозрачно передать тело запроса с одной на другую, не изменяя его или не сохраняя в памяти. FileUpload будет анализировать тело запроса только на некоторые «пригодные для использования» объекты Java, а HttpClient только создаст тот же самый объект запроса снова на основе этих объектов Java. Те объекты Java также потребляют память.

Для этого вам не нужна библиотека (или она должна быть Commons IO для замены петли for с помощью oneliner с использованием IOUtils#copy()). Достаточно просто базового API Java NET и IO API. Вот зарезка пример:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
    URLConnection connection = new URL("http://your.url.to.panda").openConnection(); 
    connection.setDoOutput(true); // POST. 
    connection.setRequestProperty("Content-Type", request.getHeader("Content-Type")); // This one is important! You may want to check other request headers and copy it as well. 

    // Set streaming mode, else HttpURLConnection will buffer everything. 
    int contentLength = request.getContentLength(); 
    if (contentLength > -1) { 
     // Content length is known beforehand, so no buffering will be taken place. 
     ((HttpURLConnection) connection).setFixedLengthStreamingMode(contentLength); 
    } else { 
     // Content length is unknown, so send in 1KB chunks (which will also be the internal buffer size). 
     ((HttpURLConnection) connection).setChunkedStreamingMode(1024); 
    } 

    InputStream input = request.getInputStream(); 
    OutputStream output = connection.getOutputStream(); 
    byte[] buffer = new byte[1024]; // Uses only 1KB of memory! 

    for (int length = 0; (length = input.read(buffer)) > 0;) { 
     output.write(buffer, 0, length); 
     output.flush(); 
    } 

    output.close(); 
    connection.getInputStream(); // Important! It's lazily executed. 
} 
+0

Вы, сэр, мой герой. Любая идея, как получить ответ от моего сервера Panda и отправить его обратно моему клиенту? – KevMo

+1

Тело ответа доступно 'connection.getInputStream()'. Просто напишите его так же, как 'response.getOutputStream()'. Вы можете получить необходимые заголовки ответов с помощью 'connection.getHeaderFields()' и передать его через 'response.setHeader (name, value)'. – BalusC

+0

, если вы загружаете большие файлы, он убьет ваш java-сервер. Это то, что у меня есть в моем приложении, каждый раз, когда я загружаю файл размером более 200 мб, я получаю java.lang.OutOfMemoryError: Java heap space. Как это исправить? – Maksim

0

Чтобы получить файл, вы можете использовать apache commons file upload. Затем вы можете использовать http client для загрузки файла на ваш сервер panda с помощью POST. С загрузкой файла apache commons вы можете обрабатывать файл в памяти, поэтому вам не нужно его хранить.

+0

, но если у меня есть несколько пользователей с загрузкой файлов около 1 Гб, мой сервер будет работать из памяти очень быстро. Я ДЕЙСТВИТЕЛЬНО хочу иметь возможность загрузить его на сервер panda, все еще получая файл от пользователя. – KevMo

+0

Вы можете использовать пользовательский сервлет, чтобы каждый раз, когда вы получаете X-число байтов, вы отправляете эти X-байты в panda с помощью http-клиента, а затем удаляете эти X-байты с сервера J2EE – Enrique

+0

именно тем, что я хочу делать .... но как ? – KevMo

0

Основываясь на ответе Энрике, я также рекомендую использовать FileUpload и HttpClient. FileUpload может дать вам stream загруженного файла:

// Create a new file upload handler 
ServletFileUpload upload = new ServletFileUpload(); 

// Parse the request 
FileItemIterator iter = upload.getItemIterator(request); 
while (iter.hasNext()) { 
    FileItemStream item = iter.next(); 
    String name = item.getFieldName(); 
    InputStream stream = item.openStream(); 
    if (item.isFormField()) { 
     System.out.println("Form field " + name + " with value " 
      + Streams.asString(stream) + " detected."); 
    } else { 
     System.out.println("File field " + name + " with file name " 
      + item.getName() + " detected."); 
     // Process the input stream 
     ... 
    } 
} 

Вы можете затем использовать HttpClient или HttpComponents сделать POST. Вы можете найти пример here.

+0

Тем не менее, поток хранится в памяти, и этого он хочет избежать. – BalusC

+0

Я предположил, что OP использует Streaming API для FileUpload (см. Ссылку в моем ответе). У меня создалось впечатление, что этот API не сохраняет ответ в памяти перед созданием потока. Я ошибаюсь? – kgiannakakis

+0

Нет, это не так. Как еще это могло бы дать ** отдельные ** элементы файла обратно через итератор? Знание того, какие предметы нужно вернуть, требует синтаксического разбора всего тела. Кроме того, вот цитата из API: «С другой стороны, это память и время.».В конце концов, если вы проверите его исходный код и/или попытаетесь повторно изобрести API FileUpload самостоятельно, вы сами увидите его. – BalusC

 Смежные вопросы

  • Нет связанных вопросов^_^