好设计,迁移不费劲
前言
尽管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了。