最近一直在搞opencms静态导出问题,发现使用opencms754自带的导出功能有一些小问题,从网上找了找相关资料,暂时没有看到比较有效果的正规答复,所以在源码方面考虑下。欢迎大家就如何使用opencms系统(开发完成后直接以原有系统使用,使用柔性缓存,或使用静态页面?或者使用静态导出的方式)提出意见
我之所以使用静态导出,也就是把数据库里的内容导出成静态网页,主要是考虑到
1.安全性问题,
2.减少对数据库的存取负载,因为数据库可能不仅仅是自己用.
3.减少系统复杂度静态导出功能
具体的问题总结起来有如下几个:
1.无法正常的进行配置404等页面
   因为我用的方式是启动两个服务器,一个服务器进行编辑,另一个服务器使用用来应对客户端的访问(指向export目录).opencms每次都会把export目录的内容全删掉,所以,如果第二个服务器有配置过404等页面的处理时时,就要完全重新配置
   如果只使用一个地址,online访问时,要么会出www.xxx.com/export/...效果,要么直接没用到这些静态页面.并且不能确定每次访问到底系统会用不用导出的内容
2.template resources默认要访问一次才能导出
  opencms静态导出的内容中,图片等内容可以很正确的导出,但是如果使用到了模板,比如新闻,就要先online访问一次才导出,特别是更改导出地址时,比如把sites/default改成/,并且ondemand式导出时,还会报404或302错误
3.编辑用的url主机地址可能和客户端实际访问的url地址主机不一样.
比如要在edit.xxx.com这个网址编辑,但实际用户访问时,可能访问的是www.xxx.com。这样也需要特别的配置。、
4.备份问题,比如最好保存最新的发布版本,和之前3个旧版本,防止一些突发状况目前使用的解决方案是重新/opencms/src/org/opencms/staticexport/CmsAfterPublishStaticExportHandler.java类,因为发布时,会调用这个类的doExportAfterPublish(List resources, I_CmsReport report)方法,而一般要求发布都会用这个方式。而这个方法会传入一个网站里所有文件的resources list.这个list里全是地址依据的原理实际很简单,如下:
1.已经发布出去的内容,使用java代码访问list里的地址,当然,前面加上edit.xxx.com,或者www.xxx.com.拷贝回来,放到文件夹里,这样就不会少template resources,解决了问题2.问题3其实也一样已经解决. if (status == HttpServletResponse.SC_OK) {


if (properties == null) {
InputStream pis = this.getClass().getClassLoader()
.getResourceAsStream("/staticexport.properties");
properties = new Properties();
properties.load(pis);
pis.close();
} String exportUrlStr = properties.get("urlprefix")
+ exportData.getRfsName();
if (!exportUrlStr.endsWith("/")) {
URL url = new URL(exportUrlStr);
File outFile = new File(properties.get("storefolder")
+ exportData.getRfsName());
if (!outFile.exists()) {
outFile.getParentFile().mkdirs();
outFile.createNewFile();
}
OutputStream os = new FileOutputStream(outFile);
// System.out.println(exportUrlStr);
InputStream is = url.openStream();
byte[] buff = new byte[1024];
while (true) {
int readed = is.read(buff);
if (readed == -1) {
break;
}
byte[] temp = new byte[readed];
System.arraycopy(buff, 0, temp, 0, readed);
os.write(temp);
}
is.close();
os.close();

String actual = properties.getProperty("actualStoredFolder") + exportData.getRfsName();
String bkfolder1 = properties.getProperty("backupfolder1")+ exportData.getRfsName();
String bkfolder2 = properties.getProperty("backupfolder2")+ exportData.getRfsName();

File actualFile = new File(actual);
if (!actualFile.exists()) {
actualFile.getParentFile().mkdirs();
}
File bkfolder1File = new File(bkfolder1);
if (!bkfolder1File.exists()) {
bkfolder1File.getParentFile().mkdirs();
}
File bkfolder2File = new File(bkfolder2);
if(!bkfolder2File.exists()){
bkfolder2File.getParentFile().mkdirs();
}
if(bkfolder2File.exists()){
bkfolder2File.delete();
}
bkfolder1File.renameTo(bkfolder2File);
actualFile.renameTo(bkfolder1File);
outFile.renameTo(actualFile); }
report.println(
org.opencms.report.Messages.get().container(
org.opencms.report.Messages.RPT_OK_0),
I_CmsReport.FORMAT_OK);
}2.备份问题,使用的是拷贝回来后,如果没问题,就直接把这个拷贝回的file rename。这个可以和配置文件的拷贝放到一起看
private static void copyfiles(File folder, File outFile,String str) throws IOException {
// System.out.println(folder + ":" + outFile);
if (folder.exists() && folder.isDirectory()) {
// System.out.println("folder:" + folder + ":" + outFile);
File[] subFiles = folder.listFiles();
for (File subFile : subFiles) {
String name = subFile.getName();
copyfiles(subFile, outFile,str + "/" + name);
}
} else if (folder.exists() && folder.isFile()) {
// System.out.println("file:" + folder + "::" + outFile);
outFile = new File(outFile + str);
if (!outFile.exists()) {
outFile.getParentFile().mkdirs();
outFile.createNewFile();
} OutputStream os = new FileOutputStream(outFile);
// System.out.println(outFile);
InputStream is = new FileInputStream(folder);
byte[] buff = new byte[1024];
while (true) {
int readed = is.read(buff);
if (readed == -1) {
break;
}
byte[] temp = new byte[readed];
System.arraycopy(buff, 0, temp, 0, readed);
os.write(temp);
}
is.close();
os.close();


String actual = properties.getProperty("actualStoredFolder") + str;
String bkfolder1 = properties.getProperty("backupfolder1") + str;
String bkfolder2 = properties.getProperty("backupfolder2") + str;

File actualFile = new File(actual);
if (!actualFile.exists()) {
actualFile.mkdirs();
}
File bkfolder1File = new File(bkfolder1);
if (!bkfolder1File.exists()) {
bkfolder1File.mkdirs();
}
File bkfolder2File = new File(bkfolder2);
if(!bkfolder2File.exists()){
bkfolder2File.mkdirs();
}

bkfolder2File.delete();
bkfolder1File.renameTo(bkfolder2File);
actualFile.renameTo(bkfolder1File);
outFile.renameTo(actualFile); }
}
这样问题都解决了。说起来可能麻烦点,但是实际使用只需要两步就能避免静态导出出错
1.在tomcat/webapps/ROOT/WEB-INF/classes/下放一个配置文件staticexport.properties,内容范例#opencms使用的地址和端口,用来从这里读取文件
urlprefix=http://localhost:9701
#暂存文件夹
storefolder=/home/dsw/export/exportfilestemp/
#操作完成后实际存储文件夹
actualStoredFolder=/home/dsw/export/exportfiles/
backupfolder1=/home/dsw/export/bk1/
backupfolder2=/home/dsw/export/bk2/
#从localhost:9701处理完内容后,会把这个文件夹里的所有文件和文件夹都拷贝到actualStoredFolder里,
#建议这里放一些配置文件,比如WEB-INF/
additionalfiles=/home/dsw/tomcat-www/webapps/ROOT/additional/web.xml等等
2.编译下面的类,并放到tomcat/webapps/ROOT/WEB-INF/classes/org/opencms/staticexport,同时tomcat/webapps/ROOT/WEB-INF/lib/opencms.jar里的org/opencms/staticexport/CmsAfterPublishStaticExportHandler.class删掉.
然后就可以正常使用静态导出功能了。类实在太长,见这里
http://wenku.baidu.com/view/33dff01155270722192ef7e4.html?st=1如果想看下不同的效果,或者查看地址list,可以把里面的system.out.println()注解打开。
还是那句:欢迎大家就如何使用opencms系统(开发完成后直接以原有系统使用,使用柔性缓存,或使用静态页面?或者使用静态导出的方式)提出意见