在这个博客的制作中,决定使用mongodb来对文章和图片进行存储,如果纯粹使用mongodb的api来进行crud操作的话,非常麻烦,
所以在这里采用Morphia,mongodb的一个orm框架,十分好用,具体dependcy如下:
<!--morphia--> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>${mongodb.version}</version> </dependency> <dependency> <groupId>org.mongodb.morphia</groupId> <artifactId>morphia</artifactId> <version>${morphia.version}</version> </dependency>在整合Morphia之前,我还参考了一下别人的博文的编写,其中采用许多那篇博文的代码:
具体分为如下:
MongoFactoryBean:
package cn.com.morphia; import com.mongodb.*; import org.springframework.beans.factory.config.AbstractFactoryBean; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2016/1/17. */ public class MongoFactoryBean extends AbstractFactoryBean<MongoClient> { /** * 表示服务器列表 */ private String[] serverStrings; /** * mongo配置对象 */ private MongoOptions mongoOptions; /** * 是否主从分离,默认为false */ private boolean readSecondary = false; public String[] getServerStrings() { return serverStrings; } public void setServerStrings(String[] serverStrings) { this.serverStrings = serverStrings; } public MongoOptions getMongoOptions() { return mongoOptions; } public void setMongoOptions(MongoOptions mongoOptions) { this.mongoOptions = mongoOptions; } public WriteConcern getWriteConcern() { return writeConcern; } public void setWriteConcern(WriteConcern writeConcern) { this.writeConcern = writeConcern; } public boolean isReadSecondary() { return readSecondary; } public void setReadSecondary(boolean readSecondary) { this.readSecondary = readSecondary; } /** * 设定写策略,默认采用SAFE模式(需要抛异常) */ private WriteConcern writeConcern = WriteConcern.SAFE; @Override public Class<?> getObjectType() { return MongoClient.class; } @Override protected MongoClient createInstance() throws Exception { MongoClient mongo = initMongo(); //设定主从分离 if (readSecondary) { mongo.setReadPreference(ReadPreference.secondaryPreferred()); } //设定写策略 mongo.setWriteConcern(writeConcern); return mongo; } /** * 初始化mongo * @return * @throws Exception */ private MongoClient initMongo() throws Exception { //根据条件创建mongo实例 MongoClient mongo = null; List<ServerAddress> serverList = getServerList(); mongo = new MongoClient(serverList.get(0)); return mongo; } /** * 获取mongo地址 * @return */ private List<ServerAddress> getServerList() throws Exception { List<ServerAddress> serverList = new ArrayList<>(); try { for (String serverString: serverStrings) { String[] temp = serverString.split(":"); String host = temp[0]; if (temp.length > 2) { throw new IllegalArgumentException( "Invalid server address string:" + serverString ); } if (temp.length == 2) { serverList.add(new ServerAddress(host, Integer.parseInt(temp[1]))); } else { serverList.add(new ServerAddress(host)); } } return serverList; } catch (Exception e) { e.printStackTrace(); throw new Exception( "Error while converting serverString to ServerAddressList", e ); } } }原博文中采用的泛型是mongo,但是现在的api基本不支持这么做了,所以我统一换成了MongoClient。
MorphiaFactory:
package cn.com.morphia; import org.mongodb.morphia.Morphia; import org.springframework.beans.factory.config.AbstractFactoryBean; /** * Created by Administrator on 2016/1/17. */ public class MorphiaFactoryBean extends AbstractFactoryBean<Morphia> { /** * 要扫描的包 * @return */ private String[] mapPackages; /** * 要映射的类 */ private String[] mapClasses; /** * 扫描包时,是否忽略不映射的类 * 这里按照Morphia的原始定义,默认设为false */ private boolean ignoreInvalidClasses; public String[] getMapPackages() { return mapPackages; } public void setMapPackages(String[] mapPackages) { this.mapPackages = mapPackages; } public String[] getMapClasses() { return mapClasses; } public void setMapClasses(String[] mapClasses) { this.mapClasses = mapClasses; } public boolean isIgnoreInvalidClasses() { return ignoreInvalidClasses; } public void setIgnoreInvalidClasses(boolean ignoreInvalidClasses) { this.ignoreInvalidClasses = ignoreInvalidClasses; } @Override public Class<?> getObjectType() { return Morphia.class; } @Override protected Morphia createInstance() throws Exception { Morphia morphia = new Morphia(); if (mapPackages != null) { for (String packageName: mapPackages) { morphia.mapPackage(packageName, ignoreInvalidClasses); } } if (mapClasses != null) { for (String entityClass: mapClasses) { morphia.map(Class.forName(entityClass)); } } return morphia; } }DatastoreFactoryBean:
package cn.com.morphia; import com.mongodb.Mongo; import com.mongodb.MongoClient; import org.mongodb.morphia.Datastore; import org.mongodb.morphia.Morphia; import org.springframework.beans.factory.config.AbstractFactoryBean; /** * Created by Administrator on 2016/1/17. */ public class DatastoreFactoryBean extends AbstractFactoryBean<Datastore> { /** * morphia实例,最好是单例 */ private Morphia morphia; /** * mongo实例,最好是单例 */ private MongoClient mongo; /** * 数据库名 */ private String dbName; /** * 用户名,可为空 */ private String username; /** * 密码,可为空 */ private String password; public Morphia getMorphia() { return morphia; } public void setMorphia(Morphia morphia) { this.morphia = morphia; } public MongoClient getMongo() { return mongo; } public void setMongo(MongoClient mongo) { this.mongo = mongo; } public String getDbName() { return dbName; } public void setDbName(String dbName) { this.dbName = dbName; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isToEnsureIndexes() { return toEnsureIndexes; } public void setToEnsureIndexes(boolean toEnsureIndexes) { this.toEnsureIndexes = toEnsureIndexes; } public boolean isToEnsureCaps() { return isToEnsureCaps; } public void setIsToEnsureCaps(boolean isToEnsureCaps) { this.isToEnsureCaps = isToEnsureCaps; } /** * 是否确认索引存在,默认false */ private boolean toEnsureIndexes = false; /** * 是否确认caps存在,默认为false */ private boolean isToEnsureCaps = false; @Override public Class<?> getObjectType() { return Datastore.class; } @Override protected Datastore createInstance() throws Exception { //这里的username和password可以为null,morphia对象会去处理 Datastore ds = morphia.createDatastore(mongo, dbName); if (toEnsureIndexes) { ds.ensureIndexes(); } if (isToEnsureCaps) { ds.ensureCaps(); } return ds; } }具体代码大概就是如上,但是还有spring中配置文件的配置还没有编写,具体如下:
<!-- mongoDB的配置对象 --> <bean id="mongoOptions" class="com.mongodb.MongoOptions"> <property name="connectionsPerHost" value="10" /> <!-- 连接超时时间(毫秒),默认为10000 --> <property name="connectTimeout" value="10000" /> <!-- 是否创建一个finalize方法,以便在客户端没有关闭DBCursor的实例时,清理掉它。默认为true --> <property name="cursorFinalizerEnabled" value="true" /> <!-- 线程等待连接可用的最大时间(毫秒),默认为120000 --> <property name="maxWaitTime" value="120000" /> <!-- 可等待线程倍数,默认为5.例如connectionsPerHost最大允许10个连接,则10*5=50个线程可以等待,更多的线程将直接抛异常 --> <property name="threadsAllowedToBlockForConnectionMultiplier" value="5" /> <!-- socket读写时超时时间(毫秒),默认为0,不超时 --> <property name="socketTimeout" value="0" /> <!-- 是socket连接在防火墙上保持活动的特性,默认为false --> <property name="socketKeepAlive" value="false" /> <!-- 对应全局的WriteConcern.SAFE,默认为false --> <property name="safe" value="true" /> <!-- 对应全局的WriteConcern中的w,默认为0 --> <property name="w" value="0" /> <!-- 对应全局的WriteConcern中的wtimeout,默认为0 --> <property name="wtimeout" value="0" /> <!-- 对应全局的WriteConcern.FSYNC_SAFE,如果为真,每次写入要等待写入磁盘,默认为false --> <property name="fsync" value="false" /> <!-- 对应全局的WriteConcern.JOURNAL_SAFE,如果为真,每次写入要等待日志文件写入磁盘,默认为false --> <property name="j" value="false" /> </bean> <!-- 使用工厂创建mongo实例 --> <bean id="mongo" class="cn.com.morphia.MongoFactoryBean"> <!-- mongoDB的配置对象 --> <property name="mongoOptions" ref="mongoOptions"/> <!-- 是否主从分离(读取从库),默认为false,读写都在主库 --> <property name="readSecondary" value="false"/> <!-- 设定写策略,默认为WriteConcern.SAFE,优先级高于mongoOptions中的safe --> <property name="writeConcern" value="SAFE"/> <!-- 设定服务器列表,默认为localhost:27017 --> <property name="serverStrings"> <array> <value>localhost:27017</value> </array> </property> </bean> <!-- 使用工厂创建morphia实例,同时完成类映射操作 --> <bean id="morphia" class="cn.com.morphia.MorphiaFactoryBean" > <!-- 指定要扫描的POJO包路径 --> <property name="mapPackages"> <array> <value>cn.com.domain</value> </array> </property> </bean> <!-- 使用工厂创建datastore,同时完成index和caps的确认操作 --> <bean id="datastore" class="cn.com.morphia.DatastoreFactoryBean" > <property name="morphia" ref="morphia"/> <property name="mongo" ref="mongo"/> <!-- collection的名称 --> <property name="dbName" value="files"/> <!-- 用户名和密码可以为空 --> <!-- <property name="username" value="my_username"/> 93 <property name="password" value="my_password"/> --> <!-- 是否进行index和caps的确认操作,默认为flase --> <property name="toEnsureIndexes" value="true"/> <property name="isToEnsureCaps" value="true"/> </bean>这里我没有再写另外一个mongodb.properties配置文件,直接将相应的参数写到了spring的配置文件中,因为这里只需要这几个参数,可以说不需要
另外再写一个配置文件配置相应的参数。
同时在datastore这个bean的编写中,我直接让这个bean扫描domain下面的所有pojo类,这样便不需要再进行相应的一个个的将相应的pojo类添加进来。
同时在mongooptions的配置中,我去掉了几个参数,在新版本中,不需要这几个参数。
现在进行测试:
package morphia; import cn.com.domain.User; import org.junit.Before; import org.junit.Test; import org.mongodb.morphia.Datastore; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by Administrator on 2016/1/19. */ public class TestMorphia { public ApplicationContext context; @Before public void init(){ context = new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml"); } @Test public void test() { Datastore datastore = (Datastore) context.getBean("datastore"); User u = new User(); u.setUsername("xx"); u.setPassword("xx"); datastore.save(u); System.out.println(datastore); } }获得datastore后,进行insert操作。
执行成功后,进mongo中查询相应的表:
如此,spring与Morphia的整合便是成功的。