web.xmlhtml
<!-- jsp轉成html過濾器 --> <filter> <filter-name>stateHtmlFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>stateHtmlFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>stateHtmlFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
package cn.com.czw.front.filter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.List; import java.util.Set; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import redis.clients.jedis.Jedis; import cn.com.czw.front.utils.DateUtils; import cn.com.czw.front.utils.RequestUtils; import cn.com.czw.front.utils.StreamCharArrayWrapper; import cn.com.czw.front.utils.Tools; import com.google.common.collect.Lists; @Component public class StateHtmlFilter extends OncePerRequestFilter { private static Logger logger = LoggerFactory.getLogger(StateHtmlFilter.class); /** 是否已初始化 */ private boolean isExternalUrlsInit = false; /** 排除不過濾的連接 */ private String externalUrlsString = ".*/druid/.*,.*/manage/.*,.*/static/.*,.*/attachs/.*,.*/assets/.*,/user/.*; /** 認證要排除的url列表 */ private List<String> externalUrls; /** * 操做redis客戶端 */ private static Jedis jedis; @Autowired private JedisConnectionFactory jedisConnectionFactory; protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { // 請求的uri String uri = request.getRequestURI(); // 若是是json請求直接繞過 if (StringUtils.endsWith(uri,".json")) { chain.doFilter(request, response); return; } // String url = request.getRequestURL().toString(); request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); // 查看文件是否存在 String method = "GET"; method = request.getMethod(); String queryString = request.getQueryString(); if ("POST".equalsIgnoreCase(method)) { // 若是是POST請求直接繞過 chain.doFilter(request, response); return; } if (StringUtils.isBlank(queryString)) { queryString = ""; } else { queryString = StringUtils.remove(queryString, "clear=1"); queryString = StringUtils.remove(queryString, "&clear=1"); } String fileName = request.getRequestURL().toString().replaceAll(":", "").replaceAll("/", "#") + queryString; String html = get(fileName); logger.info("訪問:" + uri + "---" + fileName); /** * 判斷文件是否存在 或者是否清除緩存 */ HttpServletResponse httpRes = (HttpServletResponse) response; httpRes.setHeader("Content-Encoding", "text/html;charset=UTF-8"); /** * 設置緩存 * */ response.setContentType("text/html"); // servlet頁面默認是不緩存的 // 本頁面容許在瀏覽器端或緩存服務器中緩存,時限爲60秒。 // 60秒以內從新進入該頁面的話不會進入該servlet的 java.util.Date date = new java.util.Date(); response.setDateHeader("Last-Modified", date.getTime()); // Last-Modified:頁面的最後生成時間 response.setDateHeader("Expires", date.getTime() + 1000 * 60); // Expires:過期期限值 response.setHeader("Cache-Control", "max-age=20,must-revalidate"); // Cache-Control來控制頁面的緩存與否,public:瀏覽器和緩存服務器均可以緩存頁面信息; response.setHeader("Pragma", "Pragma"); // Pragma:設置頁面是否緩存,爲Pragma則緩存,no-cache則不緩存 String finalStr = ""; if (StringUtils.isBlank(html) || RequestUtils.isClearCache(request) == true) { logger.info(RequestUtils.isClearCache(request) == true ? "清除頁面緩存" : "第一次訪問"); // HttpServletResponseWrapper responseWrapper = new // HttpServletResponseWrapper(httpRes); // 建立自定義的應答對象 StreamCharArrayWrapper responseWrapper = new StreamCharArrayWrapper(httpRes); chain.doFilter(request, responseWrapper); // 完成過濾連的業務 // responseWrapper.getWriter().flush(); // 取得存放輸出數據的 char 型數組,並組織成String類型 char[] responseChars = responseWrapper.toCharArray(); finalStr = new String(responseChars); logger.info("當前請求的輸出內容長度爲:" + finalStr.length()); int status = httpRes.getStatus(); // 只有相應返回碼status正確的response才進行網頁靜態化 if ((status >= 200 && status < 300) || status == 304) { set(fileName, finalStr, 1 * 60 * 60 * 24);// 秒 logger.info("當前請求的輸出到redis,內容長度爲:" + finalStr.length()); } // 最後,將頁面再次輸出到客戶端的頁面上 OutputStream finalOut = httpRes.getOutputStream(); // 這句話的意思,使得放入流的數據是utf8格式 finalOut.write(finalStr.getBytes("UTF-8")); logger.info("當前請求的輸出內容輸出到客戶端頁面,Finish..."); } // 若是已經生成HTML,直接把請求轉發到html文件。 else { logger.info("頁面已緩存到redis"); // 最後,將頁面再次輸出到客戶端的頁面上 httpRes.getWriter().print(html); } } protected void doFilterInternalFile(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { // 請求的uri String uri = request.getRequestURI(); String url = request.getRequestURL().toString(); request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); logger.info("訪問:" + uri + "---" + url); // 查看文件是否存在 String filePath = request.getSession().getServletContext().getRealPath("/") + "html/"; filePath = filePath.replaceAll("file:/", ""); filePath = filePath.replaceAll("%20", " "); String fileName = request.getRequestURL().toString().replaceAll(":", "").replaceAll("/", "#") + request.getQueryString() + DateUtils.today() + ".html"; filePath = filePath + fileName; File file = new File(filePath); logger.info("路徑filePath" + filePath); /** * 刪除昨天的文件 */ String filaNameYesterDay = request.getRequestURL().toString().replaceAll(":", "").replaceAll("/", "#") + DateUtils.today() + ".html"; File fileYesterDay = new File(filePath + filaNameYesterDay); if (fileYesterDay.isFile() == true && file.exists() == true) { Tools.deleteFile(fileName); logger.info("刪除filePath" + fileYesterDay); } // 不容許瀏覽器端或緩存服務器緩存當前頁面信息。 /* * response.setHeader( "Pragma", "no-cache" ); * response.setDateHeader("Expires", 0); response.addHeader( * "Cache-Control", "no-cache" );//瀏覽器和緩存服務器都不該該緩存頁面信息 * response.addHeader( "Cache-Control", "no-store" * );//請求和響應的信息都不該該被存儲在對方的磁盤系統中; response.addHeader( "Cache-Control", * "must-revalidate" ); */// 於客戶機的每次請求,代理服務器必須想服務器驗證緩存是否過期; /* * 判斷文件是否存在 或者是否清除緩存 */ if (file.isFile() == false || file.exists() == false || RequestUtils.isClearCache(request) == true) { logger.info(RequestUtils.isClearCache(request) == true ? "清除頁面緩存" : "第一次訪問"); HttpServletResponse httpRes = (HttpServletResponse) response; httpRes.setHeader("Content-Encoding", "text/html;charset=UTF-8"); // HttpServletResponseWrapper responseWrapper = new // HttpServletResponseWrapper(httpRes); // 建立自定義的應答對象 StreamCharArrayWrapper responseWrapper = new StreamCharArrayWrapper(httpRes); chain.doFilter(request, responseWrapper); // 完成過濾連的業務 // responseWrapper.getWriter().flush(); // 取得存放輸出數據的 char 型數組,並組織成String類型 char[] responseChars = responseWrapper.toCharArray(); final String finalStr = new String(responseChars); logger.info("當前請求的輸出內容長度爲:" + finalStr.length()); int status = httpRes.getStatus(); // 只有相應返回碼status正確的response才進行網頁靜態化 if ((status >= 200 && status < 300) || status == 304) { // 臨時輸出到一個url地址 file.createNewFile(); FileOutputStream tempOut = new FileOutputStream(filePath); // 構建FileOutputStream對象,文件不存在會自動新建 OutputStreamWriter tempWriter = new OutputStreamWriter(tempOut, "UTF-8"); tempWriter.append(finalStr); tempWriter.close(); // 關閉輸出流 tempOut.close(); logger.info("當前請求的輸出服務器本地,內容長度爲:" + finalStr.length()); } // 最後,將頁面再次輸出到客戶端的頁面上 OutputStream finalOut = httpRes.getOutputStream(); // 這句話的意思,使得放入流的數據是utf8格式 finalOut.write(finalStr.getBytes("UTF-8")); logger.info("當前請求的輸出內容輸出到客戶端頁面,Finish..."); } // 若是已經生成HTML,直接把請求轉發到html文件。 else { logger.info("文件已存在"); request.getRequestDispatcher("/html/" + fileName).forward(request, response); } } protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { if (isExternalUrlsInit == false) { if (StringUtils.isNotBlank(externalUrlsString) == true) { externalUrls = Lists.newArrayList(externalUrlsString.split(",")); } // 若是要排除過濾的路徑變量是空的,則置爲true,這樣,下次就不會再執行這一段被始化代碼 isExternalUrlsInit = true; } String uri = request.getRequestURI(); if (CollectionUtils.isEmpty(externalUrls) == false) { // 不爲空,匹配的都不過濾,直接獲取網站資源 for (String patten : externalUrls) { if (uri.matches(patten) == true) { return true; } } } return false; } public void destroy() { } /** * 經過key刪除(字節) * * @param key */ public void del(byte[] key) { this.getJedis().del(key); } /** * 經過key刪除 * * @param key */ public void del(String key) { this.getJedis().del(key); } /** * 添加key value 而且設置存活時間(byte) * * @param key * @param value * @param liveTime */ public void set(byte[] key, byte[] value, int liveTime) { this.set(key, value); this.getJedis().expire(key, liveTime); } /** * 添加key value 而且設置存活時間 * * @param key * @param value * @param liveTime */ public void set(String key, String value, int liveTime) { this.set(key, value); this.getJedis().expire(key, liveTime); } /** * 添加key value * * @param key * @param value */ public void set(String key, String value) { this.getJedis().set(key, value); } /** * 添加key value (字節)(序列化) * * @param key * @param value */ public void set(byte[] key, byte[] value) { this.getJedis().set(key, value); } /** * 獲取redis value (String) * * @param key * @return */ public String get(String key) { String value = this.getJedis().get(key); return value; } /** * 獲取redis value (byte [] )(反序列化) * * @param key * @return */ public byte[] get(byte[] key) { return this.getJedis().get(key); } /** * 經過正則匹配keys * * @param pattern * @return */ public Set<String> keys(String pattern) { return this.getJedis().keys(pattern); } /** * 檢查key是否已經存在 * * @param key * @return */ public boolean exists(String key) { return this.getJedis().exists(key); } /** * 清空redis 全部數據 * * @return */ public String flushDB() { return this.getJedis().flushDB(); } /** * 查看redis裏有多少數據 */ public long dbSize() { return this.getJedis().dbSize(); } /** * 檢查是否鏈接成功 * * @return */ public String ping() { return this.getJedis().ping(); } /** * 獲取一個jedis 客戶端 * * @return */ private Jedis getJedis() { if (jedis == null) { return jedisConnectionFactory.getShardInfo().createResource(); } return jedis; } }
utiljava
package cn.com.czw.front.utils; import java.io.CharArrayWriter; import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; /** * A response wrapper that takes everything the client would normally output and * saves it in one big character array. */ public class StreamCharArrayWrapper extends HttpServletResponseWrapper { private CharArrayWriter charWriter; /** * Initializes wrapper. * <P> * First, this constructor calls the parent constructor. That call is * crucial so that the response is stored and thus setHeader, *setStatus, * addCookie, and so forth work normally. * <P> * Second, this constructor creates a CharArrayWriter that will be used to * accumulate the response. */ public StreamCharArrayWrapper(HttpServletResponse response) { super(response); charWriter = new CharArrayWriter(); } /** * When servlets or JSP pages ask for the Writer, don't give them the real * one. Instead, give them a version that writes into the character array. * The filter needs to send the contents of the array to the client (perhaps * after modifying it). */ @Override public PrintWriter getWriter() { return new PrintWriter(charWriter); } /** * Get a String representation of the entire buffer. * <P> * Be sure <B>not</B> to call this method multiple times on the same * wrapper. The API for CharArrayWriter does not guarantee that it * "remembers" the previous value, so the call is likely to make a new * String every time. */ @Override public String toString() { return charWriter.toString(); } /** Get the underlying character array. */ public char[] toCharArray() { return charWriter.toCharArray(); } }