- 当以MVC方式实现之前的例子内容查看页时,每次查看都要查询数据库、模板替换、然后生成HTML ,当并发人数较多时,会给服务器带来显著压力。
内容一旦录入,存储到数据库,后期应该一般不再变化, 既然内容不变,何不生成一个静态的页面呢? 特点:一次写入,多次读取 )。所以,本例不再使用伪静态方式,而是直接就生成静态的HTML文件,每次直接访问生成的静态页面。
首先写一个类HtmlGen.java,用于生成静态html文件
package statichtml;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
public class HtmlGen
{
// 全局实例
public static HtmlGen i = new HtmlGen();
protected Configuration frmkConfig;
protected File appDir;
// appDir : 模板文件所在目录 ( app所在目录 )
// 注: 可以在BootLoader(Filter) 里初始化这个对象
public synchronized void init(File appDir)
{
if(this.appDir != null) return; // 只初始化一次
// 初始化
this.appDir = appDir;
try{
frmkConfig = new Configuration(Configuration.VERSION_2_3_28);
frmkConfig.setDirectoryForTemplateLoading(appDir); // 设置模板根目录
frmkConfig.setDefaultEncoding("UTF-8");
frmkConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
frmkConfig.setLogTemplateExceptions(false);
}
catch(Exception e)
{
System.out.println("This Should Not Happen!");
}
}
public void generate(String template, Object model, Writer out)throws Exception
{
if(appDir == null)
throw new Exception("你忘记调用init()了! 请在BootLoader里初始化!");
Template tp = frmkConfig.getTemplate(template);
tp.process(model, out);
}
// template : 模板文件
// model: 数据
// outPath: 生成的html文件路劲(相对于appDir)
public void generate(String template, Object model, String htmlPath)throws Exception
{
File htmlFile = new File(appDir, htmlPath);
Writer out = new FileWriter(htmlFile);
try{
Template tp = frmkConfig.getTemplate(template);
generate(template, model, out);
}
finally{
// 确保文件句柄被关闭
try{ out.close();}catch(Exception e){}
}
}
}
然后写一个Filter,BootLoader.java,在filter的init()方法里,初始化加载HtmlGen。
package statichtml;
import java.io.File;
import java.io.IOException;
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.annotation.WebFilter;
@WebFilter()
public class BootLoader implements Filter
{
public void init(FilterConfig fConfig) throws ServletException
{
// 系统初始化都放在这里
File appDir = new File(fConfig.getServletContext().getRealPath("/"));
HtmlGen.i.init(appDir);
}
public void destroy()
{
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
chain.doFilter(request, response);
}
}
在保存文章的时候,我们存储到数据库,并且生成一份静态的html文件,使用HtmlGen的generate(String template, Object model, String htmlPath)方法
@WebServlet("/PoemSave.api")
public class PoemSaveApi extends HttpServlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// 读取请求数据, 转成字符串
String reqText = readAsText(request.getInputStream(), "UTF-8");
JSONObject jreq=new JSONObject(reqText);
String title=jreq.getString("title");
String author=jreq.getString("author");
String dynasty=jreq.getString("dynasty");
String content=jreq.getString("content");
Poem poem=new Poem();
poem.setTitle(title);
poem.setAuthor(author);
poem.setDynasty(dynasty);
poem.setContent(content);
try (SqlSession sqlSession = db.MyBatis.sqlSessionFactory.openSession())
{
sqlSession.insert("ls.test.insertPoem", poem);
sqlSession.commit();
}
Map<String,Object> model=new HashMap<String,Object>();
model.put("poem", poem);
try
{
//生成静态html文件到 pages/n.html
HtmlGen.i.generate("poem/view.html", model, "pages/"+poem.getId()+".html");
} catch (Exception e)
{
e.printStackTrace();
}
JSONObject jresp=new JSONObject();
jresp.put("error", 0);
jresp.put("reason","OK");
//返回应答
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
Writer writer = response.getWriter();
writer.write( jresp.toString(2));
writer.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request, response);
}
//这个方法实现的功能就是从InputStream里读取数据转成字符串
public String readAsText(InputStream streamIn, String charset)
throws IOException
{
ByteArrayOutputStream cache = new ByteArrayOutputStream(1024*16);
byte[] data = new byte[1024];
while (true)
{
int n = streamIn.read(data); // n: 实际读取的字节数
if(n < 0) break; // 连接已经断开
if(n == 0) continue; // 数据未完 // TODO: 要防止超时
// 缓存起来
cache.write(data, 0, n);
if(cache.size() > 1024*512) // 上限, 最多读取512K
break;
}
return cache.toString(charset);
}
}
之后访问 http://127.0.0.1:8080/demo/pages/n.html 访问的就是生成的静态的html页面了。