到目前为止,贯穿整个文档用于URLs的规约默认为 /controller/action/id
. 然而,这个规约不是硬性的写入Grails中,实际上,它是通过一个位于 grails-app/conf/UrlMappings.groovy
的URL映射类所控制.
UrlMappings
类包含一个名为mappings
单一属性,并被赋予一个代码块:
class UrlMappings {
static mappings = {
}
}
为了创建简单的映射,只需简单的使用相对URL作为方法名,并指定控制器和操作的命名参数来映射:
"/product"(controller:"product", action:"list")
在这种情况下,我们建立URL/product
到ProductController
的list
操作的映射。你当然可以省略操作定义,来映射控制器默认的操作:
"/product"(controller:"product")
一个可选的语法是把在块中被赋值的控制器和操作传递给方法:
"/product" { controller = "product" action = "list" }
你使用哪一个句法很大程度上依赖于个人偏好.
早前的部分说明,怎样使用具体的"标记"来映射普通的URLs。在URL映射里讲过,标记是在每个斜线(/)字符之间的顺序字符。 一个具体的标记就像/product
这样被良好定义。然而,很多情况下,标记的值直到运行时才知道是什么。在这种情况下,你可以在URL中使用变量占位符,例如:
static mappings = { "/product/$id"(controller:"product") }
在这种情况下,通过嵌入一个$id变量作为第2个标记,Grails将自动映射第2个标记到一个名为id
的参数(通过params对象得到). 例如给定的URL/product/MacBook
,下面的代码将渲染"MacBook"到响应中:
class ProductController { def index = { render params.id } }
当然你可以构建更多复杂的映射示例。例如传统的blog URL格式将被映射成下面这样:
static mappings = { "/$blog/$year/$month/$day/$id"(controller:"blog", action:"show") }
上面的映射允许你这样:
/graemerocher/2007/01/10/my_funky_blog_entry
在URL里单独的标记将再次被映射到带有year
, month
, day
, id
等等可用值的 params 对象中.
变量同样可以被用于动态构造控制器和操作名。实际上,默认的Grails URL映射使用这样的技术:
static mappings = { "/$controller/$action?/$id?"() }
这里,控制器(controller)名,操作(action)名和id名,隐式的从嵌入在URL中的controller
, action
和id
中获得:
static mappings = { "/$controller" { action = { params.goHere } } }
默认映射另一个特性就是能够在一个变量的末尾附加一个?
,使它成为一个可选的标记。这个技术更进一步的示例能够运用于blog URL映射,使它具有更灵活性的连接 :
static mappings = { "/$blog/$year?/$month?/$day?/$id?"(controller:"blog", action:"show") }
下列URLs的所有映射将与放置于params对象中的唯一关联的参数匹配:
/graemerocher/2007/01/10/my_funky_blog_entry /graemerocher/2007/01/10 /graemerocher/2007/01 /graemerocher/2007 /graemerocher
你同样可以传递来自于URL映射的任意参数给控制器,把他们设置在块内传递给这个映射:
"/holiday/win" { id = "Marrakech" year = 2007 }
在这个params对象得到的这个变量将被传递给这个控制器.
硬编码任意变量是有用的,但是,有时你需要基于运行时因素来计算变量名。这个同样可能通过给变量名分配一个块:
"/holiday/win" { id = { params.id } isEligible = { session.user != null } // must be logged in }
上述情况,当URL实际被匹配,块中的代码将被解析,因此可以被用于结合所有种类的逻辑处理.
如果你想决定一个URL一个view,而无需涉及一个控制器或者操作,你也可以这样做。 例如,如果你想映射根URL /
到一个位于 grails-app/views/index.gsp
的GSP,你可以这样使用:
static mappings = { "/"(view:"/index") // map the root URL }
换句话说,假如你需要一个具体给定的控制器(Controller)中的一个视图,你可以这样使用:
static mappings = { "/help"(controller:"site",view:"help") // to a view for a controller }
Grails同样允许你映射一个HTTP响应代码到控制器,操作或视图。所有你需要做的是使用一个方法名来匹配你所感兴趣的响应代码:
static mappings = { "500"(controller:"errors", action:"serverError") "404"(controller:"errors", action:"notFound") "403"(controller:"errors", action:"forbidden") }
或者换句话说,假如你只不过想提供定制的错误页面:
static mappings = { "500"(view:"/errors/serverError") "404"(view:"/errors/notFound") "403"(view:"/errors/forbidden") }
URL映射同样可以配置成基于HTTP 方法 (GET, POST, PUT or DELETE)的map。这个对于RESTful APIs和基于HTTP方法的约束映射是非常有用的.
作为一个示例,下面的映射为ProductController
URL提供一个RESTful API URL映射:
static mappings = { "/product/$id"(controller:"product"){ action = [GET:"show", PUT:"update", DELETE:"delete", POST:"save"] } }
Grails的URL映射机制同样支持通配符映射。例如,考虑下面的映射:
static mappings = { "/images/*.jpg"(controller:"image") }
这个映射将匹配所有images路径下像/image/logo.jpg
这样的jpg。当然你可以通过一个变量来达到同样的效果:
static mappings = { "/images/$name.jpg"(controller:"image") }
然而,你可以使用双通配符来匹配多于一个层次之外的:
static mappings = { "/images/**.jpg"(controller:"image") }
这样的话,这个映射将不但匹配/image/logo.jpg
而且匹配/image/other/logo.jpg
。更好的是你可以使用一个双通配符变量:
static mappings = { // will match /image/logo.jpg and /image/other/logo.jpg "/images/$name**.jpg"(controller:"image") }
这样的话,它将储存路径,从params 对象获得命名参数里的name
通配符 :
def name = params.name println name // prints "logo" or "other/logo"
如果你使用通配符URL mappings,那么你可以排除某些来自Grails的URL mapping进程 URIs. 实现这个你可以在UrlMappings.groovy
类中设置excludes
:
class UrlMappings = { static excludes = ["/images/**", "/css/**"] static mappings = { … } }
这样,Grails不为匹配任何以 /images
或 /css
开头的URLs.
URL映射另一个重要的特性是自动定制 link 标签的行为。以便改变这个映射而不需要改变所有的连接.
通过一个URL重写技术做到这点,从URL映射反转连接设计:
static mappings = { "/$blog/$year?/$month?/$day?/$id?"(controller:"blog", action:"show") }
如果,你像下列一样使用连接标签:
<g:link controller="blog" action="show" params="[blog:'fred', year:2007]">My Blog</g:link> <g:link controller="blog" action="show" params="[blog:'fred', year:2007, month:10]">My Blog - October 2007 Posts</g:link>
Grails将自动重写URL通过适当的格式:
<a href="/fred/2007">My Blog</a> <a href="/fred/2007/10">My Blog - October 2007 Posts</a>
URL映射同样支持Grails统一 验证规约 机制, 它允许你更进一步"约束"一个URL是怎么被匹配的。例如,如果我们回到早前的blog示例代码,这个映射当前看上去会像这样 :
static mappings = { "/$blog/$year?/$month?/$day?/$id?"(controller:"blog", action:"show") }
允许URLs像这样:
/graemerocher/2007/01/10/my_funky_blog_entry
不过,它也允许这样:
/graemerocher/not_a_year/not_a_month/not_a_day/my_funky_blog_entry
当它强迫你在控制器代码中做一些聪明的语法分析时会有问题。幸运的是,URL映射能进一步的约束验证URL标记:
"/$blog/$year?/$month?/$day?/$id?" { controller = "blog" action = "show" constraints { year(matches:/d{4}/) month(matches:/d{2}/) day(matches:/d{2}/) } }
在这种情况下,约束能确保 year
, month
和 day
参数匹配一个具体有效的模式,从而在稍后来减轻你的负担 .