項目中集成Mybatis與Spring,使用的是Mybatis3.2.7,以及Spring4.0.5,mybatis-spring-1.2.2;
由於項目組成員想要偷懶,將數據從DB中查詢出來時須要將字段映射為Map,而不想封裝成Bean.
默認情況下,Mybatis對Map的解析生成, 假設值(value)為null的話,那么key也不會被增加到map中.
於是對Map遍歷時,key就遍歷不到,由於前端工具的須要,必須有這個key,網上搜索后發現須要設置 callSettersOnNulls 這個屬性.
那就設置唄, 在 sqlSessionFactory 的定義中,指定 configLocation 屬性,指向還有一個文件,例如以下所看到的
文件清單: mybatis-env-setting.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!-- 假設內網機器報錯,請使用以下這樣的笨辦法 --> <!-- <!DOCTYPE configuration PUBLIC "-//www.mybatis.org//DTD Config 3.0//EN" "E:/bao/tomcat/apache-tomcat-6.0.14/webapps/pmsys/WEB-INF/classes/mybatis/mybatis-3-config.dtd"> --> <configuration> <settings> <!-- 僅僅設置須要的,其它使用默認值 --> <!-- 開啟緩存,默認就是開啟的,2層開關,須要在Mapper文件里也指定 cache 標簽才會真正使用緩存 --> <setting name="cacheEnabled" value="true"/> <!-- 在null時也調用 setter,適應於返回Map,3.2版本號以上可用 --> <setting name="callSettersOnNulls" value="true"/> </settings> </configuration>
然后使用,一切正常,OK.
過了幾天, 實施項目時出BUG了, 由於是企業內網server,不能訪問 mybatis.org,於是啟動出錯.
【Mybatis 這個渣渣,在啟動時會去獲取並校驗DTD,眼下還不知道在哪里配置讓其不進行校驗.】
網上搜索半天,沒有好的解決的方法, 看到有方法說將dtd下載到本地,然后直接指定路徑,就像上面凝視掉的那部分一樣。
問題也算是攻克了,但是非常土,並且各個機器不一定都有相同的文件夾,這樣的掉渣的方法肯定會遭人詬病的。
於是百度谷歌又搜索了半天,沒找到辦法,根本沒有人提這茬。
於是想着自己翻源代碼看看:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> { private static final Log logger = LogFactory.getLog(SqlSessionFactoryBean.class); // 這里能夠配置configLocation資源 private Resource configLocation; private Resource[] mapperLocations; private DataSource dataSource; private TransactionFactory transactionFactory; // 這里能夠配置configurationProperties屬性 private Properties configurationProperties; ...... protected SqlSessionFactory buildSqlSessionFactory() throws IOException { Configuration configuration; XMLConfigBuilder xmlConfigBuilder = null; // 先查找 configLocation 屬性 if (this.configLocation != null) { xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties); configuration = xmlConfigBuilder.getConfiguration(); } else { if (logger.isDebugEnabled()) { logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration"); } // 假設找不到configLocation,就僅僅使用 configurationProperties configuration = new Configuration(); configuration.setVariables(this.configurationProperties); } ......
看到了 configurationProperties 這個屬性,但是 該怎么設置呢,總算找到了一篇非常靠譜的學習筆記: Spring的Bean之設置Bean值
於是,抄襲之,自己設置了一下相應的屬性
形成的配置文件片段例如以下所看到的:
<!-- myBatis配置 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 表示在mybatis.mapping包或以下全部文件夾中,以 Mapper.xml結尾全部文件 --> <property name="mapperLocations"> <value>classpath:com/cncounter/dao/oracle/**/*Mapper.xml</value> <!-- <list> <value>classpath:com/cncounter/dao/oracle/res/*Mapper.xml</value> <value>classpath:com/cncounter/dao/oracle/user/*Mapper.xml</value> </list> --> </property> <!-- <property name="configLocation"> <value>classpath:mybatis/mybatis-env-setting.xml</value> </property> --> <!-- 切換一種方式,不配置configLocation --> <property name="configurationProperties"> <props> <prop key="cacheEnabled">true</prop> <prop key="callSettersOnNulls">true</prop> </props> </property> </bean>
啟動沒報錯,但是還沒檢驗.應該沒多大問題...
補充: 還是不起作用,於是沒法子了,僅僅好拆開Mybatis的源代碼,找到類 org.apache.ibatis.session.Configuration ,然后,在自己的文件夾下把源代碼拷出來, 自己在test文件夾建一個包,建一個類,和Configuration一模一樣,然后改動 callSettersOnNulls 的默認值為 true,然后找到編譯好的3個class文件(有內部類),替換到mybatis-3.2.7.jar中去,OK,成功解決。
按理說應該是編譯整個mybatis的,但是maven有點坑,眼下還不想這樣做
看了 mybatis高級應用系列一:分頁功能 這篇文章,發覺冤枉 MyBatis了,事實上是 Mybatis-Spring挖下的坑, 校驗的時候不走Mybatis的默認通道, 而是自己解析了相應的XML文件,還要去網上搜索dtd文件,巨坑無比啊.
給了 configurationProperties 這么個選項,卻不使用,真是不好。
附上一篇, 怎樣解決Spring附加組件中dtd的這樣的坑