TestNG 监听器 ITestListener

澳门新浦京娱乐游戏 4

RelProxy 意在通过下列三种艺术加强开采功能:

Mybatis的前身是iBatis,iBatis原本正是apache的三个开源项目,二〇〇八年该项目有apache迁移到了google
code,并更名字为MyBatis。

能够在生养情状下匡正客商代码,而没有必要再一次加载整个应用。

实战 TestNG 监听器

TestNG 是一款被周围选取的自动化测量检验框架。TestNG 监听器是 TestNG
中的一些接口,通这一个接口可感到 TestNG
提供定制化的功能。本文是一篇辅导读者怎么样接收 TestNG
监听器的篇章。文章还对 TestNG
的两种监听器举行了逐条介绍,之后经过代码实例向读者体现了什么样运用部分
TestNG 监听器。

0澳门新浦京娱乐游戏 1 评论


锐,
软件程序猿, IBM

2015 年 1 月 26 日

  • 澳门新浦京娱乐游戏 2内容

澳门新浦京娱乐游戏 3

在 IBM Bluemix 云平台上支出并布署您的下一个接收。

起头你的试用

  1. 简介

加强费用成效,制止花费过多的时光加载应用且对品质不会有震慑。

TestNG 简介

TestNG 是一个开源的自动化测量检验框架,其灵感来源于 JUnit 和
NUnit,但它引入了有个别新效用,使其功用更苍劲,更便于使用。TestNG
的设计目的是能够被用于开展各连串型测量试验:单元测试、成效测量检验,端到端测量试验、集成测量检验,等等。NG
是 Next Generation
的简写,表示下一代,意在象征其产生的指标是要胜过当前具备测量试验框架。TestNG
雷同于 JUnit(极其是 JUnit 4),但它不是 JUnit
的增加,而是独立的全新设计的框架。TestNG 的创建者是 塞德里克Beust(Cedric·博伊斯特)。

TestNG 好似下特点:

  • 支撑 Java 注释作用
  • 测验运维在大肆大的线程池中,而且有多样周转战略可供接收(全部测量试验方法运转在温馨的线程中、每一种测量试验类多个线程,等等)。
  • 线程安全
  • 灵活的测量检验配置
  • 援助数据驱动测量检验(通过 @DataProvider 注释)
  • 支撑参数化
  • 无敌的运转模型(不再动用 TestSuite)
  • 有多种工具和插件扶持(Eclipse, IDEA, Maven, 等等)
  • 内嵌 BeanShell 以越发增长灵活性
  • 暗中认可提供 JDK 的周转时和日志效率
  • 提供应用服务器测验注重的艺术

 

回页首

MyBatis帮忙普通SQL查询,存款和储蓄进程和高档映射的名特别减价持久层框架,解除了大致具有的JDBC代码和参数的手动设置甚至结果集的找出。MyBatis可以利用XML或然申明用于配置和照耀,将接口和JavaBean映射成数据库的笔录。

四个指标都须要在你的使用中扩展一些 RelProxy
代码,注册成一种标准的监听、回调形式。这是一种“侵入”的点子。

TestNG 监听器概述

就算 TestNG
的暗中同意配置已经提供了重重有力的效应和灵活的选项,可是没有一种方案能够解决全部的标题。在实际上利用中,大家多多少少会意识
TestNG
自带的机能不大概满意我们的一些事实上要求,特别是关于测量检验方法运行的一言一动、报表以至通报功能。当时,大家就须求使用
TestNG 的监听器定制额外的效率以满意我们的急需。

以下是 TestNG 提供的两种监听器:

  • IAnnotationTransformer
  • IAnnotationTransformer2
  • IHookable
  • IInvokedMethodListener
  • IMethodInterceptor
  • IReporter
  • ISuiteListener
  • ITestListener

纵然名字叫监听器,但实质上它们只是一些预订义的 Java
接口。顾客创设那些接口的得以达成类,并把它们投入到 TestNG 中,TestNG
便会在测量检验运维的差异任何时候调用这个类中的接口方法。接下来,大家种种介绍
TestNG 中的每个监听器。

每多少个MyBatis的应用程序都是贰个SqlSessionFactory对象的实例为基本。SqlSessionFactory对象的实例能够通过SqlSessionFactoryBuilder对象来收获,SqlSessionFactoryBuilder对象足以从XML配置文件或从Configuration类获得。比如:

假设你是一名Java 框架或独立 Java 通用服务模块的开垦者,能够将 RelProxy
Java
嵌入到你的框架中,那样能透明地为框架的顶峰客商提供代码自动加载作用,只要求实行部分必不可缺的配置,而没有必要调用
RelProxy API。

IAnnotationTransformer

多数状态下,在运维时我们没有必要转移源代码中定义的笺注,但不时候供给那样做。那时,大家就供给利用
IAnnotationTransformer 监听器。IAnnotationTransformer 只能用来校订 @Test
注释,若是需求修改其余 TestNG 的解说(比方,@DataProvider, @Factory 以至@Configuration),要求使用 IAnnotationTransformer2
监听器。IAnnotationTransformer 须求贯彻 transform 方法,其艺术签字如下:

void transform(ITest annotation, Class testClass, Constructor testConstructor, Method testMethod);

annotation 代表就是为 testMethod 定义的 @Test 注释。调用其艺术能够改过@Test 注释属性。例如,上边包车型地铁代码在运营时将质量 enabled 改为 false
进而禁止使用了脚下的测量试验方法。

annotation.setEnabled(false);
String resource ="com/alvinliang/mybatis/mybatis-config.xml";
InputStreamis= Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =newSqlSessionFactoryBuilder().build(is);

对利用 Java 版的 RelProxy,有二种 API 可供调用:

IAnnotationTransformer2

前文已波及 IAnnotationTransformer2 监听器是用来在运作时校勘除 @Test
以外的 TestNG 的注释。上面是该监听器须要兑现的艺术。

void transform(IConfigurationAnnotation annotation, java.lang.Class testClass, 
 java.lang.reflect.Constructor testConstructor,
 java.lang.reflect.Method testMethod)
void transform(IDataProviderAnnotation annotation, java.lang.reflect.Method method)
void transform(IFactoryAnnotation annotation, java.lang.reflect.Method method)

可知,如今独有 @Configuration,@DataProvider 以致 @Factory
注释能够通过该监听器改过。而其实,@Configuration
在最新版本中已不被引入应用,需用 @BeforeSuite,@AfterSuite 等注释代替。

XML配置文件蕴涵了对MyBatis系统的着力设置,有获取数据库连接实例的数据源和垄断(monopolyState of Qatar工作约束和决定作业微电脑。详细内容前面会讲,这里给出一个简洁明了示例:

JProxy 及其相关类:主若是静态方法

IHookable

IHookable 监听器提供了相仿与面向方面编制程序(AOP)中的 Around Advice
的意义。它在测量试验方法实施前后提供了切入点,进而使客商能够在测验方法运营前后注入特定的功效。举例,客商能够在近年来测量试验方法运行前加入特定的证实逻辑以调节测量检验方法是或不是运转还是跳过,以致覆盖测量试验方法的逻辑。上边是
IHookable 监听器要求贯彻的章程具名。

void run(IHookCallBack callBack, ITestResult testResult)

如要运营原始测量试验方法逻辑,要求调用 runTestMethod 方法。

callBack.runTestMethod(testResult);
<?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">
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="com/alvinliang/mybatis/BlogMapper.xml"/>
  </mappers>
</configuration>

Java 脚本 API:基于接口

IInvokedMethodListener

澳门新浦京娱乐游戏,与 IHookable 肖似,IInvokedMethodListener
提供了近乎与面向方面编程(AOP)中的 Before Advice 和 After Advice
的功能。它同意顾客在这两天测量检验方法被试行前和实施后注入特定的逻辑,比如,可以步入日志方法。客户供给落实的形式如下。

void afterInvocation(IInvokedMethod method, ITestResult testResult) 
void beforeInvocation(IInvokedMethod method, ITestResult testResult)

还大概有不菲能够配备,上边提议了最要紧的某个。environment成分体里带有对事务管理和连接池的景况陈设。mapppers成分包括了具有mapper映射器,那些mapper的xml文件包涵了SQL代码和照耀定义音讯。
详见安插,见Mybatis官网

其次种格局更符合将 RelProxy 嵌入到你的 Java
框架中,这种措施是基于接口的,在你的 API 中没有必要揭穿公共 RelProxy
类,因为在框架中会实施运维程序。笔者将动用比较简单的
API:JProxyScriptEngineFactory.create(卡塔尔国。

IMethodInterceptor

TestNG
运行未来,第一件要做的事情是将享有的测验方法分成两类:一类是逐个运维的测量检验方法;一类是绝非一定运维顺序的测量试验方法。

TestNG 通过 @Test 注释中的 dependsOnGroups 和 dependsOnMethods
使客户能够定义测量检验方法之间的依赖关系。这种信任关系也就调控那几个测量检验方法必得按着怎么着的次第运转,那正是第一类。除此以外的正是第二类。对于第二类中的测验方法,固然默认TestNG
会尝试用类主力它们分组,可是理论上,它们的运营顺序是自由的,以至每一趟运维的各类都只怕不一样。由此为了使顾客全数对第二类测量检验方法更加大的调整权,IMethodInterceptor
监听器发生了。客商要完成的法子如下。

java.util.List<IMethodInstance> intercept(java.util.List<IMethodInstance> methods, ITestContext context)

intercept
方法在富有测验方法被分类一下后以至具备测验方法被施行前被调用。全数的测量检验方法将按部就班intercept 重返值列表中的顺序被施行。因而,顾客在 intercept
方法中得以对列表举办改造,举例重新排序,甚至增添大概减小测量检验方法。

2.完整流程

JProxyScriptEngine 的成效与 Jproxy
相符,也正是说具有类似的艺术。只是这种情景下,只必要动用接口。

IReporter

TestNG
提供了暗中同意的测量检验报表。但假诺客商期待有不相同格式的测验报表,就须求动用
IReporter 监听器。IReporter 监听器独有一个方式要求落到实处。

void generateReport(java.util.List<XmlSuite> xmlSuites, java.util.List
<ISuite> suites, java.lang.String outputDirectory)

该方式在具备测量试验方法试行落成后被调用,通过遍历 xmlSuites 和 suites
能够得到具备测量试验方法的音信以至测验结果。outputDirectory
是私下认可的测验报表生成路线,当然你能够内定其余路线生成报表。

(1) 加载配置并早先化

二个粗略的例证是上行下效怎样安置 RelProxy 的最佳点子。这几个例子是 RelProxy
的演示货仓中包蕴的 RelProxyBuiltin(relproxy_builtin_ex
项目中)。它定义了四个监听器来得以完结登记客商端的代码,多个监听器展现选项(option),另一个实行选择的一言一行。

ISuiteListener

ISuiteListener 相同于 IInvokedMethodListener,区别是
IInvokedMethodListener 针没有错是测量试验方法,而 ISuiteListener
针对的是测验套件。ISuiteListener
使客商有机遇在测量检验套件发轫实施以至试行完结之后嵌入自身的逻辑。该监听器要求落到实处的点子如下。

void onFinish(ISuite suite) 
void onStart(ISuite suite)

接触条件:加载配置文件,将SQL配置文件加载成多少个个MappedStatement对象。
至于MappedStatement是Mybatis的多少个首要类,详细见

其一Mini框架和演示使用 NetBeans 和 Maven 支付到位。

ITestListener

假诺要在测验方法试行成功、退步也许跳过时钦点差别后续展现,能够因此IInvokedMethodListener 达成,可是更为便利的形式是利用 ITestListener
监听器。ITestListener 监听器供给兑现的法子中包蕴如下三个。

void onTestFailure(ITestResult result) 
void onTestSkipped(ITestResult result) 
void onTestSuccess(ITestResult result)

除了以上多个措施,ITestListener 还注脚了别的一些办法,大家能够自行查阅
TestNG Javadoc 了然细节。

另外,TestListenerAdapter 已经完结ITestListener,况兼提供了一些使得的点子,比方分别得到具备成功退步跳过二种测量试验结果的测验方法的主意,並且ITestListner 中有众多格局而 TestListenerAdapter
已交付了默许达成。因而,世袭 TestListener艾达pter
后,便只需关心要求改革的措施。

 

回页首

(2) 选取调用需要

有五个包:

监听器的采用方法

前文已讲过,监听器的编码进度正是概念五个 Java
类完结监听器接口。上边简要介绍一下监听器的两种接受情势。

接触条件:调用MyBatis提供的API

com.innowhere.relproxy_builtin_ex :Mini框架。子包
com.innowhere.relproxy_builtin_ex.impl 只包涵多少个非公共的类。

在 testng.xml 中使用 TestNG 监听器

TestNG 通过 testng.xml 配置全部的测量试验方法。Testng.xml 提供了 listeners
和 listener 标签用来增多自定义的监听器。上面示范的是本文示例代码中含有的
testng.xml 文件。

<suite name="TestNGSample">
    <listeners>
        <listener class-name="listeners.OSFilter" />
        <listener class-name="listeners.ProgressTracker" />
    </listeners>
    <test name="ProgressTracker Demo">
        <classes>
            <class name="tests.SampleTest" />
        </classes>
    </test>
</suite>

流传参数:为SQL的ID和传播参数对象

com.innowhere.relproxy_builtin_ex_main :一个简短的使用示例。

在源代码中选择 TestNG 监听器

透过 @Listeners 注释,可以直接在 Java 源代码中增添 TestNG
监听器。下边示范的是本文示例代码中如何使用 @Listeners 注释。

@Listeners({ OSFilter.class, ProgressTracker.class })
public class SampleTest {

    @Test(groups = { OSNames.OS_LINUX })
    public void test1() {
        sleep(5000);
        System.out.println(">>>test1");
    }

值得注意的是:

  • 在 @Listeners 中加多监听器跟在 testng.xml
    增添监听器同样,将被利用到总体育项目检查评定试套件中的测验方法。借使急需调控监听器的应用范围(比方加多的监听器仅使用于有些测验测试类大概某个测量试验方法),则必得在监听器类中编辑适当的判别逻辑。
  • 在 @Listeners 中增添监听器跟在 testng.xml
    加多监听器的不相同之处在于,它不可能加多 IAnnotationTransformer 和
    IAnnotationTransformer2
    监听器。原因是因为这两种监听器必得在更早的阶段增多到 TestNG
    中技艺实施修正注释的操作,所以它们只好在 testng.xml 增加。
  • TestNG 对充裕的监听器不做去重推断。因而,要是 testng.xml
    和源代码中加多了扳平的监听器,该监听器的方法会被调用五次。有关那一点,大家能够因而运营本文附带的演示代码包中
    testng.xml 验证。由此,切记,不要通过各种措施重新扩充监听器。

管理进度:将号召传递给下层的呼吁的拍卖层进行拍卖。

Mini框架(公共类和接口):

通过 ServiceLoader 使用 TestNG 监听器

Java SE 6 早先提供了
ServiceLoader。它能够扶持顾客查找、加载和使用服务提供程序,进而在不须求改革原有代码的情状下任性地扩展指标应用程序。通过
ServiceLoader 的格局选取 TestNG 监听器,总之,正是成立二个 jar
文件,里面含有 TestNG 监听器的兑现类已经 瑟维斯Loader
必要的布置音讯,并在运行 TestNG 时把该 jar
文件加载到类路线中。具体步骤请查阅 TestNG 官方文书档案。那样做的平价是:

  1. 能够轻便地与其余人分享 TestNG 监听器。
  2. 当有相当多 testng.xml 文件时,不必要重新把监听器加多到每一种文件中。

(3) 管理操作乞请

RelProxyBuiltinRoot.java

透过命令行使用 TestNG 监听器

经过命令行使用 TestNG
监听器,须求在命令行中参与”-listener”参数。如要钦赐多少个监听器,用逗号分隔。上边是叁个调用的示范。

java org.testng.TestNG -listener MyListener testng1.xml [testng2.xml testng3.xml ...]

接触条件:API接口层传递央求过来

package com.innowhere.relproxy_builtin_ex;
import com.innowhere.relproxy_builtin_ex.impl.RelProxyBuiltinImpl;
public class RelProxyBuiltinRoot
{
    private final static RelProxyBuiltinImpl SINGLETON = new RelProxyBuiltinImpl();
    public static RelProxyBuiltin get()
    {
        return SINGLETON;
    }
}

通过 IDE 使用 TestNG 监听器

TestNG 在各类 IDE 中都有插件援救,比方 Eclipse 和 IDEA。因为最后 IDE
也是以命令行的方法调用 TestNG,因而在 IDE
中也是经过抬高“-listener”参数使用 TestNG 监听器。下图以 Eclipse
为例示范了 TestNG 监听器的配置格局。

盛传参数:为SQL的ID和散布参数对象

RelProxyBuiltin.java

图 1. Eclipse 中 TestNG 监听器的配备

澳门新浦京娱乐游戏 4

除此而外,ANT 跟 Maven 也都有对应 Task 和插件运转 TestNG
测量试验,遵照相应的文书档案配置监听器就可以,这里便不一一赘述。

 

回页首

管理进度:

package com.innowhere.relproxy_builtin_ex;
import com.innowhere.relproxy.jproxy.JProxyScriptEngine;
import java.io.InputStream;
import java.io.PrintStream;
public interface RelProxyBuiltin
{
    public JProxyScriptEngine getJProxyScriptEngine();
    public void addOutputListener(OutputListener listener);
    public void removeOutputListener(OutputListener listener);
    public int getOutputListenerCount();
    public void addCommandListener(CommandListener listener);
    public void removeCommandListener(CommandListener listener);
    public int getCommandListenerCount();
    public void runLoop(InputStream in,PrintStream out);
}

示例

本文提供了五个示范的监听器的兑现,它们各自达成了动态测量检验方法过滤和测量检验进度追踪效能。

(A卡塔尔国依据SQL的ID查找对应的MappedStatement对象。

OutputListener.java

动态测验方法过滤监听器(listeners.OSFilter)

TestNG
提供了分组特性,但它的局限是组名必需是静态的。假使,现在有点测量检验方法,部分适用于
Linux 和 Windows,部分仅适用于那么些。通过默许的 TestNG
分组个性,大约要定义四个 testng.xml
文件,内定分裂的组名,而且在内定测量试验应用时要小心不要把陈设与情形的应拌和错。

演示代码中的监听器接纳的法子是在各种测量试验方法执行前,动态获取操作系统类型新闻并将其与
@Test
注释中定义的操作系统相比以调整哪些测量检验方法应该运转。那样便细心了上述配置的分神。

只要只是为了跳过不对劲的测验方法,也足以选择 IInvokedMethodListener
监听器。但因为该监听器还要总括全体传入的测量试验方法以至被忽略的测量检验方法的数量,所以选取了
IMethodInterceptor。值得注意的是,在 TestNG
的生命周期中,IMethodInterceptor 监听器的 intercept
方法其实会被调用三次。为了防止代码被再一次实践,本示例代码将回来的测量试验方法列表定义为成员变量,并透过判定该成员变量是还是不是为
null 决定是或不是实施过滤逻辑。

(B卡塔尔国依据传入参数对象拆解剖析MappedStatement对象,获得终极要实行的SQL和试行传入参数。

package com.innowhere.relproxy_builtin_ex;
import java.io.PrintStream;
public interface OutputListener
{
    public void write(PrintStream out);
}

测验进程追踪监听器(listeners.ProgressTracker)

自动化单元测量检验和 API 测验常常运营极快,然则 UI
测验运维很慢。对于长日子运作的测量试验,大家平常想要知道当前正值周转的测验方法名称甚至预测剩余实践时间。那就是该监听器完毕的意义。

鉴于须求经过总结每种测量试验方法的运作时刻来预估剩余推行时间,该监听器选取了
IInvokedMethodListener。其它,预估剩余实施时间还亟需了然一切测量试验套件要实行的测量试验方法的数量,单单使用
IInvokedMethodListener 不恐怕赢得该信息,由此,该监听器通过
listeners.OSFilter
总计全体要试行的测验方法的数码。预估的算法是根据已经使用的岁月和进行的测量检验方法数量总结出各类测量试验方法的平分实践时间,然后用该平均时间乘以未进行的测量试验方法数目,进而得出预估剩余时间。该算法的标题在于,当种种测验方法试行时间距离极大何况测量试验方法数目非常少时,该方法春在非常大的相对误差,由此该时间只好当作参照。

(CState of Qatar获取数据库连接,依据获得的尾声SQL语句和实行传入参数到数据库试行,并收获实行结果。

CommandListener.java

什么样运转示例代码

以身作则代码是二个 Eclipse 项目导出的压缩文件,由此只要在 Eclipse
中导入该公文并安装 TestNG 的 Eclipse 插件就能够运行。

tests.SampleTest 是一个示范的 TestNG 测验类,该类中定义了 5
个测量试验方法:二个钦定为仅运转在 Linux,四个钦命为运转在 Linux 和
Windows,其余五个钦点为仅运营在 Windows。为简易时期,测量试验方法体仅用
Thread.sleep()模拟。该类中已增添了 @Listeners 注释,将此类作为 TestNG
测量试验运转,将获得如下的平常输出(此为 Linux 下的出口结果)。

[TestNG] Running:
 /tmp/testng-eclipse-814456884/testng-customsuite.xml

Ignored Test Methods: [test4(tests.SampleTest), test5(tests.SampleTest)]
[Begin] test1(SampleTest) 
>>>test1
[Progress]33% (1/3) , Elapsed:00:00:05, Estimated Time Remaining:00:00:10
[End] test1(SampleTest): Passed

[Begin] test2(SampleTest) 
>>>test2
[Progress]67% (2/3) , Elapsed:00:00:08, Estimated Time Remaining:00:00:04
[End] test2(SampleTest): Passed

[Begin] test3(SampleTest) 
>>>test3
[Progress]100% (3/3) , Elapsed:00:00:10, Estimated Time Remaining:00:00:00
[End] test3(SampleTest): Passed

PASSED: test1
PASSED: test2
PASSED: test3

===============================================
 Default test
 Tests run: 3, Failures: 0, Skips: 0
===============================================


===============================================
Default suite
Total tests run: 3, Failures: 0, Skips: 0
===============================================

[TestNG] Time taken by org.testng.reporters.JUnitReportReporter@5a31442c: 12 ms
[TestNG] Time taken by org.testng.reporters.EmailableReporter@64a0401: 5 ms
[TestNG] Time taken by org.testng.reporters.XMLReporter@a98e9456: 20 ms
[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@276fc2ae: 77 ms
[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 1 ms
[TestNG] Time taken by org.testng.reporters.jq.Main@6517ab3c: 63 ms

自己要作为楷模遵守规则代码包中还包涵有三个 testng.xml 文件。testng.xml
中也加多了监听器,因而运转 testng.xml
将看见重复的测验进程音信输出。需删除 tests.SampleTest 中 @Listeners
注释能力使 testng.xml 平常运作测验。

 

回页首

(DState of Qatar依照MappedStatement对象中的结果映射配置对获取的试行结果实行转变管理,并拿到终极的管理结果。

package com.innowhere.relproxy_builtin_ex;
import java.io.PrintStream;
public interface CommandListener
{
    public void execute(String command,String input,PrintStream out);
}

结束语

透过本文的牵线,咱们可以精晓到,TestNG 提供的有余监听器接口使 TestNG
具有强盛的扩充性。选拔什么监听器接口需依附实际必要而定。在出手开荒和谐的
TestNG
监听器以前,不要紧先找找一下网络,兴许其余顾客已经付出了相像的意义。举例,ReportNG
正是一款相比成熟的用于压实 TestNG 报表功效的插件。

(EState of Qatar释放连接资源。

现行反革命看一下兑现细节,该类演示了如何轻松地内嵌 RelProxy:

(4)重返管理结果将最后的管理结果重临。

RelProxyBuiltinImpl.java

3.意义框架

package com.innowhere.relproxy_builtin_ex.impl;
import com.innowhere.relproxy.jproxy.JProxyScriptEngine;
import com.innowhere.relproxy.jproxy.JProxyScriptEngineFactory;
import com.innowhere.relproxy_builtin_ex.CommandListener;
import com.innowhere.relproxy_builtin_ex.OutputListener;
import com.innowhere.relproxy_builtin_ex.RelProxyBuiltin;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.LinkedHashSet;
import java.util.Scanner;
public class RelProxyBuiltinImpl implements RelProxyBuiltin
{
    protected JProxyScriptEngine jProxyEngine = null;
    protected LinkedHashSet<OutputListener> outListeners = new LinkedHashSet<OutputListener>();
    protected LinkedHashSet<CommandListener>  commandListeners = new LinkedHashSet<CommandListener>();
    @Override
    public JProxyScriptEngine getJProxyScriptEngine()
    {
        if (jProxyEngine == null) jProxyEngine = (JProxyScriptEngine)JProxyScriptEngineFactory.create().getScriptEngine();
        return jProxyEngine;
    }
    public JProxyScriptEngine getJProxyScriptEngineIfConfigured()
    {
        if (jProxyEngine == null || !jProxyEngine.isEnabled())
            return null;
        return jProxyEngine;
    }
    @Override
    public void addOutputListener(OutputListener listener)
    {
        JProxyScriptEngine jProxy = getJProxyScriptEngineIfConfigured();
        if (jProxy != null)
        {
            listener = jProxy.create(listener,OutputListener.class);
        }
        outListeners.add(listener);
    }
    @Override
    public void removeOutputListener(OutputListener listener)
    {
        JProxyScriptEngine jProxy = getJProxyScriptEngineIfConfigured();
        if (jProxy != null)
        {
            listener = jProxy.create(listener,OutputListener.class);
        }
        outListeners.remove(listener);
    }
    @Override
    public int getOutputListenerCount()
    {
        return outListeners.size();
    }
    @Override
    public void addCommandListener(CommandListener listener)
    {
        JProxyScriptEngine jProxy = getJProxyScriptEngineIfConfigured();
        if (jProxy != null)
        {
            listener = jProxy.create(listener,CommandListener.class);
        }
        commandListeners.add(listener);
    }
    @Override
    public void removeCommandListener(CommandListener listener)
    {
        JProxyScriptEngine jProxy = getJProxyScriptEngineIfConfigured();
        if (jProxy != null)
        {
            listener = jProxy.create(listener,CommandListener.class);
        }
        commandListeners.remove(listener);
    }
    @Override
    public int getCommandListenerCount()
    {
        return commandListeners.size();
    }
    @Override
    public void runLoop(InputStream in,PrintStream out)
    {
        Scanner scanner = new Scanner(in);
        while(true)
        {
            out.print("Enter phrase:");
            String input = scanner.nextLine();
            out.println("Command list:");
            for(OutputListener listener : outListeners)
                listener.write(out);
            out.print("Enter command (or quit):");
            String command = scanner.nextLine();
            if ("quit".equals(command))
                break;
            for(CommandListener listener : commandListeners)
                listener.execute(command,input,out);
        }
    }
}

Mybatis能够分为三层:

那八个方法能够表达怎样运转 RelProxy Java
引擎,怎么着轻巧地利用指令监听器来注册热加载。

(1)
API接口层:提要求外部使用的接口API,开拓人士能够透过地面API来决定数据库。

RelProxyBuiltinImpl.java (部分)

(2)
数据管理层:肩负具体的SQL查找、SQL剖析、SQL实施和进行结果映射管理等。

  @Override
    public JProxyScriptEngine getJProxyScriptEngine()
    {
        if (jProxyEngine == null) jProxyEngine = (JProxyScriptEngine)JProxyScriptEngineFactory.create().getScriptEngine();
        return jProxyEngine;
    }
    public JProxyScriptEngine getJProxyScriptEngineIfConfigured()
    {
        if (jProxyEngine == null || !jProxyEngine.isEnabled())
            return null;
        return jProxyEngine;
    }
    @Override
    public void addOutputListener(OutputListener listener)
    {
        JProxyScriptEngine jProxy = getJProxyScriptEngineIfConfigured();
        if (jProxy != null)
        {
            listener = jProxy.create(listener,OutputListener.class);
        }
        outListeners.add(listener);
    }

(3)
根底支撑层:肩负最大旨的效率扶植,包涵三回九转管理、事务管理、配置加载和缓存管理等。

国有措施 RelProxyBuiltin.getJProxyScriptEngine(卡塔尔(قطر‎必得在运行时实践,用于配置 RelProxy。若无配备,RelProxy 就不起功效。

4.简单易行利用

请记住,通过 create(…卡塔尔(قطر‎ 创立的代理对象急需能准确的实践 hashCode(State of Qatar 方法和
equals(Object卡塔尔国方法,监听器集结、监听记录重视那多个章程来分别监听器对象。

先从SqlSessionFactory对象来获取SqlSession的实例,SqlSession对象饱含了对数据库的保有实行SQL操作的不二秘诀。比方:

那是基于调节台的上行下效代码(名称与 JUnit 雷同,但的确不是 JUnit
的测验示例):

SqlSession session = sqlSessionFactory.openSession();
try {  
Blogblog = (Blog) session.selectOne("com.alvinliang.mybatis.BlogMapper.selectBlog", 1);
} finally {  
session.close();
}

Main.java

上面给出映射的SQL语句:

package com.innowhere.relproxy_builtin_ex_main;
import com.innowhere.relproxy.RelProxyOnReloadListener;
import com.innowhere.relproxy.jproxy.JProxy;
import com.innowhere.relproxy.jproxy.JProxyCompilerListener;
import com.innowhere.relproxy.jproxy.JProxyConfig;
import com.innowhere.relproxy.jproxy.JProxyDiagnosticsListener;
import com.innowhere.relproxy.jproxy.JProxyInputSourceFileExcludedListener;
import com.innowhere.relproxy.jproxy.JProxyScriptEngine;
import com.innowhere.relproxy_builtin_ex.CommandListener;
import com.innowhere.relproxy_builtin_ex.RelProxyBuiltin;
import com.innowhere.relproxy_builtin_ex.RelProxyBuiltinRoot;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject;
public class Main
{
    public static void main(String[] args) throws Exception
    {
        new Main();
    }
    public Main()
    {
        // Note: NetBeans Console window works bad (no input) with Maven Test tasks http://stackoverflow.com/questions/3035351/broken-console-in-maven-project-using-netbeans
        // this is why is not a really JUnit test.
        setUp();
        try
        {
            mainTest();
        }
        finally
        {
            tearDown();
        }
        System.exit(0);
    }
    public void setUp()
    {
        URL res = this.getClass().getResource("/"); // .../target/classes/
        // Use example of RelProxy in development time:
        String inputPath = res.getFile() + "/../../src/main/java/";
        if (new File(inputPath).exists())
        {
            System.out.println("RelProxy to be enabled, development mode detected");
        }
        else
        {
            System.out.println("RelProxy disabled, production mode detected");
            return;
        }
        JProxyInputSourceFileExcludedListener excludedListener = new JProxyInputSourceFileExcludedListener()
        {
            @Override
            public boolean isExcluded(File file, File rootFolderOfSources)
            {
                String absPath = file.getAbsolutePath();
                if (file.isDirectory())
                {
                    return absPath.endsWith(File.separatorChar + "relproxy_builtin_ex");
                }
                else
                {
                    return absPath.endsWith(File.separatorChar + Main.class.getSimpleName() + ".java");
                }
            }
        };
        String classFolder = null; // Optional
        Iterable<String> compilationOptions = Arrays.asList(new String[]{"-source","1.6","-target","1.6"});
        long scanPeriod = 1000;
        RelProxyOnReloadListener proxyListener = new RelProxyOnReloadListener() {
            @Override
            public void onReload(Object objOld, Object objNew, Object proxy, Method method, Object[] args) {
                System.out.println("Reloaded " + objNew + " Calling method: " + method);
            }
        };
        JProxyCompilerListener compilerListener = new JProxyCompilerListener(){
            @Override
            public void beforeCompile(File file)
            {
                System.out.println("Before compile: " + file);
            }
            @Override
            public void afterCompile(File file)
            {
                System.out.println("After compile: " + file);
            }
        };
        JProxyDiagnosticsListener diagnosticsListener = new JProxyDiagnosticsListener()
        {
            @Override
            public void onDiagnostics(DiagnosticCollector<JavaFileObject> diagnostics)
            {
                List<Diagnostic<? extends JavaFileObject>> diagList = diagnostics.getDiagnostics();
                int i = 1;
                for (Diagnostic diagnostic : diagList)
                {
                   System.err.println("Diagnostic " + i);
                   System.err.println("  code: " + diagnostic.getCode());
                   System.err.println("  kind: " + diagnostic.getKind());
                   System.err.println("  line number: " + diagnostic.getLineNumber());
                   System.err.println("  column number: " + diagnostic.getColumnNumber());
                   System.err.println("  start position: " + diagnostic.getStartPosition());
                   System.err.println("  position: " + diagnostic.getPosition());
                   System.err.println("  end position: " + diagnostic.getEndPosition());
                   System.err.println("  source: " + diagnostic.getSource());
                   System.err.println("  message: " + diagnostic.getMessage(null));
                   i++;
                }
            }
        };
        RelProxyBuiltin rpbRoot = RelProxyBuiltinRoot.get();
        JProxyScriptEngine engine = rpbRoot.getJProxyScriptEngine();
        JProxyConfig jpConfig = JProxy.createJProxyConfig();
        jpConfig.setEnabled(true)
                .setRelProxyOnReloadListener(proxyListener)
                .setInputPath(inputPath)
                .setJProxyInputSourceFileExcludedListener(excludedListener)
                .setScanPeriod(scanPeriod)
                .setClassFolder(classFolder)
                .setCompilationOptions(compilationOptions)
                .setJProxyCompilerListener(compilerListener)
                .setJProxyDiagnosticsListener(diagnosticsListener);
        engine.init(jpConfig);
        System.out.println("RelProxy running");
    }
    public void tearDown()
    {
        RelProxyBuiltin rpbRoot = RelProxyBuiltinRoot.get();
        JProxyScriptEngine engine = rpbRoot.getJProxyScriptEngine();
        engine.stop();
        System.out.println("RelProxy stopped");
    }
    public void mainTest()
    {
        RelProxyBuiltin rpbRoot = RelProxyBuiltinRoot.get();
        TestListener listener = new TestListener();
        rpbRoot.addOutputListener(listener);
        assertTrue(rpbRoot.getOutputListenerCount() == 1);
        rpbRoot.removeOutputListener(listener);
        assertTrue(rpbRoot.getOutputListenerCount() == 0);
        rpbRoot.addOutputListener(listener);
        CommandListener commandListener = listener.getCommandListener();
        rpbRoot.addCommandListener(commandListener);
        assertTrue(rpbRoot.getCommandListenerCount() == 1);
        rpbRoot.removeCommandListener(commandListener);
        assertTrue(rpbRoot.getCommandListenerCount() == 0);
        rpbRoot.addCommandListener(commandListener);
        rpbRoot.runLoop(System.in,System.out);
    }
    private static void assertTrue(boolean res)
    {
        if (!res) throw new RuntimeException("Unexpected Error");
    }
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.alvinliang.mybatis.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

看一下这段代码:

这里只是给出了叁个简洁明了的例子,在那之中在命名空间“com.alvinliang.mybatis.BlogMapper”中定义了二个名字为“selectBlog”的映射语句,那样它同意你使用完全限制名“com.alvinliang.mybatis.BlogMapper.selectBlog”来调用映射语句。

Main.java (部分)

留心:现在定名空间是必得的,并且命名空间使得接口绑定成为也许,使用命名空间并将它放在合适的Java包空间下,将会让你的代码变得简洁,会在非常长的日子内增加MyBatis的作用。

 URL res = this.getClass().getResource("/"); // .../target/classes/
        // Use example of RelProxy in development time:
        String inputPath = res.getFile() + "/../../src/main/java/";
        if (new File(inputPath).exists())
        {
            System.out.println("RelProxy to be enabled, development mode detected");
        }
        else
        {
            System.out.println("RelProxy disabled, production mode detected");
            return;
        }
        JProxyInputSourceFileExcludedListener excludedListener = new JProxyInputSourceFileExcludedListener()
        {
            @Override
            public boolean isExcluded(File file, File rootFolderOfSources)
            {
                String absPath = file.getAbsolutePath();
                if (file.isDirectory())
                {
                    return absPath.endsWith(File.separatorChar + "relproxy_builtin_ex");
                }
                else
                {
                    return absPath.endsWith(File.separatorChar + Main.class.getSimpleName() + ".java");
                }
            }
        };
  1. 限定和生命周期

咱俩收获并注册应用源代码的根目录,该代码“大概”会被再一次加载。

SqlSessionFactoryBuilder

我们供给破除框架代码,因为那显明不是客商的代码(无需再一次加载)。别的,还索要免去
Main.java 文件,该文件蕴含了测量检验代码,也无需再行加载,独有TestListener.java 类(与 Main.java
在同等文件夹下)需求(必须)重新加载。

本条类能够被实例化,使用和打消。一旦你创建了SqlSessionFactory后,这些类就无需了。由此SqlSessionFactoryBuilder实例的一流范围正是格局范围(约等于当地点法变量)。你能够选取SqlSessionFactoryBuilder来创设七个SqlSessionFactory实例。

最后 TestListener.java 类包蕴五个监听器,CommandListener
的兑现利用无名氏内部类的办法,重要指标是为着演示。

SqlSessionFactory

TestListener.java

假诺被创立,SqlSessionFactory应该在您的接纳试行时期都设有,未有理来管理大概另行创建它。使用SqlSessionFactory的精品执行是在利用运营时期不要再一次创设多次。因而SqlSessionFactory的生命周期是Application范围。超级多方法能够完毕,如单例方式也许静态单例形式。

package com.innowhere.relproxy_builtin_ex_main;
import com.innowhere.relproxy_builtin_ex.CommandListener;
import com.innowhere.relproxy_builtin_ex.OutputListener;
import java.io.PrintStream;
public class TestListener implements OutputListener
{
    @Override
    public void write(PrintStream out)
    {
        out.println("uppercase");
        out.println("lowercase");
    }
    public CommandListener getCommandListener()
    {
        return new CommandListener()
        {
            @Override
            public void execute(String command,String text,PrintStream out)
            {
                if ("uppercase".equals(command))
                    out.println(text.toUpperCase());
                else if ("lowercase".equals(command))
                    out.println(text.toLowerCase());
                else
                    out.println("Unknown command:" + command);
            }
        };
    }
}

SqlSession

先预订义可采纳,然后施行 Main 类。为了校验 RelProxy
是还是不是起效率,能够在不安歇程序的周转的幼功上平添贰个新的可选项“same”。

每一种线程都应该有它本人的SqlSession实例。SqlSession的实例不可能被分享,也是线程不安全的。由此最棒范围应当是request或然method范围。绝对不可以将SqlSession实例的援引坐落于二个类的静态字段以致是实例字段中。也断然不能够将SqlSession实例引用坐落于其余项目标军管范围中,比方Servlet中的HttpSession。倘使你正在接收Web框架,能够思量将SqlSession放在三个和Http
Request对象日常的限量内。下边包车型地铁上行下效就是二个保障SqlSession关闭的基本方式:

@Override
    public void write(PrintStream out)
    {
        out.println("uppercase");
        out.println("lowercase");
        out.println("same");  // NEW
    }
    public CommandListener getCommandListener()
    {
        return new CommandListener()
        {
            @Override
            public void execute(String command,String text,PrintStream out)
            {
                if ("uppercase".equals(command))
                    out.println(text.toUpperCase());
                else if ("lowercase".equals(command))
                    out.println(text.toLowerCase());
                else if ("same".equals(command)) // NEW
                    out.println(text); // NEW
                else
                    out.println("Unknown command:" + command);
            }
        };
    }
}
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {  
session.close();
}

下一篇作品师长管理包涵当前“same”的作为,无需停止调控台应用。

在您的代码中稳固的使用这种格局,将会保证具有的数据库财富都健康的关闭。

ItsNat web 框架大概是率先个应用 RelProxy 技巧的运用(版本 v1.4)。

完整的Example

注意:使用 RelProxy 0.8.7 或更加高的本子,那个本子在放手药方式上做了改进。

**Step1: **Create a Maven project and configure MyBatis
dependencies.

<project xmlns='http://maven.apache.org/POM/4.0.0' 
 xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
 xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 
 http://maven.apache.org/xsd/maven-4.0.0.xsd'>
 <modelVersion>4.0.0</modelVersion>

 <groupId>com.sivalabs</groupId>
 <artifactId>mybatis-demo</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>mybatis-demo</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
     <source>1.6</source>
     <target>1.6</target>
     <encoding>${project.build.sourceEncoding}</encoding>
    </configuration>
   </plugin>
  </plugins>
 </build>

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.10</version>
   <scope>test</scope>
  </dependency>

  <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.1.1</version>
  </dependency>
  <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>5.1.21</version>
             <scope>runtime</scope>
         </dependency>
 </dependencies>
</project>

Step#2: Create the table USER and a Java domain Object User as follows:

CREATE TABLE  user (
  user_id int(10) unsigned NOT NULL auto_increment,
  email_id varchar(45) NOT NULL,
  password varchar(45) NOT NULL,
  first_name varchar(45) NOT NULL,
  last_name varchar(45) default NULL,
  PRIMARY KEY  (user_id),
  UNIQUE KEY Index_2_email_uniq (email_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

package com.sivalabs.mybatisdemo.domain;
public class User 
{
 private Integer userId;
 private String emailId;
 private String password;
 private String firstName;
 private String lastName;

 @Override
 public String toString() {
  return 'User [userId=' + userId + ', emailId=' + emailId
    + ', password=' + password + ', firstName=' + firstName
    + ', lastName=' + lastName + ']';
 }
 //setters and getters 
}

Step#3: Create MyBatis configuration files.
a) Create jdbc.properties file in src/main/resources folder

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-demo
jdbc.username=root
jdbc.password=admin

b) Create mybatis-config.xml file in src/main/resources folder

<?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'>
<configuration>
 <properties resource='jdbc.properties'/>
 <typeAliases>
  <typeAlias type='com.sivalabs.mybatisdemo.domain.User' alias='User'></typeAlias>
 </typeAliases>
 <environments default='development'>
  <environment id='development'>
    <transactionManager type='JDBC'/>
    <dataSource type='POOLED'>    
   <property name='driver' value='${jdbc.driverClassName}'/>
   <property name='url' value='${jdbc.url}'/>
   <property name='username' value='${jdbc.username}'/>
   <property name='password' value='${jdbc.password}'/>
    </dataSource>
  </environment>
  </environments>
  <mappers>
 <mapper resource='com/sivalabs/mybatisdemo/mappers/UserMapper.xml'/>
  </mappers>
</configuration>

Step#4: Create an interface UserMapper.java in src/main/java folder in
com.sivalabs.mybatisdemo.mappers package.

package com.sivalabs.mybatisdemo.mappers;

import java.util.List;
import com.sivalabs.mybatisdemo.domain.User;

public interface UserMapper 
{

 public void insertUser(User user);

 public User getUserById(Integer userId);

 public List<User> getAllUsers();

 public void updateUser(User user);

 public void deleteUser(Integer userId);

}

Step#5: Create UserMapper.xml file in src/main/resources folder in
com.sivalabs.mybatisdemo.mappers package.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE mapper PUBLIC '-//mybatis.org//DTD Mapper 3.0//EN'
  'http://mybatis.org/dtd/mybatis-3-mapper.dtd'>

<mapper namespace='com.sivalabs.mybatisdemo.mappers.UserMapper'>

  <select id='getUserById' parameterType='int' resultType='com.sivalabs.mybatisdemo.domain.User'>
     SELECT 
      user_id as userId, 
      email_id as emailId , 
      password, 
      first_name as firstName, 
      last_name as lastName
     FROM USER 
     WHERE USER_ID = #{userId}
  </select>
  <!-- Instead of referencing Fully Qualified Class Names we can register Aliases in mybatis-config.xml and use Alias names. -->
   <resultMap type='User' id='UserResult'>
    <id property='userId' column='user_id'/>
    <result property='emailId' column='email_id'/>
    <result property='password' column='password'/>
    <result property='firstName' column='first_name'/>
    <result property='lastName' column='last_name'/>   
   </resultMap>

  <select id='getAllUsers' resultMap='UserResult'>
   SELECT * FROM USER
  </select>

  <insert id='insertUser' parameterType='User' useGeneratedKeys='true' keyProperty='userId'>
   INSERT INTO USER(email_id, password, first_name, last_name)
    VALUES(#{emailId}, #{password}, #{firstName}, #{lastName})
  </insert>

  <update id='updateUser' parameterType='User'>
    UPDATE USER 
    SET
     PASSWORD= #{password},
     FIRST_NAME = #{firstName},
     LAST_NAME = #{lastName}
    WHERE USER_ID = #{userId}
  </update>

  <delete id='deleteUser' parameterType='int'>
    DELETE FROM USER WHERE USER_ID = #{userId}
  </delete>

</mapper>

Step#6: Create MyBatisUtil.java to instantiate SqlSessionFactory.

package com.sivalabs.mybatisdemo.service;

import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyBatisUtil 
{
 private static SqlSessionFactory factory;

 private MyBatisUtil() {
 }

 static
 {
  Reader reader = null;
  try {
   reader = Resources.getResourceAsReader('mybatis-config.xml');
  } catch (IOException e) {
   throw new RuntimeException(e.getMessage());
  }
  factory = new SqlSessionFactoryBuilder().build(reader);
 }

 public static SqlSessionFactory getSqlSessionFactory() 
 {
  return factory;
 }
}

Step#7: Create UserService.java in src/main/java folder.

package com.sivalabs.mybatisdemo.service;

import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.sivalabs.mybatisdemo.domain.User;
import com.sivalabs.mybatisdemo.mappers.UserMapper;

public class UserService
{

 public void insertUser(User user) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  userMapper.insertUser(user);
  sqlSession.commit();
  }finally{
   sqlSession.close();
  }
 }

 public User getUserById(Integer userId) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  return userMapper.getUserById(userId);
  }finally{
   sqlSession.close();
  }
 }

 public List<User> getAllUsers() {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  return userMapper.getAllUsers();
  }finally{
   sqlSession.close();
  }
 }

 public void updateUser(User user) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  userMapper.updateUser(user);
  sqlSession.commit();
  }finally{
   sqlSession.close();
  }

 }

 public void deleteUser(Integer userId) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  userMapper.deleteUser(userId);
  sqlSession.commit();
  }finally{
   sqlSession.close();
  }

 }

}

Step#8: Create a JUnit Test class to test UserService methods.

package com.sivalabs.mybatisdemo;

import java.util.List;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import com.sivalabs.mybatisdemo.domain.User;
import com.sivalabs.mybatisdemo.service.UserService;

public class UserServiceTest 
{
 private static UserService userService;

 @BeforeClass
    public static void setup() 
 {
  userService = new UserService();
 }

 @AfterClass
    public static void teardown() 
 {
  userService = null;
 }

    @Test
 public void testGetUserById() 
 {
  User user = userService.getUserById(1);
  Assert.assertNotNull(user);
  System.out.println(user);
 }

    @Test
    public void testGetAllUsers() 
    {
  List<User> users = userService.getAllUsers();
  Assert.assertNotNull(users);
  for (User user : users) 
  {
   System.out.println(user);
  }

 }

    @Test
    public void testInsertUser() 
    {
     User user = new User();
     user.setEmailId('test_email_'+System.currentTimeMillis()+'@gmail.com');
     user.setPassword('secret');
     user.setFirstName('TestFirstName');
     user.setLastName('TestLastName');

     userService.insertUser(user);
  Assert.assertTrue(user.getUserId() != 0);
  User createdUser = userService.getUserById(user.getUserId());
  Assert.assertNotNull(createdUser);
  Assert.assertEquals(user.getEmailId(), createdUser.getEmailId());
  Assert.assertEquals(user.getPassword(), createdUser.getPassword());
  Assert.assertEquals(user.getFirstName(), createdUser.getFirstName());
  Assert.assertEquals(user.getLastName(), createdUser.getLastName());

 }

    @Test
    public void testUpdateUser() 
    {
     long timestamp = System.currentTimeMillis();
  User user = userService.getUserById(2);
  user.setFirstName('TestFirstName'+timestamp);
     user.setLastName('TestLastName'+timestamp);
     userService.updateUser(user);
  User updatedUser = userService.getUserById(2);
  Assert.assertEquals(user.getFirstName(), updatedUser.getFirstName());
  Assert.assertEquals(user.getLastName(), updatedUser.getLastName());
 }

   @Test
   public void testDeleteUser() 
   {
     User user = userService.getUserById(4);
     userService.deleteUser(user.getUserId());
  User deletedUser = userService.getUserById(4);
  Assert.assertNull(deletedUser);   

 }
}

Now, I will explain how to perform CRUD operations using MyBatis
Annotation support without need of Queries configuration in XML mapper
files.

Step#1: Create a table BLOG and a java domain Object Blog.

CREATE TABLE  blog (
  blog_id int(10) unsigned NOT NULL auto_increment,
  blog_name varchar(45) NOT NULL,
  created_on datetime NOT NULL,
  PRIMARY KEY  (blog_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

package com.sivalabs.mybatisdemo.domain;

import java.util.Date;

public class Blog {

 private Integer blogId;
 private String blogName;
 private Date createdOn;

 @Override
 public String toString() {
  return 'Blog [blogId=' + blogId + ', blogName=' + blogName
    + ', createdOn=' + createdOn + ']';
 }
 //Seeters and getters
}

Step#2: Create UserMapper.java interface with SQL queries in
Annotations.

package com.sivalabs.mybatisdemo.mappers;

import java.util.List;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import com.sivalabs.mybatisdemo.domain.Blog;

public interface BlogMapper 
{
 @Insert('INSERT INTO BLOG(BLOG_NAME, CREATED_ON) VALUES(#{blogName}, #{createdOn})')
 @Options(useGeneratedKeys=true, keyProperty='blogId')
 public void insertBlog(Blog blog);

 @Select('SELECT BLOG_ID AS blogId, BLOG_NAME as blogName, CREATED_ON as createdOn FROM BLOG WHERE BLOG_ID=#{blogId}')
 public Blog getBlogById(Integer blogId);

 @Select('SELECT * FROM BLOG ')
 @Results({
  @Result(id=true, property='blogId', column='BLOG_ID'),
  @Result(property='blogName', column='BLOG_NAME'),
  @Result(property='createdOn', column='CREATED_ON')  
 })
 public List<Blog> getAllBlogs();

 @Update('UPDATE BLOG SET BLOG_NAME=#{blogName}, CREATED_ON=#{createdOn} WHERE BLOG_ID=#{blogId}')
 public void updateBlog(Blog blog);

 @Delete('DELETE FROM BLOG WHERE BLOG_ID=#{blogId}')
 public void deleteBlog(Integer blogId);

}

Step#3: Configure BlogMapper in mybatis-config.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'>
<configuration>
 <properties resource='jdbc.properties'/>
 <environments default='development'>
  <environment id='development'>
    <transactionManager type='JDBC'/>
    <dataSource type='POOLED'>
   <!-- <property name='driver' value='com.mysql.jdbc.Driver'/>
   <property name='url' value='jdbc:mysql://localhost:3306/mybatis-demo'/>
   <property name='username' value='root'/>
   <property name='password' value='admin'/> -->
   <property name='driver' value='${jdbc.driverClassName}'/>
   <property name='url' value='${jdbc.url}'/>
   <property name='username' value='${jdbc.username}'/>
   <property name='password' value='${jdbc.password}'/>
    </dataSource>
  </environment>
  </environments>
  <mappers>
    <mapper class='com.sivalabs.mybatisdemo.mappers.BlogMapper'/>
  </mappers>
</configuration>

Step#4: Create BlogService.java

package com.sivalabs.mybatisdemo.service;

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.sivalabs.mybatisdemo.domain.Blog;
import com.sivalabs.mybatisdemo.mappers.BlogMapper;

public class BlogService
{

 public void insertBlog(Blog blog) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
  blogMapper.insertBlog(blog);
  sqlSession.commit();
  }finally{
   sqlSession.close();
  }
 }

 public Blog getBlogById(Integer blogId) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
  return blogMapper.getBlogById(blogId);
  }finally{
   sqlSession.close();
  }
 }

 public List<Blog> getAllBlogs() {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
  return blogMapper.getAllBlogs();
  }finally{
   sqlSession.close();
  }
 }

 public void updateBlog(Blog blog) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
  blogMapper.updateBlog(blog);
  sqlSession.commit();
  }finally{
   sqlSession.close();
  }  
 }

 public void deleteBlog(Integer blogId) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
  blogMapper.deleteBlog(blogId);
  sqlSession.commit();
  }finally{
   sqlSession.close();
  }

 }

}

Step#5: Create JUnit Test for BlogService methods

package com.sivalabs.mybatisdemo;

import java.util.Date;
import java.util.List;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import com.sivalabs.mybatisdemo.domain.Blog;
import com.sivalabs.mybatisdemo.service.BlogService;

public class BlogServiceTest 
{
 private static BlogService blogService;

 @BeforeClass
    public static void setup() 
 {
  blogService = new BlogService();
 }

 @AfterClass
    public static void teardown() 
 {
  blogService = null;
 }

    @Test
 public void testGetBlogById() 
 {
  Blog blog = blogService.getBlogById(1);
  Assert.assertNotNull(blog);
  System.out.println(blog);
 }

    @Test
    public void testGetAllBlogs() 
    {
  List<Blog> blogs = blogService.getAllBlogs();
  Assert.assertNotNull(blogs);
  for (Blog blog : blogs) 
  {
   System.out.println(blog);
  }

 }

    @Test
    public void testInsertBlog() 
    {
     Blog blog = new Blog();
     blog.setBlogName('test_blog_'+System.currentTimeMillis());
     blog.setCreatedOn(new Date());

     blogService.insertBlog(blog);
  Assert.assertTrue(blog.getBlogId() != 0);
  Blog createdBlog = blogService.getBlogById(blog.getBlogId());
  Assert.assertNotNull(createdBlog);
  Assert.assertEquals(blog.getBlogName(), createdBlog.getBlogName());

 }

    @Test
    public void testUpdateBlog() 
    {
     long timestamp = System.currentTimeMillis();
  Blog blog = blogService.getBlogById(2);
  blog.setBlogName('TestBlogName'+timestamp);
     blogService.updateBlog(blog);
  Blog updatedBlog = blogService.getBlogById(2);
  Assert.assertEquals(blog.getBlogName(), updatedBlog.getBlogName());
 }

   @Test
   public void testDeleteBlog() 
   {
     Blog blog = blogService.getBlogById(4);
     blogService.deleteBlog(blog.getBlogId());
  Blog deletedBlog = blogService.getBlogById(4);
  Assert.assertNull(deletedBlog);
 }
}
You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图