手把手教会你开发动态web项目(3)

本章讲述如何进行业务开发,比如我们需要开发一个联系人的业务,显示联系人列表,增加联系人,修改联系人信息,删除联系人。此处所有的开发都不需要重启服务器,完全动态加载。我已经把代码提交到了src/test/resources/groovy目录下,可以直接进行测试。

1. 定义entity

@Entity(name = "TestContact")
class TestContact extends LongKeyEntity {
    String name
    String phone
}

定义了一个TestContact对象,对象包括联系人姓名和电话两个字段,并继承于LongKeyEntity,LongKeyEntity定义了id是long值,并自动增加 

2. 定义Dao

@Repository
class TestContactDao extends BaseDao<TestContact> {

    @Autowired
    public TestContactDao(SessionFactory sessionFactory) {
        super(sessionFactory)
    }

    def list() {
        createCriteria().list()
    }

    @PostConstruct
    def createTableIfNecessary() {
        def session = sessionFactory().openStatelessSession()
        try {
            session.createSQLQuery("""
                CREATE TABLE IF NOT EXISTS `${TestContact.class.simpleName}`  (
                  `id` bigint(20) NOT NULL AUTO_INCREMENT,
                  `name` varchar(100) NOT NULL,
                  `phone` varchar(100) NOT NULL,
                  `createdTime` datetime NOT NULL,
                  `updatedTime` datetime NOT NULL,
                  `createdBy` varchar(100) NOT NULL,
                  `updatedBy` varchar(100) NOT NULL,
                  PRIMARY KEY (`id`)
                ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
            """).executeUpdate()
        } finally {
            session.close()
        }
    }
}

 Dao继承于BaseDao,提供了一些最基本的操作,比如save一个对象,通过id获取一个对象,所以这里只定义了一个list方法,用来显示所有联系人。由于是测试使用,所以在创建该dao的同时也创建测试数据表。

扫描二维码关注公众号,回复: 333430 查看本文章

3. 定义service

@Service
@Transactional
@Import([groovy.com.geo.aop.TestAspect.class, groovy.com.geo.config.TestResourceConfig.class])
class TestContactService extends BaseService<TestContact> {
    @Autowired
    public TestContactService(TestContactDao dao) {
        super(dao)
    }

}

 定义一个service,继承于BaseService,BaseService是对BaseDao的方法进行事务定义。

注意,这里的service并没有定义一个类似下面的方法

def list() {
    dao().list()
}

 主要是因为我使用了groovy的动态调用方法,定义在了BaseService里,会自动去调用dao的相应的方法,所以不需要再重复定义了

还有一点注意,这里引入了Import的注解,目的是让classloader可以获取到TestAspect和TestResourceConfig的配置信息,并注册到当前的applicationContext中,TestAspect定义了一个AOP切面,TestResourceConfig则是定义了在这个service下需要使用的配置,比如hibernate的配置,事务管理器的配置,及其他资源的定义

@Configuration
@EnableAspectJAutoProxy
@Aspect
class TestAspect {
    def logger = LoggerFactory.getLogger(getClass())

    @Before('execution (* groovy.com.geo.service..*(..))')
    def before() {
        logger.info "i am invoked........."
    }
}

这里的AOP定义了拦截所有groovy.com.geo.service包下的servcie类的方法,在调用这些方法前先打印一条被调用的信息 

@Configuration
class TestResourceConfig extends BasicResourceConfig {

    @Override
    def Class<?>[] defineHibernateAnnotatedClasses() {
        return [TestContact.class]
    }

}

 这里继承了BasicResourceConfig,它定义了一个sessionFactory和一个事务管理器。这里只需要告诉BasicResoureConfig去查找哪个entity类让hibernate知道即可。

4. 定义controller

@RestController
@RequestMapping("/testContact")
class TestContactController {

    @Autowired
    TestContactService testService

    @RequestMapping(value = "/list", method = [RequestMethod.GET])
    def list() {
        testService.list()
    }

    @RequestMapping(value = "/save", method = [RequestMethod.POST])
    def save(@RequestBody TestContact updatedContact) {
        def currentUser = UserSession.CONTEXT().get()
        def oldContact = updatedContact
        if(updatedContact.id) {
            oldContact = testService.get(updatedContact.id)
            BeanUtils.copyProperties(updatedContact, oldContact, "createdBy", "createdTime", "updatedBy", "updatedTime")
        } else {
            oldContact.setCreatedBy(currentUser.username)
        }
        oldContact.setUpdatedBy(currentUser.username)
        testService.save(oldContact).toString()
    }

    @RequestMapping(value = "/delete/{id}", method = [RequestMethod.DELETE])
    def delete(@PathVariable("id") Long id) {
        def oldContact = testService.load(id)
        testService.delete(oldContact)
    }

}

 这里定义了一个contact的controller,提供了CRUD操作,这里需要注意,需要为每个controller在类上定义一个RequestMapping,这里定义的是testContact,然后每个操作都需要定义对应的RequestMapping,这样框架才能正确找到相应的入口

5. 定义入口映射



 找到如图位置的groovy文件,点击进入定义controller的mapping入口

class DynamicEntryMapping {
    public static final def map = [
            "testContact": "groovy.com.geo.web.TestContactController",
    ]
}

定义testContact对应的controller类名,目的是让框架可以定位到这个controller文件

6. 配置安全

框架使用spring security,这里需要你稍微了解一下spring security的web expression,对url进行安全配置



 如图找到DynamicSecurityMapping,然后定义安全

class DynamicSecurityMapping {
    public static final def map = [
            "/**": "hasRole('ROLE_SUPER_ADMIN')",
    ]
}

 上面的意思是所有的请求都需要有超级管理员的权限

至此,所有的业务开发完成,只需要访问业务相关的页面,这里访问的是http://localhost:8080/test/contact.html

整个过程不需要你重启服务器,每个类都可以进行动态的增删改

猜你喜欢

转载自georgezeng.iteye.com/blog/2282344