轉載的。。。。。http://zhenghuazhi.iteye.com/blog/1468992
頁面輸入:男,數據庫保存male,女,數據庫保存為female。
使用interceptor,typeHandler
- package cn.dcr.mybatis.util;
- import java.util.Properties;
- import org.apache.ibatis.executor.Executor;
- import org.apache.ibatis.mapping.MappedStatement;
- import org.apache.ibatis.plugin.Interceptor;
- import org.apache.ibatis.plugin.Intercepts;
- import org.apache.ibatis.plugin.Invocation;
- import org.apache.ibatis.plugin.Plugin;
- import org.apache.ibatis.plugin.Signature;
- import org.apache.ibatis.session.ResultHandler;
- import org.apache.ibatis.session.RowBounds;
- import com.test.pojos.User;
- @Intercepts({
- @Signature(type = Executor.class, method = "update", args = {
- MappedStatement.class, Object.class }),
- @Signature(type = Executor.class, method = "query", args = {
- MappedStatement.class, Object.class, RowBounds.class,
- ResultHandler.class }) })
- public class MyInterceptor implements Interceptor {
- private static final String R_FEMALE = "女";
- private static final String R_MALE = "男";
- private static final String FEMALE = "female";
- private static final String MALE = "male";
- private Properties properties;
- /*
- * (non-Javadoc)
- *
- * @see
- * org.apache.ibatis.plugin.Interceptor#intercept(org.apache.ibatis.plugin
- * .Invocation)
- */
- public Object intercept(Invocation invocation) throws Throwable {
- MappedStatement mappedStatement = (MappedStatement) invocation
- .getArgs()[0];
- String sqlId = mappedStatement.getId();
- String namespace = sqlId.substring(0, sqlId.indexOf('.'));
- Executor exe = (Executor) invocation.getTarget();
- String methodName = invocation.getMethod().getName();
- if (methodName.equals("query")) {
- Object parameter = invocation.getArgs()[1];
- RowBounds rowBounds = (RowBounds) invocation.getArgs()[2];
- }
- else if(methodName.equals("update")){
- Object parameter = invocation.getArgs()[1];
- if(parameter instanceof User)
- ((User)parameter).setGender(saveValueToDb(((User)parameter).getGender()));
- }
- return invocation.proceed();
- }
- /*
- * (non-Javadoc)
- *
- * @see org.apache.ibatis.plugin.Interceptor#plugin(java.lang.Object)
- */
- public Object plugin(Object target) {
- return Plugin.wrap(target, this);
- }
- /*
- * (non-Javadoc)
- *
- * @see
- * org.apache.ibatis.plugin.Interceptor#setProperties(java.util.Properties)
- */
- public void setProperties(Properties properties) {
- this.properties = properties;
- }
- /**插入數據庫
- * @param value
- * @return
- */
- private String saveValueToDb(String value) {
- if (value.equals(R_FEMALE)) {
- return FEMALE;
- } else if (value.equals(R_MALE)) {
- return MALE;
- } else {
- throw new IllegalArgumentException("數據庫異常!" + value);
- }
- }
- }
- @Intercepts({
- @Signature(type = Executor.class, method = "update", args = {
- MappedStatement.class, Object.class }),
- @Signature(type = Executor.class, method = "query", args = {
- MappedStatement.class, Object.class, RowBounds.class,
- ResultHandler.class }) })
mybatis 攔截器好像只能使用注解,而且對於接口Executor,method只定義了update,query,flushStatements,commit,rollback,createCacheKey,isCached,clearLocalCache,deferLoad,getTransaction,close,isClosed這幾個方法,沒有delete和insert方法。
具體詳見:
- package org.apache.ibatis.executor;
- import org.apache.ibatis.cache.CacheKey;
- import org.apache.ibatis.mapping.MappedStatement;
- import org.apache.ibatis.reflection.MetaObject;
- import org.apache.ibatis.session.ResultHandler;
- import org.apache.ibatis.session.RowBounds;
- import org.apache.ibatis.transaction.Transaction;
- import java.sql.SQLException;
- import java.util.List;
- public interface Executor {
- ResultHandler NO_RESULT_HANDLER = null;
- int update(MappedStatement ms, Object parameter) throws SQLException;
- List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
- List<BatchResult> flushStatements() throws SQLException;
- void commit(boolean required) throws SQLException;
- void rollback(boolean required) throws SQLException;
- CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds);
- boolean isCached(MappedStatement ms, CacheKey key);
- void clearLocalCache();
- void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key);
- Transaction getTransaction();
- void close(boolean forceRollback);
- boolean isClosed();
- }
當我疑惑為什么mybatis沒有在insert和delete的時候攔截呢?
看到了mybatis googleCode上的issue16。
Issue 16: | Update interceptor (plugin) fires for inserts |
- Reporter: Eli Kizhnerman
- The iBatis plugin does not seem to be resolving the target methods to
- intercept properly. An interceptor that is defined to intercept only
- updates is also executed on inserts.
- I have the following definition:
- @Intercepts({@Signature(
- type=Executor.class,
- method="update",
- args={MappedStatement.class,Object.class})})
- public class UpdateInterceptor implements Interceptor {
- ...
- }
- In Plugin.invoke you have the following code:
- Set<Method> methods = signatureMap.get(method.getDeclaringClass());
- if (methods != null && methods.contains(method)) {
- return interceptor.intercept(new Invocation(target, method, args));
- }
- DefaultSqlSession.insert internally calls an update method:
- public int insert(String statement, Object parameter) {
- return update(statement, parameter);
- }
- I suspect that the Method that is being passed to plugin.invoke is actually
- the update method and therefore the interceptor is executed.
原來在DefaultSqlSession的insert,delete方法也是調用了update方法。
- public int insert(String statement, Object parameter) {
- return update(statement, parameter);
- }
- public int delete(String statement, Object parameter) {
- return update(statement, wrapCollection(parameter));
- }
mybatis太不厚道了,它的文檔也沒有具體的說明。
有人提出這是個bug,不過mybatis沒有承認。
- Clinton Begin added a comment - 10/Dec/09 03:58 PM
- Executor only has update and query methods. Thus inserts and deletes are also
- considered updates. It sounds like to do what you want, we need another interception
- point, at the session level. You can do so right now with a proxy class between the
- SqlSession interface and the default implementation.
- [ Show » ]
- Clinton Begin added a comment - 10/Dec/09 03:58 PM Executor only has update and query
- methods. Thus inserts and deletes are also considered updates. It sounds like to do
- what you want, we need another interception point, at the session level. You can do
- so right now with a proxy class between the SqlSession interface and the default
- implementation.
- [ Permalink | Delete | « Hide ]
- Eli Kizhnerman added a comment - 11/Dec/09 12:28 PM
- This is not working the way I expected it but that it is not a bug. I can get what I
- need from the MappedStatement SqlCommandType.
- package cn.dcr.mybatis.util;
- import java.sql.CallableStatement;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import org.apache.ibatis.type.BaseTypeHandler;
- import org.apache.ibatis.type.JdbcType;
- /**自定義typeHandler<br/>
- * 1 插入數據庫,男轉為male
- * 2 查詢,maile轉為男
- * @author Administrator
- *
- */
- public class GenderTypeHandlerCallback extends BaseTypeHandler<String> {
- private static final String R_FEMALE = "女";
- private static final String R_MALE = "男";
- private static final String FEMALE = "female";
- private static final String MALE = "male";
- @Override
- public String getNullableResult(CallableStatement cs, int columnIndex)
- throws SQLException {
- return cs.getString(columnIndex);
- }
- @Override
- public String getNullableResult(ResultSet rs, String columnName)
- throws SQLException {
- String t = rs.getString(columnName);
- return converSex(t);
- }
- @Override
- public void setNonNullParameter(PreparedStatement preparedStatement, int i,
- String str, JdbcType jdbcType) throws SQLException {
- preparedStatement.setString(i, saveValueToDb(str));
- }
- /**插入數據庫
- * @param value
- * @return
- */
- private String saveValueToDb(String value) {
- if (value.equals(R_FEMALE)) {
- return FEMALE;
- } else if (value.equals(R_MALE)) {
- return MALE;
- } else {
- throw new IllegalArgumentException("數據庫異常!" + value);
- }
- }
- /** 從數據庫讀出
- * @param value
- * @return
- */
- private String converSex(String value){
- if (value.equals(FEMALE)) {
- return R_FEMALE;
- } else if (value.equals(MALE)) {
- return R_MALE;
- } else {
- throw new IllegalArgumentException("數據庫異常!" + value);
- }
- }
- }
在自定義typeHandler的getNullableResult方法中調整自己的結果集,可以說是在sql執行后,IOC的理論叫后置通知,interceptor應該是前置通知。
- @Override
- public String getNullableResult(ResultSet rs, String columnName)
- throws SQLException {
- String t = rs.getString(columnName);
- return converSex(t);
- }
在typeHandler的setNonNullParameter,應該是參數傳入前轉換參數的功能,但是實際操作中沒有被調用,不知道為什么。
- @Override
- public void setNonNullParameter(PreparedStatement preparedStatement, int i,
- String str, JdbcType jdbcType) throws SQLException {
- preparedStatement.setString(i, saveValueToDb(str));
- }
以上是對mybatis 的切入點的實踐。總體感覺和struts2的攔截器比,還有差距,至少我理解struts2的攔截器比理解它的要快。