Техническое задание на загрузчик файлов для веб-интерфейсов на основе платформы Java и языка Javascript Под загрузчиком файлов понимается интерфейс пользователя, позволяющий открывать диалог выбора файла, осуществлять этот выбор и загружать выбранный файл на сервер. Основные цели использования загрузчика Главным назначением загрузчика является повышение удобства пользовтеля при необходимости отправки больших (до нескольких гигабайт) файлов по сравнению с полем <input type="file">; повышение удобства заключается в следующих аспектах: 1. Возможность асинхронной отправки формы. Другими словами, разделение во времени загрузки файла и отправки остальных полей - чтобы пользователь мог заполнять форму, пока файл уже загружается на сервер. 2. Информирование пользователя о ходе загрузки: какая часть файла загружена, скорость загрузки, оставшееся время и др. 3. Стилизация интерфейса загрузки (необходима для улучшения внешнего вида веб-страниц). 4. Возможность автоматического возобновления загрузки при ошибках соединения. Требования к интерфейсной части 1. Возможность ограничивать тип и размер файлов на клиентской стороне в момент выбора файлов. 2. Поддержка загрузки нескольких файлов. В этом случае одновременно загружается только один файл, остальные ждут. Показатели хода загрузки (какая часть загружена) рассчитываются для текущего файла и для всей очереди. Очередь можно достраивать динамически - пока выбранные файлы загружаются, пользователь может добавить ещё. 3. Возможность выбора нескольких файлов сразу. При открытии диалогового окна выбора файлов можно отметить несколько файлов сразу и начать их загрузку. 4. Возможность отмены загрузки файла (как на этапе загрузки, так и во время ожидания в очереди) и удаления из списка уже загруженных файлов. Основные технические требования 1. Программный код загрузчика должен быть эксклюзивным, то есть написан лично исполнителем для данного проекта; исполнитель должен полностью понимать, как работает код, и нести ответственность за его качество и работоспособность. Адаптация чужого решения возможна лишь при условии полного понимания исполнителем принципов его работы и согласуется дополнительно. 2. Код должен быть минимальным достаточным для выполнения задачи: загрузчик должен быть сделан именно как загрузчик, а не взято что-то, что может быть и загрузчиком – подобная универсальность не нужна. 3. Нагрузка на Java-часть должна быть сведена к минимуму: с помощью Java нужно делать только то, что невозможно с помощью Javascript (в идеальном случае - если такое возможно визуальная составляющая у Java-части практически отсутствует: при инициализации загрузчика генерируется прозрачный объект; он накрывает собой HTML-элемент, к которому привязан загрузчик (как правило это кнопка типа <button>). При генерации объект должен принимать размеры этого элемента - так, чтобы ровно его накрыть и ловить над ним щелчок мыши). Стилизация интерфейса будет проводиться засчет HTML-разметки и не относится к Javaчасти. 5. Планируется интенсивное использование Javascript, в т.ч. библиотеки jQuery. Разработка Javascript-части будет вестись совместно с заказчиком. Фактически, от исполнителя в отношении Javascript требуется просто предоставить набор функций со входными и выходными параметрами. Тонкая настройка функций и доводка интерфейса будут вестись, в основном, силами заказчика. 6. Одним из основных технических требований является как можно большая прозрачность Java-части для javascript-кода. В основном, это касается различных ошибок при загрузке: debug-режим работы загрузчика должен предоставлять детальную информацию о происходящем и о причинах ошибок: например, вывод непосредственно ответов с сервера при отправке файлов и др.. 7. Для каждого загружаемого файла должен генерироваться уникальный идентификатор, не пересекающийся с другими возможными загрузками (например, uuid). При загрузке файлов их идентификаторы записываются в скрытое поле формы с данными (чтобы серверная сторона могла распознать нужные файлы - ведь форма отправляется отдельно). Взаимодействие с серверной стороной Серверная сторона обслуживается nginx. Это предоставляет дополнительные возможности: 1. Возобновление загрузки Для возобновления загрузки от клиентской стороны требуется передать уникальный идентификатор файла и отдавать файл порциями. Последнее должно осуществляться Java-частью. На клиенте файл должен читаться по мере надобности. Подробнее о возобновлении загрузки: http://www.grid.net.ru/nginx/resumable_uploads.en.html (более детально будет обсуждаться непосредственно при работе). 2. Получение от сервера информации о ходе загрузки. Для этого понадобится передача серверу уникального идентификатора загрузки. В ответ сервер будет возвращать строку в формате JSON с информацией о ходе загрузки вида new Object({ 'state' : 'uploading', 'received' : <size_received>, 'size' : <total_size> }) Подробнее см. http://wiki.nginx.org/NginxHttpUploadProgressModule#report_uploads (более детально будет обсуждаться при работе). При отсутствии необходимых инструментов в Javascript реализацию этих возможностей должна взять на себя Java-часть. О структуре Javascript-кода Одной из основных задач исполнителя является составление списка возможных событий Java-части (таких как успешный выбор файла, начало загрузки, ответ с сервера о ходе загрузки, окончание загрузки файла и др.) и предоставление программного интерфейса для обработки этих событий с помощью Javascript - в виде соответствующих функций (прежде всего необходима спецификация входных и выходных параметров и пояснения по сути работы этих функций; конечный вариант их кода будет разрабатываться силами заказчика). При разработке следует планировать использование библиотеки jQuery. Javascript-код загрузчика следует инкапсулировать в отдельный объект. Названия свойств и методов класса согласуются с заказчиком. Привязка загрузчика к элементу на странице должна выглядеть примерно так: <button class="pseudo-file-upload">Загрузить файл</button> <script type="text/javascript"> var uploader = New SHJuploader; // SHJuploader - название для загрузчика uploader.settings = { max_file_size: '600M', file_types: ['avi', 'wmv', 'mp4', 'mpeg'], file_description: 'Видеофайлы', multiple: true, max_queue_size: 10, max_total_size: '3G', button_more_text: 'Загрузить еще', upload_url: '/upload' }; var element = $('button.pseudo-file-upload'); uploader.bind(element); </script> Далее следует набросок части Javascript-кода (один из возможных вариантов). SHJUploader.prototype.bind = function(element) { this.setDefaults(element); // создается прозрачный объект // шириной width и высотой height, // накрывающий собой кнопку // и так далее } SHJUploader.prototype.setDefaults = function(element) { // содрано с загрузчика SWFUpload на основе технологии Flash this.makeDefault('width', $(element).width()); this.makeDefault('height', $(element).height()); this.makeDefault('upload_url', '/upload'); this.makeDefault('max_file_size', '600M'); this.makeDefault('file_types', '*.*'); this.makeDefault('file_description', 'Все файлы'); this.makeDefault('multiple', false); this.makeDefault('max_queue_size', 0); this.makeDefault('max_total_size', '3G'); this.makeDefault('button_more_text', 'Загрузить ещё'); this.makeDefault('debug', false); this.makeDefault('resumable', true); this.makeDefault('resume_on_error', true); } SHJUploader.prototype.makeDefault = function(setting_name, default_value) { if (this.settings[setting_name] == undefined) this.settings[setting_name] = default_value; } /**************************************************** ******* ДАЛЕЕ НАЗНАЧАЮТСЯ ОБРАБОТЧИКИ СОБЫТИЙ ******* *** И ОБЪЯВЛЯЮТСЯ РАЗНООБРАЗНЫЕ СЛУЖЕБНЫЕ ФУНКЦИИ *** ****************************************************/ SHJUploader.protytype.onStart = function(/*[параметры]*/) { }; SHJUploader.protytype.onComplete = function(/*[параметры]*/) { }; // и так далее для всех событий