关于输出mini版HTML代码的方法

在实际开发中,我们不可避免需要优化输出的内容,使得用户体验优化的效果。

其中,在Web开发当中就有tomcat的gzip来压缩输出流,使得网络带宽压力下降,从而提升浏览器的文件下载速度。这个办法的好处是配置简单,资源较多的情况下效果明显。

但是也有缺点:

1、增加CPU的负担。故此方法不适合CPU资源紧张的服务器。

2、压缩得还不算彻底。
3、需要相应支持的浏览器。

哪怕有上面这些问题,总体上来讲,这个技术还是利大于弊。毕竟CPU便宜过带宽。

为了压缩得更加彻底,我们可以尝试在gzip的基础上,实现一个进一步的代码压缩,把所有jsp、HTML、css、js这些资源文件自动输出成mini版。这样就可以到达进一步压缩的目的。但是会加深CPU、RAM的消耗以及,这个方法是通过自行写代码实现,所以有一定的难度以及可能不够灵活。

具体实现方式是:

1、继承javax.servlet.http.HttpServletResponseWrapper来编写一个Java类。

2、创建一个专门处理资源文件输出的Filter。

3、实现一段处理字符串的逻辑。

4、Filter过滤全部的请求,并且里面要分开各种资源请求的类型来进行不同处理。

5、字符串输出。

继承HttpServletResponseWrapper的Java代码:

import java.io.CharArrayWriter;
import java.io.PrintWriter;

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

public class ResponseWrapper extends HttpServletResponseWrapper {
	private CharArrayWriter out;
	
	public ResponseWrapper(HttpServletResponse response) {
		super(response);
		out = new CharArrayWriter();
	}
	
	public PrintWriter getWriter() {
		return new PrintWriter(out);
	}
	 
	public String toString() {
		return getCharArrayWriter().toString();
	}
	
	public CharArrayWriter getCharArrayWriter() {
		return out;
	}
}

负责过滤请求并返回处理后的信息的Filter以及内部写的一些处理方法:

import java.io.IOException;

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

import org.apache.commons.lang.StringUtils;

import com.winsun.warpper.ResponseWrapper;

/**
 * 专门用于对输出的内容进行格式化
 * 可以起到一定的保密作用,以及优化服务器的流量带宽,但是对服务器CPU、RAM有一定的消耗
 * @author Lph
 * @date 2015年11月27日
 */
public class HTMLFilter implements Filter {
	//用于控制本FIlter的功能是否启动
	private static boolean FILTER_SWITCH = true;

	public void destroy() {
		
	}

	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
		if(FILTER_SWITCH) {
			HttpServletRequest request = (HttpServletRequest)servletRequest;
			HttpServletResponse response = (HttpServletResponse)servletResponse;
			String servletPath = request.getServletPath();
			String url = request.getContextPath() + servletPath;
			if(url.endsWith(".jsp") || url.endsWith(".action")) {
				ServletOutputStream outStream = servletResponse.getOutputStream();
		        ResponseWrapper wrapper = new ResponseWrapper(response);
		        chain.doFilter(request, wrapper);
				String code = wrapper.toString();
		        String[] rows = code.split("\n");
		        StringBuffer codeBuffer = new StringBuffer();
		        String row = null;
		        for(int i = 0 ; i < rows.length; i++) {
		        	row = rows[i];
		        	row = clearTabcharacter(row);
		        	row = clearRowTheNodes(row);
		        	if(StringUtils.isBlank(row) || row.equals("\n")) {
		        		//清除空行
		        		continue;
		        	}
		        	codeBuffer.append(row);
		        }
		        String result = codeBuffer.toString();
		        /*if(url.endsWith("css") || url.endsWith("js") || url.endsWith("map")) {
		        	System.out.println("Output Content:");
		        	System.out.println(result);
		        }*/
		        //result = clearRowsTheNodes(result);
		        outStream.write(result.getBytes("UTF-8"));
				outStream.flush();
				outStream.close();
			} else {
				chain.doFilter(request, response);
			}
		} else {
			chain.doFilter(servletRequest, servletResponse);
		}
	}

	public void init(FilterConfig config) throws ServletException {
		String filterSwitch = config.getInitParameter("FilterSwitch");
		FILTER_SWITCH = StringUtils.isBlank(filterSwitch) || filterSwitch.equals("on");
	}
	
	/**
	 * 清除字符串对象的其实制表符和结束的制表符
	 * @param row
	 * @return
	 */
	public String clearTabcharacter(String row) {
		char[] chars = row.toCharArray();
		int startIndex = -1, endIndex = -1;
		int i = 0;
		for(i = 0; i < chars.length; i++) {
			if(chars[i] == "\t".charAt(0) || chars[i] == " ".charAt(0)) {
				startIndex = i;
			} else {
				break;
			}
		}
		for(i = chars.length - 1; i >= 0; i--) {
			if(chars[i] == "\t".charAt(0) || chars[i] == " ".charAt(0)) {
				endIndex = i;
			} else {
				break;
			}
		}
		if(startIndex < 0) {
			return row;
		} else {
			if(endIndex < 1) {
				endIndex = row.length();
			}
			return row.substring(startIndex + 1, endIndex);
		}
	}
	
	/**
	 * 清除行注释,仅仅是判断"//"
	 * 满足则返回空字符串。否则原样返回
	 * @param row	一行的内容
	 * @return
	 */
	public String clearRowTheNodes(String row) {
		if(row.startsWith("//")) {
			row = "";
		}
		return row;
	}
	
	public String clearRowsTheNodes(String content) {
		StringBuffer code = new StringBuffer();
		char[] chars = content.toCharArray();
		boolean captureStart = false, captrueEnd = false;
		for(int i = 0; i < chars.length; i++) {
			if(i + 1 < chars.length) {
				if(chars[i] == "/".charAt(0) && chars[i + 1] == "*".charAt(0)) {
					captureStart = true;
				}
				if(chars[i] == "*".charAt(0) && chars[i + 1] == "/".charAt(0)) {
					captrueEnd = true;
				}
				if(captureStart == false && captrueEnd == false) {
					code.append(chars[i]);
					captureStart = false;
					captrueEnd = false;
				}
			}
		}
		return code.toString();
	}
}
  • 这里仅仅是举例,没有彻底完成所以并不能完成的mini输出。
  • 目前贴出来的代码仅仅支持jsp。其他资源文件还没处理。
  • 支持JSP内“//”这种行注释的去除。
  • 具体可以达到什么样的效果要看代码的实现。
  • 自动输出迷你版在自动去除注释的情况下可以起到一定的保密作用。
  • 方便更新版本,不需要每次修改文件都生成一次迷你版。
  • 此方法是在jsp编译完毕之后才会进行处理,故jstl\el等情况不需要考虑

相关推荐