文档章节

Grails In Action-06.Controlling application flow

寡鸡蛋
 寡鸡蛋
发布于 2013/11/26 15:30
字数 966
阅读 210
收藏 2
点赞 0
评论 0

第六章主要讲解使用controller实现页面之间的跳转。在系统中实现了Post信息提交及显示功能。主要的知识点有:

  • 访问路径控制:http://url:port/app/controller/action/params
  • addPost方法:timeline页面的form将表单提交给addPost方法,addPost方法返回
  • .操作符:list.prop
  • ?:操作符:表达式?如果true:如果false
  • ${flash.massage}
  • spock单元测试:controller页面重定向测试
  • spock单元测试:@spock.lang.Unroll
  • spock单元测试:"Testing id of #suppliedId redirects to #expectedUrl"
  • spock集成测试

默认访问index,重定向给timeline/params,如果没有params,默认给一个.

<!-- lang: groovy -->
......
def index() {
    if (!params.id) 
        params.id = "jeff"
        redirect action: 'timeline', params: params
    }

def timeline() {
    def user = User.findByLoginId(params.id)
    if (!user) {
        response.sendError(404)
    } else {
        [ user : user ]
    }
}
......

增加一个post,因为post需要指定user,所以需要user登录,前面的index指定了一个user params,可以直接使用.后续增加登录功能

<!-- lang: groovy -->
......
def addPost() {
    def user = User.findByLoginId(params.id)
    if (user) {
        def post = new Post(params)
        user.addToPosts(post)
        if (user.save()) {
            flash.message = "Successfully created Post"
        } else {
            flash.message = "Invalid or empty post"
        }
    } else {
        flash.message = "Invalid User Id"
    }
    redirect(action: 'timeline', id: params.id)
}
......

访问index,重定向给timeline,timeline.gsp负责提交post并显示post信息,所以,timeline分这两个部分.

<!-- lang: groovy -->
<html>
    <head>
        <title>Timeline for ${ user.profile ? user.profile.fullName : user.loginId }</title>
        <meta name="layout" content="main"/>
    </head>

    <body>
        <div id="newPost">
            <h3>
                What is ${ user.profile ? user.profile.fullName : user.loginId } hacking on right now?
            </h3>

            <g:if test="${flash.message}">
                <div class="flash">${flash.message}</div>
            </g:if>

            <@!-- 提交(addPost) -->
            <p>
                <g:form action="addPost" id="${params.id}">
                    <g:textArea id='postContent' name="content" rows="3" cols="50"/><br/>
                    <g:submitButton name="post" value="Post"/>
                </g:form>
            </p>
        </div>

        <@!-- 显示(timeline/params) -->
        <div class="allPosts">
            <g:each in="${user.posts}" var="post">
                <div class="postEntry">
                    <div class="postText">${post.content}</div>
                    <div class="postDate">${post.dateCreated}</div>
                </div>
            </g:each>
        </div>
    </body>
</html>

这本书在测试上下了一些功夫,讲解的也很到位. 单元测试:test/unit/com.grailsinaction.PostControllerSpec.groovy

<!-- lang: groovy -->
package com.grailsinaction

import grails.test.mixin.Mock
import grails.test.mixin.TestFor

import spock.lang.Specification

@TestFor(PostController)
@Mock([User,Post])
class PostControllerSpec extends Specification {
    def "Get a users timeline given their id"() {
        given: "A user with posts in the db"
            User chuck = new User(loginId: "chuck_norris", password: "password").save(failOnError: true)
            chuck.addToPosts(new Post(content: "A first post"))
            chuck.addToPosts(new Post(content: "A second post"))

        and: "A loginId parameter"
            params.id = chuck.loginId

        when: "the timeline is invoked"
            def model = controller.timeline()

        then: "the user is in the returned model"
            model.user.loginId == "chuck_norris"
            model.user.posts.size() == 2
    }

    def "Check that non-existent users are handled with an error"() {

        given: "the id of a non-existent user"
            params.id = "this-user-id-does-not-exist"

        when: "the timeline is invoked"
            controller.timeline()

        then: "a 404 is sent to the browser"
            response.status == 404

    }

    def "Adding a valid new post to the timeline"() {
        given: "A user with posts in the db"
            User chuck = new User(loginId: "chuck_norris", password: "password").save(failOnError: true)

        and: "A loginId parameter"
            params.id = chuck.loginId

        and: "Some content for the post"
            params.content = "Chuck Norris can unit test entire applications with a single assert."

        when: "addPost is invoked"
            def model = controller.addPost()

        then: "our flash message and redirect confirms the success"
            flash.message == "Successfully created Post"
            response.redirectedUrl == "/post/timeline/${chuck.loginId}"
            Post.countByUser(chuck) == 1
    }

    def "Adding a invalid new post to the timeline trips an error"() {
        given: "A user with posts in the db"
            User chuck = new User(loginId: "chuck_norris", password: "password").save(failOnError: true)

        and: "A loginId parameter"
            params.id = chuck.loginId

        and: "Some content for the post"
            params.content = null

        when: "addPost is invoked"
            def model = controller.addPost()

        then: "our flash message and redirect confirms the success"
            flash.message == "Invalid or empty post"
            response.redirectedUrl == "/post/timeline/${chuck.loginId}"
            Post.countByUser(chuck) == 0

    }

    @spock.lang.Unroll
    def "Testing id of #suppliedId redirects to #expectedUrl"() {
        given:
            params.id = suppliedId

        when: "Controller is invoked"
            controller.index()

        then:
            response.redirectedUrl == expectedUrl

        where:
            suppliedId | expectedUrl
            'joe_cool' | '/post/timeline/joe_cool'
            null | '/post/timeline/chuck_norris'
    }
}

集成测试:test/integration/com.grailsinaction.PostIntegrationSpec.groovy

<!-- lang: groovy -->
package com.grailsinaction

import grails.plugin.spock.IntegrationSpec

class PostIntegrationSpec extends IntegrationSpec {
	
	def "Adding posts to user links post to user"() {

		given: "A brand new user"
			def user = new User(loginId: 'joe',
				password: 'secret').save(failOnError: true)

		when: "Several posts are added to the user"
			user.addToPosts(new Post(content: "First post... W00t!"))
			user.addToPosts(new Post(content: "Second post..."))
			user.addToPosts(new Post(content: "Third post..."))

		then: "The user has a list of posts attached"
			3 == User.get(user.id).posts.size()
	}


	def "Ensure posts linked to a user can be retrieved"() {

		given: "A user with several posts"
			def user = new User(loginId: 'joe', password: 'secret').save(failOnError: true)
			user.addToPosts(new Post(content: "First"))
			user.addToPosts(new Post(content: "Second"))
			user.addToPosts(new Post(content: "Third"))

		when: "The user is retrieved by their id"
			def foundUser = User.get(user.id)
			List<String> sortedPostContent = foundUser.posts.collect { it.content }.sort()

		then: "The posts appear on the retrieved user"
			sortedPostContent == ['First', 'Second', 'Third']
	}

	def "Exercise tagging several posts with various tags"() {

		given: "A user with a set of tags"
			def user = new User(loginId: 'joe', password: 'secret').save(failOnError: true)
			def tagGroovy = new Tag(name: 'groovy')
			def tagGrails = new Tag(name: 'grails')
			user.addToTags(tagGroovy)
			user.addToTags(tagGrails)

		when: "The user tags two fresh posts"
			def groovyPost = new Post(content: "A groovy post")
			user.addToPosts(groovyPost)
			groovyPost.addToTags(tagGroovy)

			def bothPost = new Post(content: "A groovy and grails post")
			user.addToPosts(bothPost)
			bothPost.addToTags(tagGroovy)
			bothPost.addToTags(tagGrails)

		then:
			user.tags*.name.sort() == ['grails', 'groovy']
			1 == groovyPost.tags.size()
			2 == bothPost.tags.size()
	}
}

© 著作权归作者所有

共有 人打赏支持
寡鸡蛋
粉丝 12
博文 51
码字总数 19107
作品 0
中山
售前工程师
Grails 1.2参考文档速读系列

一个很好的Grails中文参考资料。 Grails 1.2参考文档速读(1):第1、2章 Grails 1.2参考文档速读(2):配置基础和环境 Grails 1.2参考文档速读(3):日志配置 Grails 1.2参考文档速读(4...

groovyland
2010/02/25
0
1
Keycloak 1.8.0.CR1 发布,SSO 集成解决方案

Keycloak 1.8.0.CR1 发布,更新如下: Default Admin User Removed - we no longer have a built in admin account, instead a new account has to be created initially from mcehref="htt......

oschina
2016/01/14
975
1
SpringSource Tool Suite 2.6.0 发布

SpringSource Tool Suite 今天发布了 2.6.0 版本,主要值得关注的改进包括: All the updates that you got from 2.5.2.SR1 included (Spring Roo 1.1.2, Eclipse Helios SR2, Groovy 1.7.8......

红薯
2011/03/19
444
1
When Monolithic Is the Way: Play vs. Spring Boot vs. Grails

Nowadays, when we are going to start a new project, the developer starts thinking about the technology, and usually they come up with something like: microservices, RESTFul, Act......

Marini Fabio
2017/12/20
0
0
Grails 中导入Excel报错

ERROR errors.GrailsExceptionResolver NoClassDefFoundError occurred when processing request: [POST] /abroadOnBusiness/employee/importer - parameters: importing: true actionimport......

想念缤纷
2014/08/01
843
1
weblogic部署报错,jpa+spring

无法访问所选应用程序。 Error loading the persistence descriptorWEB-INF/classes/META-INF/persistence.xml from the module webframework. See thefollowing stack trace for nested err......

古怪945
2015/05/29
689
2
Ls 1 - Understanding the nature of Spark Streaming

What is Spark Streaming? According to the Official Apache Spark website, Spark Streaming is an extension of the core Spark API that enables scalable, high-throughput, fault-tole......

jcchoiling
2016/05/09
738
0
自动化端对端测试框架-Protractor How It Works

How It Works Protractor is an end-to-end test framework for AngularJS applications. Protractor is a Node.js program that supports the Jasmine and Mocha test frameworks. Selenium......

dhb_oschina
2016/04/24
29
0
ExtremeTalk部署问题

@ExtremeTalk 你好,想跟你请教个问题:部署在tomcat环境下,初始化数据时出错,麻烦帮忙看下。 Init Privileges... Grails Runtime Exception Error Details Error 500: Executing action ...

zslfly
2012/11/21
536
2
URL重写库--Rewrite

Rewrite 是一个开源、基于过滤器的 Java 库,用于实现 URL 重写。可实现漂亮的 URL 地址。优雅的解决 RESTful URL 问题。主要特性包括:页面加载动作、管理参数解析、无缝的 CDI 集成、Sprin...

红薯
2013/07/27
2.2K
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

对基于深度神经网络的Auto Encoder用于异常检测的一些思考

一、前言 现实中,大部分数据都是无标签的,人和动物多数情况下都是通过无监督学习获取概念,故而无监督学习拥有广阔的业务场景。举几个场景:网络流量是正常流量还是攻击流量、视频中的人的...

冷血狂魔
18分钟前
0
0
并发设计之A系统调用B系统

A-->B A在发送请求之前,用乐观锁,减少对B的重复调用,这样一定程度上是幂等性。 比如A系统支付功能,要调用B系统进行支付操作,但是前端对"支付"按钮不进行控制,即用户会不断多次点击支付...

汉斯-冯-拉特
39分钟前
0
0
HTTP协议通信原理

了解HTTP HTTP(HyperText Transfer Protocol)是一套计算机通过网络进行通信的规则。计算机专家设计出HTTP,使HTTP客户(如Web浏览器)能够从HTTP服务器(Web服务器)请求信息和服务。 HTTP使用...

寰宇01
今天
0
0
【Java动态性】之反射机制

一、Java反射机制简介

谢余峰
今天
1
0
Centos 6.X 部署环境搭建

1.Linux学习笔记CentOS 6.5(一)--CentOS 6.5安装过程

IT追寻者
今天
0
0
博客即同步至腾讯云+社区声明

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=8vy9bsmadbko...

xiaoge2016
今天
1
0
大数据教程(3.1):Linux系统搭建网络YUM源服务器

博主在前面的2.5章节讲述了linux系统本地YUM服务器的搭建和httpd轻量级静态网站服务器的安装,本节博主将为大家分享内网环境中搭建自己的网络YUM服务器的全过程。如果大家对本地YUM服务器还不...

em_aaron
今天
1
0
蚂蚁技术专家:一篇文章带你学习分布式事务

小蚂蚁说: 分布式事务是企业集成中的一个技术难点,也是每一个分布式系统架构中都会涉及到的一个东西,特别是在这几年越来越火的微服务架构中,几乎可以说是无法避免,本文就围绕分布式事务...

Java大蜗牛
今天
1
0
新的Steam应用将拓展服务项目

导读 未来几周,Steam将推出两个免费的应用程序Steam Link和Steam Video。这两个应用程序都旨在拓展Steam平台的业务和便利性。 即将开放的Steam Link应用程序最先提供了Android测试版,它将允...

问题终结者
今天
0
0
golang 第三方包的使用总结

golang 第三方包的安装的方法: 1. go get 安装 $ go get github.com/gin-gonic/gin 注意:执行go get 命令需要先安装git命令,并配置git全局变量。 2. 源码包安装 由于国内网络问题,很多时...

科陆李明
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部