首页 > 代码库 > 「Java Web」主页静态化的实现

「Java Web」主页静态化的实现

一个网站的主页一般不会频繁变动,而大多数用户在访问网站时仅仅是浏览一下主页(未登陆),然后就离开了。对于这类访问请求,如果每次都要通过查询数据库来显示主页的话,显然会给服务器带来多余的压力。这时候我们可以将主页静态化,在减轻数据库服务器压力的同时又能大大提高主页高访问速度。


对于Java来说,现在有很多框架可是实现主页的静态化。其实这并不难,我们也可以自己手动实现。思路如下:

首先编写一个小程序模拟浏览器向web服务器发送GET请求,得到主页的HTML代码后,将其保存到文件中。然后写一个过滤器拦截访问请求,一旦发现访问的是主页,那么就直接将保存好的静态HTML文件返回给客户端。这样就避开了框架(如 Spring MVC),更避开了数据库查询。如果主页内容发生了变化,我们可以再运行一下小程序以得到最新的主页HTML代码。


编写HTTP客户端程序模拟浏览器

这里我使用 apache 的 HttpClient 库编写这个小程序。如下例,我们通过向 http://locahost:8080/codeschool/ 发送GET请求来得到服务器返回的HTML代码:
/**
 * 向localhost:8080发送GET请求,获取返回的HTML代码并保存到文件中
 * @author whf
 *
 */
public class Client {

	public static void main(String[] args) throws Exception {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		try {
			HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/codeschool");
			CloseableHttpResponse response = httpclient.execute(httpGet);
			try {
				System.out.println(response.getStatusLine());
				HttpEntity entity = response.getEntity();
				
				// entity封装了服务器返回的数据
				String html =  EntityUtils.toString(entity);
				// 将HTML代码写入到文件中
				saveContent(html, "/home/whf/workspace-sts/codeschool/home.html");
				
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}

		} finally {
			httpclient.close();
		}
	}
	
	/**
	 * 将HTML写入到指定文件中
	 * 
	 * @param html
	 * @param path 文件路径
	 * @throws IOException
	 */
	private static void saveContent(String html, String path) throws IOException {
		FileOutputStream fos = new FileOutputStream(path);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		bos.write(html.getBytes());
		bos.close();
	}

}

所需的 dependency 如下:
<dependencies>
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
			<version>4.3.4</version>
		</dependency>
		
	</dependencies>

执行一下该程序,就会得到 home.html 文件。

编写过滤器

编写一个 url-pattern 为 /* 的 Filter 过滤器,一旦发现用户访问的是主页,则直接返回上面生成的 home.html 文件,关闭输出流。代码如下:
public class SecureFilter implements Filter {
	private static final Logger logger = LoggerFactory
			.getLogger(SecureFilter.class);
	private ServletContext ctx;

	@Override
	public void destroy() {

	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {

		// 防止中文乱码
		request.setCharacterEncoding("UTF-8");

		HttpServletRequest req = (HttpServletRequest) request;
		String path = req.getRequestURI();

		// 请求的是资源,跳过
		if (true == path.startsWith("/codeschool/resources")) {
			chain.doFilter(request, response);
			return;
		}

		// 用户未登陆
		// 用户访问主页
		// 返回静态页面
		if (path.equals("/codeschool/") || path.equals("/")) {
			writeStaticHomePage(req, (HttpServletResponse) response);
			return;
		}

		chain.doFilter(request, response);
	}

	/**
	 * 将静态主页返回给客户端
	 * 
	 * @param req
	 * @param resp
	 * @throws IOException
	 */
	private void writeStaticHomePage(HttpServletRequest req,
			HttpServletResponse resp) throws IOException {
		// 返回静态化页面
		// 得到home.html路径
		String pagePath = (String) ctx.getInitParameter("HOME_PAGE_PATH");

		if (logger.isDebugEnabled()) {
			logger.debug("主页静态页面路径:{}", pagePath);
		}

		// 将homt.html返回给客户端
		ServletOutputStream out = resp.getOutputStream();

		FileInputStream pageInStream = new FileInputStream(pagePath);
		BufferedInputStream bufInStream = new BufferedInputStream(pageInStream);
		byte[] buf = new byte[2048];
		int len = 0;
		while ((len = bufInStream.read(buf)) != -1) {
			out.write(buf, 0, len);
		}
		bufInStream.close();

		out.close();
	}

	@Override
	public void init(FilterConfig cfg) throws ServletException {
		this.ctx = cfg.getServletContext();
	}

}

可以在web.xml里配置 home.html 的路径:
<!-- 静态主页的路径 -->
	<context-param>
		<param-name>HOME_PAGE_PATH</param-name>
		<param-value>/home/whf/workspace-sts/codeschool/home.html</param-value>
	</context-param>


这样在我们在访问主页的时候就能明显感觉到速度大大加快。