其实这是一个很简单的技术,在新闻网站中应用的很普遍。原理是将数据保存为硬盘文件,直接通过URL访问,用来减轻数据库访问的压力。
数据库与表:
mysql> use mysecondnews; Database changed mysql> desc news; +---------+---------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+---------------+------+-----+---------+----------------+ | id | int(10) | | PRI | NULL | auto_increment | | title | varchar(240) | | | | | | path | varchar(240) | | | | | | content | text | | | | | | addtime | timestamp(14) | YES | | NULL | | +---------+---------------+------+-----+---------+----------------+
Database.java://定义数据库
package org.eleaf.firstnews.database;
import java.sql.ResultSet; public interface Database { String DATABASE = "mysecondnews"; String USERNAME = "bitan"; String PASSWORD = "bitan"; String URL_PREFIX = "jdbc:mysql://localhost/" + DATABASE; String DRIVER = "org.gjt.mm.mysql.Driver";
int doUpdate(String sql); ResultSet doSelect(String sql); }
TouchDatabase.java://自定义JDBC接口类。为简单起见,未处理close()方法。 package org.eleaf.firstnews.database;
import java.sql.*; public class TouchDatabase implements Database { private Connection conn; private Statement stmt; private PreparedStatement prepstmt;
private void init() throws SQLException, ClassNotFoundException { stmt = null; prepstmt = null;
Class.forName(DRIVER); conn = DriverManager.getConnection(URL_PREFIX, USERNAME, PASSWORD); } /** * Constructor for Statement. * */ public TouchDatabase() { try { this.init(); stmt = conn.createStatement(); } catch (SQLException sqle) { sqle.printStackTrace(); } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } } /** * Constructor for PreparedStatement. * @param sql Pre-compile SQL string. */ public TouchDatabase(String sql) { try { this.init(); prepstmt = conn.prepareStatement(sql); } catch (SQLException sqle) { sqle.printStackTrace(); } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } }
public int doUpdate(String sql) { // TODO 自动生成方法存根 try { return stmt.executeUpdate(sql); } catch (SQLException sqle) { sqle.printStackTrace(); return 0; } }
public ResultSet doSelect(String sql) { // TODO 自动生成方法存根 try { return stmt.executeQuery(sql); } catch (SQLException sqle) { sqle.printStackTrace(); return null; } catch (Exception e) { e.printStackTrace(); return null; } }
public void setField(int index, String field) { try { prepstmt.setString(index, field); } catch (SQLException sqle) { sqle.printStackTrace(); } }
public ResultSet doPrepareSelect() { try { return prepstmt.executeQuery(); } catch (SQLException sqle) { sqle.printStackTrace(); return null; } catch (Exception e) { e.printStackTrace(); return null; } } }
News.java://新闻文章的数据结构 package testnews; public class News { private String id; private String title; private String path; private String content; private String addtime; /** * @return 返回 addtime。 */ public String getAddtime() { return addtime; } /** * @param addtime 要设置的 addtime。 */ public void setAddtime(String addtime) { this.addtime = addtime; } /** * @return 返回 content。 */ public String getContent() { return content; } /** * @param content 要设置的 content。 */ public void setContent(String content) { this.content = content; } /** * @return 返回 id。 */ public String getId() { return id; } /** * @param id 要设置的 id。 */ public void setId(String id) { this.id = id; } /** * @return 返回 path。 */ public String getPath() { return path; } /** * @param path 要设置的 path。 */ public void setPath(String path) { this.path = path; } /** * @return 返回 title。 */ public String getTitle() { return title; } /** * @param title 要设置的 title。 */ public void setTitle(String title) { this.title = title; } }
DoneNews.java://通过JDBC接口类操作数据库 package testnews;
import java.util.*; import java.sql.*; import org.eleaf.firstnews.database.*; public class DoneNews { public Vector getAllNews() { Vector vNews = new Vector(); String sql = "SELECT * FROM news"; TouchDatabase tdata = new TouchDatabase(); ResultSet rs = tdata.doSelect(sql); try { while (rs.next()) { News news = new News(); news.setId(rs.getString("id")); news.setTitle(rs.getString("title")); news.setPath(rs.getString("path")); news.setContent(rs.getString("content")); news.setAddtime(rs.getString("addtime")); vNews.addElement(news); } } catch (SQLException sqle) { sqle.printStackTrace(); } return vNews; } public boolean addNews(News news) { boolean success = false; if (news != null) { String sql = "INSERT news (title,path,content) VALUES('" + news.getTitle() + "','" + news.getPath() + "','" + news.getContent() + "')"; TouchDatabase tdata = new TouchDatabase(); success = (0 != tdata.doUpdate(sql)); } return success; } }
WriteNews.java://写数据流到硬盘。并调用DoneNews.addNews()方法。 package testnews;
import java.io.*; import java.util.*; public class WriteNews { private final String MIDDLE_DIR = "";//可自定义衔接目录。 private final String FILE_SUFFIX = ".html";//可自定义文件后缀名。 public boolean write(News news, String realPathPrefix, Calendar calendar) { int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH) + 1; int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); String fileName = calendar.getTimeInMillis() + FILE_SUFFIX; String realPath = realPathPrefix + MIDDLE_DIR + year + "\\" + month + "\\" + dayOfMonth + "\\"; try { if (!mkDirs(realPath)) { //throw new IOException("make dir('" + realPath + "') unsuccessfully!"); } FileOutputStream fos = new FileOutputStream(new File(realPath + fileName)); byte[] conBytes = news.getContent().getBytes(); fos.write(conBytes); fos.close(); } catch (IOException ioe) { ioe.printStackTrace(); return false; } String newsPath = year + "/" + month + "/" + dayOfMonth + "/" + fileName; news.setPath(newsPath); return new DoneNews().addNews(news); } private boolean mkDirs(String realPath) { boolean success = false; File path = new File(realPath); if(!path.exists()) { success = path.mkdirs(); } return success; } }
form.jsp://输入表单
<%@ page language="java" %> <!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <title>Lomboz JSP</title> </head> <body bgcolor="#FFFFFF"> <FORM METHOD=POST ACTION="save.jsp"> <INPUT TYPE="text" NAME="title"><BR> <TEXTAREA NAME="content" ROWS="10" COLS="50"></TEXTAREA><BR> <INPUT TYPE="submit"> </FORM> </body> </html>
save.jsp://保存数据.为简单起见,这里未对输入数据做任何字符过滤或转化工作。
<%@ page language="java" %> <%@ page import="java.util.*,testnews.*" %> <!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <title>Lomboz JSP</title> </head> <body bgcolor="#FFFFFF"> <% String title = request.getParameter("title"); String content = request.getParameter("content"); if (title == null | content == null) { response.sendRedirect("form.jsp"); return; } News news = new News(); news.setTitle(title); news.setContent(content); String realPathPrefix = application.getRealPath("/"); Calendar calendar = Calendar.getInstance(); boolean success = new WriteNews().write(news, realPathPrefix, calendar); String message = ""; if (success) { message = "Add the news successfully. Please return."; } else { message = "Add the news unsuccessfully. Please return."; } %> <%=message%><br> <a href="form.jsp">return to form.jsp</a><br> <a href="show.jsp">go to show.jsp</a><br> </body> </html>
show.jsp://显示链接
<%@ page language="java" %> <%@ page import="java.util.*,testnews.*" %> <!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <title>Lomboz JSP</title> </head> <body bgcolor="#FFFFFF"> <% Vector vNews = new DoneNews().getAllNews(); if (vNews != null) { for (int i=0; i<vNews.size(); i++) { News news = (News) vNews.elementAt(i); %> ` <a href="<%=request.getContextPath()%>/<%=news.getPath()%>"><%=news.getTitle()%></a><br> <% } } %> </body> </html>
然后就可以以类似如下的网址访问文章了: http://localhost:2000/secondnews/2004/10/31/1099234459546.html 
|