前言

尽管java的口号:Write Once, Run Anywhere ,但现实非常残酷。不同的操作系统、不同的容器总是让我们:Write Once,Debug Anywhere。所以关键还是要看设计。好的设计能降低迁移成本。


近期须要将roller迁移到百度云中,发现roller设计的真不错。很easy就看迁移到云中了。


迁移的主要是数据,roller使用mysql,而百度云也提高mysql。这个基本不须要考虑迁移。主要是roller的图片上传功能:

1、怎样将已经上传的图片迁移到百度的bcs中?

2、怎样以最小的代价让将上传图片的功能迁移到百度bcs中?


添加一个切换开关:roller.properties

baiduyun.accessKey=dtjTg3L9xm
baiduyun.secretKey=9V1L9mul9IVb
baiduyun.bucket=hello
enabled.use.baiduyun=true




扩展存储文件的实现类

package org.apache.roller.weblogger.business;

import java.io.InputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.weblogger.config.WebloggerConfig;
import org.apache.roller.weblogger.pojos.FileContent;
import org.apache.roller.weblogger.pojos.MediaFile;
import org.apache.roller.weblogger.pojos.Weblog;
import org.apache.roller.weblogger.util.RollerMessages;

import com.baidu.inf.iis.bcs.BaiduBCS;
import com.baidu.inf.iis.bcs.auth.BCSCredentials;
import com.baidu.inf.iis.bcs.model.Empty;
import com.baidu.inf.iis.bcs.model.ObjectMetadata;
import com.baidu.inf.iis.bcs.model.X_BS_ACL;
import com.baidu.inf.iis.bcs.request.PutObjectRequest;


/**
* Manages contents of the file uploaded to Roller weblogs.
*
* This base implementation writes file content to a file system.
*/
public class BaiduYunFileContentManagerImpl extends FileContentManagerImpl {

private static Log log = LogFactory.getLog(BaiduYunFileContentManagerImpl.class);

private String host = "bcs.duapp.com";
private String accessKey = "";
private String secretKey = "";
private String bucket = "";
private BaiduBCS baiduBCS = null;

/**
* Create file content manager.
*/
public BaiduYunFileContentManagerImpl() {

accessKey = WebloggerConfig.getProperty("baiduyun.accessKey");
secretKey = WebloggerConfig.getProperty("baiduyun.secretKey");
bucket = WebloggerConfig.getProperty("baiduyun.bucket");

BCSCredentials credentials = new BCSCredentials(accessKey, secretKey);
baiduBCS = new BaiduBCS(credentials, host);
baiduBCS.setDefaultEncoding("UTF-8"); // Default UTF-8


}


/**
* @see org.apache.roller.weblogger.model.FileContentManager#getFileContent(weblog, java.lang.String)
*/
public FileContent getFileContent(Weblog weblog, String fileId)
throws FileNotFoundException, FilePathException {

log.info("=====================get file content:" + fileId);
final InputStream is = baiduBCS.getObject(bucket, getObjectStoragePath(weblog, fileId)).getResult().getContent();
return new FileContent(weblog, fileId, null) {
private InputStream ins = is;
@Override
public InputStream getInputStream() {
return ins;
}
};
}

private String getObjectStoragePath(Weblog weblog ,String fileId) {
return '/' + weblog.getHandle() + '/' + fileId;
}


public void saveFileContent(Weblog weblog, MediaFile mediaFile)
throws FileNotFoundException, FilePathException, FileIOException {

log.info("==========saveFileContent start ->" + mediaFile.getId());

ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType(mediaFile.getContentType());
objectMetadata.setContentLength(mediaFile.getLength());

PutObjectRequest request = new PutObjectRequest(bucket,
getObjectStoragePath(weblog, mediaFile.getId()),
mediaFile.getInputStream(),
objectMetadata);

ObjectMetadata result = baiduBCS.putObject(request).getResult();
log.info(result);
baiduBCS.putObjectPolicy(bucket, getObjectStoragePath(weblog, mediaFile.getId()),X_BS_ACL.PublicRead);

log.info("==========saveFileContent end");

}


/**
* @see org.apache.roller.weblogger.model.FileContentManager#deleteFile(weblog, java.lang.String)
*/
public void deleteFile(Weblog weblog, String fileId)
throws FileNotFoundException, FilePathException, FileIOException {

log.info("==========deleteFile start:" + fileId);

Empty result = baiduBCS.deleteObject(bucket, getObjectStoragePath(weblog, fileId)).getResult();
baiduBCS.deleteObject(bucket, getObjectStoragePath(weblog, fileId) + "_sm").getResult();

log.info(result);

log.info("==========deleteFile start");

}


/**
* @see org.apache.roller.weblogger.model.FileContentManager#overQuota(weblog)
*/
public boolean overQuota(Weblog weblog) {

return false;
}



@Override
public boolean canSave(Weblog weblog, String fileName, String contentType,
long size, RollerMessages messages) {

return true;
}



}


改动ioc注入:

JPAWebloggerModule.java

if(WebloggerConfig.getBooleanProperty("enabled.use.baiduyun")) {
binder.bind(FileContentManager.class).to( BaiduYunFileContentManagerImpl.class);
}
else {
binder.bind(FileContentManager.class).to( FileContentManagerImpl.class);
}



最后想说的是这种方法參数设计不太好,应该把MediaFile作为參数。而非用其个别字段(fileId和inputstream)

public void saveFileContent(Weblog weblog,
String fileId,
InputStream is)
throws FileNotFoundException, FilePathException, FileIOException;



这样,roller就能够把百度bcs作为存储图片的server了。