其实这是一个很简单的技术,在新闻网站中应用的很普遍。原理是将数据保存为硬盘文件,直接通过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
本文地址:http://com.8s8s.com/it/it14035.htm