我们可能都已经注意到了,访问诸如新浪这样的大型站点的新闻时,我们会发现每一篇文章都会对应一个静态的页面,以此方式在大量并发访问时减小数据库服务器的负担。刚开始做web应用程序时,对于这类需求感觉非常之难,且不知从何处着手。偶然的机会看到一个论坛上实现介绍这类应用实现原理的讨论,突然大悟,就试着实现了该应用,现在正是我工作还没着落的最不如意的时期,正好边学习,边整理曾经的学习笔记,避免以后用得着的时候笔记又丢失的无影无踪。
 
原理倒也简单:在页面中以编程的方式访问一篇文章,通过拦截响应内容并写入html文件。
使用方法:只需要在添加完文章代码之后:设置相关属性(加背景色的代码需要的属性),并且使用<jsp:include>元素或具有相同功能的代码访问servlet即可
 
注意:使用了文字背景的部分,使用时注意查看访问该servlet时是否设置了相关属性,否则servlet可能不能正常执行。
servlet 代码如下:
 
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class toHtml extends HttpServlet {
 private static final long serialVersionUID = 1L;
 
 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
  request.setCharacterEncoding("GBK"); 
  //测试表明:通过REFERER 可以在服务器段获得发送请求的页面完整的路径信息
  String send_req_url =request.getHeader("REFERER");
 
  
  //获取应用程序在服务器端文件系统的绝对路径
  ServletContext context=getServletContext();  
  String rootRealPath=context.getRealPath("/");  
  
  String foldPath="/m/fy/fmd";//模板文件的目录结构
  String modelName="/m_article.jsp";//模板文件的名字
  
  //构造rootPath,形如:" http://localhost:8080/AjaxTrip"
  String contextStr=request.getContextPath();
  String urlStr=request.getRequestURL().toString();
  String rootPath=urlStr.substring(0, urlStr.indexOf(contextStr))+contextStr;//" http://localhost:8080/AjaxTrip"  
  
   String htmlId=(String)request.getAttribute("htmlId");
  String action=(String)request.getAttribute("action");

  String queryStr=null;
  
  //构造访问模板文件的url
  String sourceUrl=rootPath+foldPath+modelName;
  
  if("addArticle".equals(action)){
    queryStr=(String)request.getAttribute("queryStr");
  }
  if(queryStr!=null){
   sourceUrl=sourceUrl+"?"+queryStr;
  }
  /* JspToHtml :自定义类,实现依据当期日期生成响应的目录结构和文件:如:n/2009/1108/htmlId.html
   * 并且提供了将响应内容写入文件的方法:
   * */
     JspToHtml jth=new JspToHtml();
     jth.setUrl(rootRealPath);//设置io操作的绝对路径
   
 //使用URL对象通过编程的方式访问指定的文章,读取响应内容保存到sTotalString中
 String sCurrentLine="";
 String sTotalString="";
 InputStream l_urlStream ;
 URL l_url=new URL(sourceUrl);
 HttpURLConnection l_conn=(HttpURLConnection)l_url.openConnection();
 l_conn.connect();
 l_urlStream=l_conn.getInputStream();
 
 
 BufferedReader l_reader=new BufferedReader(new InputStreamReader(l_urlStream,"utf-8"));
 while((sCurrentLine=l_reader.readLine())!=null){
  sTotalString+=sCurrentLine; 
 }
 
 /*
  * 向浏览器发送数据时,输出内容使用的默认字符集也不支持中文, 避免出现乱码,必须
  * 在发送数据之前调用下面的方法设置响应内容的编码方式
  * */
 response.setContentType("text/html;charset=utf-8");
 if(null!=htmlId){
  //JspToHtml 调用相应方法创建html文件
  boolean bool=jth.createHtml(sTotalString,htmlId);
   request.setAttribute("htmlReady", "ok");
 }else{
  System.out.println("htmlId is null");
     }
 }
 
 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  // TODO Auto-generated method stub
  doGet(request,response);
 }
}
===下面是辅助类:JspToHtml.java源代码
 
package com.java.yanjie.translate;
import java.util.*;
import java.io.*;
import java.text.*;
/*
 * 使用该类注意事项:功能:封装对目录和文件的相关操作。
 * 2:必须先调用setUrl()方法设置文件和目录操作的绝对路径,然后调用createHtml(String content,String id)
 * 创建指定名称和内容的文件。创建的文件保存在如下格式的路径下:根目录/n/year/monthday/*.html
 * 如:在2009-10-31 创建的文件位于:/n/2009/1031/id.html
 *
 *
 * */
public class JspToHtml {
 private String baseUrl="D:\\java_workspace\\AjaxTrip\\WebContent";
 private String prefixFold=" \\n";
 private String foldUrl;
 /*
  * 类的功能:封装对目录和文件的操作
  * */
 public JspToHtml(){
  
 }
 
 /*
  * name:setUrl
  * function:设置目录和文件操作的时使用的根路径(web应用程序的根文件夹的绝对路径)
  * */
 public void setUrl(String baseUrl){
  this.baseUrl=baseUrl;
 }
 
 private String getBaseUrl(){
  return baseUrl;
 };
 /*
  * name:setFoldUrl
  * function:设置文件目录结构字符串
  * */
 private void setFoldUrl(String fileUrl){
  this.foldUrl=fileUrl;
 }
 private String getFoldUrl(){
  return foldUrl;
 }
 private String getPrefixFold(){
  return prefixFold;
 }
 
 /*
  * name;createHtml
  * function:创建html文件,内容是content,名称是id.html
  *
  * */
 public boolean createHtml(String content,String id){
  boolean bool=false;
  String cont=content;
  String id1=generateFileNameStr();
  String fileName=id+".html";
  
  FileWriter toFile;
  BufferedWriter out;
   try{
    if(formatUrl()){
    
    toFile=new FileWriter(getFoldUrl()+" \\"+fileName);
    out=new BufferedWriter(toFile);
    out.write(cont,0,cont.length());
    out.close();
    toFile.close();
    bool=true;    
    
    }
   }
   catch(IOException ioe){
    ioe.printStackTrace();
   }
   return bool;
  
 }//createHtml
 /*
  * name:deleteHtml
  * function:删除指定id(文件名称去除后缀)的html文件
  *
  * */
 
 public boolean deleteHtml(String htmlId){
  boolean bool=false;
  String name=htmlId;
  if(htmlId==null){
   return bool;
  }
  String yearStr=htmlId.substring(0, 4);
  String monthDayStr=htmlId.substring(4,8);
  String fileUrl=getBaseUrl()+getPrefixFold()+" \\"+yearStr+"\\"+monthDayStr+"\\"+htmlId+".html";
  File file_del=new File(fileUrl);
  if(file_del.exists()){
   file_del.delete();
   bool=true;//删除成功标志
  }  
  return bool;
 }
 /*
  * name:formatUrl
  * function:检查当前日期的文件目录结构是否存在,若不存在,则创建对应的目录结构,并且若目录结构存在,
  * 则保存该目录结构字符串 保存
  *
  * */
 private boolean formatUrl(){
  /*
    如果存放当前日期文件的目录结构不存在,则创建对应的目录结构   
   * */
  boolean bool=false;
   File file=new File(getBaseUrl());
   if(file.exists()&&file.isDirectory()){
    String foldStr=getTodayFilePath();
    File filePath=new File(foldStr);
    if(!filePath.exists()){
     filePath.mkdirs();
    }
    if(filePath.isDirectory()){
    bool=true;
    setFoldUrl(foldStr);
    }
   }
   return bool;
 }//formatUrl()
 
 //存放*.html的目录结构: .../.../根目录/年/月日/*.html
 /*
  * name:getTodayFilePath
  * function:该方法返回文件名之前的部分呢
  * */
 
 private String getTodayFilePath(){
  
   String tPath="";
   String dateStr[];
   dateStr=new String[2];
      String patternStr[]={"yyyy","MMdd"};
      dateStr[0]=new SimpleDateFormat(patternStr[0]).format(new Date());
      dateStr[1]=new SimpleDateFormat(patternStr[1]).format(new Date());
      tPath=getBaseUrl()+getPrefixFold()+" \\"+dateStr[0]+"\\"+dateStr[1];
   return tPath;
  }
 private String generateFileNameStr(){
  String fileName="";
  fileName=new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
  return fileName;
  
 }
 /*
  * main 方法测试类是否正常工作
  *
  * */
public static void main(String args[]){
 JspToHtml jspToHtml=new JspToHtml();
 jspToHtml.createHtml("aa", "11");
 System.out.println("create html success!!");
 jspToHtml.deleteHtml("20091031191355");
 
 
}
}