<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 22, 文章 - 0, 評論 - 1, 引用 - 0
    數(shù)據(jù)加載中……

    morphia與spring的整合

    最近研究mongoDB的各種pojo-mapping框架,中意的就兩個:morphia和spring-data-mongodb。
    本來想著spring-data-mongodb與spring的結(jié)合更緊密些,但悲劇的是其要求spring3.0.x以上版本,與生產(chǎn)環(huán)境不符。查了查stackoverflow,大家評價morphia更老牌更穩(wěn)定一些,于是就用這個了。
    研究了一番,果然與spring整合起來很麻煩。
    首先看stackoverflow上的帖子,提問者跟我的想法完全一樣:在spring里,我沒有現(xiàn)成的辦法調(diào)用ensureIndexes()這樣的方法啊,腫么辦?
    http://stackoverflow.com/questions/5365315/using-morphia-with-spring
    回答者給出的兩個鏈接我也看了,真心沒啥收獲。
    后來又搜到一篇帖子:
    http://topmanopensource.iteye.com/blog/1449889
    很粗略的看了一下,還不錯,總之都得自己實現(xiàn)那些工廠類,完成與spring的集成。
    看來網(wǎng)上這方面的需求還不少,甚至在google-code上找到一個項目叫“spring-morphia”,專門來解決這個問題:
    http://code.google.com/p/spring-morphia/
    貌似荒廢已久,沒有完成的可供下載的jar包,但是在其svn上,可以看到一些可供我們參考的類:
    http://code.google.com/p/spring-morphia/source/browse/trunk/spring-morphia/src/main/java/com/so/smorphia/
    本文基本上就是根據(jù)上面兩個連接的思路寫的,自己總結(jié)一下而已,不做過多解釋了,代碼里有注釋。

    首先我們需要一個生成和配置mongodb的工廠類:

     1 public class MongoFactoryBean extends AbstractFactoryBean<Mongo> {
     2 
     3     // 表示服務(wù)器列表(主從復制或者分片)的字符串數(shù)組
     4     private String[] serverStrings;
     5     // mongoDB配置對象
     6     private MongoOptions mongoOptions;
     7     // 是否主從分離(讀取從庫),默認讀寫都在主庫
     8     private boolean readSecondary = false;
     9     // 設(shè)定寫策略(出錯時是否拋異常),默認采用SAFE模式(需要拋異常)
    10     private WriteConcern writeConcern = WriteConcern.SAFE;
    11 
    12     @Override
    13     public Class<?> getObjectType() {
    14         return Mongo.class;
    15     }
    16 
    17     @Override
    18     protected Mongo createInstance() throws Exception {
    19         Mongo mongo = initMongo();
    20         
    21         // 設(shè)定主從分離
    22         if (readSecondary) {
    23             mongo.setReadPreference(ReadPreference.secondaryPreferred());
    24         }
    25 
    26         // 設(shè)定寫策略
    27         mongo.setWriteConcern(writeConcern);
    28         return mongo;
    29     }
    30     
    31     /**
    32      * 初始化mongo實例
    33      * @return
    34      * @throws Exception
    35      */
    36     private Mongo initMongo() throws Exception {
    37         // 根據(jù)條件創(chuàng)建Mongo實例
    38         Mongo mongo = null;
    39         List<ServerAddress> serverList = getServerList();
    40 
    41         if (serverList.size() == 0) {
    42             mongo = new Mongo();
    43         }else if(serverList.size() == 1){
    44             if (mongoOptions != null) {
    45                 mongo = new Mongo(serverList.get(0), mongoOptions);
    46             }else{
    47                 mongo = new Mongo(serverList.get(0));
    48             }
    49         }else{
    50             if (mongoOptions != null) {
    51                 mongo = new Mongo(serverList, mongoOptions);
    52             }else{
    53                 mongo = new Mongo(serverList);
    54             }
    55         }
    56         return mongo;
    57     }
    58     
    59     
    60     /**
    61      * 根據(jù)服務(wù)器字符串列表,解析出服務(wù)器對象列表
    62      * <p>
    63      * 
    64      * @Title: getServerList
    65      *         </p>
    66      * 
    67      * @return
    68      * @throws Exception
    69      */
    70     private List<ServerAddress> getServerList() throws Exception {
    71         List<ServerAddress> serverList = new ArrayList<ServerAddress>();
    72         try {
    73             for (String serverString : serverStrings) {
    74                 String[] temp = serverString.split(":");
    75                 String host = temp[0];
    76                 if (temp.length > 2) {
    77                     throw new IllegalArgumentException(
    78                             "Invalid server address string: " + serverString);
    79                 }
    80                 if (temp.length == 2) {
    81                     serverList.add(new ServerAddress(host, Integer
    82                             .parseInt(temp[1])));
    83                 } else {
    84                     serverList.add(new ServerAddress(host));
    85                 }
    86             }
    87             return serverList;
    88         } catch (Exception e) {
    89             throw new Exception(
    90                     "Error while converting serverString to ServerAddressList",
    91                     e);
    92         }
    93     }
    94 
    95     /* ------------------- setters --------------------- */
    96 }

    其次我們需要一個產(chǎn)生和配置morphia對象的工廠類:

     1 public class MorphiaFactoryBean extends AbstractFactoryBean<Morphia> {
     2     /**
     3      * 要掃描并映射的包
     4      */
     5     private String[] mapPackages;  
     6     
     7     /**
     8      * 要映射的類
     9      */
    10     private String[] mapClasses;  
    11     
    12     /**
    13      * 掃描包時,是否忽略不映射的類
    14      * 這里按照Morphia的原始定義,默認設(shè)為false
    15      */
    16     private boolean ignoreInvalidClasses;
    17     
    18     @Override
    19     protected Morphia createInstance() throws Exception {
    20         Morphia m = new Morphia();
    21         if (mapPackages != null) {
    22             for (String packageName : mapPackages) {
    23                 m.mapPackage(packageName, ignoreInvalidClasses);
    24             }
    25         }
    26         if (mapClasses != null) {  
    27             for (String entityClass : mapClasses) {
    28                 m.map(Class.forName(entityClass));
    29             }
    30         }
    31         return m;
    32     }
    33 
    34     @Override
    35     public Class<?> getObjectType() {
    36         return Morphia.class;
    37     }
    38     
    39     /*----------------------setters-----------------------*/
    40 }

    最后我們還需要一個產(chǎn)生和配置Datastore的工廠類:

     1 public class DatastoreFactoryBean extends AbstractFactoryBean<Datastore> {
     2     
     3     private Morphia morphia;    //morphia實例,最好是單例
     4     private Mongo mongo;    //mongo實例,最好是單例
     5     private String dbName;    //數(shù)據(jù)庫名
     6     private String username;    //用戶名,可為空
     7     private String password;    //密碼,可為空
     8     private boolean toEnsureIndexes=false;    //是否確認索引存在,默認false
     9     private boolean toEnsureCaps=false;    //是否確認caps存在,默認false
    10     
    11 
    12     @Override
    13     protected Datastore createInstance() throws Exception {
    14         //這里的username和password可以為null,morphia對象會去處理
    15         Datastore ds = morphia.createDatastore(mongo, dbName, username,
    16                 password==null?null:password.toCharArray());
    17         if(toEnsureIndexes){
    18             ds.ensureIndexes();
    19         }
    20         if(toEnsureCaps){
    21             ds.ensureCaps();
    22         }
    23         return ds;
    24     }
    25 
    26     @Override
    27     public Class<?> getObjectType() {
    28         return Datastore.class;
    29     }
    30 
    31     @Override
    32     public void afterPropertiesSet() throws Exception {
    33         super.afterPropertiesSet();
    34         if (mongo == null) {
    35             throw new IllegalStateException("mongo is not set");
    36         }
    37         if (morphia == null) {
    38             throw new IllegalStateException("morphia is not set");
    39         }
    40     }
    41     
    42     /*----------------------setters-----------------------*/
    43 }

    我們來仿照morphia文檔,寫兩個測試的POJO:

     1 @Entity
     2 public class Hotel {
     3     @Id private ObjectId id;
     4     
     5     private String name;
     6     private int stars;
     7     
     8     @Embedded
     9     private Address address;    
    10     
    11     /*-----------gettters & setters----------*/
    12 }

    1 @Embedded
    2 public class Address {
    3     private String street;
    4     private String city;
    5     private String postCode;
    6     private String country;
    7     /*-----------gettters & setters----------*/
    8 }

    還需要一個為測試POJO專門服務(wù)的DAO,這里繼承morphia里的BasicDAO:

    1 public class HotelDAO extends BasicDAO<Hotel, ObjectId> {
    2 
    3     protected HotelDAO(Datastore ds) {
    4         super(ds);
    5     }
    6     
    7     /* ----------------以下是自定義的數(shù)據(jù)查詢方法(finder)----------------- */
    8 }

    最后是spring的XML文件:

      1 <?xml version="1.0" encoding="UTF-8"?>  
      2 <beans xmlns="http://www.springframework.org/schema/beans"  
      3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" 
      4     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
      5     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">  
      6     
      7     <!-- 配置文件 -->
      8     <context:property-placeholder location="classpath:config.properties" />
      9     
     10     <!-- mongoDB的配置對象 -->
     11     <bean id="mongoOptions" class="com.mongodb.MongoOptions">
     12         <!-- 服務(wù)器是否自動重連,默認為false -->
     13         <property name="autoConnectRetry" value="false" />
     14         <!-- 對同一個服務(wù)器嘗試重連的時間(毫秒),設(shè)為0時默認使用15秒 -->
     15         <property name="maxAutoConnectRetryTime" value="0" />
     16         <!-- 與每個主機的連接數(shù),默認為10 -->
     17         <property name="connectionsPerHost" value="10" />
     18         <!-- 連接超時時間(毫秒),默認為10000 -->
     19         <property name="connectTimeout" value="10000" />
     20         <!-- 是否創(chuàng)建一個finalize方法,以便在客戶端沒有關(guān)閉DBCursor的實例時,清理掉它。默認為true -->
     21         <property name="cursorFinalizerEnabled" value="true" />
     22         <!-- 線程等待連接可用的最大時間(毫秒),默認為120000 -->
     23         <property name="maxWaitTime" value="120000" />
     24         <!-- 可等待線程倍數(shù),默認為5.例如connectionsPerHost最大允許10個連接,則10*5=50個線程可以等待,更多的線程將直接拋異常 -->
     25         <property name="threadsAllowedToBlockForConnectionMultiplier" value="5" />
     26         <!-- socket讀寫時超時時間(毫秒),默認為0,不超時 -->
     27         <property name="socketTimeout" value="0" />
     28         <!-- 是socket連接在防火墻上保持活動的特性,默認為false -->
     29         <property name="socketKeepAlive" value="false" />
     30         <!-- 對應(yīng)全局的WriteConcern.SAFE,默認為false -->
     31         <property name="safe" value="true" />
     32         <!-- 對應(yīng)全局的WriteConcern中的w,默認為0 -->
     33         <property name="w" value="0" />
     34         <!-- 對應(yīng)全局的WriteConcern中的wtimeout,默認為0 -->
     35         <property name="wtimeout" value="0" />
     36         <!-- 對應(yīng)全局的WriteConcern.FSYNC_SAFE,如果為真,每次寫入要等待寫入磁盤,默認為false -->
     37         <property name="fsync" value="false" />
     38         <!-- 對應(yīng)全局的WriteConcern.JOURNAL_SAFE,如果為真,每次寫入要等待日志文件寫入磁盤,默認為false -->
     39         <property name="j" value="false" />
     40     </bean>
     41     
     42     <!-- 使用工廠創(chuàng)建mongo實例 -->
     43     <bean id="mongo" class="me.watchzerg.test.morphia.spring.MongoFactoryBean">
     44         <!-- mongoDB的配置對象 -->
     45         <property name="mongoOptions" ref="mongoOptions"/>
     46         
     47         <!-- 是否主從分離(讀取從庫),默認為false,讀寫都在主庫 -->
     48         <property name="readSecondary" value="false"/>
     49         
     50         <!-- 設(shè)定寫策略,默認為WriteConcern.SAFE,優(yōu)先級高于mongoOptions中的safe -->
     51         <property name="writeConcern" value="SAFE"/>
     52         
     53         <!-- 設(shè)定服務(wù)器列表,默認為localhost:27017 -->
     54         <property name="serverStrings">
     55             <array>
     56                 <value>${mongoDB.server}</value>
     57             </array>
     58         </property>
     59     </bean>
     60     
     61     
     62     <!-- 使用工廠創(chuàng)建morphia實例,同時完成類映射操作 -->
     63     <bean id="morphia" class="me.watchzerg.test.morphia.spring.MorphiaFactoryBean" >
     64         <!-- 指定要掃描的POJO包路徑 -->
     65         <property name="mapPackages">
     66             <array>
     67                 <value>me.watchzerg.test.morphia.pojo</value>
     68             </array>
     69         </property>
     70         
     71         <!-- 指定要映射的類 -->
     72         <!-- <property name="mapClasses">
     73             <array>
     74                 <value>me.watchzerg.test.morphia.pojo.Hotel</value>
     75                 <value>me.watchzerg.test.morphia.pojo.Address</value>
     76             </array>
     77         </property> -->
     78         
     79         <!-- 掃描包時是否忽略不可用的類,默認為false -->
     80         <!-- <property name="ignoreInvalidClasses" value="false"/> -->
     81     </bean>
     82     
     83     <!-- 使用工廠創(chuàng)建datastore,同時完成index和caps的確認操作 -->
     84     <bean id="datastore" class="me.watchzerg.test.morphia.spring.DatastoreFactoryBean" >
     85         <property name="morphia" ref="morphia"/>
     86         <property name="mongo" ref="mongo"/>
     87         
     88         <!-- collection的名稱 -->
     89         <property name="dbName" value="${mongoDB.dbName}"/>
     90         
     91         <!-- 用戶名和密碼可以為空 -->
     92         <!-- <property name="username" value="my_username"/>
     93         <property name="password" value="my_password"/> -->
     94         
     95         <!-- 是否進行index和caps的確認操作,默認為flase -->
     96         <property name="toEnsureIndexes" value="true"/>
     97         <property name="toEnsureCaps" value="true"/>
     98     </bean>
     99     
    100     <!-- ===============以下是具體DAO的實現(xiàn)===================== -->
    101     
    102     <bean id="hotelDAO" class="me.watchzerg.test.morphia.dao.impl.HotelDAO">
    103         <constructor-arg ref="datastore"/>
    104     </bean>
    105     
    106 </beans> 

    最后寫一個測試類看看我們的成果:

      1 public class MorphiaTest {
      2     private static HotelDAO hotelDAO;
      3 
      4     /**
      5      * 測試Morphia的DAO層
      6      * 
      7      * @param args
      8      * @throws Exception
      9      */
     10     public static void main(String[] args) throws Exception {
     11         // 初始化DAO
     12         initDAO();
     13 
     14         // 插入測試
     15         saveTest();
     16 
     17         // 更新測試
     18         // updateTest();
     19 
     20         // 刪除測試
     21         // deleteTest();
     22 
     23         // 查詢測試
     24         // queryHotel();
     25 
     26         System.out.println("done!");
     27     }
     28 
     29     /**
     30      * 初始化DAO
     31      * <p>
     32      * @Title: initDAO
     33      * </p>
     34      */
     35     private static void initDAO() {
     36         ApplicationContext context = new ClassPathXmlApplicationContext(
     37                 "config.xml");
     38         hotelDAO = (HotelDAO) context.getBean("hotelDAO");
     39     }
     40 
     41     /**
     42      * 生成指定個數(shù)的hotelList
     43      * <p>
     44      * @Title: getHotelList
     45      * </p>
     46      * 
     47      * @param num
     48      * @return
     49      */
     50     private static List<Hotel> getHotelList(int num) {
     51         List<Hotel> list = new ArrayList<Hotel>();
     52         for (int i = 0; i < num; i++) {
     53             Hotel hotel = new Hotel();
     54             hotel.setName("編號為[" + i + "]的旅店");
     55             hotel.setStars(i % 10);
     56             Address address = new Address();
     57             address.setCountry("中國");
     58             address.setCity("北京");
     59             address.setStreet("上帝南路");
     60             address.setPostCode("10000" + (i % 10));
     61             hotel.setAddress(address);
     62             list.add(hotel);
     63         }
     64         return list;
     65     }
     66 
     67     /**
     68      * 將hotelList插入數(shù)據(jù)庫
     69      * <p>
     70      * @Title: saveHotelList
     71      * </p>
     72      * 
     73      * @param hotelDAO
     74      * @param hotelList
     75      */
     76     private static void saveTest() {
     77         List<Hotel> hotelList = getHotelList(100);
     78         for (Hotel hotel : hotelList) {
     79             // Key<Hotel> key=hotelDAO.save(hotel,WriteConcern.SAFE);
     80             Key<Hotel> key = hotelDAO.save(hotel);
     81             System.out.println("id為[" + key.getId() + "]的記錄已被插入");
     82         }
     83     }
     84 
     85     /**
     86      * 更新操作測試
     87      * <p>
     88      * @Title: updateTest
     89      * </p>
     90      * 
     91      * @throws Exception
     92      */
     93     private static void updateTest() throws Exception {
     94         //生成查詢條件
     95         Query<Hotel> q = hotelDAO.createQuery().field("stars")
     96                 .greaterThanOrEq(9);
     97         //生成更新操作
     98         UpdateOperations<Hotel> ops = hotelDAO.createUpdateOperations()
     99                 .set("address.city", "shanghai").inc("stars");
    100         // UpdateResults<Hotel> ur=hotelDAO.update(q, ops);
    101         UpdateResults<Hotel> ur = hotelDAO.updateFirst(q, ops);
    102         if (ur.getHadError()) {
    103             System.out.println(ur.getError());
    104             throw new Exception("更新時發(fā)生錯誤");
    105         }
    106         if (ur.getUpdatedExisting()) {
    107             System.out.println("更新成功,更新條數(shù)為[" + ur.getUpdatedCount()
    108                     + "],插入條數(shù)為[" + ur.getInsertedCount() + "]");
    109         } else {
    110             System.out.println("沒有記錄符合更新條件");
    111         }
    112     }
    113 
    114     /**
    115      * 刪除操作測試
    116      * <p>
    117      * @Title: deleteTest
    118      * </p>
    119      */
    120     private static void deleteTest() {
    121         ObjectId id = hotelDAO.findIds().get(0);
    122         hotelDAO.deleteById(id);
    123 
    124         Query<Hotel> q = hotelDAO.createQuery().field("stars")
    125                 .greaterThanOrEq(100);
    126         hotelDAO.deleteByQuery(q);
    127     }
    128 
    129     /**
    130      * 查詢測試
    131      * <p>
    132      * @Title: queryHotel
    133      * </p>
    134      */
    135     private static void queryHotel() {
    136         // 顯示所有記錄
    137         System.out.println("\nhotelDAO.find()=");
    138         for (Hotel hotel : hotelDAO.find()) {
    139             System.out.println(hotel);
    140         }
    141 
    142         // 統(tǒng)計star大于等于9的數(shù)目
    143         System.out
    144                 .println("\nhotelDAO.count(hotelDAO.createQuery().field(\"stars\").greaterThanOrEq(9))="
    145                         + hotelDAO.count(hotelDAO.createQuery().field("stars")
    146                                 .greaterThanOrEq(9)));
    147 
    148         // 顯示符合條件的記錄ID
    149         List<ObjectId> ids = hotelDAO.findIds("stars", 8);
    150         System.out.println("\nhotelDAO.findIds(\"stars\", 8)=");
    151         for (ObjectId id : ids) {
    152             System.out.println(id);
    153         }
    154     }
    155 
    156 }

    大功告成~

    posted on 2012-09-21 18:09 王星游 閱讀(8440) 評論(0)  編輯  收藏 所屬分類: java

    主站蜘蛛池模板: 亚洲第一精品电影网| 美美女高清毛片视频黄的一免费 | 国产精品久久久亚洲| 最近中文字幕mv免费高清电影| 国产午夜不卡AV免费| 视频一区二区三区免费观看| 激情综合亚洲色婷婷五月APP| 亚洲高清国产AV拍精品青青草原| 四虎影视精品永久免费网站| 黄页网站在线看免费| 午夜影院免费观看| 国产一级在线免费观看| 国产99久久亚洲综合精品| 亚洲综合成人婷婷五月网址| 亚洲最大在线观看| 亚洲成色在线影院| 久久精品国产亚洲香蕉| 在线精品亚洲一区二区三区| AV在线亚洲男人的天堂| 一本久久综合亚洲鲁鲁五月天| 成年在线网站免费观看无广告| 亚洲黄色免费观看| 99久久免费中文字幕精品| 国内永久免费crm系统z在线| 久久国产免费直播| 精品国产污污免费网站入口在线| 免费观看又污又黄在线观看| 国产成人亚洲综合a∨| 亚洲AV无码专区在线观看成人| 亚洲成_人网站图片| 亚洲偷自精品三十六区| 亚洲国产精品综合一区在线 | 久久国产精品萌白酱免费| 中文字幕免费观看视频| 9i9精品国产免费久久| 精品国产免费一区二区三区| 色www永久免费| 免费国产成人午夜在线观看| 在线观看免费播放av片| 精品国产一区二区三区免费| 无码专区AAAAAA免费视频|