Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Фильтр сжатия данных


Автор: diablero 27.9.2007, 17:59
Народ, как вы сжимаете конечные html  страницы?
Используете готовые решения, если да, то какие или писали свои фильтры? 
Я сейчас пишу свой такой фильтр, и вот задумался, а стоит ли? Может лутше взять готовый?

Автор: polosatij 27.9.2007, 18:26


не надо ничего писать..
ты под какой сервер пишешь всё? как правило тебе нужно полазить в конфигурациях веб сервера, поставить что-то типа "труе" и всё  smile 

например, в jboss, файл: server.xml (если мне помять не изменяет)  smile 

Автор: Alexis 27.9.2007, 18:42
Можно и написать. Где-то давно уже стащил, вроде бы из какой-то книги, так и пользуюсь.

Код

package com.domain.filters;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class GZIPFilter implements Filter {
    
    protected static final Log logger = LogFactory.getLog(GZIPFilter.class);

    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {
          if (req instanceof HttpServletRequest) {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
            String ae = request.getHeader("accept-encoding");
            if (ae != null && ae.indexOf("gzip") != -1) {
              logger.debug("GZIP supported, compressing.");
              GZIPResponseWrapper wrappedResponse =
                new GZIPResponseWrapper(response);
              chain.doFilter(req, wrappedResponse);
              wrappedResponse.finishResponse();
              return;
            }
            chain.doFilter(req, res);
          }
        }

        public void init(FilterConfig filterConfig) {
          // noop
        }

        public void destroy() {
          // noop
        }

}


Код

package com.domain.filters;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

public class GZIPResponseStream extends ServletOutputStream {

    // abstraction of the output stream used for compression
    protected OutputStream bufferedOutput = null;

    // state keeping variable for if close() has been called
    protected boolean closed = false;

    // reference to original response
    protected HttpServletResponse response = null;

    // reference to the output stream to the client's browser
    protected ServletOutputStream output = null;

    // default size of the in-memory buffer
    private int bufferSize = 50000;

    public GZIPResponseStream(HttpServletResponse response) throws IOException {
        super();
        closed = false;
        this.response = response;
        this.output = response.getOutputStream();
        bufferedOutput = new ByteArrayOutputStream();
    }

    public void close() throws IOException {
        // This hack shouldn't be needed, but it seems to make JBoss and Struts
        // like the code more without hurting anything.
        /*
         * // verify the stream is yet to be closed if (closed) { throw new
         * IOException("This output stream has already been closed"); }
         */
        // if we buffered everything in memory, gzip it
        if (bufferedOutput instanceof ByteArrayOutputStream) {
            // get the content
            ByteArrayOutputStream baos = (ByteArrayOutputStream) bufferedOutput;
            // prepare a gzip stream
            ByteArrayOutputStream compressedContent = new ByteArrayOutputStream();
            GZIPOutputStream gzipstream = new GZIPOutputStream(
                    compressedContent);
            byte[] bytes = baos.toByteArray();
            gzipstream.write(bytes);
            gzipstream.finish();
            // get the compressed content
            byte[] compressedBytes = compressedContent.toByteArray();
            // set appropriate HTTP headers
            response.setContentLength(compressedBytes.length);
            response.addHeader("Content-Encoding", "gzip");
            output.write(compressedBytes);
            output.flush();
            output.close();
            closed = true;
        }
        // if things were not buffered in memory, finish the GZIP stream and
        // response
        else if (bufferedOutput instanceof GZIPOutputStream) {
            // cast to appropriate type
            GZIPOutputStream gzipstream = (GZIPOutputStream) bufferedOutput;
            // finish the compression
            gzipstream.finish();
            // finish the response
            output.flush();
            output.close();
            closed = true;
        }
    }

    public void flush() throws IOException {
        if (closed) {
            throw new IOException("Cannot flush a closed output stream");
        }
        bufferedOutput.flush();
    }

    public void write(int b) throws IOException {
        if (closed) {
            throw new IOException("Cannot write to a closed output stream");
        }
        // make sure we aren't over the buffer's limit
        checkBufferSize(1);
        // write the byte to the temporary output
        bufferedOutput.write((byte) b);
    }

    private void checkBufferSize(int length) throws IOException {
        // check if we are buffering too large of a file
        if (bufferedOutput instanceof ByteArrayOutputStream) {
            ByteArrayOutputStream baos = (ByteArrayOutputStream) bufferedOutput;
            if (baos.size() + length > bufferSize) {
                // files too large to keep in memory are sent to the client
                // without Content-Length specified
                response.addHeader("Content-Encoding", "gzip");
                // get existing bytes
                byte[] bytes = baos.toByteArray();
                // make new gzip stream using the response output stream
                GZIPOutputStream gzipstream = new GZIPOutputStream(output);
                gzipstream.write(bytes);
                // we are no longer buffering, send content via gzipstream
                bufferedOutput = gzipstream;
            }
        }
    }

    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }

    public void write(byte b[], int off, int len) throws IOException {
        if (closed) {
            throw new IOException("Cannot write to a closed output stream");
        }
        // make sure we aren't over the buffer's limit
        checkBufferSize(len);
        // write the content to the buffer
        bufferedOutput.write(b, off, len);
    }

    public boolean closed() {
        return (this.closed);
    }

    public void reset() {
        // noop
    }

}


Код

package com.domain.filters;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class GZIPResponseWrapper extends HttpServletResponseWrapper {

    protected HttpServletResponse origResponse = null;

    protected ServletOutputStream stream = null;

    protected PrintWriter writer = null;

    public GZIPResponseWrapper(HttpServletResponse response) {
        super(response);
        origResponse = response;
    }

    public ServletOutputStream createOutputStream() throws IOException {
        return (new GZIPResponseStream(origResponse));
    }

    public void finishResponse() {
        try {
            if (writer != null) {
                writer.close();
            } else {
                if (stream != null) {
                    stream.close();
                }
            }
        } catch (IOException e) {
        }
    }

    public void flushBuffer() throws IOException {
        stream.flush();
    }

    public ServletOutputStream getOutputStream() throws IOException {
        if (writer != null) {
            throw new IllegalStateException(
                    "getWriter() has already been called!");
        }

        if (stream == null)
            stream = createOutputStream();
        return (stream);
    }

    public PrintWriter getWriter() throws IOException {
        if (writer != null) {
            return (writer);
        }

        if (stream != null) {
            throw new IllegalStateException(
                    "getOutputStream() has already been called!");
        }

        stream = createOutputStream();
        // BUG FIX 2003-12-01 Reuse content's encoding, don't assume UTF-8
        writer = new PrintWriter(new OutputStreamWriter(stream, origResponse
                .getCharacterEncoding()));
        return (writer);
    }

    public void setContentLength(int length) {
    }

}


В web.xml
Код

<filter>
        <filter-name>GZIPFilter</filter-name>
        <filter-class>com.domain.filters.GZIPFilter</filter-class>
</filter>
<filter-mapping>
        <filter-name>GZIPFilter</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>


Теоретически должно работать на любом сервере. У меня работает и на Tomcat 5.5 и на Resin 3.0

Автор: polosatij 27.9.2007, 18:49

Alexis, не наю.. чисто моё мнение, что это всё ООООЧЕНЬ сильно будет загружать систему... smile

Автор: diablero 27.9.2007, 18:51
Цитата(polosatij @  27.9.2007,  18:26 Найти цитируемый пост)
ты под какой сервер пишешь всё? как правило тебе нужно полазить в конфигурациях веб сервера, поставить что-то типа "труе" и всё

До server.xml не всегда есть доступ.
Нашел почти тоже самое http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html
Только мне кажется, что как-то кривовато, разбираюсь и правлюsmile

Автор: diablero 27.9.2007, 20:24
Вот если бы еще знающий человек покритиковал код...
Вот код из статьи, которую я привел выше. Практически тоже самое, что привел и Alexis. Малость исправленный:
Код

public class GZIPFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if (servletRequest instanceof HttpServletRequest) {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            if (isGzipSupported(request)) {
                GZIPResponseWrapper wrappedResponse = new GZIPResponseWrapper(response);
                filterChain.doFilter(servletRequest, wrappedResponse);
                wrappedResponse.finishResponse();
                return;
            }
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
    public void destroy() {

    }
    private boolean isGzipSupported(HttpServletRequest request) {
        String browserEncodings = request.getHeader("Accept-Encoding");
        return ((browserEncodings != null) && (browserEncodings.indexOf("gzip") != -1));
    }
}

Код

public class GZIPResponseStream extends ServletOutputStream {
    protected ByteArrayOutputStream baos;
    protected GZIPOutputStream gzipstream;
    protected HttpServletResponse response;
    protected boolean closed = false;

    public GZIPResponseStream(HttpServletResponse response) throws IOException {
        super();
        closed = false;
        this.response = response;
        baos = new ByteArrayOutputStream();
        gzipstream = new GZIPOutputStream(baos);
    }

    public void close() throws IOException {
        if (closed) {
            throw new IOException("This output stream has already been closed");
        }
        gzipstream.finish();

        byte[] bytes = baos.toByteArray();

        response.setContentLength(bytes.length);
        response.addHeader("Content-Encoding", "gzip");
        
        ServletOutputStream output = response.getOutputStream();
        output.write(bytes);
        output.flush();
        output.close();
        closed = true;
    }

    public void flush() throws IOException {
        if (closed) {
            throw new IOException("Cannot flush a closed output stream");
        }
        gzipstream.flush();
    }

    public void write(int b) throws IOException {
        if (closed) {
            throw new IOException("Cannot write to a closed output stream");
        }
        gzipstream.write((byte) b);
    }

    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }

    public void write(byte b[], int off, int len) throws IOException {
        if (closed) {
            throw new IOException("Cannot write to a closed output stream");
        }
        gzipstream.write(b, off, len);
    }

    public boolean closed() {
        return (this.closed);
    }
}

Код

public class GZIPResponseWrapper extends HttpServletResponseWrapper {
    protected HttpServletResponse httpServletResponse;
    protected ServletOutputStream outputStream;
    protected PrintWriter writer;

    public GZIPResponseWrapper(HttpServletResponse httpServletResponse) {
        super(httpServletResponse);
        this.httpServletResponse = httpServletResponse;
    }

    public ServletOutputStream createOutputStream() throws IOException {
        return (new GZIPResponseStream(httpServletResponse));
    }

    public void finishResponse() throws IOException {
        if (writer != null) writer.close();
        if (outputStream != null) outputStream.close();
    }

    public void flushBuffer() throws IOException {
        outputStream.flush();
    }

    public ServletOutputStream getOutputStream() throws IOException {
        if (writer != null) {
            throw new IllegalStateException("getWriter() has already been called!");
        }
        if (outputStream == null) {
            outputStream = createOutputStream();
        }
        return outputStream;
    }

    public PrintWriter getWriter() throws IOException {
        if (outputStream != null) {
            throw new IllegalStateException("getOutputStream() has already been called!");
        }
        if (writer != null) {
            return writer;
        }
        outputStream = createOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(outputStream, httpServletResponse.getCharacterEncoding()));
        return writer;
    }
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)