Начальная

Windows Commander

Far
WinNavigator
Frigate
Norton Commander
WinNC
Dos Navigator
Servant Salamander
Turbo Browser

Winamp, Skins, Plugins
Необходимые Утилиты
Текстовые редакторы
Юмор

File managers and best utilites

Включение поддержки Java Web Start в IDE NetBeans. Java web выгрузка больших файлов из браузера


Study & Dev | Blog Archive

Заметки про java и загрузку файлов с помощью commons fileupload

Введение

Сегодня я расскажу о том, как выполнять загрузку файлов из браузера в ваш сервлет или jsp-файл. Не секрет, что встроенной поддержки загрузки файлов в j2ee нет. Иногда по форумам кочуют самодельные скрипты парсинга http-запроса (несколько лет назад я и сам баловался написанием анализатора http-запросов), но то время прошло и теперь все большее количество java-разработчиков открывают для себя Commons FileUpload.

Напомню, что для того, чтобы html-форма могла отправить файл, необходимо указать для нее метод отправки “method” равный “post” (ну не в адресной же строке передавать содержимое файла…). А также необходимо указать способ кодирования отправляемой информации равным “multipart/form-data” (есть два алгоритма кодирования информации перед отправкой по сети: “multipart/form-data” и “x-www-form-urlencoded”). Для доступа к обычным (текстовым) полям формы мы используем либо вызовы:

  1. String variableValue = request.getParameter(variableName);
Либо jstl синтаксис:
  1. <c:out value="${para.userFio}" />
Проблема в том, что так добраться до присланных из формы полей можно лишь в случае, если данные были присланы методом “x-www-form-urlencoded”. В случае же метода “multipart/form-data”, мы не можем добраться не только до полей с файлами, но и даже до обычных текстовых полей. Особенность парсинга входящих запросов в java в том, что первое же обращение к присланным веб-приложению параметрам с помощью getParameter приведет к потере “сырых” данных и другие приложения не смогут выполнить повторный парсинг данных (с учетом каких-либо особенностей входного потока). Например, если вы работаете со struts (который сам выполняет парсинг mutipart-запросов), то использование commons fileupload вызывает ряд сложностей. Но хватит слов, давайте напишем немного кода:

Немножко кода

Стадия настройки: в методе init сервлет-а необходимо создать фабрику DiskFileItemFactory. Ее назначение – управлять параметрами обработки запроса. Дело в том, что все входящие переменные (как обычные, так и файловые) сохраняются либо в памяти либо на жестком диске сервера в зависимости от их размера. Откровенно говоря, мне не нравится такой подход, т.к. почти всегда данные пришедшие из текстовых полей приходится помещать в базу данных и эти данные действительно должны находиться в памяти. А вот ситуации с обработкой пришедших файлов (например, изменение размера картинки или конвертация видео-файла являются достаточно редкими) обычно файл просто переносится в определенную папку на сервера. А в базу данных заносится имя этого файла. Возвращаясь к вопросу создания фабрики, вы должны указать в качестве параметров конструктора число (играющее роль порога для принятия решения: сохранять ли входную переменную на диск или в файл), вторым же параметром при создании DiskFileItemFactory выступает путь к каталогу, где будут сохраняться временные файлы. Если вы эти значения не укажите, то в качестве пороговой величины будет принята отметка в 10240 байт, а для каталога с файлами используется значение возвращаемой системной переменной:

  1. System.getProperty("java.io.tmpdir").
Для обеспечения автоматического удаления временных файлов вы можете запустить специальный сервис FileCleanerCleanup. Этот сервлет-слушатель, запускает специальный сервис отслеживания ненужных файлов и уничтожения их, как только все ссылки на подобный файл будут уничтожены (надо сказать, что в документации написано, что поддержка удаления файлов будет выполнена автоматически при выполнении сборки мусора – но оставлять этот вопрос на самотек не желательно). Для регистрации “сборщика мусора” нужно добавить в файл web.xml следующие строки:
  1. <listener>
  2. <listener-class>
  3. org.apache.commons.fileupload.servlet.FileCleanerCleanup
  4. </listener-class>
  5. </listener>
После создания фабрики DiskFileItemFactory вы создаете объект, непосредственно отвечающий за процесс парсинга входящего запроса. Делать это нужно в зависимости от того, в какой среде выполняется ваше приложение, если это обычный сервлет или jsp, то используйте вызов:
  1. ServletFileUpload upload = new ServletFileUpload(factory);
Ну а если ваше приложение организовано как портлет, то нужно создать другой объект:
  1. PortletFileUpload upload = new PortletFileUpload (factory);
Все эти два класса являются наследниками от org.apache.commons.fileupload.FileUploadBase. После создания парсер можно настроить указав ряд параметров:

setSizeMax – задает максимальный размер суммарно всех файлов загружаемых на сервер. Для установки предельного значения для файла в отдельности используется вызов setFileSizeMax. Также здесь можно установить с помощью вызова setProgressListener специальный класс-слушатель прогресса загрузки файлов – это может быть полезным для ajax-приложений.

Но перед тем как мы выполним парсинг запроса, необходимо проверить является ли входящий запрос “понятным” для commons fileupload. Для этого вызовите статический метод isMultipartContent, передав ему ссылку на объект входящего запроса ServletRequest.

Если метод вернет false, значит данные пришли будучи закодированными с помощью “x-www-form-urlencoded” и на этом участие commons fileupload заканчивается. Собственно, парсинг выполняется вызовом метода parseRequest. В качестве результат будет возвращен список “элементов” запроса, каждый из этих элементов представляет собой объект, реализующий интерфейс FileItem. В составе этого интерфейса есть методы позволяющие получить подробные сведения об загруженных файлах или обычных полях. Например:

  1. boolean isMultipart = ServletFileUpload.isMultipartContent(request);
  2. if (isMultipart) {
  3. ServletFileUpload upload = new ServletFileUpload(factory);
  4. List items = upload.parseRequest(request);
  5. Iterator iter = items.iterator();
  6. // получили список всех полей из html-формы
  7. while (iter.hasNext()) {
  8. FileItem item = (FileItem) iter.next();
  9. // берем элемент формы и анализируем то, какого он типа
  10. if (item.isFormField()) {
  11. // если обычное поле, то мы можем получить его значение в выбранной кодировке
  12. // с помощью вызова getString(нужная кодировка)
  13. item.getString(usedCharset);
  14. }
  15. else {
  16. // если файл
  17. // так мы получим значение оригинального имени файла
  18. String name = item.getName();
  19. long filelen = item.getSize();
  20. // так мы определим его размер
  21. // а так мы определим его content-type
  22. String cct = item.getContentType()
  23.  
  24. // а теперь нужно что-то сделать с самим содержимым файла ....
  25.  
  26. }//else если это обычное текстовое поле, а не файл
  27. } // завершили обработку запроса с помощью mutipart/form-data.
Работа, собственно, с содержимым файла не сильно зависит от того, находится ли он на диске, во временном файле, или в памяти. Фактически мы можем проверить наличие файла в памяти с помощью вызова isInMemory, но практического смысла это не имеет. Вы можете получить сырое содержимое файла в виде массива байтов с помощью вызова:
  1. byte[] data = item.get();
Если файл текстовый и вы знаете его кодировку, то можно сразу прочитать все его содержимое в выбранной кодировке с помощью вызова:
  1. String fcontent = item.getString(“utf-8”)
Надо сказать, что такой же метод getString используется и для получения значения обычного текстового поля.

Или вы можете получить ссылку на байтовый поток с помощью вызова:

  1. InputStream is = item.getInputStream();

Мой велосипед

В целом ничего сложного. Тем не менее, я в свое время создал сервлет-фильтр работающий совместно с fileuploads и решающим одну неприятную проблему: после того как данные были обработаны с помощью fileuploads, вы вынуждены работать с данными только показанным выше способом (через объекты FileItem). Вызов же метода request.getParameter (‘имя_переменной’) ничего не возвращает.

Как работает мой сервлет фильтр? Прежде всего, вы должны скопировать в папку lib вашего веб-приложения библиотеки нужные для работы собственно commons fileuploads, это архивы: commons-fileupload-1.1.1.jar и commons-io-1.2.jar. Затем вы регистрируете в файле web.xml сервлет фильтр и указываете то, какие адреса он должен обрабатывать. В качестве параметров сервлета нужно указать значение кодировки, в которой будут рассматриваться входящие обычные текстовые переменные (этот параметр необходим т.к. стандартная методика с request.setCharacterEncoding не работает: ведь вызов сервлета фильтра будет выполнен до того как управление попадет к вашему сервлету или jsp-файлу). Все обычные переменные будут помещены внутрь объекта request и вы можете обращаться к ним как раньше без какого либо изменения в коде. Фактически ваше приложение вообще не будет догадываться о том, что перед ним работает commons fileuploads и мой фильтр. Относительно загружаемых файлов, то все они помещаются стандартного каталога для временных файлов, а после окончания работы вашего кода будут автоматически удалены. Так что вам необходимо выполнить перемещение этих файлов в какой-то другой каталог (если, конечно, эти файлы вам нужны, в противном случае ничего с ними не делайте и они будут автоматически удалены). Фактически метод работы фильтра очень похож на принятую в php методику загрузки файлов: файлы хранятся во временном каталоге, а в специальной переменной (в атрибуты запроса помещается переменная с именем f$) хранится список описаний загруженных файлов. А вот на формате хранения данных о файлах стоит остановиться попозже подробнее.

Вот пример подключения сервлета-фильтра к вашему веб-приложению:

  1. <filter>
  2. <filter-name>SmartFileUploads</filter-name>
  3. <filter-class>helpers.SmartFileUploads</filter-class>
  4. <init-param>
  5. <param-name>force-set-encoding-urlencoded</param-name>
  6. <param-value>utf-8</param-value>
  7. </init-param>
  8. <init-param>
  9. <param-name>force-set-encoding-multipart</param-name>
  10. <param-value>utf-8</param-value>
  11. </init-param>
  12. </filter>
  13. <filter-mapping>
  14. <filter-name>SmartFileUploads</filter-name>
  15. <url-pattern>/*</url-pattern>
  16. </filter-mapping>
Обратите внимание на параметры фильтра: force-set-encoding-multipart и force-set-encoding-urlencoded. Они оба указывают на используемую при анализе полученного содержимого формы кодировку. Однако в случае если эти параметры не указаны, то их значения интерпретируются по-разному. В первом случае используется кодировка ISO8859-1, во втором же случае, запрос пропускается без парсинга входящего набора данных. И установка нужного значения кодировки должна быть выполнена пользовательским сервлетом или jsp-файлом.

Итак, доступ к обычным полям формы выполняется так, как вы привыкли (с помощью getParameter), а как быть с выходными данными.

Есть два стиля возвращаемых данных и зависящих от параметров в файле web.xml. Ни в одном из этих случаев, нет доступа к структурам данных, используемым fileuploads: фактически, разработчик может не догадывался об их существовании (плохо это или хорошо – думайте сами). Чем обусловлено существование двух стилей возвращаемых данны? Очевидно удобством работы.

Вот пример формы, которая отправит данные на сервер:

  1. <form action="servertest.jsp" method="post" enctype="multipart/form-data">
  2. File <input type="file" name="foto" size="40" value=""/>
  3. File 1<input type="file" name="pics[]" size="40"/>
  4. File 2<input type="file" name="pics[]" size="40"/>
  5. <input type="submit" name="btnsubmit" value="Send"/>
  6. </form>
Обратите внимание, что есть два элемента формы, имеющие одинаковые имена, заканчивающиеся на “[]”. Фактически вы можете загрузить на сервер набор файлов с одинаковым именем (это удобно в случае динамической генерации списка полей для загрузки файла).

Элементарная единица информации, которая хранит сведения о файле (оригинальное имя файла, его размер, mime-тип, а также путь к каталогу с временными файлами, где находится загруженный файл) - это карта HashMap . В качестве ключей этой карты выступают предопределенные имена ключей: orig_name, tmp_name, size , content-type . Все сведения об полученных файлах помещаются внутрь еще одной карты вида HashMap . В качестве, ключа этой карты выступают имена переменных формы (foto, pics[]).

В случае если имя поля формы не заканчивается на “[]”, то в качестве значения “карты” находится одиночный HashMap. В противном случае в качетсве значения “карты” выступает список (ArrayList) хранящий сведения об множестве файлов загруженных на сервер под одним и тем же именем. Рассмотрим это на примере:

Примеры работы

В конфигурационный файл приложения необходимо добавить опцию:

  1. <init-param>
  2. <param-name>force-unified-result-style</param-name>
  3. <param-value>false</param-value>
  4. </init-param>
Для того что бы прочитать данные в таком стиле вы следует использовать следующий код:
  1. HashMap f = (HashMap) request.getAttribute("f$");
  2. if (f != null){
  3. out.println ("Получены в качестве параметров несколько файлов ... анализирую...");
  4. final Iterator set = f.keySet().iterator();
  5. while (set.hasNext()){
  6. String varName = (String) set.next();
  7. Object value = f.get(varName);
  8. if (value instanceof ArrayList){
  9. out.println("Переменная содержит список файлов");
  10. ArrayList alistValues = (ArrayList) value;
  11. for (Object alistValue : alistValues) {
  12. HashMap paramFile = (HashMap) alistValue;
  13. out.println ("-------------");
  14. out.println ("orig_name: "+ paramFile.get("orig_name"));
  15. out.println ("tmp_name: "+ paramFile.get("tmp_name"));
  16. out.println ("size: "+ paramFile.get("size"));
  17. out.println ("content-type: "+ paramFile.get("content-type"));
  18. out.println ("-------------");
  19. }
  20. }
  21. else{
  22. out.println("Переменная содержит только один файл");
  23. HashMap paramFile = (HashMap) value;
  24. out.println ("-------------");
  25. out.println ("orig_name: "+ paramFile.get("orig_name"));
  26. out.println ("tmp_name: "+ paramFile.get("tmp_name"));
  27. out.println ("size: "+ paramFile.get("size"));
  28. out.println ("content-type: "+ paramFile.get("content-type"));
  29. out.println ("-------------");
  30. }
  31. }
  32. }
  33. else{
  34. out.println ("Файлов нет ... не анализирую...");
  35. }
Возможно вам покажется громоздким выполнение проверки что же именно хранится в карте “f$”: обычный HashMap (тогда это обычный одиночный файл), или же там хранится ArrayList (когда выполняется загрузка массива файлов). С другой стороны, если вы работаете только с одиночными загружаемыми файлами, то ваш код будет наиболее простым.

А вот как будут выглядеть полученные сведения о файлах в случае использования стиля оформления результата # 1:

foto=[{orig_name=Baza_6_2.png, content-type=image/png, size=13643, tmp_name=E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9822zedzed} ]   pics=[{orig_name=Baza_6_1.png, content-type=image/png, size=6012, tmp_name=E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9823zedzed}, {orig_name=Baza_6_3.png, content-type=image/png, size=31879, tmp_name=E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9824zedzed} ]   Файлы Получены в качестве параметров несколько файлов ... анализирую... Переменная содержит только один файл ------------- orig_name: Baza_6_2.png tmp_name: E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9829zedzed size: 13643 content-type: image/png ------------- Переменная содержит список файлов ------------- orig_name: Baza_6_1.png tmp_name: E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9830zedzed size: 6012 content-type: image/png ------------- ------------- orig_name: Baza_6_3.png tmp_name: E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9831zedzed size: 31879 content-type: image/png ------------- Во втором случае результаты разбора запроса будут унифицированы и не зависимо от того, передан один файл или их массив, в качестве значения карты “f$” будет храниться список (возможно состоящий из одного элемента). Зато такие данные удобно обрабатывать в циклах:

Вот так будет выглядеть конфигурационный параметр в файле web.xml:

  1. <init-param>
  2. <param-name>force-unified-result-style</param-name>
  3. <param-value>true</param-value>
  4. </init-param>
Код который формирует подобный список информации более выглядит более компактно:
  1. HashMap<String, ArrayList<HashMap<String, String>>> f =
  2. (HashMap<String, ArrayList<HashMap<String, String>>>) request.getAttribute("f$");
  3. if (f != null) {
  4. out.println("Получены в качестве параметров несколько файлов ... анализирую...");
  5. final Iterator set = f.keySet().iterator();
  6. while (set.hasNext()) {
  7. String varName = (String) set.next();
  8. Object value = f.get(varName);
  9. out.println("Переменная содержит список файлов");
  10. ArrayList alistValues = (ArrayList) value;
  11. for (Object alistValue : alistValues) {
  12. HashMap paramFile = (HashMap) alistValue;
  13. out.println("-------------");
  14. out.println("orig_name: " + paramFile.get("orig_name"));
  15. out.println("tmp_name: " + paramFile.get("tmp_name"));
  16. out.println("size: " + paramFile.get("size"));
  17. out.println("content-type: " + paramFile.get("content-type"));
  18. out.println("-------------");
  19. }
  20. }// while
  21. } else {
  22. out.println("Файлов нет ... не анализирую...");
  23. }
А вот как будут выглядеть полученные сведения о файлах в случае использования стиля оформления результата # 2:foto=[{orig_name=Baza_6_2.png, content-type=image/png, size=13643, tmp_name=E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9850zedzed} ]   pics=[{orig_name=Baza_6_1.png, content-type=image/png, size=6012, tmp_name=E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9851zedzed}, {orig_name=Baza_6_3.png, content-type=image/png, size=31879, tmp_name=E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9852zedzed} ]   Получены в качестве параметров несколько файлов ... анализирую... Переменная содержит список файлов ------------- orig_name: Baza_6_2.png tmp_name: E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9850zedzed size: 13643 content-type: image/png ------------- Переменная содержит список файлов ------------- orig_name: Baza_6_1.png tmp_name: E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9851zedzed size: 6012 content-type: image/png ------------- ------------- orig_name: Baza_6_3.png tmp_name: E:\Program_Files_2\apache-tomcat-6.0.14\temp\zedzed9852zedzed size: 31879 content-type: image/png -------------

И код самого сервлета-фильтра

  1. package helpers;
  2.  
  3. import org.apache.commons.fileupload.FileItem;
  4. import org.apache.commons.fileupload.FileItemFactory;
  5. import org.apache.commons.fileupload.disk.DiskFileItemFactory;
  6. import org.apache.commons.fileupload.servlet.ServletFileUpload;
  7. import org.apache.commons.io.FilenameUtils;
  8.  
  9. import javax.servlet.*;
  10. import javax.servlet.http.HttpServletRequest;
  11. import javax.servlet.http.HttpServletRequestWrapper;
  12. import java.io.File;
  13. import java.io.IOException;
  14. import java.util.*;
  15.  
  16.  
  17. public class SmartFileUploads implements Filter {
  18. private class UTf8MakerReqiestWrapper extends HttpServletRequestWrapper {
  19. HashMap<String, String[]> params = new HashMap<String, String[]>();
  20.  
  21. public String getParameter(String s) {
  22. if (params.get(s) == null) return null;
  23. return params.get(s).length != 0 ? params.get(s)[0] : null;
  24. }
  25.  
  26. public Map getParameterMap() {
  27. return params;
  28. }
  29.  
  30. public Enumeration getParameterNames() {
  31. return Collections.enumeration(params.keySet());
  32. }
  33.  
  34. public String[] getParameterValues(String s) {
  35. return params.get(s);
  36. }
  37.  
  38. private HashMap parseFile(FileItem item) throws Exception {
  39. String name = item.getName();
  40. long filelen = item.getSize();
  41. HashMap<String, String> nextfile = new HashMap<String, String>();
  42. if (name != null && (name.length() > 0)) {// если файл был загружен
  43.  
  44. name = FilenameUtils.getName(name);
  45. final File tempFile = File.createTempFile("zedzed", "zedzed");
  46. // здесь файл не клонируется а в случае возмоности переименовывается
  47. item.write(tempFile);
  48. nextfile.put(PARAM_ORIG_NAME, name);
  49. nextfile.put(PARAM_SIZE_NAME, "" + filelen);
  50. nextfile.put(PARAM_TMP_NAME, tempFile.getAbsolutePath());
  51. nextfile.put(PARAM_CONTENTTYPE_NAME, item.getContentType());
  52. // после парсинга файл необходимо зарегистрировать в специальном
  53. // списке файлов подлежащих удалению после завершения работы фильтра
  54. origNames.add(tempFile.getAbsolutePath());
  55.  
  56. } else {
  57. nextfile.put(PARAM_ORIG_NAME, null);
  58. nextfile.put(PARAM_SIZE_NAME, "-1");
  59. nextfile.put(PARAM_TMP_NAME, null);
  60. nextfile.put(PARAM_CONTENTTYPE_NAME, null);
  61. }
  62. return nextfile;
  63. }
  64.  
  65. private ArrayList<String> origNames = new ArrayList<String>();
  66.  
  67. private UTf8MakerReqiestWrapper(HttpServletRequest hreq) throws Exception {
  68. super(hreq);
  69. final String usedCharset = hreq.getCharacterEncoding();
  70.  
  71. final HashMap<String, Object> f = new HashMap<String, Object>();
  72. hreq.setAttribute("f$", f);
  73.  
  74. ServletFileUpload upload = new ServletFileUpload(factory);
  75. List items = upload.parseRequest(hreq);
  76. Iterator iter = items.iterator();
  77.  
  78. while (iter.hasNext()) {
  79. FileItem item = (FileItem) iter.next();
  80. String fld_name = item.getFieldName();
  81. Boolean is_multifield = false;
  82. if (fld_name.endsWith("[]")) {
  83. fld_name = fld_name.substring(0, fld_name.length() - 2);
  84. is_multifield = true;
  85. }
  86. if (item.isFormField()) {
  87. final String fValue = item.getString(usedCharset);
  88. // если поле содержит массив строк
  89. if (is_multifield) {
  90. if (params.containsKey(fld_name)) {
  91. String[] strings = params.get(fld_name);
  92. String[] strings2 = new String[1 + strings.length];
  93. System.arraycopy(strings, 0, strings2, 0, strings.length);
  94. strings2[strings.length] = fValue;
  95. strings = null;
  96. params.put(fld_name, strings2);
  97. } else {
  98. params.put(fld_name, new String[]{fValue});
  99. }
  100. }//if multi values
  101. else {
  102. //if single value (skip old values)
  103. params.put(fld_name, new String[]{fValue});
  104. }
  105. // теперь обработаем файлы
  106. } else {
  107. // если у выполняется загрузка массива файлов
  108. if (is_multifield) {
  109. if (f.containsKey(fld_name)) {
  110. ((ArrayList<HashMap<String, String>>)f.get(fld_name)).add(parseFile(item));
  111. }//if has item by this name
  112. else {
  113. final ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
  114. list.add(parseFile(item));
  115. f.put(fld_name, list);
  116. }
  117. } else {
  118. // если файл загружается в единственном экземпляре, то необходимо
  119. // проигнорировать все остальные значения
  120. // однако следует учитывать стиль формирования результата
  121. if (forceUnifiedResultSetStyle){
  122. final ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
  123. list.add(parseFile(item));
  124. f.put(fld_name, list);
  125. }
  126. else
  127. f.put(fld_name, parseFile(item));
  128. }
  129. }//else if fileupload, not regular fieldname
  130. // но это еще не все возможно что поле попало в раздел файлов и теперь необходимо сделать так
  131. // чтобы удалились все эти вредные файлы
  132. try {
  133. item.delete();
  134. } catch (Exception e) {
  135. log("--UTF8Maker::cannot delete tmp file (parse stage)--: " + hreq.getRequestURI());
  136. }
  137.  
  138. }// while
  139.  
  140. }// constructor
  141.  
  142. private void cleanup() {
  143. // необходимо удалить все файлы которые были созданы на стадии парсинга запроса,
  144. // но все еще не были удалены после его окончания
  145. // файл должен быть либо удален либо перенесен в другое место
  146. for (String origName : origNames) {
  147. try {
  148. File ftmp = new File(origName);
  149. if (ftmp.exists())
  150. ftmp.delete();
  151. } catch (Exception e) {
  152. log("--UTF8Maker::cannot delete tmp file (cleanup stage)--: " + origName);
  153. }
  154. }
  155. }
  156. }// end of CLASS
  157.  
  158. // сведения об загруженных файлах хранятся в виде HashMap <string, String>
  159. // в качестве ключей этой "карты" возможны следующие значения:
  160. // 1. Оригинальное имя файла (естественно, без каталогов)
  161. private static final String PARAM_ORIG_NAME = "orig_name";
  162. // 2. Имя временного файла в котором хранится информация
  163. private static final String PARAM_TMP_NAME = "tmp_name";
  164. // 3. Размер загруженного файла (необходимо выполнить парсинг строки)
  165. private static final String PARAM_SIZE_NAME = "size";
  166. // 4. Тип загруженного документа
  167. private static final String PARAM_CONTENTTYPE_NAME = "content-type";
  168.  
  169. // имя параметра под которым в кофигурационном файле хранятся сведения об том,
  170. // в какую кодировку необходимо установить параметры входящего запроса
  171. private static final String FORCE_SET_ENCODING_URLENCODED_INIT_PARAM_NAME = "force-set-encoding-urlencoded";
  172. private static final String FORCE_SET_ENCODING_MULTIPART_INIT_PARAM_NAME = "force-set-encoding-multipart";
  173. private static final String FORCE_UNIFIED_RESULT_STYLE_INIT_PARAM_NAME = "force-unified-result-style";
  174.  
  175.  
  176.  
  177. private FileItemFactory factory = null;
  178.  
  179. private String forceSetEncodingMultpart = null;
  180. private String forceSetEncodingURLEncoded = null;
  181. private Boolean forceUnifiedResultSetStyle = false;
  182. private FilterConfig config = null;
  183. private File tempDir;
  184. private Integer MAX_SIZE_IN_MEMORY = 2000;
  185.  
  186. // завершение жизненного цикла сервлета - не выполняется никаких действий
  187. public void destroy() {
  188. config.getServletContext().log("--UTF8Maker::destroy--");
  189. }
  190.  
  191. // выполнение фильтрации запроса
  192. public void doFilter(ServletRequest req, ServletResponse resp,
  193. FilterChain chain) throws ServletException, IOException {
  194. // если входящий запрос не Http, то мы не умеем его обрабатывать и пропускаем без изменений
  195. if (!(req instanceof HttpServletRequest)) {
  196. chain.doFilter(req, resp);
  197. return;
  198. }
  199. HttpServletRequest hreq = (HttpServletRequest) req;
  200. // теперь следует узнать то, следует ли нам выполнять обработку такого запроса
  201. boolean isMultipart = ServletFileUpload.isMultipartContent(hreq);
  202. if (isMultipart) {
  203. // устанавливаем значение кодировки
  204. if (forceSetEncodingMultpart != null)
  205. req.setCharacterEncoding(forceSetEncodingMultpart);
  206. else
  207. req.setCharacterEncoding("ISO8859-1");
  208. log("--UTF8Maker::process--: " + hreq.getRequestURI());
  209. // нужно создать обертку над объектом входящего HttpServletRequest,
  210. // в котором переопределить выполняемый парсинг входных данных
  211. UTf8MakerReqiestWrapper req2 = null;
  212. try {
  213. req2 = new UTf8MakerReqiestWrapper((HttpServletRequest) req);
  214. // выполняем обработку запроса как будто ничего не случилось
  215. chain.doFilter(req2, resp);
  216. // теперь нужно подчистить за собой - удалить временные файлы
  217. req2.cleanup();
  218. } catch (Exception e) {
  219. log("--UTF8Maker::exception--: " + e.getMessage());
  220. throw new ServletException(e);
  221. }
  222. } else {
  223. // если обработка не нужна то пропускаем запрос без изменений
  224. if (forceSetEncodingURLEncoded != null)
  225. req.setCharacterEncoding(forceSetEncodingURLEncoded);
  226. log("--UTF8Maker::skip--: " + hreq.getRequestURI());
  227. chain.doFilter(req, resp);
  228. }
  229.  
  230. }//end of --doFilter--
  231.  
  232.  
  233. // инициализация, здесь выполняется создание фабрики парсинга входящих запросов DiskFileItemFactory.
  234. // затем выполняется чтение конфигурационного файла web.xml и установка значений
  235. // для переменных управляющих работой фильтра преобразований
  236. public void init(FilterConfig config) throws ServletException {
  237. this.config = config;
  238. try {
  239. final File tempFile = File.createTempFile("zedzed", "zedzed");
  240. tempDir = tempFile.getParentFile();
  241. tempFile.delete();
  242. factory = new DiskFileItemFactory(MAX_SIZE_IN_MEMORY, tempDir);
  243. } catch (IOException e) {
  244. log("--UTF8Maker::fail init--" + e.getMessage());
  245. throw new ServletException(e);
  246. }
  247. log("--UTF8Maker::init--");
  248. forceSetEncodingMultpart = config.getInitParameter(FORCE_SET_ENCODING_MULTIPART_INIT_PARAM_NAME);
  249. forceSetEncodingURLEncoded = config.getInitParameter(FORCE_SET_ENCODING_URLENCODED_INIT_PARAM_NAME);
  250. forceUnifiedResultSetStyle = Boolean.parseBoolean(config.getInitParameter(FORCE_UNIFIED_RESULT_STYLE_INIT_PARAM_NAME));
  251. log("param (forceSetEncoding) = " + forceSetEncodingMultpart + " / " +
  252. forceSetEncodingURLEncoded + " / "+forceUnifiedResultSetStyle);
  253. }
  254.  
  255. private void log(String s) {
  256. config.getServletContext().log(s);
  257. }
  258.  
  259. }

study-and-dev.com

апплет для загрузки и скачивания файлов

Новости продукта:

JavaPowUpload - это Java апплет, который позволяет как скачивать файлы с сервера, так и загружать их на сервер. Технология Java позволяет получить полный доступ к файловой системе пользователя, что, в свою очередь, позволяет загружать не только файлы , но и целую структуру папок; отображать локальную файловую систему пользователя прямо в апплете на веб странице; сжимать файлы перед отправкой; скачивать множество файлов одним нажатием и многое другое.

Основные примущества:

  • Поддержка различных языков. (Английский, Французский, немецкий и другие Более 30 языков ) Новое в v2.0.5
  • Сжатие файлов перед отправкой на сервер. Новое в v2.1.0
  • Загрузка на сервер сразу нескольких файлов и папок. Демо
  • Скачивание сразу множества файлов и папок  Демо
  • Возможность продолжить скачивание или загрузку на сервер с момента разъединения. Новое в v2.0.3 Демо
  • Загрузка огромных файлов Новое в v2.0.3
  • Предпросмотрт изображений, создание и загрузка на сервер миниатюр  Демо
  • Загрузка файлов напрямую на сервера Amazon S3 (Simple Storage Service) Новое в v2.1.0
View themes sample  Онлайн демо   Screenshots  

JavaPowUpload универсальный иснтрумент

JavaPowUpload может работать на 99% браузеров и сайтов. Он поддерживает все популярные браузеры(IE, Firefox, Opera, Safari, и другие). Большинство из пользователей уже имеют установленную Java (и количество таких пользователей постоянно растет), также JRE может быть автоматически установлена в течение нескольких минут. JavaPowUpload может работать на любой системе, где установлена JRE ( Java Runtime Environment) .JavaPowUpload поддерживает все популярные сервера и скрипты для сохранения файлов: PHP, ASP.NET, Perl и другие.

Кому может пригодиться JavaPowUpload?

JavaPowUpload может быть интегрирован на любой веб сайт и на любую веб страницу. При этом веб мастеру не обязательно быть программистом, чтобы сделать это. И, уж тем более, нет никакой необходимости изучать язык Java. Любой, кто хочет предоставить своим посетителям возможность скачивать и загружать множество файлов и и папок, может использовать JavaPowUpload. При этом вашим пользователям не нужно будет устанавливать какие-либо дополнительные программы (например, менеджеры загрузки или ftp клиенты). Большинство задач, связанных с загрузкой и скачиванием фалов, может быть решено с помощью JavaPowUpload.

Основные функции JavaPowUpload

  • Функции выбора файлов и папок:
    • Выбор нескольких файлов за раз мышкой или с помощью клавиш Ctrl и Shift.
    • Выбор нескольких папок (включая подкаталоги) для зарузки на сервер.
    • Поддержка технологии Drag-n-drop для файлов и папок - можно перетаскивать файлы и папки прямо с рабочего стола.
  • Дополнительные функции:
    • Возобновление загрузки если соединение с сервером было разорвано.
    • Загрузка огромных файлов (10 ГБ проверено).
    • Загрузка файла целиком или частями (chunked).
    • Нет зависимости от ограничений сервера на рзмер запроса (настройки в php.ini, web.config, и т.д.)
  • Функции работы с изображениями:
    • Просмотр изображений в интерфейсе JavaPowUpload.
    • Операции с изображениями: поворот, обрезка, изменение размера.
    • Отправка изображений на сервер, после применения всех операций.
    • Возможность использовать водяной знак.
  • Удобный и настраиваемый интерфейс:
    • Поддержка тем. 45 тем включено.
    • Отображение информации о процессе загрузки файлов.
    • Поддержка различных языков. Английский, Французский, немецкий и другие Более 30 языков
    • Возможность полностью контролировать апплет с помощью JavaScript API. Это позволяет вам использовать ваш собственный интерфейс, основанный на HTML и javaScript и подходящий под дизайн именно вашего сайта.
    • Загрузка и скачивание файлов в одном продукте, с единым стилем.
  • Возможность задать ограничения:
    • Возможность задать ограничения на тип загружаемых файлов, из размер и количество. Например, вы можете разрешить зарзку только изображений.
    • Возможность задать список игнорируемых файлов. Например, запретить загрузку файлов с расширениями exe, com, bat.
    • Диалог выбора файлов может настроен для выбора файлов и папок, только файлов или только папок.
  • Поддержка технологий и стандартов:
    • Для отправки файлов на сервер JavaPowUpload использует стандарт RFC1867.
    • Поддреджка протоколов HTTP, SSL/HTTPS, FTP, FTPS.
    • Поддержка аутентификации (Forms, Basic, Windows ).
    • JavaPowUpload автоматически подхватит и отправит на сервер Cookies , которые доступны для текущей страницы.
    • Поддержка прокси (Proxy) серверов. Настройки прокси (Proxy ) сервера автоматически берутся из системы, при этом пользователь может, хадать их вручную в интерфейсе JavaPowUpload.
Не нашли нужной функциональности? Посмотрите другие продукты: основанный на Flash MultiPowUpload , основанный на Silverlight Ultimate Uploader , ActiveX ActiveXPowUpload.

Требования к серверной части:

  • Любая операционная система и любой веб сервер.
  • Стандартный скрипт, который будет сохранять файлы на сервере. В дистрибутив включены серверные скрипты для платформ: ASP, ASP.NET, PHP, JSP, ColdFusion и Perl.

Требования для пользовательской части:

  • Любая операционная система.
  • Любой браузер.
  • Java Runtime Environment версии > 1.5 (выпущена в 2004 году). Установлена у большинство пользователей.

www.element-it.com

Включение поддержки Java Web Start в IDE NetBeans

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

В этому учебном курсе в качестве примера используется простое приложение на языке Java – "Converter", преобразующее измерения расстояний из метрической системы измерений в систему измерений, принятую в США. Код этого примера доступен для загрузки; возможно, чтобы запустить проект, используя Java Web Start, придется выполнить его настройку. Файлы приложения можно загрузить на любой доступный удаленный веб-сервер.

Изучение материала, представленного в этом учебном курсе, занимает приблизительно 20 минут.

Содержание

Содержимое на этой странице применимо к IDE NetBeans 6.9, 7.0, 7.1, 7.2 и 7.3

Для работы с этим учебным курсом требуются программное обеспечение и материалы, перечисленные в таблице ниже.

Открытие проекта

Откройте приложение Converter в среде IDE. Приложение уже упаковано как проект IDE NetBeans, поэтому пользователю нужно просто открыть проект в среде IDE.

Исходный код демонстрационного примера Converter содержится в учебном курсе Java. Сведения о способах написания этого небольшого приложения приведены в разделе Использование компонентов Swing учебного курса по Java. В данном учебном курсе описана настройка проекта для запуска данного приложения Java в веб-браузере.

  1. Загрузите архивный файл ZIP, содержащий демонстрационное приложение Converter.
  2. Распакуйте его в любую папку на компьютере.
  3. В среде IDE выберите команду "Файл" > "Открыть проект" из главного меню. В окне "Проекты" откроется проект ConverterPrj. Для просмотра исходных файлов разверните узел проекта.

Изображение, показывающее содержимое ConverterPrj.

Настройка проекта для активации Java Web Start

С помощью Java Web Start пользователь может запустить приложение Java, щелкнув HTML-ссылку на файл JNLP этого приложения в веб-браузере. Файл JNLP, являющийся специальным файлом настройки, дает Java Web Start команду на загрузку, кэширование и запуск приложения Java. Для запуска приложений с помощью Java Web Start необходимо наличие установленной совместимой версии Java Runtime Environment (JRE) на клиентской машине. Установка комплекта для разработчика на языке Java (JDK) не требуется.

Для запуска приложения Java совместно с Java Web Start необходимо настроить свойства создания проекта средой IDE. Если Java Web Start активирован в свойствах проекта, среда IDE вместе с файлом JAR автоматически создает файл JNLP и страницу HTML со ссылкой на файл JNLP.

Настройка проекта для активации Java Web Start

В этом упражнении вы выполните настройку проекта для активации Java Web Start и протестируете ее выполнение локально.

  1. Щелкните правой кнопкой мыши узел проекта ConverterPrj и выберите команду "Свойства".
  2. В группе "Categories" выберите "Web Start" и установите флажок "Enable Web Start".
  3. Выберите параметр "Локальное выполнение" из раскрывающегося списка "Кодовая база", поскольку сначала мы выполним приложение локально. В поле "Codebase Preview" отображается путь к локальным файлам приложения.
  4. Нажмите кнопку "Настроить", чтобы открыть диалоговое окно "Подписывание". Выберите параметр Самоподписание сгенерированным ключом. Файл приложения JAR подписывается сертификатом, генерируемым автоматически при создании проекта. Благодаря самоподписанному сертификату приложение сможет получить доступ к тем же ресурсам компьютера, что и обычное приложение, запускаемое локально. Так, самоподписанные сертификаты дают приложению доступ к локальным файлам и сети.
  5. Оставьте флажок "Включить защиту программного обеспечения" в раскрывающемся списке "Смешанный код", затем нажмите кнопку "ОК".
  6. (Дополнительно) В диалоговом окне 'Свойства проекта' выберите панель 'Приложение' и измените название и поставщика приложения.
  7. Нажмите кнопку "ОК" для закрытия диалогового окна "Свойства проекта".

Изображение, показывающее свойства ConverterPrj.

Компиляция и выполнение приложения Java Web Start из среды IDE

Чтобы скомпилировать и запустить приложения для локального тестирования Java Web Start выполните следующие действия:

  1. Выберите узел проекта ConverterPrj в окне ''Проекты', затем выберите 'Выполнить > Выбрать основной проект > ConverterPrj' в главном меню.
  2. Выберите "Выполнить" > "Выполнить основной проект" или нажмите клавишу F6. Среда IDE скомпилирует исходный код, после чего появится экран запуска Java и предупреждение об опасности выполнения неподписанного приложения.

    Предупреждение

  3. Установите флажок, подтверждающий, что вы доверяете содержимому приложения, и нажмите кнопку "Выполнить" в окне предупреждения. Приложение Converter будет запущено.

    Изображение, показывающее приложение Converter.

Просмотр файлов Java Web Start

Перейдем к подробному рассмотрению файлов Java Web Start, созданных средой IDE в процессе сборки (Выполнить > Собрать проект).

Для просмотра файлов откройте окно "Файлы" в среде IDE и разверните папку dist.

Изображение, показывающее файлы, созданные для приложения Converter.

Для Java Web Start были созданы два дополнительных файла:

  • launch.jnlp — файл XML со специальными элементами и атрибутами, указывающий браузеру способы выполнения приложения. JNLP означает Java Network Launching Protocol. Атрибуты файлов JNLP могут включать в себя версию спецификации JNLP, заголовок приложения, имя поставщика, ссылку на файл JAR приложения и т.п.;
  • launch.html — автоматически созданная страница HTML, содержащая ссылку на файл JNLP. Для запуска приложения посредством Java Web Start достаточно щелкнуть эту ссылку. Также этот файл HTML содержит закомментированную ссылку на общедоступный инструментарий Java Deployment Toolkit (deployJava.js), предоставляющий функции JavaScript, позволяющие избежать проблем совместимости. Более подробные сведения по Java Deployment Toolkit приведены по данной ссылке.

    Попробуйте сделать следующее: вне среды IDE перейдите к файлу launch.html, откройте его в браузере и щелкните ссылку, запускающую демонстрационное приложение Converter.

Запуск приложения из удаленного местоположения

После успешного запуска приложения с Java Web Start из локального источника попробуем выгрузить его на удаленный сервер и запустить оттуда.

Примечание. Для развертывания приложений с использованием Java Web Start через Интернет, используемый веб-сервер должен поддерживать обработку файлов JNLP. Веб-сервер должен быть настроен на распознавание файлов JNLP в качестве приложений, т.е. в настройки веб-сервера необходимо добавить тип MIME для JNLP. В противном случае файлы JNLP будут обрабатываться сервером как обычные текстовые файлы. Дополнительные сведения по настройке веб-сервера приведены в Руководстве по Java Web Start.

Изменение файла JNLP

Для запуска приложения из Интернета необходимо включить ссылку на файл исходного кода приложения в Интернете в файл JNLP.

  1. Щелкните правой кнопкой мыши узел проекта ConverterPrj и выберите в группе "Категории" пункт "Web Start".
  2. Выберите в списке "Кодовая база" вариант "Пользовательская".
  3. Введите в поле "Предварительный просмотр базы кода" URL-адрес сервера, на который будут выгружены файлы исходного кода. Например, http://mydomain.com/myuser/converter/.
  4. Нажмите кнопку "ОК" в окне "Свойства проекта".
  5. Щелкните правой кнопкой мыши узел ConverterPrj и выберите "Очистить и построить". Эта команда среды IDE удаляет все ранее скомпилированные файлы и результаты сборки, перекомпилирует приложение и создает файл результатов сборки с текущими настройками.

Выгрузка файлов с исходным кодом

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

  1. Войдите на веб-сервер и перейдите к области загрузки проекта. В этом случае проект называется "IDE NetBeans Documentation Area"
  2. Выгрузите следующие файлы из локальной папки вашего проекта dist в каталог проекта: ConverterPrj.jar, launch.html и launch.jnlp.

    На рисунке ниже показана область загрузок для проекта IDE NetBeans Documentation Area.

    Рисонок, на котором показана область загрузок для проекта документации по IDE NetBeans

  3. Запустите приложение. Введите в окне браузера URL-адрес файла launch.html и перейдите по ссылке "Запустить приложение".

    Приложение Converter будет запущено с помощью Java Web Start.

Заключение

В этом коротком учебном курсе описывается простое создание приложения Java, которое может быть развернуто через Интернет с помощью IDE NetBeans. Это только один из способов развертывания приложений Java.

Дополнительные сведения

Для получения дополнительных сведений о технологиях Java Web Start можно воспользоваться следующими материалами:

  • Руководство по Java Web Start — руководство по использованию технологии Java Web Start;
  • Урок: Java Web Start из учебного курса по Java — практические примеры использования Java Web Start для создания приложений.

netbeans.org


Смотрите также

 

..:::Новинки:::..

Windows Commander 5.11 Свежая версия.

Новая версия
IrfanView 3.75 (рус)

Обновление текстового редактора TextEd, уже 1.75a

System mechanic 3.7f
Новая версия

Обновление плагинов для WC, смотрим :-)

Весь Winamp
Посетите новый сайт.

WinRaR 3.00
Релиз уже здесь

PowerDesk 4.0 free
Просто - напросто сильный upgrade проводника.

..:::Счетчики:::..