JSP去空格

发表于:2018-06-15 12:24:39,已有1360次阅读

在使用JSP动态生成HTML时,由于JSP的标签操作,因此生成的HTML会有很多多余的空行,这样多余的空格会占用一定的网络带宽,同时也使生成的HTML很不美观,那有什么办法可以去除这些空格呢?


1.对于Tomcat 5.5+的可以在Tomcat的安装目录conf/web.xml中配置如下:

<init-param>
     <param-name>trimSpaces</param-name>
     <param-value>true</param-value>
</init-param>


2.JSP 2.1+版本的可以在JSP中使用如下标签:

 <%@ page trimDirectiveWhitespaces="true" %>

另外对于支持Servlet XSD 2.5+,也可以在web程序的WEB-INFO/web.xml中添加如下配置:

<jsp-config>
    <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <trim-directive-whitespaces>true</trim-directive-whitespaces>
    </jsp-property-group>
</jsp-config>

这里好像说是需要Tomcat 6.0+才行,对应查看是否支持Servlet XSD 2.5可以通过查看web-app的声明:

<web-app
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    metadata-complete="false"
    version="2.5">

这里的版本即是。

以上基本可以满足空行去除的需求,如果想进一步去除空格,压缩HTML为一行,则可以通过简单的实现JSP的Filter过滤器,通过自定义实现HttpServletResponse类的Writer类判断每一行字符串去除空格和换行符来实现。如下引用Bauke ScholtzWhitespaceFilter类:

/**
 * net/balusc/webapp/WhitespaceFilter.java
 * 
 * Copyright (C) 2007 BalusC
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program; if
 * not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */
package net.balusc.webapp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 * This filter class removes any whitespace from the response. It actually trims all leading and 
 * trailing spaces or tabs and newlines before writing to the response stream. This will greatly
 * save the network bandwith, but this will make the source of the response more hard to read.
 *
 * @author BalusC
 * @link http://balusc.blogspot.com/2007/12/whitespacefilter.html
 */
public class WhitespaceFilter implements Filter {

    // Constants ----------------------------------------------------------------------------------

    // Specify here where you'd like to start/stop the trimming.
    // You may want to replace this by init-param and initialize in init() instead.
    static final String[] START_TRIM_AFTER = {"<html", "</textarea", "</pre"};
    static final String[] STOP_TRIM_AFTER = {"</html", "<textarea", "<pre"};

    // Actions ------------------------------------------------------------------------------------

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig config) throws ServletException {
        //
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException
    {
        if (response instanceof HttpServletResponse) {
            HttpServletResponse httpres = (HttpServletResponse) response;
            chain.doFilter(request, wrapResponse(httpres, createTrimWriter(httpres)));
        } else {
            chain.doFilter(request, response);
        }
    }

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
        //
    }

    // Utility (may be refactored to public utility class) ----------------------------------------

    /**
     * Create a new PrintWriter for the given HttpServletResponse which trims all whitespace.
     * @param response The involved HttpServletResponse.
     * @return A PrintWriter which trims all whitespace.
     * @throws IOException If something fails at I/O level.
     */
    private static PrintWriter createTrimWriter(final HttpServletResponse response)
        throws IOException
    {
        return new PrintWriter(new OutputStreamWriter(response.getOutputStream(), "UTF-8"), true) {
            private StringBuilder builder = new StringBuilder();
            private boolean surround = false;  // 在特殊标签(不能去换行符)的范围里

            public void write(int c) {
                builder.append((char) c); // It is actually a char, not an int.
            }

            public void write(char[] chars, int offset, int length) {
                builder.append(chars, offset, length);
                this.flush(); // Preflush it.
            }

            public void write(String string, int offset, int length) {
                builder.append(string, offset, length);
                this.flush(); // Preflush it.
            }

            // Finally override the flush method so that it trims whitespace.
            public void flush() {
                synchronized (builder) {
                    String oldContent = builder.toString();
                    BufferedReader reader = new BufferedReader(new StringReader(oldContent));
                    String line = null;
                    StringBuffer  content = new StringBuffer();

                    try {
                        String startTags = join(START_TRIM_AFTER, "|");
                        String regex = join(STOP_TRIM_AFTER, "|") + "|" + join(START_TRIM_AFTER, "|");
                        Pattern pattern = Pattern.compile(regex);
                        while ((line = reader.readLine()) != null) {
                            StringBuffer smallLine = new StringBuffer();
                            Matcher matcher = pattern.matcher(line);
                            int lastIndex = 0;
                            boolean find = false;
                            // 行内去空格
                            while (matcher.find()){
                                find = true;
                                String tag = matcher.group();
                                if(tag.matches(startTags)) {  // 结束标签,前面的部分不能动
                                    smallLine.append(line.substring(lastIndex, matcher.end()));
                                    surround = false;
                                } else {
                                    // 开始标签,前面的部分可以动
                                    if(surround) {
                                        smallLine.append(line.substring(lastIndex, matcher.end()));
                                    } else {
                                        smallLine.append(cleanEmptyChar(line.substring(lastIndex, matcher.end())));
                                    }
                                    surround = true;
                                }
                                lastIndex = matcher.end();
                            }
                            if(find) {
                                if(surround && lastIndex < line.length()) {
                                    smallLine.append(line.substring(lastIndex, line.length())).append("\n");
                                } else if(!surround && lastIndex < line.length()) {
                                    smallLine.append(cleanEmptyChar(line.substring(lastIndex, line.length())));
                                }
                            } else {
                                // 没有找到特别的标签则判断是否在包围里
                                // 没有找到且不在包围里则去空格
                                if(surround) {
                                    smallLine.append(line).append("\n");
                                } else {
                                    smallLine.append(cleanEmptyChar(line));
                                }
                            }
                            content.append(smallLine);
                        }
                        // 由于截取是的部分HTML,可能readline读的本来就没有换行
                        // 故在这里与原内容进行比对,原内容最后没有空格的这里去换行
                        if(!oldContent.endsWith("\n")) {
                            out.write(content.toString().replaceAll("(\n+)$", ""));
                        } else {
                            out.write(content.toString());
                        }
                    } catch (IOException e) {
                        setError();
                        // Log e or do e.printStackTrace() if necessary.
                    }

                    // Reset the local StringBuilder and issue real flush.
                    builder = new StringBuilder();
                    super.flush();
                }
            }

            // 去除HTML标签中无用的行内空格
            private String cleanEmptyChar(String text) {
                return text.replaceAll("^\\s+?<", "<").replaceAll(">(\\s)+?<", "><")
                           .replaceAll(">\\s+?$", ">").replaceAll("(\\s)+", "$1").replaceAll("^\\s$", "");
            }

            private String join(String[] array, String separator) {
                StringBuffer s = new StringBuffer();
                String step = "";
                for (String item : array) {
                    s.append(step).append(item);
                    step = separator;
                }
                return s.toString();
            }
        };
    }

    /**
     * Wrap the given HttpServletResponse with the given PrintWriter.
     * @param response The HttpServletResponse of which the given PrintWriter have to be wrapped in.
     * @param writer The PrintWriter to be wrapped in the given HttpServletResponse.
     * @return The HttpServletResponse with the PrintWriter wrapped in.
     */
    private static HttpServletResponse wrapResponse(
        final HttpServletResponse response, final PrintWriter writer) {
        return new HttpServletResponseWrapper(response) {
            public PrintWriter getWriter() throws IOException {
                return writer;
            }
        };
    }

}
注意:在这里修改了原作者的flush方法,增强了行内去空格的功能,同时修正多余换行符的问题。原方法中的builder.toString()方法返回的是截断了的部分HTML内容,可能最后一行是完整的一行被截断的字符串,它本没有换行符,但由于这里使用了readLine()方法读(读取一行字符返回,但不包含换行符),处理后用println()还原换行符的形式,最后会出现builder.toString()截取的字符最后本无换行符,而被额外添加换行符的BUG。故而这里修改最后对新生成的字符串与原字符串进行比对,原字符最后无换行符的,新字符额外添加换行符的话就去除。使用了该修改后的过滤器后,不再需要额外添加如上web.xml去空格配置,因为该过滤器会自动压缩生成的HTML。

这个类同样也照顾了<textareat><pre>标签,跳过了里面的空格处理,使用的话可以在web.xml中如下配置:

<filter>
    <description>
        This filter class removes any whitespace from the response. It actually trims all
        leading and trailing spaces or tabs and newlines before writing to the response stream.
        This will greatly save the network bandwith, but this will make the source of the
        response more hard to read.
    </description>
    <filter-name>whitespaceFilter</filter-name>
    <filter-class>net.balusc.webapp.WhitespaceFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>whitespaceFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

这个Filter过滤器中对经过HttpServletResponse类的请求处理,对于那些静态CSS、JS、图片文件则不会处理。详情的介绍可以参见作者的博客:http://balusc.omnifaces.org/2007/12/whitespacefilter.html 以上。


相关参见:

http://raibled esigns.com/rd/entry/trim_spaces_in_your_jsp 

http://raibledesigns.com/rd/entry/trim_spaces_in_your_jsp1

https://blog.giantgeek.com/?p=348

http://blog.51cto.com/xuzhiwei/1262766

https://www.javatips.net/blog/remove-whitespace-from-html-jsp-jsf


分享到:

扫一扫,用手机观看!

用微信扫描还可以

分享至好友和朋友圈

二维码分享
评论

暂无评论

您还可输入120个字