2015年8月22日 星期六

攔截器 Mybatis3.x(十一)

攔截器就是直接某個動作時,攔截下來做某件事,和PL/SQL的TRIGGER類似
先不管mybatis的設定,先寫個main method,注意內部類別:
public static void main(String[] args) {
    List<String> list = (List<String>) new MyInterceptor()
            .plugin(new ArrayList<>());
    list.add(0, "aaa");
}

@Intercepts(value = { @Signature(args = { int.class, Object.class }, method = "add", type = List.class) })
private static class MyInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("intercept");
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        System.out.println("plugin");
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        System.out.println("setProperties");
    }
}

結果:
plugin
intercept

.args是小括弧的參數
.只要執行了add方法,就會攔截
.setProperties會先執行,但目前還沒寫,再來是plugin method,最後是intercept method
.如果想攔截其他方法,但沒有參數,就寫args = {}
.只要設定有錯,就會拋找不到方法的錯誤訊息

※先用Mybatis3.x(九)的例子,可以run再說

由於我Mybatis3.x(九)的程式碼不見了,只好再做一次了,這一次做不一樣的好了
CREATE TABLE DEPT (
    DEPTNO NUMBER NOT NULL, 
    DNAME VARCHAR2(255 BYTE), 
    LOC VARCHAR2(255 BYTE), 
    CONSTRAINT DEPT_PK PRIMARY KEY(DEPTNO)
);
INSERT INTO DEPT (DEPTNO,DNAME,LOC) VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO DEPT (DEPTNO,DNAME,LOC) VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO DEPT (DEPTNO,DNAME,LOC) VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO DEPT (DEPTNO,DNAME,LOC) VALUES (40, 'OPERATIONS', 'BOSTON');

vo類,故意和資料庫取不一樣的名字
public class Department {
    private Integer deptno;
    private String dname;
    private String loc;
    //setter/getter...
}

DAO:
public interface IDepartmentDAO {
    @Insert("INSERT INTO DEPT(DEPTNO, DNAME, LOC) VALUES (#{deptno}, #{dname}, #{loc})")
    public boolean insert(Department vo);

    @Select("SELECT DEPTNO, DNAME, LOC FROM DEPT")
    public List<Department> findAll();
}

mybatis-config.xml最後要加這一段,有四種方式,可參考Mybatis3.x(九)
<mappers>
    <mapper class="dao.IDepartmentDAO"/>
</mappers>

測試類:
SqlSession sqlSession = MybatisUtil.getSession();

//查詢
IDepartmentDAO dao = sqlSession.getMapper(IDepartmentDAO.class);
Iterator<Department> iter = dao.findAll().iterator();
while (iter.hasNext()) {
    Department dept = iter.next();
    System.out.println("getDeptno=" + dept.getDeptno());
    System.out.println("getDname=" + dept.getDname());
    System.out.println("getLoc=" + dept.getLoc());
    System.out.println("=========================");
}

//新增
Department dept2 = new Department();
dept2.setDeptno(50);
dept2.setDname("MONEY");
dept2.setLoc("FRANCH");
IDepartmentDAO dao2 = sqlSession.getMapper(IDepartmentDAO.class);
System.out.println(dao2.insert(dept2));

sqlSession.commit();
MybatisUtil.closeSession();

都可以run後,再加攔截器的程式碼

※攔截器

有兩個地方要加
mybatis-config.xml加這一段,注意順序,錯誤會有提示
<plugins>
    <plugin interceptor="plugin.MyInterceptor">
        <property name="param1" value="abc" />
        <property name="param2" value="123" />
    </plugin>
</plugins>

繼承Interceptor的類別:
@Intercepts(value = {
        @Signature(args = { MappedStatement.class, Object.class,
                RowBounds.class, ResultHandler.class }, method = "query", type = Executor.class),
        @Signature(args = { Connection.class }, method = "prepare", type = StatementHandler.class) })
public class MyInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object result = invocation.proceed();
        System.err.println("result=" + result);
        return result;
    }

    @Override
    public Object plugin(Object target) {
        System.err.println("target=" + target);
        return Plugin.wrap(target, this);
    }

    // 取得properties,設定在mybatis-config.xml
    @Override
    public void setProperties(Properties properties) {
        String param1 = properties.getProperty("param1");
        String param2 = properties.getProperty("param2");
        System.err.println("param1 = " + param1);
        System.err.println("param2 = " + param2);
    }
}

官方提供四種支援如下:
.org.apache.ibatis.executor.Executor
.org.apache.ibatis.executor.parameter.ParameterHandler
.org.apache.ibatis.executor.resultset.ResultSetHandler
.org.apache.ibatis.executor.statement.StatementHandler
其中StatementHandler又有兩個實作類別
BaseStatementHandler(抽象)和RoutingStatementHandler
BaseStatementHandler又有三個兒子
CallableStatementHandler:處理CallableStatement
PreparedStatementHandler:處理PreparedStatement
SimpleStatementHandler:處理Statement

.第一個Signature針對查詢,主要用
abstract <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)

.第二個Signature有連資料庫就在呼叫方法之前攔截,所以增刪改查都OK
abstract Statement prepare(Connection connection)

.測試時,result有印出來才表示有成功攔截
.使用這些方法時,我是理解出來的,因為官方網站的API,都沒寫註解,原始碼我也看不太懂

沒有留言:

張貼留言