其实这是一个很简单的技术,在新闻网站中应用的很普遍。原理是将数据保存为硬盘文件,直接通过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  
 
  |