zoukankan      html  css  js  c++  java
  • java笔记:自己动手写javaEE框架(二)业务层Service以及Service单元测试

      前一篇博文里有三位童鞋留言了,第一位童鞋问道我提出的那个技术难题,我得到一个答案,但是我比较怀疑这个方法的技术实现,以后我会验证下,还有位童鞋问道源码,我现在还没有写完,写完后我会把源码发到博客里的,最后一位童鞋的问题我要着重讲讲。其实开起这个系列时我是想过用什么题目,例如用ssh或者 ssi等等,但是这种命名就局限了,因为这里面每一个单词都是指一个技术框架,而我想用到的框架比较多,这样的标题不能代表我写的所有内容。用 javaEE是有理由的,javaEE是j2ee的新名称,(注意:为了严谨我下面的理解是我自己经验得来的理解,写下面内容时候我没有查阅相关资料,假如不正确,大家可以直接指出),sun公司出品的java语言,当然现在是甲骨文的产品了,一共包括三大部分,j2se,j2ee和j2me,而j2ee 是什么了?是sun运用java语言为企业级开发提供的一套解决方案,j2ee也可以说是一套框架,这个框架里面主要是定义了java为企业级开发提供了那些技术,但是这些技术只是提供了接口和规范,而非是具体实现,最开始sun出品了ejb,但是ejb太繁琐,最后就有类似ssh框架的实现,但是 j2ee的范畴很大,我们平时开发时候只是实现了其中的部分功能,例如一个页面发出请求到后台程序运算最后查询数据库,返回数据到页面展示,这是j2ee 的一个子集实现,j2ee还有很多,比如jms,webservice,xml等等技术,我这里想写的框架绝不是简单的针对页面请求响应,我还想引入很多功能到这些框架,比如webservice,mq,velocity,spring的调度,ant,缓存等等,要不我写一个大众化的框架放到博客里意义不大,就是重复。而且后面那些技术并不是能常用到,但很有可能会成为你面试的软肋,因为有些现在我用过忘了,有些你没用过别人会给你印象减分,这是功力的说法了,但是接触的技术越到你做项目的余地越大,所以我用javaEE左标题,我想做一个尽量完善的j2ee规范实现的子集。
      转入正题还是要闲话下,最近在为公司的平台做权限开发设计,由于人力和时间的原因这个功能复杂度的要求被降低了,就算降低了,这次权限设计还是和我以前的经验比较起来有很大不同,我们做的是到程序方法级别的控制和数据级别的权限控制,数据级别的权限控制我以后再说了,这个主要是从系统设计块实现,技术没有特别之处。前者会用到spring的aop,这个和我现在写的这个系列有关,所以我这里要提到这个问题。
      今天我将写service层,然后写service的测试类,然后我会加入一个拦截器:拦截service的请求,这个拦截器是针对方法的拦截,这个拦截器里面我们可以知道调用到了那个service类,那个method,可以截获到传入的参数,也能截获到返回值。我在公司的项目里的aop就会拦截到 service的方法,大家也许会很奇怪,为什么不做到action而是service,哎,这个没法子,我们前台用的是flex,而flex调用 java跟rpc很像,就是flex直接调用service的方法,因此控制层在前台,和前台的耦合度太高,只得做service方法级别的拦截了。
    我是按下面顺序开发的:
    1.先看看我新的目录结构

    还要加入三个jar包,都是AspectJ相关的,如下图:


    2.在cn.com.sharpxiajun.service包下新建接口UsersService,代码如下:

    package cn.com.sharpxiajun.service;

    import java.util.List;
    import java.util.Map;

    public interface UsersService {

    public List<Map<String, Object>> queryUsersList(Map<String, Object> map) throws Exception;

    }

    3.实现UsersService接口,在cn.com.sharpxiajun.service.impl包下面新建类UsersServiceImpl,代码如下:

    package cn.com.sharpxiajun.service.impl;

    import java.util.List;
    import java.util.Map;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Service;

    import cn.com.sharpxiajun.dao.UsersDao;
    import cn.com.sharpxiajun.service.UsersService;

    @SuppressWarnings("unchecked")
    @Scope("prototype")
    @Service("userService")
    public class UsersServiceImpl implements UsersService {

    @Autowired
    @Qualifier("usersDao")
    private UsersDao usersDao = null;

    @Override
    public List<Map<String, Object>> queryUsersList(Map<String, Object> map)
    throws Exception {
    return usersDao.queryUserList(map);
    }

    }

    大家可以看到service注解是@service,其他和dao差不多(我感觉要写篇文章好好介绍下spring相关注解,只有这样才能对框架有深刻理解)

    4.接下来编写方法拦截器,这个类放在cn.com.sharpxiajun.common.aop包下,类名是:MethodServiceAdvisor,代码如下:

    package cn.com.sharpxiajun.common.aop;

    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;

    import cn.com.sharpxiajun.service.UsersService;

    public class MethodServiceAdvisor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

    Object obj = null;

    System.out.println("进入到了方法拦截器。。。。");

    System.out.println("调用的service:");
    System.out.println(invocation.getThis());

    System.out.println("调用的方法:");
    System.out.println(invocation.getMethod());

    System.out.println("参数是:");

    for (int i = 0;i < invocation.getArguments().length;i++)
    {
    Object[] objs = invocation.getArguments();
    System.out.println(objs[i]);
    }

    obj = invocation.proceed();

    System.out.println("返回结果是:");
    System.out.println(obj);
    System.out.println("拦截器执行结束!!");

    return obj;
    }

    }

    拦截器的注解我今天不写,太晚了,而且记得不清,下一篇里我会补上这些内容。

    5.下面是修改后的applicationContext.xml配置文件,内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context
    ="http://www.springframework.org/schema/context"
    xmlns:aop
    ="http://www.springframework.org/schema/aop"
    xmlns:tx
    ="http://www.springframework.org/schema/tx"
    xsi:schemaLocation
    ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

    <!-- 扫描该路径下的spring组件 -->
    <context:component-scan base-package="cn.com.sharpxiajun"/>

    <!-- 读取资源文件 -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
    <list>
    <value>classpath:conf/constants.properties</value>
    </list>
    </property>
    </bean>

    <!-- 配置数据源 -->
    <!-- <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${db.driverClass}"/>
    <property name="jdbcUrl" value="${db.jdbcUrl}"/>
    <property name="user" value="${db.user}"/>
    <property name="password" value="${db.password}"/>
    </bean>
    -->

    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${db.driverClass}"/>
    <property name="url" value="${db.jdbcUrl}"/>
    <property name="username" value="${db.user}"/>
    <property name="password" value="${db.password}"/>
    </bean>

    <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
    <property name="configLocation">
    <value>classpath:conf/SqlMapConfig.xml</value>
    </property>
    <property name="dataSource" ref="myDataSource"/>
    </bean>

    <bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
    <property name="sqlMapClient">
    <ref local="sqlMapClient"/>
    </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource">
    <ref local="myDataSource"/>
    </property>
    </bean>

    <!-- 将我自己定义的拦截器生成bean -->
    <bean id="methodServiceAdvisor" class="cn.com.sharpxiajun.common.aop.MethodServiceAdvisor"/>

    <aop:config>
    <!--配置规则,满足以下规则的将拦截,第一个*表示所有返回类型,第二个表示service包下的所有class,第三个表示所有方法-->
    <aop:pointcut id="baseServiceMethods" expression="execution(* cn.com.sharpxiajun.service.*.*(..))"/>
    <!-- 符合上面规则的拦截器都会调用到methodServiceAdvisor -->
    <aop:advisor advice-ref="methodServiceAdvisor" pointcut-ref="baseServiceMethods"/>
    </aop:config>

    </beans>

    这里用到了aop:config这是spring为了迎合AspectJ,对于AspectJ这个以后有机会我也想研究下,写篇文章。

    6.最后编写针对UsersService的测试类UsersServiceImplTest,所在包是:cn.com.sharpxiajun.junittest.service,代码如下:

    package cn.com.sharpxiajun.junittest.service;

    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.context.transaction.TransactionConfiguration;

    import cn.com.sharpxiajun.service.UsersService;

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"classpath:conf/applicationContext.xml"})
    @TransactionConfiguration(defaultRollback = false)
    public class UsersServiceImplTest extends
    AbstractTransactionalJUnit4SpringContextTests {

    @Autowired
    private UsersService usersService = null;

    public UsersServiceImplTest()
    {
    System.out.println("初始化测试类....");
    }

    @Before
    public void setUp() throws Exception
    {
    System.out.println("测试开始....");
    }

    @After
    public void tearDown() throws Exception
    {
    System.out.println("测试结束!!");
    }

    @Test
    public void testQueryUserList()
    {
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("username", "sharpxiajun");
    try {
    List<Map<String, Object>> list = usersService.queryUsersList(map);
    System.out.println(list);
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }

    }

    运行结果如下:

    初始化测试类....
    2011-10-11 23:44:45 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    信息: Loading XML bean definitions from class path resource [conf/applicationContext.xml]
    2011-10-11 23:44:45 org.springframework.context.support.AbstractApplicationContext prepareRefresh
    信息: Refreshing org.springframework.context.support.GenericApplicationContext@290fbc: startup date [Tue Oct 11 23:44:45 CST 2011]; root of context hierarchy
    2011-10-11 23:44:46 org.springframework.core.io.support.PropertiesLoaderSupport loadProperties
    信息: Loading properties file from class path resource [conf/constants.properties]
    2011-10-11 23:44:46 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
    信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@922804: defining beans [usersDao,userService,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,propertyConfigurer,myDataSource,sqlMapClient,sqlMapClientTemplate,transactionManager,methodServiceAdvisor,org.springframework.aop.config.internalAutoProxyCreator,baseServiceMethods,org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0]; root of factory hierarchy
    2011-10-11 23:44:46 org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
    信息: Began transaction (1): transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@8de972]; rollback [false]
    测试开始....
    进入到了方法拦截器。。。。
    调用的service:
    cn.com.sharpxiajun.service.impl.UsersServiceImpl@15fc672
    调用的方法:
    public abstract java.util.List cn.com.sharpxiajun.service.UsersService.queryUsersList(java.util.Map) throws java.lang.Exception
    参数是:
    {username=sharpxiajun}
    返回结果是:
    [{enabled=false, username=admin, password=admin}, {enabled=false, username=test, password=test}]
    拦截器执行结束!!
    [{enabled=false, username=admin, password=admin}, {enabled=false, username=test, password=test}]
    测试结束!!
    2011-10-11 23:44:46 org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
    信息: Committed transaction after test execution for test context [[TestContext@58e2a1 testClass = UsersServiceImplTest, locations = array<String>['classpath:conf/applicationContext.xml'], testInstance = cn.com.sharpxiajun.junittest.service.UsersServiceImplTest@186f3b3, testMethod = testQueryUserList@UsersServiceImplTest, testException = [null]]]

    看来达到我们预期的结果了!!!

    总结下了:这样写程序蛮有成就感,而且一步步来感觉很清晰。工作永远是匆忙的,总是快的让人无法思考,我想这就是聪明的中国为什么没有那么多优秀开源框架的原因把。今天我又得到一个js开源框架,获得源码,它能做出yfiles一样的效果,非常强大,也是老外写的,牛的不行啊,我们平台开发本来对前端要求很高的,要求图形化实现,真正做图形化才知道他的复杂度之高,以后我会介绍下这个图形化的框架,他能实现画图,自定义工作流,还能为关系复杂的图形进行布局合理的自动绘制,太牛了。

    下个阶段可能要回归javascript了,java框架暂停一下。





     

  • 相关阅读:
    阶段3 1.Mybatis_10.JNDI扩展知识_2 补充-JNDI搭建maven的war工程
    阶段3 1.Mybatis_10.JNDI扩展知识_1 补充-JNDI概述和原理
    阶段3 1.Mybatis_09.Mybatis的多表操作_9 mybatis多对多操作-查询用户获取用户所包含的角色信息
    阶段3 1.Mybatis_09.Mybatis的多表操作_8 mybatis多对多操作-查询角色获取角色下所属用户信息
    阶段3 1.Mybatis_09.Mybatis的多表操作_7 mybatis多对多准备角色表的实体类和映射配置
    阶段3 1.Mybatis_09.Mybatis的多表操作_6 分析mybatis多对多的步骤并搭建环境
    阶段3 1.Mybatis_09.Mybatis的多表操作_5 完成user的一对多查询操作
    阶段3 1.Mybatis_09.Mybatis的多表操作_4 完成account一对一操作-建立实体类关系的方式
    inline函数不能在for循环中使用的原因
    Linux 内核死锁
  • 原文地址:https://www.cnblogs.com/sharpxiajun/p/2208012.html
Copyright © 2011-2022 走看看