Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Хранение ресурсов web-приложения в jar'e, Хотелось бы запаковать картинки и css 
:(
    Опции темы
Maksym
  Дата 11.2.2007, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


.
***


Профиль
Группа: Участник Клуба
Сообщений: 1456
Регистрация: 19.8.2005
Где: Odessa, Black Sea

Репутация: 24
Всего: 62



Собственно, сабж.
Хочется запаковать все ресурсы web-приложения в jar и положить этот jar в dependencies нескольких проектов с одинаковой идеей интерфейса.
Подскажите, пожалуйста, можно ли в jsp сослаться на css или изображение, спрятанное в jar'e, и если можно то как?
ЗЫ.
Используется ли такая практика? или, может быть, есть другие приемы хранения и предоставления в web-интерфейсы общих ресурсов?
PM MAIL   Вверх
MisterCleric
Дата 12.2.2007, 13:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1043
Регистрация: 16.2.2006
Где: Харьков, Украина

Репутация: 33
Всего: 38



Собственно можно. Как универсально сделать не подскажу. Но покажу пример. 
Я использую webwork. В его jar'e запакован FCKeditor он лежит по таком пути: webwork-2.2.2.jar\com\opensymphony\webwork\static\richtexteditor\

на странице к его js & css обращаюсь так:
 <script language="JavaScript" type="text/javascript"
        src="<%=request.getContextPath()%>/webwork/richtexteditor/fckeditor.js"></script>

Как я понимаю путь ищеться от: 
<filter>
        <filter-name>webwork</filter-name>
        <filter-class>com.opensymphony.webwork.dispatcher.FilterDispatcher</filter-class>
</filter>

В общем и все. Других вариантов не пробовал. И как-то мысли даже не было. 
Пробуй


--------------------
ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ...
PM MAIL ICQ   Вверх
Maksym
Дата 12.2.2007, 14:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


.
***


Профиль
Группа: Участник Клуба
Сообщений: 1456
Регистрация: 19.8.2005
Где: Odessa, Black Sea

Репутация: 24
Всего: 62



MisterCleric
Большое спасибо. Формат не очень нравится (<%=request.getContextPath()%>/webwork/richtexteditor/fckeditor.js>), но конечно попробую.
All
Нет ли еще идей? 
(честно говоря я рассчитывал на прямой путь, заложенный в технологию, а не на трюк)
PM MAIL   Вверх
Stampede
Дата 12.2.2007, 15:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 66
Всего: 144



Maksym, идея как бы понятна: распространять модуль в виде бинарника, в котором уже запакованы все элементы его вебного интерфейса. Подтыкнул к проекту - и сразу пользуйся.

Может, и не лишено смысла. Реализовать тоже можно, и даже не особенно трудно. Щас раскажу как. Мне видятся два пути. Оба связаны с написанием кастомного сервлета.

1. Сервлет, выдающий содержимое архива.

Напишем сервлет, который, скажем, по адресу "/archive/yourfile.jar/img/button.gif" понимает, что нужно пойти в стандартную папку WEB-INF/lib, найти там yourfile.jar, открыть его как архив, прочитать содержимое файла img/button.gif и выдать его в поток вывода.

2. Сервлет, выдающий ресурсы

Здесь предлагается написать сервлет, который использует метод Class.getResourceAsStream(String path). Опять-таки, надо продумать шаблон пути, который будет однозначно мапиться на даный сервлет, и часть которого будет указывать на путь внутри архива. Для все того же файла кнопки в yourfile.jar УРЛ мог бы выглядеть так: "/resources/img/buton.gif".

Теперь сравним варианты. Второй быстрее в реализации, поскольку поиск и разрешение пути к ресурсу за тебя сделает система, используя стандартный механизм лукапа загрузчиками классов. Кроме того, УРЛ'ы при этом получаются компактными, и в них не надо явно прописывать имя архива.

С другой стороны, первый сервлет может быть более универсальным, так как теоретически мы могли бы запрограммировать его таким образом, чтобы он доставал нам статику из любого архива, который мы укажем - и не обязательно лежащего на classpath. А уж как это указать - это целиком дело фантазии разработчиков. Можно задавать через параметры инициализации сервлета, можно через собственную конфигурацию, можно через часть УРЛ, а можно все вместе.

Так что дерзай. Интересно будет услышать, что и как получается.





--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Maksym
Дата 12.2.2007, 17:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


.
***


Профиль
Группа: Участник Клуба
Сообщений: 1456
Регистрация: 19.8.2005
Где: Odessa, Black Sea

Репутация: 24
Всего: 62



Stampede
Спасибо. Первый вариант кажется более интересным с точки зрения масштабируемости и реиспользования.
Удивляет отсутствие готовых решений.
PM MAIL   Вверх
Maksym
  Дата 19.2.2007, 17:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


.
***


Профиль
Группа: Участник Клуба
Сообщений: 1456
Регистрация: 19.8.2005
Где: Odessa, Black Sea

Репутация: 24
Всего: 62



Выкроил время и написал коротенькое решение. Работает. Прошу о code-review.

Код

package test.framework.ui.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class ResourcesStorageServlet extends HttpServlet {
    
    private static String RESOURCES_LOCATION = "/test/framework/ui/resources";
    
    public void init() throws ServletException {
        // TODO Initialization actions        
    }
    
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        InputStream is = ResourcesStorageServlet.class.getResourceAsStream(RESOURCES_LOCATION + request.getPathInfo());
        
        if (is != null) {
            try {
                OutputStream os = response.getOutputStream();
                
                int _byte = is.read(); 
                while (_byte != -1) {
                    os.write(_byte);
                    _byte = is.read();            
                }
                
                os.flush();        
                os.close();
                is.close();
            } catch (IOException exc) {
//                TODO IOException processing
            }
        } else {
//             TODO MissingResource processing
        }
        
        super.doGet(request, response);
    }
}


В пакет test.framework.ui.resources.img кладутся все общие изображения, в test.framework.ui.resources.css -- общие стили и т.п.

Все это запаковывается в framework.jar (в Eclipse удобно создать для этих целей Utility Project и подключать его к зависимым приложениям), который подключается в j2ee dependencies тех web-приложений, которые будут использовать эти ресурсы.
В web.xml этих приложений не забываем указать:
Код

...
    <servlet>
        <servlet-name>Resources Storage Servlet</servlet-name>
        <servlet-class>test.framework.ui.utils.ResourcesStorageServlet</servlet-class>
        <load-on-startup>1</load-on-startup>        
    </servlet>    
    <servlet-mapping>
        <servlet-name>Resources Storage Servlet</servlet-name>
        <url-pattern>/allresources/*</url-pattern>
    </servlet-mapping>
...


И после этого в проектах запросто можно пользоваться общими ресурсам:
Код

...
<img src="allresources/img/logo.gif" width="200" height="60" border="0" />
...



Это сообщение отредактировал(а) Maksym - 19.2.2007, 18:27
PM MAIL   Вверх
Tony
Дата 19.2.2007, 18:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1159
Регистрация: 3.3.2006
Где: Riga

Репутация: 6
Всего: 12



Код

        InputStream input = this.getClass().getResourceAsStream("");
        OutputStream out = response.getOutputStream();
        byte buffer [] = new byte [4096];
        int size = 0 ;
        while ((size = input.read(buffer))!=-1)
            out.write(buffer, 0, size);


A ещё можно 4ерз NIO.


--------------------
user posted image
user posted image
PM MAIL Skype   Вверх
Maksym
Дата 19.2.2007, 18:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


.
***


Профиль
Группа: Участник Клуба
Сообщений: 1456
Регистрация: 19.8.2005
Где: Odessa, Black Sea

Репутация: 24
Всего: 62



Tony
Спасибо. С буфером, конечно, будет быстрее. А что даст использование nio?

Добавлено @ 18:51 
Размер буфера 4096 чем подсказан? исходя из чего его стоит вычислять?
PM MAIL   Вверх
Tony
Дата 19.2.2007, 20:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1159
Регистрация: 3.3.2006
Где: Riga

Репутация: 6
Всего: 12



NIO (new IO) побыстрее работает с input/output, чем класси4еская модель in/out.
Код

Размер буфера 4096 чем подсказан? исходя из чего его стоит вычислять?

Зависит от коли4ества запросов к ресурсу. Если мало запросов и маленкие файлики(цсс,иконки...) то можно сразу весь файл загрузить в массив и выдать его, не исползуя for (как в примере выше).
Нас4ёт NIO.(вариант 2)
Код

        ReadableByteChannel in = Channels.newChannel(this.getClass().getResourceAsStream(""));
        WritableByteChannel out = Channels.newChannel(response.getOutputStream());
                ByteBuffer buffer = ByteBuffer.allocate(4096); 
        while (in.read(buffer)!=-1){
            out.write(buffer);
            buffer.flip();
         }
        in.close();

 

Это сообщение отредактировал(а) Tony - 19.2.2007, 20:47


--------------------
user posted image
user posted image
PM MAIL Skype   Вверх
Maksym
Дата 19.2.2007, 22:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


.
***


Профиль
Группа: Участник Клуба
Сообщений: 1456
Регистрация: 19.8.2005
Где: Odessa, Black Sea

Репутация: 24
Всего: 62



Tony
Apache IO API предлагает сделать все вызовом одного метода -- IOUtils.copy(InputStream input, OutputStream output) (вариант 3)
Какой способ эффективнее? Все таки речь идет о многократно повторяющейся операции smile 
PM MAIL   Вверх
Tony
Дата 19.2.2007, 23:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1159
Регистрация: 3.3.2006
Где: Riga

Репутация: 6
Всего: 12



Да знаю 4то есть у Jakarti. Если ты хо4ешь ложить либу ради одного метода флаг в руки. Нас4ёт производительности надо сорсы смотреть. Сорри нету времени(завтра).


--------------------
user posted image
user posted image
PM MAIL Skype   Вверх
Maksym
  Дата 24.2.2007, 16:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


.
***


Профиль
Группа: Участник Клуба
Сообщений: 1456
Регистрация: 19.8.2005
Где: Odessa, Black Sea

Репутация: 24
Всего: 62



Tony
Исходник org.apache.commons.io.IOUtils.copy(InputStream input, OutputStream output):
Код

    /**
     * The default buffer size to use.
     */
    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;

   /**
     * Copy bytes from an <code>InputStream</code> to an
     * <code>OutputStream</code>.
     * <p>
     * This method buffers the input internally, so there is no need to use a
     * <code>BufferedInputStream</code>.
     * <p>
     * Large streams (over 2GB) will return a bytes copied value of
     * <code>-1</code> after the copy has completed since the correct
     * number of bytes cannot be returned as an int. For large streams
     * use the <code>copyLarge(InputStream, OutputStream)</code> method.
     * 
     * @param input  the <code>InputStream</code> to read from
     * @param output  the <code>OutputStream</code> to write to
     * @return the number of bytes copied
     * @throws NullPointerException if the input or output is null
     * @throws IOException if an I/O error occurs
     * @throws ArithmeticException if the byte count is too large
     * @since Commons IO 1.1
     */
    public static int copy(InputStream input, OutputStream output) throws IOException {
        long count = copyLarge(input, output);
        if (count > Integer.MAX_VALUE) {
            return -1;
        }
        return (int) count;
    }

    /**
     * Copy bytes from a large (over 2GB) <code>InputStream</code> to an
     * <code>OutputStream</code>.
     * <p>
     * This method buffers the input internally, so there is no need to use a
     * <code>BufferedInputStream</code>.
     * 
     * @param input  the <code>InputStream</code> to read from
     * @param output  the <code>OutputStream</code> to write to
     * @return the number of bytes copied
     * @throws NullPointerException if the input or output is null
     * @throws IOException if an I/O error occurs
     * @since Commons IO 1.3
     */
    public static long copyLarge(InputStream input, OutputStream output)
            throws IOException {
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        long count = 0;
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
            count += n;
        }
        return count;
    }

Разницы с твоим вариантом для io, кажется, нет. Дополнительно вычисляется никому не нужный count (the number of bytes copied) и все.

All
Не работал с nio. Действительно ли его предпочтительнее изпользовать в подобных ситуациях? В чем заключается его оптимизация по сравнению со стандартной моделью?
PM MAIL   Вверх
Tony
Дата 24.2.2007, 20:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1159
Регистрация: 3.3.2006
Где: Riga

Репутация: 6
Всего: 12



Код

Не работал с nio. Действительно ли его предпочтительнее изпользовать в подобных ситуациях? В чем заключается его оптимизация по сравнению со стандартной моделью?

Полно имфы (и на русском языке).
statja


--------------------
user posted image
user posted image
PM MAIL Skype   Вверх
Maksym
  Дата 20.3.2007, 20:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


.
***


Профиль
Группа: Участник Клуба
Сообщений: 1456
Регистрация: 19.8.2005
Где: Odessa, Black Sea

Репутация: 24
Всего: 62



Окончательный вариант (на данный момент). Используется в серии проектов с большим количеством общих ресурсов. Пока проблем не было.
Код

package test.framework.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ResourcesStorageServlet extends HttpServlet {

    private static final String RESOURCES_LOCATION = "/test/framework/ui/resources";
    private static final String SERVLET_PARAM_NAME_BUFFER_SIZE = "buffer_size";

    private int bufferSize = 1024;

    public void init() throws ServletException {
        String bufferSizeStr = getServletConfig().getInitParameter(SERVLET_PARAM_NAME_BUFFER_SIZE);
        if (bufferSizeStr != null) {
            try {
                bufferSize = Integer.parseInt(bufferSizeStr);
            } catch (NumberFormatException exp) {
                UILogger.log().warn("Buffer_size param can't be read from servlet parameter. Default is using.");
            }
        }
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String requestPath = request.getRequestURI().replaceAll(request.getContextPath(), "");

        InputStream is = ResourcesStorageServlet.class.getResourceAsStream(RESOURCES_LOCATION + requestPath);

        if (is != null) {
            try {

                OutputStream os = response.getOutputStream();
                byte buffer[] = new byte[bufferSize];
                int size = 0;
                while ((size = is.read(buffer)) != -1)
                    os.write(buffer, 0, size);
                os.flush();
                os.close();
                is.close();

            } catch (IOException exc) {
                UILogger.log().warn("IOException during resource (reading from file)/(sending to response).", exc);
            }
        } else {
            UILogger.log().warn("Missing resource: " + requestPath);
        }

        super.doGet(request, response);
    }
}
 
Размер буфера параметризуется в зависимости от приложения. Для логирования используется внешний класс UILogger (helper для использования log4j).
Интересно, что реалзиация через nio не заработала... Код молча отработал и в response все ушло, но к пользователю ничего не попало...  smile 
PM MAIL   Вверх
Tony
Дата 22.3.2007, 17:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1159
Регистрация: 3.3.2006
Где: Riga

Репутация: 6
Всего: 12



Код

Интересно, что реалзиация через nio не заработала... Код молча отработал и в response все ушло, но к пользователю ничего не попало...  

Вот это интерсно


--------------------
user posted image
user posted image
PM MAIL Skype   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.1727 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.