(快速参考)

4.0.2

控制器

控制器处理请求并创建或准备响应控制器可以直接生成响应或委托给视图。要创建控制器,只需创建一个名称以结尾的类即可。控制者在里面365bet地区应用程序控制器子目录中的目录(如果在软件包中)

默认值URL映射配置确保将控制器名称的第一部分映射到URI,并且在控制器内定义的每个操作都映射到控制器名称URI中的URI。

了解控制器和动作

创建一个控制器

可以使用要么生成控制器365bet地区例如,请尝试从365bet地区项目的根目录运行以下命令

grails创建控制器书

该命令将在该位置创建一个控制器grails应用程序控制器myapp BookController groovy:

myapp BookController {

    定义 指数() { }
}

其中myapp将是应用程序的名称,如果未指定,则为默认软件包名称

BookController默认情况下,映射到相对于应用程序根目录的书URI

生成控制器命令只是为了方便起见,您也可以使用自己喜欢的文本编辑器或IDE轻松创建控制器

创建动作

一个控制器可以有多种公共操作方法,每个方法都映射到一个URI。

 BookController {

    定义 清单() {

        做控制器逻辑
        建立模型

        返回模型

此示例映射到书单默认情况下,由于属性被命名为URI清单.

默认动作

控制器具有默认URI的概念,该默认URI映射到控制器的根URI。对于BookController请求默认URI时调用的操作由以下规则决定

  • 如果只有一个动作,则为默认动作

  • 如果您有一个名为指数这是默认值

  • 另外,您也可以使用defaultAction属性

静态的defaultAction"清单"

控制器和示波器

可用范围

范围是类似于哈希的对象,您可以在其中存储变量以下范围可用于控制器

  • servletContext也称为应用程序作用域,该作用域使您可以在整个Web应用程序之间共享状态。servletContext是ServletContext

  • 会议会话允许将状态与给定用户相关联,并且通常使用Cookie将会话与客户端相关联。会话对象是的实例HttpSession

  • request对象仅允许存储当前请求的对象。request对象是以下对象的实例

  • 参数传入请求查询字符串或POST参数的可变映射

  • 见下文

访问范围

可以使用上面的变量名结合Groovy的数组索引运算符来访问作用域,即使在Servlet API提供的类(例如,:

 BookController {
    定义 () {
        定义findBy参数""]
        定义appContext请求""]
        定义loggingUser会话"登录的用户"]
    }
}

您还可以使用de reference运算符访问范围内的值,从而使语法更加清晰

 BookController {
    定义 () {
        定义findBy参数findBy定义appContext请求foo定义loggingUser会话登录的用户

365bet地区这是365bet地区统一访问不同范围的方式之一

使用Flash Scope

365bet地区365bet地区支持以下概念:作用域作为临时存储区,以使属性仅可用于此请求和下一个请求。之后,清除属性。这对于直接在重定向之前设置消息很有用,例如

定义 () {
    定义b获取参数ID如果b即时消息"找不到ID的使用者${参数ID}"重新导向行动清单剩余的代码
}

当。。。的时候要求采取行动信息值将在范围内,可用于显示信息消息。它将从第二个请求后的范围

请注意,属性名称可以是您想要的任何名称,并且值通常是用于显示消息的字符串,但可以是任何对象类型

范围控制器

新创建的应用程序具有grails控制器defaultScope属性设置为in中的单例值您可以将此值更改为下面列出的任何受支持的范围如果未在所有控制器上为该属性分配值,则默认为原型范围

支持的控制器范围是

  • 原型默认值将为每个建议的操作请求创建一个新的控制器作为关闭属性

  • 会议为用户会话的范围创建了一个控制器

  • 单身人士建议仅将控制器的一个实例用于操作作为方法

要启用其中一个范围,请添加静态范围具有上面列出的有效范围值之一的类的属性

静态的范围"单身人士"

您可以在中定义默认策略grails控制器defaultScope例如键

ils:
    :
        defaultScope单身人士
明智地使用作用域控制器例如,我们不建议在单例作用域控制器中使用任何属性,因为它们将为所有要求

模型和视图

退回模型

模型是视图在渲染时使用的Map,该Map中的键对应于视图可访问的变量名称。有两种返回模型的方法:首先,您可以显式返回Map实例。

定义 () {
    [: 获取参数ID
以上确实反映您应该在脚手架视图中使用的内容,请参见脚手架部分更多细节

一种更高级的方法是返回Spring的实例的ModelAndView

 组织springframework Web servlet ModelAndView

定义 指数() {
    为索引页面获取一些书籍,也许是您的最爱
    定义最喜欢的书转发到列表视图以显示它们
    返回 的ModelAndView"书单"bookList最喜欢的书

要记住的一件事是某些变量名称不能在模型中使用

  • 属性

  • 应用

365bet地区当前,如果您使用它们,将不会报告任何错误,但是希望在将来的365bet地区版本中会有所改变。

选择视图

在前两个示例中,没有代码指定365bet地区渲染因此365bet地区如何知道该选择哪个答案答案在于约定365bet地区会在该位置查找视图365bet地区应用程式观看次数显示gsp为了这行动

 BookController {
    定义 () {
         [: 获取参数ID

要渲染其他视图,请使用渲染方法

定义 () {
    定义地图: 获取参数id渲染: "显示", 模型地图

365bet地区在这种情况下,365bet地区将尝试在该位置渲染视图grails应用视图图书显示gsp365bet地区请注意,365bet地区会自动使用目录grails应用程序视图目录这很方便,但是要访问共享视图,请使用绝对路径而不是相对路径

定义 () {
    定义地图: 获取参数id渲染: "共享显示", 模型地图

365bet地区在这种情况下,365bet地区将尝试在该位置渲染视图grails应用视图共享显示gsp.

365bet地区365bet地区还支持将JSP作为视图,因此,如果在预期的位置找不到GSP,但是将使用JSP代替

为命名空间的控制器选择视图

如果控制器使用命名空间365bet地区属性,它将影响365bet地区在其中查找用相对路径指定的视图的根目录。名称空间控制器呈现的视图的默认根目录为grails应用程序视图//365bet地区如果在命名空间目录中找不到该视图,则365bet地区将回退以在非命名空间目录中查找该视图

参见下面的例子

 ReportingController {
    静态的命名空间'商业'

    定义 人力资源() {
        这将使grails应用程序视图业务报告humanResources gsp
        如果存在

        如果grails应用程序查看业务报告,则humanResources gsp不会
        存在后备将是grails应用视图报告humanResources gsp

        命名空间的GSP优先于非命名空间的GSP

        [在职员工人数: 9]
    }

    定义 应收账款() {
        这将显示grails应用程序视图业务报告编号Crunch gsp
        如果存在

        如果grails应用查看了业务报告编号,则Crunch gsp不会
        存在后备将是grails应用程序视图报告报告数量

        命名空间的GSP优先于非命名空间的GSP渲染: 'numberCrunch', 模型: [在职员工人数: 13]
    }
}

呈现回应

有时,例如使用Ajax应用程序更容易直接从控制器将文本或代码段呈现为响应。渲染可以使用的方法

渲染"你好,世界"

上面的代码将文本Hello World写入响应中,其他示例包括

写一些标记渲染对于b图书divIDb id b标题
呈现特定视图渲染: '')
为集合中的每个项目渲染模板渲染模板: '书模板', 采集: 清单
用编码和内容类型渲染一些文本渲染文本: "一些XML", 内容类型: "文字xml", 编码方式: "UTF")

如果您打算使用Groovy s标记生成器生成HTML以便与渲染365bet地区方法要小心,例如,命名HTML元素和365bet地区标签之间的冲突

 groovy xml MarkupBuilderdef登录定义作家 StringWriter()
    定义建造者MarkupBuilder作者构建器html标题'登录'身体h'你好'形成定义html writer toString渲染html

这实际上调用表单标签这将返回一些文本,这些文本将被标记生成器正确输出

定义 登录() {
    // ...身体h'你好'建造者表格// ...
}

重定向和链接

重新导向

可以使用重新导向控制器方式

 概述控制器 {

    定义 登录() {}

    定义 () {
        如果会话用户重定向行动: '登录')
            返回
        }
        ...
    }
}

内部重新导向方法使用HttpServletResponse对象sendRedirect方法

重新导向方法期望以下之一

  • 动作名称和控制器名称(如果重定向不是当前控制器中的动作)

重新导向控制者: '', 行动: '指数')
  • 相对于应用程序上下文路径的资源的URI

重定向到显式URI重新导向小号: "登录html")
  • 或完整网址

重定向到URL重新导向网址: "http grails org")
重定向到域实例
获取域实例重定向书

365bet地区在上面的示例中,365bet地区将使用domain类构造链接ID如果存在

可以选择使用以下命令将参数从一个动作传递到下一个动作:参数方法的论点

重新导向行动: '', 参数: [myparam: "我的价值"])

这些参数可通过参数访问请求参数的动态属性如果指定的参数名称与请求参数的名称相同,则将覆盖请求参数,并使用控制器参数

自从参数object是一个Map,您可以使用它将当前请求参数从一个操作传递到下一个操作

重新导向行动: "下一个", 参数参数

最后,您还可以在目标URI中包含一个片段

重新导向控制者: "测试", 行动: "", 分段: "轮廓")

这将取决于URL映射重定向到类似myapp test show profile的内容

链式

动作也可以链接起来链接允许将模型从一个动作保留到下一个动作,例如调用第一采取行动

 ExampleChainController {

    定义 第一行动模型: [: 1])
    }

    定义 第二行动第三模型: [: 2])
    }

    定义 第三() {
        [: 3])
    }
}

[: 1, : 2, : 3]

可使用以下命令在链中的后续控制器操作中访问模型链模型map此动态属性仅存在于调用的动作之后方法

  {

    定义 nextInChain() {
        定义myModel chainModel模型

重新导向方法,您还可以将参数传递给方法

行动: "行动", 模型: [: 1], 参数: [myparam: ""])
chain方法使用HTTP会话,因此仅在您的应用程序是有状态的时才应使用

数据绑定

数据绑定是将传入的请求参数绑定到对象或对象的整个图上的行为。数据绑定应处理所有必要的类型转换,因为通常由表单提交传递的请求参数始终是字符串,而对象的属性通常是字符串。 Groovy或Java对象可能不是

基于地图的绑定

数据绑定器能够将Map中的值转换并分配给对象的属性。数据绑定器将使用Map中具有与对象属性名称相对应的值的键将Map中的条目关联到对象的属性。代码演示了基础知识

365bet地区应用程序域人groovy
  {
    名字整数年龄
定义bindingMap名字: '彼得', : '加布里埃尔', : 63]

定义人绑定图断言人名'彼得'
断言人姓'加布里埃尔'
断言人年龄63

要更新域对象的属性,您可以将地图分配给属性域类的属性

定义bindingMap名字: '彼得', : '加布里埃尔', : 63]

定义人员人员获取someId人员属性bindingMap断言人名'彼得'
断言人姓'加布里埃尔'
断言人年龄63

活页夹可以使用Maps of Maps填充对象的完整图

  {
    名字整数年龄地址家庭住址 地址 {
    国家
定义bindingMap名字: '彼得', : '加布里埃尔', : 63, 家庭地址: [: '萨里', 国家: '英国'] ]

定义人绑定图断言人名'彼得'
断言人姓'加布里埃尔'
断言人年龄63
断言人家地址县'萨里'
断言人家地址国家'英国'

绑定到收藏和地图

数据绑定程序可以填充和更新Collections和Maps。以下代码显示了填充清单域类中对象的数量

  {
    静态的有很多专辑专辑清单专辑 专辑 {
    标题整数numberOfTracks
定义bindingMap: '创世记',
                  '专辑': [标题: '狐步舞', numberOfTracks: 6],
                  '专辑': [标题: '苗圃', numberOfTracks: 7]]

定义带绑定图断言乐队名称'创世记'
断言乐队专辑大小2
断言乐队专辑0标题'狐步舞'
断言乐队专辑0numberOfTracks6
断言乐队专辑1标题'苗圃'
断言乐队专辑1numberOfTracks7

该代码将以相同的方式工作,如果专辑是一个数组而不是一个清单.

请注意,绑定到的结构被束缚于与a的相同绑定到清单但由于是无序的,索引不一定对应于元素中的顺序在上面的代码示例中,如果专辑是一个代替清单bindingMap看起来可能完全一样,但Foxtrot可能是否则可能是第二个。被分配给一定有ID其中的元素代表如下例所示进行更新

索引和相册以及相册中的值是任意值,可以是任意值,只要它们在Map中是唯一的即可。它们不对应于相册中元素的顺序,因为相册是Set
定义bindingMap'专辑': [ID: 9, 标题: '羔羊躺在百老汇']
                  '专辑': [ID: 4, 标题: '用英镑卖英格兰']]

定义band Band获得someBandId这将在ID为的专辑中找到该专辑并将其标题设置为The Lamb Lies Down On Broadway,并在ID为的专辑中找到该专辑并将其标题设置为Selling England By The Pound在两种情况下,如果无法在专辑中找到该专辑,则将通过ID从数据库中检索该专辑。该专辑将被添加到专辑中,并使用上述值进行更新。如果在数据库中找不到具有指定ID的专辑,则绑定错误将被创建并与band对象相关联。带属性bindingMap

绑定到绑定的结构与a的结构相同用于绑定到清单或一个而方括号内的索引对应于势必看下面的代码

 专辑 {
    标题静态的有很多玩家们播放器玩家们 播放器 {
    那么
定义bindingMap标题: '羔羊躺在百老汇',
                  '吉他手': [: '史蒂夫·哈克特'],
                  '玩家声带': [: '彼得·加布里埃尔'],
                  '播放器键盘': [: '托尼·班克斯']]

定义专辑相册装订图断言专辑标题'羔羊躺在百老汇'
断言专辑播放器大小3
断言专辑播放器吉他名称'史蒂夫·哈克特'
断言专辑播放器的人声名称'彼得·加布里埃尔'
断言专辑播放器键盘名称'托尼·班克斯'

当更新现有的如果绑定中指定了密钥在中不存在绑定到一个新值将被创建并添加到使用指定的键,如以下示例所示

定义bindingMap标题: '羔羊躺在百老汇',
                  '吉他手': [: '史蒂夫·哈克特'],
                  '玩家声带': [: '彼得·加布里埃尔'],
                  '播放器键盘': [: '托尼·班克斯']]

定义专辑相册装订图断言专辑标题'羔羊躺在百老汇'
断言专辑播放器大小3
断言专辑播放器吉他名称'史蒂夫·哈克特'
断言专辑播放器的人声名称'彼得·加布里埃尔'
断言专辑播放器键盘名称'托尼·班克斯'

定义UpdatedBindingMap'球员鼓': [: '菲尔·柯林斯'],
                         '播放器键盘': [: '安东尼·乔治·班克斯'相册属性已更新断言专辑标题'羔羊躺在百老汇'
断言专辑播放器大小4
断言专辑播放器吉他名称'史蒂夫·哈克特'
断言专辑播放器的人声名称'彼得·加布里埃尔'
断言专辑播放器键盘名称'安东尼·乔治·班克斯'
断言专辑播放器鼓名称'菲尔·柯林斯'

将请求数据绑定到模型

参数控制器中可用的对象具有特殊的行为,有助于将点的请求参数名称转换为数据绑定程序可以使用的嵌套映射,例如,如果请求包含名为人家地址国家人家地址城市分别具有美国和圣路易斯的价值参数将包括这些条目

[: [家庭地址: [国家: '美国', : '圣路易斯']]]

有两种方法将请求参数绑定到域类的属性上:第一种涉及使用域类Map构造函数

定义 () {
    定义b 参数b保存

数据绑定发生在代码内新书参数通过参数365bet地区域类构造函数的对象365bet地区会自动识别您正在尝试从请求参数进行绑定,因此,如果我们有一个传入请求,例如

图书保存标题The Stand作者Stephen King

然后标题作者请求参数将在域类上自动设置。您可以使用属性用于将数据绑定到现有实例的属性

定义 () {
    定义b获取参数id b属性参数b保存

与使用隐式构造函数的效果相同

绑定空字符串时,如果其中没有字符甚至没有空格的字符串都被绑定,则数据绑定器会将空字符串转换为null。这简化了最常见的情况,其目的是将空表单字段视为具有null值,因为实际将null提交为请求参数的方法当这种行为不是所希望的时,应用程序可以直接分配该值

质量属性绑定机制默认情况下会在绑定时自动修剪所有字符串。要禁用此行为,请设置继承数据绑定trimStrings属性为falsegrails应用配置会议应用程序.

默认值是true继承数据绑定trimStrings

// ...

mass属性绑定机制默认会在绑定时自动将所有空字符串转换为null要禁用此行为,请设置继承数据绑定convertEmptyStringsToNull属性为falsegrails应用配置会议应用程序.

默认值是true继承数据绑定convertEmptyStringsToNull

// ...

事件的顺序是发生字符串修整,然后发生空转换,所以如果trimStringsconvertEmptyStringsToNull空字符串不仅会转换为null,而且还会将空字符串转换为空。修剪方法返回空字符串

365bet地区365bet地区中的这些形式的数据绑定非常方便,但是也可以不加选择地进行替换。换句话说,它们将绑定所有365bet地区目标对象的非瞬态类型实例属性,包括您可能不想绑定的那些实例属性,因为用户界面中的表单未提交所有属性,攻击者仍然可以通过原始HTTP请求发送恶意数据针对此类攻击的更多信息,请参见标题为“数据绑定和安全问题”的部分。

数据绑定和单端关联

如果你有一个一对一要么多对一365bet地区关联,您也可以使用365bet地区数据绑定功能来更新这些关系,例如,如果您有一个传入请求,例如

图书保存作者编号

365bet地区365bet地区会自动检测到ID在request参数上添加后缀并查找作者进行数据绑定时给定id的实例,例如

定义b 参数

关联属性可以设置为空值通过传递文字null例如

图书保存作者ID为null

数据绑定和许多终止的关联

如果您具有一对多或多对多关联,则根据关联类型,可以使用不同的数据绑定技术

如果你有一个基于关联的默认有很多那么填充关联的最简单方法是发送标识符列表,例如,考虑使用下面

<> ="图书"
          ="图书清单"
          尺寸="5" ="" optionKey="ID"
          ="作者书" />

365bet地区这将产生一个选择框,使您可以选择多个值。在这种情况下,如果您提交表单,365bet地区将自动使用选择框中的标识符来填充图书协会

但是,如果您要更新关联对象的属性,则此技术将无法使用,而是使用下标运算符

<> ="书名" ="展台" />
<> ="书名" ="闪耀" />

但是用基于关联的关系,至关重要的是,您要按照计划进行更新的顺序来渲染标记,这是因为没有顺序的概念,所以尽管我们指的是图书图书除非您自己进行一些明确的排序,否则不能保证关联的顺序在服务器端是正确的

如果使用,这不是问题清单基于清单具有已定义的顺序和可以参考的索引基于协会

还要注意,如果要绑定的关联的大小为2,并且引用的元素超出了关联的大小

<> ="书名" ="展台" />
<> ="书名" ="闪耀" />
<> ="书名" ="红魔" />

365bet地区然后365bet地区将在定义的位置自动为您创建一个新实例

您可以将关联类型的现有实例绑定到清单使用相同ID与单端关联一起使用的语法例如

<> ="书籍编号" ="bookList"
          ="作者书籍编号" />

<> ="书籍编号" ="bookList"
          ="作者书籍编号" />

<> ="书籍编号" ="bookList"
          ="作者书籍编号" />

允许在书籍清单单独选择

特定索引中的条目也可以用相同的方法删除。例如

<> ="书籍编号"
          ="图书清单"
          ="作者书籍编号"
          noSelection="空值"/>

将呈现一个选择框,该选择框将删除以下位置的关联图书如果选择了空选项

绑定到属性的工作方式相同,只是参数名称中的列表索引被映射键替换

<> ="图片封面编号"
          ="图片清单"
          ="图书图片封面ID"
          noSelection="空值"/>

这会将选定的图像绑定到属性图片在...的关键之下覆盖.

绑定到“地图数组和集合”时,数据绑定器将根据需要自动增大集合的大小

绑定程序将增长集合的最大大小的默认限制是:如果数据绑定器遇到一个要求将集合增长到该限制之外的条目,则该条目将被忽略。可以通过为该赋值来配置该限制。继承数据绑定autoGrowCollectionLimit财产应用程序.
grails应用配置会议应用程序
默认值为继承数据绑定autoGrowCollectionLimit128

// ...

具有多个域类的数据绑定

可以将数据从参数宾语

例如,您有一个传入请求

图书保存书名The Stand作者姓名Stephen King

您会注意到与上述请求的区别在于每个参数都有一个前缀,例如作者要么365bet地区用于隔离哪些参数属于哪种365bet地区类型参数对象就像多维散列,您可以对其进行索引以仅隔离要绑定的参数的子集

定义b 参数书

请注意,我们如何使用前缀的第一个点书名参数以仅隔离此级别以下的参数进行绑定我们可以使用作者域类

定义一种作者params作者

数据绑定和动作参数

控制器动作自变量受请求参数数据绑定的约束控制器动作自变量的类别第一类是命令对象复杂类型被视为命令对象命令对象有关详细信息,请参见用户指南的“其他”部分。其他类别是基本对象类型。支持的类型是基元及其对应的类型包装器和java长字符串默认行为是按名称将请求参数映射到操作参数

 AccountingController {

   帐号将使用参数帐号的值进行初始化
   accountType将使用参数accountType初始化
   定义 显示发票(帐号整型帐户类型// ...
   }
}

对于原始参数和作为任何原始类型包装器类实例的参数,必须先进行类型转换,然后才能将请求参数值绑定到动作参数。类型转换会自动发生。参数accountType请求参数必须转换为整型如果由于某种原因类型转换失败,则该参数将按照常规Java行为具有其默认值,对于类型包装器而言,该参数为null;对于布尔值,该参数为false;对于数字,该参数为零;并且相应的错误将添加到错误定义控制器的属性

会计显示发票帐户编号B帐户类型假值

由于bogusValue不能转换为int类型,accountType的值将为零,控制器错误hasErrors将是真实的控制器错误errorCount将等于和控制器错误getFieldError accountType将包含相应的错误

如果参数名称与请求参数的名称不匹配,则grails web RequestParameter可以将注解应用于自变量,以表达应绑定到该自变量的请求参数的名称

 grails web RequestParameter

 AccountingController {

   主帐号将使用参数帐号的值进行初始化
   accountType将使用参数accountType初始化
   定义 显示发票(RequestParameter('帐号') Mainarikon整型帐户类型// ...
   }
}

数据绑定和类型转换错误

365bet地区有时在执行数据绑定时,无法将特定的String转换为特定的目标类型。这会导致类型转换错误365bet地区会将类型转换错误保留在内部错误365bet地区365bet地区域类的属性,例如

 URL发布者URL

这里我们有一个领域类使用Java网络网址给定URL等给定请求的URL类

图书保存PublisherURL错误的URL

无法绑定字符串错误的网址PublisherURL属性发生类型不匹配错误您可以像这样检查这些

定义b 参数如果b hasErrors println"价值${b错误getFieldError'PublisherURL'被拒绝的值}" +
            "不是有效的网址"
}

尽管我们尚未涵盖错误代码以获取更多信息,请参阅验证对于类型转换错误,您需要从365bet地区应用程序在消息属性中用于错误的文件您可以使用通用错误消息处理程序,例如

typeMismatch java net URL字段0不是有效的网址

或更具体的一个

typeMismatch图书PublisherURL发行者网址您指定的无效网址

BindUsing注释

绑定使用批注可以用于为类中的特定字段定义自定义绑定机制,只要将数据绑定应用于字段,便会使用参数调用批注的闭包值。第一个参数是正在应用数据绑定的对象到,第二个参数是DataBindingSource这是数据绑定的数据源。从闭包返回的值将绑定到属性。以下示例将导致源中的值将应用于数据绑定期间的字段

 grails数据绑定BindUsing

 某类 {
    绑定使用obj源源是DataSourceBinding,类似于Map
        并定义了getAt操作,但此处不能使用源名称
        为了从源获取名称,请使用getAt,如下所示资源''至大写那么
请注意,仅当请求参数的名称与类中的字段名称匹配时,才可以进行数据绑定来自请求参数匹配某类.

绑定使用注释可用于为特定类上的所有字段定义自定义绑定机制。将注释应用于类时,分配给注释的值应为实现以下内容的类:绑定助手接口只要将值绑定到已应用此注释的类中的属性,就将使用该类的实例。

绑定使用SomeClassWhichImplementsBindingHelper 某类 {
    someProperty整数一些其他财产

BindInitializer批注

BindInitializer如果未定义,则注释可以用于初始化类中的关联字段。绑定使用注释数据绑定将继续绑定此关联上的所有嵌套属性

 继承数据绑定BindInitializer

 帐户{}

 用户帐号帐号BindInitializer期望您返回该类型的实例
  在这种情况下,您可以将source用作参数
  BindInitializer用户联系帐户用户帐号联系方式联系方式 联系帐号帐号名字
根据此用例,BindInitializer仅对关联的实体有意义

定制数据转换器

绑定器将自动执行很多类型转换。某些应用程序可能想要定义自己的用于转换值的机制,而执行此操作的一种简单方法是编写一个实现值转换器并在Spring应用程序上下文中将该类的实例注册为Bean

使用myapp转换器 grails数据绑定转换器ValueConverter

一个自定义转换器,它将城市形式的String转换为Address对象
 AddressValueConverter 实施值转换器布尔值canConvert值的值实例 
    }

    定义 兑换定义价值分割':')
        com myapp地址0], 1])
    }

    getTargetType com myapp地址

该类的实例需要在Spring应用程序上下文中注册为bean。bean名称并不重要。所有实现ValueConverter的bean将自动插入到数据绑定过程中

grails app conf春季资源groovy
bean addressConverter com myapp转换器AddressValueConverter// ...
}
  {
    名字地址家庭地址 地址 {
    定义人人属性名字: '杰夫', 家庭地址: "奥法伦密苏里州"]
断言人名'杰夫'
断言人家地址城市"法伦"
断言人的住所地址状态'密苏里州'

数据绑定的日期格式

通过将字符串绑定到Date值时,可以指定要使用的自定义日期格式。绑定格式日期字段的注释

 继承数据绑定BindingFormat

  {
    绑定格式('马迪')
    日期生日

可以在以下位置配置全局设置应用程序定义绑定到日期时将在整个应用程序范围内使用的日期格式

grails应用配置会议应用程序
继承数据绑定dateFormats'马迪', 'yyyy MM dd HH mm ss S', "yyyy MM dd T hh mm ss Z"]

指定的格式继承数据绑定dateFormats如果将属性标记为,将尝试按它们在列表中的顺序进行尝试。绑定格式绑定格式将优先于中指定的值继承数据绑定dateFormats.

默认配置的格式是

  • yyyy MM dd HH mm ss S

  • yyyy MM dd T hh mm ss Z

  • yyyy MM dd HH mm ss S z

  • yyyy MM dd T HH mm ss SSSX

自定义格式的转换器

您可以为自己的绑定格式通过编写实现FormattedValueConverter接口,并将该类的实例注册为Spring应用程序上下文中的Bean。下面是一个简单的自定义String格式化程序的示例,该格式化程序可以根据分配给BindingFormat批注的值转换String的大小写

使用myapp转换器 grails数据绑定转换器FormattedValueConverter

 FormattedStringValueConverter 实施FormattedValueConverter定义 兑换格式如果('大写'格式值值toUpperCase其他 如果('小写'格式值值到小写值getTargetType指定此转换器可以应用的类型
        
    }
}

该类的实例需要在Spring应用程序上下文中注册为bean。bean名称并不重要。所有实现FormattedValueConverter的bean将自动插入数据绑定过程中。

grails app conf春季资源groovy
豆formattedStringConverter com myapp转换器FormattedStringValueConverter// ...
}

有了这个绑定格式注释可以应用于字符串字段,以通知数据绑定器利用自定义转换器

 继承数据绑定BindingFormat

  {
    绑定格式('大写')
    someUpperCaseString绑定格式('小写')
    someLowerCaseStringsomeOtherString

本地绑定格式

绑定格式注释通过使用可选功能支持本地化格式字符串属性如果将值分配给了代码属性,则该值将用作消息代码,以从messageSourcebean在Spring应用程序上下文中,并且该查找将被本地化

 继承数据绑定BindingFormat

  {
    绑定格式'日期格式生日')
    日期生日
#grails应用程序确认消息属性日期格式生日MMddyyyy
#grails应用程序确认消息和属性日期格式生日ddMMyyyy

结构化数据绑定编辑器

结构化数据绑定编辑器是一个帮助程序类,可以将结构化请求参数绑定到属性。结构化绑定的常见用例是绑定到日期对象,它可以由几个请求参数中包含的一些较小的信息片段构成,这些请求参数的名称类似于生日月份, 生日生日年结构化的编辑器将检索所有这些单独的信​​息,并使用它们来构造一个日期.

该框架提供了用于绑定到的结构化编辑器日期对象应用程序可以为任何适当的类型注册其自己的结构化编辑器考虑以下类

src main groovy数据绑定小工具groovy
数据绑定 小工具 {
    形状expandShape形状压缩形状
src主groovy数据绑定Shape groovy
数据绑定 形状 {
    整型区域

一种小工具形状栏位A形状有一个区域属性可能是应用程序想要接受请求参数,例如宽度高度并用这些来计算区域形状在绑定时,结构化的绑定编辑器非常适合

向数据绑定过程注册结构化编辑器的方法是添加一个实例。继承数据绑定TypedStructuredBindingEditor与Spring应用程序上下文的接口最简单的实现方法TypedStructuredBindingEditor界面是扩展组织grails数据绑定转换器AbstractStructuredBindingEditor抽象类并覆盖getPropertyValue方法如下图

src主groovy数据绑定转换器StructuredShapeEditor groovy
数据绑定转换器 数据绑定形状

 组织grails数据绑定转换器AbstractStructuredBindingEditor

 结构化形状编辑器 延伸AbstractStructuredBindingEditor形状> {

    上市 形状getPropertyValue价值观从地图中检索单个值
        定义宽度值width 整型
        定义高度值高度 整型

        使用这些值计算Shape的面积
        定义区域宽度高度创建并返回具有适当面积的Shape
         形状(区域区域

该类的实例需要在Spring应用程序上下文中注册

grails app conf春季资源groovy
bean shapeEditor数据绑定转换器结构化ShapeEditor// ...
}

当数据绑定器绑定到小工具类,它将检查是否有带有名称的请求参数压缩形状expandShape具有struct的值,如果确实存在,则将触发使用结构化形状编辑器结构的各个组成部分必须具有以下格式的参数名称:propertyName结构元素名称小工具上面的类意味着压缩形状request参数的值应为struct,并且压缩形状宽度压缩形状高度参数应具有代表压缩后的宽度和高度的值形状同样expandShaperequest参数的值应为struct,并且扩展形状宽度形状高度参数应具有代表展开后的宽度和高度的值形状.

grails应用程序控制器演示DemoController groovy
 演示控制器 {

    定义 createGadget小工具演示createGadget ExpandedShape结构体ExpandedShape宽度expandShape高度压缩Shape结构CompressedShape宽度compressionShape高度

        带有上面显示的请求参数的小工具expandShape区域将是
        和小工具compressedShape区域将是
        // ...
    }
}

通常,以struct作为其值的请求参数将由隐藏的表单字段表示

数据绑定事件侦听器

DataBindingListener接口提供了一种机制,可将数据绑定事件通知给侦听器。接口看起来像这样

数据绑定事件 发生数据绑定错误BindingError;

一个监听器,该监听器将被通知有关数据绑定作者Jeff Brown期间生成的事件的信息,请参见DataBindingListenerAdapter
上市 接口DataBindingListener如果侦听器对指定类型的事件感兴趣,则返回true
    布尔值支持爵士乐当数据绑定将要开始参数目标时调用对象数据绑定是对参数错误施加的,Spring Errors实例为org springframework验证,如果数据绑定应该继续,则Result返回true
    布尔型beforeBinding宾语目标宾语错误当即将对属性param目标施加数据绑定时调用将对对象param属性施加对象数据绑定propertyName被绑定到param值的属性的名称被绑定的属性的值param错误Spring Errors实例进行org springframework验证如果应该继续数据绑定,则BindingResult返回true,否则返回false
    布尔型beforeBinding宾语目标propertyName宾语宾语错误在对属性param目标强加数据绑定之后调用在对参数param强加对象数据绑定之后propertyName绑定到param错误的属性的名称Spring Errors实例进行org springframework验证BindingResult
    虚空afterBinding宾语目标propertyName宾语错误在数据绑定完成参数目标之后调用对象数据绑定是对参数错误施加的,Spring Errors实例是一个org springframework验证BindingResult
    虚空afterBinding宾语目标宾语错误发生错误时,将错误绑定到属性参数错误,该错误将封装有关绑定错误参数的信息,Spring Errors实例为org springframework验证BindingResult,请参见BindingError
    虚空bindingError BindingError错误宾语错误

Spring应用程序上下文中实现该接口的任何bean都会自动向数据绑定程序注册。DataBindingListenerAdapter类实现DataBindingListener接口,并提供接口中所有方法的默认实现,因此此类非常适合于子类化,因此您的侦听器类仅需要为您的侦听器感兴趣的方法提供实现

直接使用数据绑定器

在某些情况下,应用程序可能需要直接使用数据绑定程序,例如在Service上对不是域类的某些任意对象进行绑定。属性属性是只读的

src main groovy bindingdemo Widget groovy
绑定演示 小部件 {
    整数尺寸
grails应用程序服务bindingdemo WidgetService常规
绑定演示 WidgetService {

    定义 updateWidget小部件小部件数据这将引发异常,因为
        属性是只读的小部件属性数据

数据绑定程序的一个实例在Spring应用程序上下文中,其bean名称为grailsWebDataBinder该bean实现了DataBinder的接口以下代码演示直接使用数据绑定程序

grails应用程序服务绑定dmeo WidgetService
绑定演示 继承数据绑定SimpleMapDataBindingSource

 WidgetService {

    这个bean将被自动连接到服务中
    定义grailsWebDataBinder定义 updateWidget小部件小部件数据grailsWebDataBinder绑定小部件数据SimpleMapDataBindingSource

看到DataBinder的文档,以获取有关重载版本的更多信息。捆绑方法

数据绑定和安全问题

从请求参数批量更新属性时,请注意不要允许客户端将恶意数据绑定到域类并保留在数据库中。您可以使用下标运算符来限制将哪些属性绑定到给定的域类

定义p人得到1p个属性'名字',''参数

在这种情况下,只有名字属性将被绑定

另一种方法是使用命令对象作为数据绑定的目标而不是域类的目标bindData方法

bindData方法允许相同的数据绑定功能,但可以绑定到任意对象

定义p人bindData p参数

bindData方法还允许您排除某些不想更新的参数

定义p人bindData p参数排除: '出生日期'])

或仅包含某些属性

定义p人bindData p参数包括: ['名字', '']])
如果提供了一个空列表作为值包括参数,那么如果未明确排除所有字段,则将对其进行绑定

可绑定的约束可用于全局阻止某些属性的数据绑定

用JSON响应

使用response方法输出JSON

响应方法是返回JSON并与之集成的首选方法内容协商JSON视图.

响应方法提供内容协商策略,以智能地为给定客户端生成适当的响应

例如给出以下控制器和动作

grails应用程序控制器示例BookController groovy
 BookController {
    定义 指数响应清单

响应方法将采取以下步骤

  1. 如果客户接受标头指定一种媒体类型,例如应用程序json用那个

  2. 如果以URI为文件扩展名图书json包括在的财产grails应用配置会议应用yml使用配置中定义的媒体类型

响应然后将寻找合适的方法渲染器对象和从中计算出的媒体类型RendererRegistry.

365bet地区365bet地区包括许多预先配置的渲染器实现将为传递给的参数生成JSON响应的默认表示形式响应书jsonURI将产生JSON,例如

[
    {一世d:1,"标题":"展台"},
    {一世d:2,"标题":"闪亮的"}
]

控制媒体类型的优先级

365bet地区默认情况下,如果您定义了一个控制器,则不存在将哪种格式发送回客户端的优先级,365bet地区假定您希望将HTML作为响应类型提供

但是,如果您的应用程序主要是API,则可以使用responseFormats属性

grails应用程序控制器示例BookController groovy
 BookController {
    静态的responseFormats'json', 'html']
    定义 指数响应清单

365bet地区在上面的示例中,365bet地区默认会以json如果无法通过接受标头或文件扩展名

使用视图输出JSON响应

如果您定义视图,则是GSP还是JSON视图365bet地区然后365bet地区将在使用响应通过从传递给参数的模型计算模型响应.

例如,在上一个清单中,如果要定义365bet地区应用程式浏览量索引gson365bet地区应用程序观看次数索引gsp查看这些将在客户要求时使用应用程序json要么文字HTML因此,您可以定义一个后端,该后端能够提供对Web浏览器的响应或代表您的应用程序的API

365bet地区渲染视图时,365bet地区会根据传递给的值的类型来计算要传递给视图的模型响应方法

下表总结了此约定

参数类型 计算模型变量

回应书单

bookList

响应

空清单

回复预订

范例书

响应

整数列表

按设定回应

java有用集

integerSet

响应为整数

整数

整数数组

使用此约定,您可以引用传递给的参数响应从您的观点

365bet地区应用程式浏览量书籍索引gson
领域 清单<bookList[]json bookList书名书名

您会注意到,如果图书清单返回一个空列表,然后将模型变量名称转换为空清单这是设计使然,如果未指定模型变量(例如),则应在视图中提供默认值。清单在上面的例子中

365bet地区应用程式浏览量书籍索引gson
默认为空列表
领域 清单<bookList[]
...

在某些情况下,您可能希望更明确地控制模型变量的名称,例如,如果您有一个域继承层次结构,清单我返回的依赖于自动计算的不同子类可能并不可靠

在这种情况下,您应该直接使用响应和地图参数

响应bookList: 清单
在集合中使用任何混合参数类型进行响应时,请始终使用显式模型名称

如果您只是想扩充计算出的模型,则可以通过传递一个模型论点

响应清单模型: [bookCount: 计数

上面的例子将产生一个像bookList图书bookCount总图书计算的模型与传递给模型的模型相结合模型论点

使用render方法输出JSON

渲染方法也可以用于输出JSON,但仅应用于不保证创建JSON视图的简单情况

定义 清单() {

    定义结果列表渲染内容类型: "应用程序json"图书成绩b标题b标题

在这种情况下,结果将类似于

[
    {"标题":"展台"},
    {"标题":"闪亮的"}
]
对于非常简单的响应,这种呈现JSON的技术可能没问题,但通常来说,您应该赞成使用JSON视图并使用视图层而不是在应用程序中嵌入逻辑

与上述XML命名冲突相同的危险也适用于JSON构建

有关JSONBuilder的更多信息

365bet地区上一节有关XML和JSON响应的部分介绍了呈现XML和JSON响应的简单示例,而365bet地区使用的XML构建器是标准的XmlSlurper在Groovy中找到

365bet地区对于JSON,因为365bet地区 365bet地区使用Groovy流JsonBuilder默认情况下,您可以参考Groovy文档流JsonBuilder有关如何使用它的API文档

用XML响应

上载档案

程序化文件上传

365bet地区365bet地区支持使用Spring进行文件上传MultipartHttpServletRequest界面上传文件的第一步是创建一个多部分表单,如下所示

上载表格<> />
    <> 行动="上载">
        <> 类型="文件" ="myFile" />
        <> 类型="提交" />
    

uploadForm编码多部分表单数据归因于标准标签

然后,有很多方法可以处理文件上传。一种是与Spring一起使用。多部分文件直接实例

定义 上载() {
    定义f请求getFile'myFile')
    如果f空Flash消息'文件不能为空'渲染视图: 'uploadForm')
        返回f transferTo 文件('一些本地目录myfile txt'响应sendError200, '完成')
}

这样可以方便地进行到其他目标的传输和直接操作文件,因为您可以获得输入流以此类推多部分文件接口

通过数据绑定上传文件

也可以使用数据绑定执行文件上传图片域类

 图片 {
    字节[]myFile静态的约束将上传文件的大小限制为MBmyFilemaxSize: 1024 * 1024 * 2
    }
}

如果您使用参数365bet地区如下例所示,构造函数中的object对象会自动将文件的内容绑定为myFile属性

定义img 图片参数

设置尺寸要么maxSize约束,否则您的数据库可能创建时具有很小的列大小,无法处理合理大小的文件。例如,对于H和MySQL,默认情况下,它们的blob大小为字节大小属性

也可以通过更改文件的类型将文件的内容设置为字符串。myFile图像上的属性设置为String类型

 图片 {
   myFile

增加上传最大文件大小

365bet地区365bet地区文件上传的默认大小为KB当超过此限制时,您将看到以下异常

org springframework web multipart MultipartException无法解析multipart servlet请求嵌套的异常是java lang IllegalStateException org apache tomcat util http fileupload FileUploadBase$SizeLimitExceededException

您可以在如下

grails应用配置会议应用yml
ils:
    :
        上载:
            maxFileSize: 2000000
            maxRequestSize: 2000000

maxFileSize上载档案的最大大小

maxRequestSize多部分表格数据请求允许的最大大小

将文件大小限制为最大值,以防止拒绝服务攻击

存在这些限制是为了防止DoS攻击并增强整体应用程序性能

命令对象

365bet地区365bet地区控制器支持命令对象的概念。命令对象是与以下命令结合使用的类数据绑定通常允许验证可能不适合现有域类的数据

仅当将类用作动作的参数时,才将其视为命令对象

声明命令对象

命令对象类的定义与其他任何类一样

 登录命令 实施grails验证有效用户名密码静态的约束用户名空白: , 最小尺寸: 6密码空白: , 最小尺寸: 6)
    }
}

在此示例中,命令对象类实现了有效期有效期特质允许定义约束条件就像在域类365bet地区如果命令对象与使用它的控制器在同一源文件中定义,365bet地区将自动使它成为命令对象有效期不需要命令对象类是可验证的

默认情况下,全部有效期不是以下实例的对象属性java util集合要么java util Map可为空的false的实例java util集合java util Map默认为可为空的true如果你想要一个有效期具有可为空的true属性默认情况下,您可以通过定义一个defaultNullable类中的方法

 作者搜索命令 实施grails验证有效整数静态的 布尔值defaultNullable
    }
}

在这个例子中验证期间将允许空值

使用命令对象

365bet地区要使用命令对象,控制器动作可以选择指定任意数量的命令对象参数。必须提供参数类型,以便365bet地区知道要创建和初始化的对象

365bet地区在执行控制器动作之前,365bet地区将自动创建命令对象类的实例,并通过绑定请求参数来填充其属性(如果命令对象类标记为)有效期然后将验证命令对象

 LoginController {

    定义 登录LoginCommand cmd如果cmd hasErrors重定向行动: '登录表单')
            返回
        }

        
    }
}

如果命令对象的类型是域类的类型,并且有一个ID然后使用request参数,而不是调用域类构造函数来创建新实例,而是调用static得到域类的方法和值ID参数将作为参数传递

从该调用返回的所有内容得到是将传递给控制器​​动作的内容,这意味着如果存在ID请求参数,并且在数据库中找不到相应的记录,则命令对象的值将为空值如果从数据库中检索实例时发生错误,则空值将作为参数传递给控制器​​操作,并且将向控制器添加错误错误属性

如果命令对象的类型是域类,则没有ID请求参数或有一个ID请求参数,其值为空空值除非HTTP请求方法是POST,否则它将传递到控制器操作中,在这种情况下,将通过调用域类构造函数来创建域类的新实例。对于所有域类实例为非null的情况,仅数据绑定如果HTTP请求方法是POST PUT或PATCH,则执行

命令对象和请求参数名称

通常,请求参数名称将直接映射到命令对象中的属性名称,嵌套参数名称可用于以直观的方式绑定对象图

在下面的示例中,请求参数名为将被绑定到的属性实例和一个名为的请求参数地址城市将被绑定到的属性地址物业.

 StoreController {
    定义 购买人购买者// ...
    }
}

  {
    名称地址地址 地址 {
    

如果控制器操作接受恰好包含相同属性名称的多个命令对象,则可能会出现问题,请考虑以下示例

 StoreController {
    定义 购买人购买者产品产品// ...
    }
}

  {
    名称地址地址 地址 {
     产品 {
    那么

如果有一个请求参数名为目前尚不清楚是否应该代表该名称产品或名称如果控制器动作接受相同类型的命令对象,则可能会出现该问题的另一个版本,如下所示

 StoreController {
    定义 购买人购买者人销售者产品产品// ...
    }
}

  {
    名称地址地址 地址 {
     产品 {
    那么

为了帮助解决此问题,框架强加了将参数名称映射到命令对象类型的特殊规则。命令对象数据绑定将把以控制器操作参数名称开头的所有参数都视为对应的命令对象

例如产品名称request参数将绑定到物业产品争论买方名称request参数将绑定到物业买方争论卖家地址城市request参数将绑定到的属性地址的属性卖方论据等

命令对象和依赖注入

365bet地区命令对象可以参与依赖项注入如果您的命令对象具有一些使用365bet地区的自定义验证逻辑,则这很有用服务:

 登录命令 实施grails验证有效定义loginService用户名密码静态的约束用户名验证器val obj obj loginService canLogin obj用户名obj密码

在此示例中,命令对象与loginService从春季通过名称注入的beanApplicationContext.

将请求主体绑定到命令对象

365bet地区当发出对接受命令对象的控制器操作的请求,并且该请求包含主体时,365bet地区将尝试根据请求内容类型来解析请求的主体,并使用该主体对命令对象进行数据绑定。下面的例子

grails应用程序控制器bindingdemo DemoController groovy
绑定演示 演示控制器 {

    定义 createWidget小部件w渲染"name${w名称}尺寸${尺寸}"
    }
}

 小部件 {
    整数尺寸
curl H内容类型应用程序json d名称某些窗口小部件大小localhost demo createWidget名称某些窗口小部件尺寸curl H内容类型应用程序xml d其他一些小部件2112本地主机bodybind演示createWidget名称其他Widget大小

在以下情况下不会解析请求正文

  • 请求方法是GET

  • 请求方法是DELETE

  • 内容长度为

请注意,正在解析请求的主体以使其正常工作。在此之后,任何尝试读取请求主体的尝试都将失败,因为对应的输入流将为空。控制器动作可以使用命令对象,也可以解析主体直接或通过引用类似于请求JSON之类的请求本身,但不能同时执行

grails应用程序控制器bindingdemo DemoController groovy
绑定演示 演示控制器 {

    定义 createWidget小部件w这将失败,因为它需要阅读身体
        已经读过了
        定义json请求JSON// ...

    }
}

使用命令对象列表

命令对象的常见用例是包含另一个对象的集合的命令对象。

 演示控制器 {

    定义 createAuthorAuthorCommand命令// ...

    }

     作者命令 {
        全名清单图书 BookCommand {
        标题伊斯本

在此示例中,我们要创建一个包含多本书的作者

为了从UI层进行这项工作,您可以在GSP中执行以下操作

<> ="提交作者书籍" 控制者="演示" 行动="createAuthor">
    <> ="全名" =""/>
    
  • <> ="书名" =""/> <> ="书本" =""/>
  • <> ="书名" =""/> <> ="书本" =""/>

    还支持JSON,因此您可以使用正确的数据绑定提交以下内容

    {
        "全名": "格雷姆·罗彻(Graeme Rocher)",
        "图书": [{
            "标题": "365bet地区权威指南",
            "伊斯本": "1111-343455-1111"
        }, {
            "标题": "365bet地区权威指南",
            "伊斯本": "1111-343455-1112"
        }],
    }

    处理重复的表格提交

    365bet地区365bet地区内置了使用同步器令牌模式处理重复表单提交的支持。要开始使用,请在形成标签

    <> 失落的县="" ...>

    然后,您可以在控制器代码中使用withForm处理有效和无效请求的方法

    withForm好要求invalidToken错误的请求
    }

    如果您仅提供withForm方法而不是链式invalidToken365bet地区方法,默​​认情况下365bet地区会将无效令牌存储在闪存invalidToken变量并将请求重定向回原始页面然后可以在视图中检查

    <> 测试="闪存invalidToken">不要单击按钮两次
    withForm标签利用了会议因此,如果在集群中使用,则需要会话关联性或集群会话

    简单类型转换器

    类型转换方法

    如果您希望避免数据绑定并且只想将传入的参数(通常是字符串)转换为另一个更合适的类型参数每种类型的对象都有许多便利方法

    定义总参数int'')

    上面的示例使用整型方法,还有一些方法布尔值, , 四个, 等等,这些方法中的每一个都是null安全的,并且不会出现任何解析错误,因此您不必对参数执行任何其他检查

    每种转换方法都允许将默认值作为可选的第二个参数传递。如果在映射中找不到对应的条目,或者在转换期间发生错误,则将返回默认值。示例

    定义总参数int'', 42)

    这些相同的类型转换方法也可以在属性GSP标签的参数

    处理多个参数

    一个常见的用例是处理多个同名的请求参数,例如,您可以获得一个查询字符串,例如名字鲍勃名字朱迪.

    在这种情况下,处理一个参数和处理多个参数具有不同的语义,因为Groovy的迭代机制遍历每个字符为了避免此问题,参数对象提供了一个清单总是返回列表的方法

    对于那么参数列表''println名称

    声明式控制器异常处理

    365bet地区365bet地区控制器支持声明性异常处理的简单机制,如果控制器声明了接受单个参数的方法,且参数类型为java lang异常java lang异常每当该控制器中的某个操作抛出该类型的异常时,该方法都将被调用。请参见以下示例

    grails应用程序控制器演示DemoController groovy
    演示 演示控制器 {
    
        定义 someAction() {
            做一些工作
        }
    
        定义 handleSQLException(SQLException并渲染'处理了SQLException'
        }
    
        定义 handleBatchUpdateException(BatchUpdateException重定向控制者: '测井', 行动: '批处理问题'
        }
    
        定义 handleNumberFormatException(NumberFormatExceptionfe问题描述: '号码无效']
        }
    }

    该控制器的行为就像写了这样的东西

    grails应用程序控制器演示DemoController groovy
    演示 演示控制器 {
    
        定义 someAction() {
            尝试 {
                做一些工作
            } 抓住 (BatchUpdateException返回处理BatchUpdateException e抓住 (SQLException返回处理SQLException e抓住 (NumberFormatException返回处理NumberFormatException e定义 handleSQLException(SQLException并渲染'处理了SQLException'
        }
    
        定义 handleBatchUpdateException(BatchUpdateException重定向控制者: '测井', 行动: '批处理问题'
        }
    
        定义 handleNumberFormatException(NumberFormatExceptionfe问题描述: '号码无效']
        }
    }

    异常处理程序的方法名称可以是任何有效的方法名称。名称不是使该方法成为异常处理程序的名称。例外参数类型是重要的部分

    异常处理程序方法可以执行控制器操作可以执行的任何操作,包括调用渲染, 重新导向返回模型等

    在多个控制器之间共享异常处理程序方法的一种方法是使用继承异常处理程序方法被继承到子类中,因此应用程序可以在多个控制器扩展自的抽象类中定义异常处理程序。在多个控制器之间共享异常处理程序方法的另一种方法是:使用如下所示的特征

    src主要groovy com演示DatabaseExceptionHandler groovy
    具有演示特征DatabaseExceptionHandler定义 handleSQLException(SQLException处理SQLException
        }
    
        定义 handleBatchUpdateException(BatchUpdateException处理BatchUpdateException
        }
    }
    grails应用控制器com演示DemoController groovy
    带演示 演示控制器 实施DatabaseExceptionHandler定义的所有异常处理程序方法
        在数据库中ExceptionHandler将被添加到
        此类在编译时
    }

    异常处理程序方法必须在编译时出现。不支持运行时元编程到控制器类上的异常处理程序方法。

    Groovy服务器页面

    Groovy服务器页面365bet地区或简称GSP是365bet地区视图技术,旨在让ASP和JSP等技术的用户熟悉,但更加灵活和直观

    尽管GSP不仅可以呈现HTML,而且可以呈现任何格式,但它是围绕呈现标记而设计的。如果您正在寻找一种简化JSON响应的方法,请查看JSON视图.

    GSP居住在grails应用程序视图目录,通常按照惯例或使用渲染诸如

    渲染视图: "指数")

    GSP通常是标记和GSP标签的组合,有助于视图渲染

    尽管可以在您的GSP中嵌入Groovy逻辑,并且在本文档中将对此进行介绍,但我们强烈建议不要这样做,因为混合标记和代码是东西,大多数GSP页面不包含任何代码,不需要这样做

    GSP通常具有一个模型,该模型是用于视图渲染的一组变量。该模型从控制器传递到GSP视图。例如,考虑以下控制器动作

    定义 () {
        [: 获取参数ID

    此操作将查找实例并创建一个包含名为的键的模型然后可以使用以下名称在GSP视图中引用此密钥::

    $书名
    嵌入从用户输入中接收到的数据可能会使您的应用程序容易受到跨站点脚本XSS攻击的威胁,请阅读以下文档:XSS预防有关如何防止XSS攻击的信息

    有关使用GSP的更多信息,请参阅专用的GSP文档.

    网址映射

    到目前为止,在整个文档中,URL的约定一直是控制器动作ID365bet地区但是,此约定不是硬连接到365bet地区中的,实际上是由位于以下位置的URL映射类控制的grails应用程序控制器mypackage UrlMappings groovy.

    网址映射类包含一个称为映射已经分配了一段代码

    mypackage的 网址映射 {
        静态的映射

    映射到控制器和动作

    要创建简单的映射,只需使用相对URL作为方法名称,并为控制器和要映射到的操作指定命名参数。

    "产品"(控制者: "产品", 行动: "清单")

    在这种情况下,我们已经映射了URL产品清单的行动产品控制器省略动作定义以映射到控制器的默认动作

    "产品"(控制者: "产品")

    另一种语法是在传递给方法的块中分配要使用的控制器和动作

    "产品"控制者"产品"行动"清单"
    }

    您使用哪种语法在很大程度上取决于个人喜好

    如果所有映射都属于特定路径,则可以使用方法

    "产品", {
        "苹果"(控制者:"产品", ID:"苹果")
        "htc"(控制者:"产品", ID:"htc")
    }

    您也可以创建嵌套网址映射

    "商店""产品", {
            "/$ID"(控制者:"产品")
        }
    }

    要将一个URI重写到另一个显式URI而不是控制器操作对上,请执行以下操作

    "你好"(小号: "你好派遣")

    与其他框架集成时,重写特定的URI通常很有用

    映射到REST资源

    365bet地区由于365bet地区可以创建RESTful URL映射,该URL映射可以按约定映射到控制器上,因此语法如下

    "图书"(资源:'')

    您可以使用定义基本URI和要映射到的控制器的名称资源参数上面的映射将导致以下URL

    HTTP方法 URI 格力行动

    得到

    图书

    指数

    得到

    书籍创作

    创建

    开机自检

    图书

    得到

    书籍编号

    得到

    图书编号

    编辑

    书籍编号

    更新

    删除

    书籍编号

    如果不确定要为您的案例生成哪个映射,请运行以下命令网址映射报告在您的grails控制台中,它将为您提供所有URL映射的真实报告

    如果您希望包含或排除任何生成的URL映射,可以使用包括要么排除365bet地区接受365bet地区操作名称包括或排除的参数

    "图书"(资源:'', 排除:['', '更新'要么"图书"(资源:'', 包括:['指数', ''])

    显式REST映射

    365bet地区从365bet地区开始,如果您不想依赖于资源映射定义您的映射,然后您可以在所有URL映射前面加上小写的HTTP方法名称,以指示它适用于该HTTP方法。以下URL映射

    "图书"(资源:'')

    相当于

    得到"图书"(控制者:"", 行动:"指数"得到"书籍创作"(控制者:"", 行动:"创建"发布"图书"(控制者:"", 行动:""得到"图书$ID"(控制者:"", 行动:""得到"图书$ID编辑"(控制者:"", 行动:"编辑""图书$ID"(控制者:"", 行动:"更新"删除"图书$ID"(控制者:"", 行动:"")

    请注意,HTTP方法名称是如何在每个URL映射定义之前添加前缀的

    单一资源

    单个资源是系统中每个用户可能只有一个资源的资源。您可以使用参数而不是资源):

    ""(:'')

    这导致以下URL映射

    HTTP方法 URI 格力行动

    得到

    图书创建

    创建

    开机自检

    得到

    得到

    书籍编辑

    编辑

    更新

    删除

    主要区别在于ID不包含在URL映射中

    嵌套资源

    您可以嵌套资源映射以生成子资源,例如

    "图书"(资源:'') {
      "作家"(资源:"作者")
    }

    以上将导致以下URL映射

    HTTP方法 网址 格力行动

    得到

    书籍bookId作者

    指数

    得到

    bookId作者创建的书籍

    创建

    开机自检

    书籍bookId作者

    得到

    图书bookId作者ID

    得到

    书籍bookId作者编辑id

    编辑

    图书bookId作者ID

    更新

    删除

    图书bookId作者ID

    您还可以在资源映射中嵌套常规URL映射

    "图书"(资源: "") {
        "发布者"(控制者:"发布者")
    }

    这将导致以下URL可用

    HTTP方法 网址 365bet地区格力行动

    得到

    图书bookId出版商

    指数

    要将URI直接映射到资源下方,然后使用收集块

    "图书"(资源: ""采集"发布者"(控制者:"发布者")
        }
    }

    这将导致以下URL可用而没有ID

    HTTP方法 网址 格力行动

    得到

    图书出版商

    指数

    链接到RESTful映射

    您可以链接到使用g连结365bet地区只需通过引用链接到的控制器和操作即可由365bet地区提供标签

    <G链接控制器""行动"指数"我的链接/g连结

    为了方便起见,您还可以将域实例传递给资源的属性链接标签

    <G链接资源"${}"我的链接/g连结

    在这种情况下,这将自动生成ID为的正确链接

    嵌套资源的情况略有不同,因为它们通常需要两个标识符,即资源的id和一个嵌套在其中的标识符。例如,给定嵌套的资源

    "图书"(资源:'') {
      "作家"(资源:"作者")
    }

    如果您希望链接到的行动作者你会写的控制器

    图书作者的结果
    <G链接控制器"作者"行动""方法"得到"参数"bookId"ID"2"作者/g连结

    但是,为了使它更简洁,有一个资源链接标记的属性,可以代替使用

    图书作者的结果
    <G链接资源"书作者"行动""bookId"1"ID"2"我的链接/g连结

    在本案例中,resource属性接受以斜杠分隔的资源路径。标记的属性可用于指定必要的bookId参数

    URL映射中的重定向

    365bet地区从365bet地区开始,可以定义用于指定重定向的URL映射当URL映射在映射与传入请求匹配的任何时间指定重定向时,将使用映射提供的信息启动重定向。

    当URL映射指定重定向时,该映射必须提供表示要重定向到的URI的字符串,或者必须提供表示重定向目标的Map。该Map的结构就像可以作为参数传递给Map的Map一样。重新导向控制器中的方法

    "ViewBooks"(重新导向: [小号: '书籍清单'])
    "viewAuthors"(重新导向: [控制者: '作者', 行动: '清单'])
    "viewPublishers"(重新导向: [控制者: '发布者', 行动: '清单', 常驻: ])

    默认情况下,原始请求中包含的请求参数将不包含在重定向中。要包含这些参数,必须添加参数keepParamsWhenRedirect true.

    "ViewBooks"(重新导向: [小号: '书籍清单', keepParamsWhenRedirect: ])
    "viewAuthors"(重新导向: [控制者: '作者', 行动: '清单', keepParamsWhenRedirect: ])
    "viewPublishers"(重新导向: [控制者: '发布者', 行动: '清单', 常驻: , keepParamsWhenRedirect: ])

    嵌入式变量

    简单变量

    上一节演示了如何使用具体令牌映射简单的URL在URL映射中,令牌是每个斜杠之间的字符序列。具体令牌是定义明确的令牌,例如产品但是,在许多情况下,直到运行时您都不知道特定令牌的值。在这种情况下,您可以在URL中使用变量占位符,例如

    静态的映射"产品$ID"(控制者: "产品")
    }

    365bet地区在这种情况下,通过将id变量作为第二个令牌嵌入,365bet地区会自动将第二个令牌映射到可通过参数对象称为ID例如给定的URL产品MacBook以下代码将使MacBook响应

     产品控制器 {
         定义 指数渲染参数id

    您当然可以构造更复杂的映射示例,例如,传统博客URL格式可以按以下方式映射

    静态的映射"/$博客/$/$/$/$ID"(控制者: "博客", 行动: "")
    }

    上面的映射可以让你做类似的事情

    graemerocher我的时髦博客文章

    网址中的各个令牌会再次映射到参数具有可用值的对象, , , ID等等

    动态控制器和动作名称

    365bet地区变量也可以用于动态构造控制器和操作名称。事实上,默认的365bet地区 URL映射使用此技术。

    静态的映射"/$控制者/$行动?/$ID?"()
    }

    此处,控制器动作的名称和id是从变量隐式获得的控制者, 行动ID嵌入在URL中

    您还可以解析控制器名称和操作名称,以使用闭包动态执行

    静态的映射"/$控制者"动作参数在这里

    可选变量

    默认映射的另一个特征是能够在变量的末尾附加a,使其成为可选标记。在另一个示例中,可以将该技术应用于博客URL映射以具有更灵活的链接

    静态的映射"/$博客/$?/$?/$?/$ID?"(控制者:"博客", 行动:"")
    }

    借助此映射,所有这些URL都将仅与正在填充的相关参数匹配。参数宾语

    graemerocher我的时髦博客文章graemerocher graemerocher graemerocher graemerocher

    可选文件扩展名

    如果您希望捕获特定路径的扩展名,则存在特殊情况映射

    "/$控制者/$行动?/$ID?(.$格式)?"()

    通过添加格式映射,您可以使用回应格式控制器中的属性

    定义 指数渲染"扩展名是${回应格式}"
    }

    任意变量

    您也可以通过在传递给映射的块中设置任意参数来将URL映射中的任意参数传递给控制器​​。

    "假期赢"ID"马拉喀什"2007
    }

    此变量将在参数对象传递给控制器

    动态解析变量

    硬编码的任意变量很有用,但有时您需要根据运行时因素来计算变量的名称,这也可以通过将块分配给变量名称来实现

    "假期赢"id参数id isEligible会话用户空值 } 必须登录
    }

    在上述情况下,当URL实际匹配时,将解析块中的代码,因此可以与各种逻辑结合使用

    映射到视图

    您可以将URL解析为不涉及控制器或操作的视图,例如,映射根URL/到该位置的GSP365bet地区应用程序观看次数索引gsp你可以用

    静态的映射"/"(视图: "指数")  映射根URL
    }

    或者,如果您需要特定于给定控制器的视图,则可以使用

    静态的映射"救命"(控制者: "现场", 视图: "救命") 到控制器的视图
    }

    映射到响应代码

    365bet地区365bet地区还允许您将HTTP响应代码映射到控制器的操作或视图,只需使用与您感兴趣的响应代码匹配的方法名称即可。

    静态的映射"403"(控制者: "错误", 行动: "禁止的")
       "404"(控制者: "错误", 行动: "未找到")
       "500"(控制者: "错误", 行动: "SERVERERROR")
    }

    或者您可以指定自定义错误页面

    静态的映射"403"(视图: "禁止的错误")
       "404"(视图: "错误未找到")
       "500"(视图: "错误serverError")
    }

    声明式错误处理

    此外,您可以为单个异常配置处理程序

    静态的映射"403"(视图: "禁止的错误")
       "404"(视图: "错误未找到")
       "500"(控制者: "错误", 行动: "非法论点",
             例外: IllegalArgumentException)
       "500"(控制者: "错误", 行动: "nullPointer",
             例外: 空指针异常)
       "500"(控制者: "错误", 行动: "自定义异常",
             例外MyException"500"(视图: "错误serverError")
    }

    使用此配置IllegalArgumentException将由非法论点行动错误控制器一种空指针异常将由nullPointer动作和MyException将由自定义异常动作其他异常将由“全部捕获”规则处理,并使用错误serverError视图

    您可以使用请求s从自定义错误处理视图或控制器操作中访问异常。例外像这样的属性

     错误控制器 {
        定义 handleError() {
            定义异常请求异常执行所需的处理以处理异常
        }
    }
    如果您的错误处理控制器操作也引发了异常,您将得到一个StackOverflowException.

    映射到HTTP方法

    URL映射也可以配置为基于HTTP方法进行映射GET POST PUT或DELETE这对于RESTful API和基于HTTP方法的映射限制非常有用

    举例来说,以下映射为RESTful API URL映射提供了产品控制器:

    静态的映射"产品$ID"(控制者:"产品", 行动: "更新", 方法: "")
    }

    请注意,如果您在网址映射中指定的HTTP方法不是GET,则在创建相应链接时还必须通过传递方法争论g连结要么g createLink获得所需格式的链接

    映射通配符

    365bet地区365bet地区 URL映射机制还支持通配符映射,例如,请考虑以下映射

    静态的映射"图片jpg"(控制者: "图片")
    }

    此映射将匹配图像的所有路径,例如派克jpgo当然,使用变量可以达到相同的效果

    静态的映射"图片$jpg"(控制者: "图片")
    }

    但是,您也可以使用双通配符来匹配以下多个级别

    静态的映射"图片jpg"(控制者: "图片")
    }

    在这种情况下,映射将匹配派克jpgo以及图片其他徽标jpg更好的是,您可以使用双通配符变量

    静态的映射将匹配图像徽标jpg和图像其他徽标jpg
        "图片$jpg"(控制者: "图片")
    }

    在这种情况下,它将与通配符匹配的路径存储在可从参数宾语

    定义名称参数名称println名称打印徽标或其他徽标

    365bet地区如果您使用通配符URL映射,则可能要从365bet地区 URL映射过程中排除某些URI。为此,您可以提供排除设置在UrlMappings常规

     网址映射 {
        静态的排除"图片", "的CSS"]
        静态的映射

    365bet地区在这种情况下,365bet地区不会尝试匹配任何以开头的URI图片要么的CSS.

    自动链接重写

    URL映射的另一个重要功能是,它们会自动自定义链接标记,以便更改映射不需要您去更改所有链接

    这是通过URL重写技术完成的,该技术对URL映射中的链接进行了反向工程,因此在前面的部分中给出了一种映射,例如Blog。

    静态的映射"/$博客/$?/$?/$?/$ID?"(控制者:"博客", 行动:"")
    }

    如果您按如下方式使用链接标记

    <> 控制者="博客" 行动=""
            参数="博客弗雷德年">我的博客
    
    <> 控制者="博客" 行动=""
            参数="博客fred年月">我的博客十月帖子

    365bet地区365bet地区将以正确的格式自动重写URL

    <> href="弗雷德">我的博客
    <> href="弗雷德">我的博客十月帖子

    应用约束

    365bet地区URL映射还支持365bet地区统一验证约束该机制可让您进一步限制URL的匹配方式例如,如果我们从较早的地方重新访问博客示例代码,则当前的映射如下所示

    静态的映射"/$博客/$?/$?/$?/$ID?"(控制者:"博客", 行动:"")
    }

    这样可以使用以下网址

    graemerocher我的时髦博客文章

    但是它也允许

    graemerocher不是一年,不是一个月,不是一天,我的时髦博客条目

    这是有问题的,因为它迫使您在控制器代码中进行一些巧妙的解析。幸运的是,可以限制URL映射以进一步验证URL令牌

    "/$博客/$?/$?/$?/$ID?"控制者"博客"行动""约束年火柴:/\\d{4}/火柴:/\\d{2}/火柴:/\\d{2}/)
         }
    }

    在这种情况下,约束条件可确保, 参数匹配特定的有效模式,从而减轻您以后的负担

    命名URL映射

    URL映射还支持命名映射,即具有与之关联的名称的映射。在生成链接时,该名称可用于引用特定的映射

    定义命名映射的语法如下

    静态的映射名称:  {
          // ...
       }
    }

    例如

    静态的映射名称人名单: "showPeople"控制者''行动'清单'那么帐户详细资料: "细节$帐号"控制者'产品'行动'帐户详细资料'
        }
    }

    可以在GSP中的链接标记中引用该映射

    <> 映射="人名单">列出人员

    那会导致

    <> href="showPeople">列出人员

    可以使用params属性指定参数

    <> 映射="帐户详细资料" 参数="帐号">显示帐号

    那会导致

    <> href="细节">显示帐号

    或者,您可以使用链接名称空间引用命名映射。

    列出人员

    那会导致

    <> href="showPeople">列出人员

    链接名称空间方法允许将参数指定为属性

    <> 帐号="8675309">显示帐号

    那会导致

    <> href="细节">显示帐号

    指定应应用于生成的属性href指定一个的价值属性属性这些属性将直接应用于未传递的href用作请求参数

    <> 属性="阶级幻想" 帐号="8675309">显示帐号

    那会导致

    <> href="细节" ="花式的">显示帐号

    自定义URL格式

    默认的URL映射机制在URL中支持驼峰式案例名称。默认URL用于访问名为addNumbers在名为MathHelperController会像mathHelper addNumbers365bet地区365bet地区允许自定义此模式,并提供了一种实现,该实现将驼峰式约定替换为支持URL之类的连字符约定数学助手加数字要启用带连字符的网址,请为分配一个带连字符的值grails网站网址转换器财产grails应用配置会议应用程序.

    grails应用配置会议应用程序
    grails网站网址转换器'连字号'

    可以通过提供实现以下内容的类来插入任意策略网址转换器接口,并将该类的实例添加到具有Bean名称的Spring应用程序上下文中grails web UrlConverter域名365bet地区如果365bet地区在上下文中找到具有该名称的Bean,它将被用作默认转换器,则无需为该Bean分配值。grails网站网址转换器配置属性

    与我的应用程序 MyUrlConverterImpl 实施grails web UrlConvertertoUrlElementpropertyOrClassName返回应该在URL中使用的属性或类名称的某种表示形式
        }
    }
    grails app conf春季资源groovy
    豆子"${grails web UrlConverter域名}"与myapplication MyUrlConverterImpl

    命名空间控制器

    如果应用程序在不同的程序包中定义了多个具有相同名称的控制器,则必须在名称空间中定义控制器。为控制器定义名称空间的方法是定义一个名为命名空间在控制器中,并将String分配给表示名称空间的属性

    grails应用程序控制器com应用程序报告AdminController常规
    com应用报告 管理员控制器 {
    
        静态的命名空间'报告'
    
        // ...
    }
    grails应用程序控制器com应用程序安全性AdminController常规
    com app安全 管理员控制器 {
    
        静态的命名空间'使用者'
    
        // ...
    }

    在定义应与命名空间控制器关联的网址映射时,命名空间变量必须是URL映射的一部分

    grails应用程序控制器UrlMappings groovy
     网址映射 {
    
        静态的映射'userAdmin'控制者'管理员'命名空间'使用者'
            }
    
            'reportAdmin'控制者'管理员'命名空间'报告'
            }
    
            "/$命名空间/$控制者/$行动?"()
        }
    }

    反向网址映射还要求命名空间

    <G链接控制器"管理员"命名空间"报告"单击以获取报告管理员/g连结
    <G链接控制器"管理员"命名空间"使用者"单击用户管理员/g连结

    在解析与命名空间控制器正向或反向的URL映射时,仅当命名空间如果应用程序在不同的程序包中提供了多个具有相同名称的控制器,则大多数情况下都可以定义它们而无需命名空间属性如果有多个同名的控制器没有定义一个命名空间属性,框架将不知道如何区分它们之间的正向或反向映射分辨率

    允许应用程序使用为控制器提供与应用程序提供的控制器同名的插件,并且两个控制器都不能定义插件。命名空间属性,只要控制器在单独的程序包中即可。例如,一个应用程序可能包含一个名为com会计ReportingController并且该应用程序可以使用一个插件,该插件提供一个名为与人力资源ReportingController唯一的问题是插件提供的控制器的URL映射需要明确指定该映射适用于ReportingController由插件提供

    请参阅以下示例

    静态的映射"会计报告"控制者"报告"
        }
        "humanResourceReports"控制者"报告"插入"人力资源"
        }
    }

    有了该映射后,会计报告将由ReportingController在应用程序中定义的humanResourceReports将由ReportingController人力资源插入

    可以有任意数量的ReportingController由任意数量的插件提供的控制器,但没有一个插件可以提供多个控制器ReportingController即使它们在单独的程序包中定义

    插入仅当应用程序和/或插件在运行时提供多个具有相同名称的控制器时,才需要映射中的变量。人力资源插件提供了ReportingController没有别的ReportingController在运行时可用,以下映射将起作用

    静态的映射"humanResourceReports"控制者"报告"
        }
    }

    最好的做法是明确说明控制器由插件提供

    365bet地区Spring Boot提供了开箱即用的CORS支持,但是由于使用UrlMappings而不是用于定义URL的注释,因此在365bet地区应用程序中进行配置很困难。从365bet地区开始,我们添加了一种在365bet地区应用程序中有意义的配置CORS的方法

    启用后,默认设置将完全打开

    ils:
        :
            已启用: 

    这将产生到所有URL的映射/**

    allowedOrigins

    ['*']

    allowedMethods

    ['*']

    ['*']

    暴露的标题

    空值

    最大年龄

    1800

    allowCredentials

    其中一些设置直接来自Spring Boot,可以在将来的版本中进行更改,请参见Spring CORS配置文档

    所有这些设置都可以轻松覆盖

    ils:
        :
            已启用: 
            allowedOrigins:
                - HTTP本地主机

    在上面的示例中allowedOrigins设置将替换[*].

    您还可以配置不同的URL

    ils:
        :
            已启用: 
            :
                - 内容类型
            映射:
                :
                    allowedOrigins:
                        - HTTP本地主机
                    未指定的其他配置默认为全局配置
    指定至少一个映射将禁用全局映射的创建/**如果您希望保留该设置,则应将其与其他映射一起指定

    上面的设置将产生一个单一的映射具有以下设置

    allowedOrigins

    HTTP本地主机

    allowedMethods

    ['*']

    内容类型

    暴露的标题

    空值

    最大年龄

    1800

    allowCredentials

    如果您不想覆盖任何默认设置,而只想指定URL,则可以像下面的示例一样进行操作

    ils:
        :
            已启用: 
            映射:
                : 继承

    拦截器

    365bet地区365bet地区使用以下功能提供独立的拦截器创建拦截器命令

    grails创建拦截器MyInterceptor

    上面的命令将在365bet地区应用程序控制器

     我的拦截器 {
    
      布尔值之前 }
    
      布尔值 }
    
      虚空后视没有操作
      }
    
    }

    拦截器与过滤器

    365bet地区在365bet地区之前的365bet地区版本中,365bet地区支持过滤器的概念,为了向后兼容,仍支持这些过滤器,但认为已弃用

    365bet地区365bet地区中的新拦截器概念在许多方面都具有优越性,最重要的是拦截器可以使用Groovy静态编译注释以优化性能,这通常很关键,因为可以对每个请求执行拦截器

    定义拦截器

    BookInterceptor那么所有对动作的请求BookController将触发拦截器

    一个拦截器实现拦截器特征,并提供可用于拦截请求的方法

    在匹配的操作返回之前执行
    布尔值之前 }
    
    在操作执行之后但在视图渲染之前执行,如果视图渲染应继续为false,则返回True
    布尔值 }
    
    视图渲染完成后执行
    虚空后视

    如上所述之前方法在操作之前执行,并且可以通过返回来取消操作的执行.

    方法在操作执行后执行,如果返回false,则可以暂停视图呈现。方法还可以使用来修改视图或模型视图模型分别的属性

    布尔值后模型foo"酒吧" 添加一个名为foo的新模型属性视图'备用' 
      
    }

    后视视图呈现完成后执行该方法如果发生异常,则可以使用抛出的属性拦截器特征

    与拦截器匹配请求

    如上一节所述,默认情况下,拦截器将仅按约定将请求匹配到关联的控制器。但是您可以使用以下命令将拦截器配置为匹配任何请求比赛要么matchAll方法中定义的.

    匹配方法返回一个灯具实例,可用于配置拦截器如何匹配请求

    例如,以下拦截器将匹配除登录控制者

     AuthInterceptor matchAll排除控制者:"登录")
      }
    
      布尔值之前执行身份验证
      }
    }

    您还可以使用命名参数执行匹配

     记录拦截器LoggingInterceptor匹配控制者:"", 行动:"") 使用字符串比赛控制者: ~/作者出版者/) 使用正则表达式
      }
    
      布尔值之前

    您可以使用在拦截器中定义的任意数量的匹配器,它们将按照定义它们的顺序执行。例如,上述拦截器将与以下所有匹配项匹配

    • 当。。。的时候的行动BookController叫做

    • 什么时候AuthorController要么叫做

    除以下所有命名参数小号接受字符串或正则表达式小号参数支持与Spring兼容的String路径AntPathMatcher可能的命名参数为

    • 命名空间控制器的名称空间

    • 控制者控制器名称

    • 行动动作名称

    • 方法HTTP方法

    • 小号请求的URI如果使用此参数,则所有其他参数将被忽略,仅使用此参数

    订购拦截器执行

    拦截器可以通过定义一个订购定义优先级的属性

    例如

      {
    
      整型订购最高精度

    的默认值订购属性是拦截器的执行顺序是通过对订购属性沿上升方向并首先执行最低数字顺序的拦截器

    价值最高的精度最低精度可用于定义应分别首先运行或最后运行的过滤器

    请注意,如果编写一个供其他人使用的拦截器,则最好增加或减少最高的精度最低精度允许在您创作的拦截器之前或之后插入其他拦截器

    整型订购最高精度50
    
    要么
    
    整型订购最低价格50

    要找出拦截器的计算顺序,您可以将调试记录器添加到logback groovy如下

    日志'365bet地区人工拦截器'调试'标准输出'], 

    您可以使用中的bean覆盖配置覆盖所有拦截器的默认顺序grails应用配置会议应用yml:

    :
      authInterceptor:
        订购: 50

    或在grails应用配置会议应用程序:

    bean authInterceptor顺序50
      }
    }

    因此,您可以完全控制拦截器的执行顺序

    内容协商

    365bet地区365bet地区内置了对内容协商使用HTTP接受标头是显式格式请求参数或映射的URI的扩展名

    配置Mime类型

    365bet地区在开始进行内容协商之前,您需要告诉365bet地区您希望支持的内容类型默认情况下,365bet地区内配置了许多不同的内容类型grails应用配置会议应用yml使用grails mime类型设置

    ils:
        哑剧:
            类型:
                所有: '*/*'
                原子: 应用程序原子xml
                的CSS: 
                CSV: 文字csv
                形成: 申请表x www表格urlencoded
                html:
                  - 文字HTML
                  - 应用程序xhtml xml
                js: 文字javascript
                json:
                  - 应用程序json
                  - 文字json
                multipartForm: 多部分表格数据
                rss: 应用程序rss xml
                文本: 纯文字
                案件:
                  - 应用程序hal json
                  - 应用程序hal xml
                XML文件:
                  - 文字xml
                  - 应用程序XML

    设置也可以在grails应用配置会议应用程序如下所示

    第一个是默认格式
        所有:           '*/*', 所有映射到withFormat或第一个可用格式
        原子:          '应用程序原子xml',
        的CSS:           '',
        CSV:           '文字csv',
        形成:          '申请表x www表格urlencoded',
        html:          ['文字HTML','应用程序xhtml xml'],
        js:            '文字javascript',
        json:          ['应用程序json', '文字json'],
        multipartForm: '多部分表格数据',
        rss:           '应用程序rss xml',
        文本:          '纯文字',
        案件:           ['应用程序hal json','应用程序hal xml'],
        XML文件:           ['文字xml', '应用程序XML']
    ]

    365bet地区上面的配置允许365bet地区将包含文本xml或应用程序xml媒体类型的请求的格式检测为简单的xml。您可以通过在映射中简单地添加新条目来添加自己的类型。第一个是默认格式

    使用请求参数格式的内容协商

    假设控制器动作可以返回多种格式的资源HTML XML和JSON客户端将获得哪种格式客户端控制此操作的最简单,最可靠的方法是通过格式URL参数

    因此,如果您作为浏览器或其他客户端希望将资源作为XML,则可以使用这样的URL

    http我的域组织书籍xml
    请求参数格式也被允许http我的域org图书格式xml365bet地区但是默认的365bet地区 URL映射获取控制器格式动作索引将覆盖格式带有null的参数,因此默认映射应更新为获取控制器动作索引.

    在服务器端的结果是格式财产响应具有值的对象XML文件 .

    您也可以在网址映射定义

    "书单"(控制者:"", 行动:"清单"格式"XML文件"
    }

    您可以对控制器操作进行编码,以基于此属性返回XML,但也可以使用特定于控制器的控制器withFormat方法

    此示例需要添加org grails插件grails插件转换器插入
     grails转换器JSON
     grails转换器XML
    
     BookController {
    
        定义 清单() {
            定义图书列出withFormat htmlbookList书籍json呈现书籍JSON XML渲染书XML格式'*'渲染书JSON格式

    365bet地区在此示例中,365bet地区将仅在内部执行块withFormat匹配请求的内容类型,因此,如果首选格式是html365bet地区然后365bet地区将执行html仅调用每个块都可以是对应视图的映射模型,如我们在上面的示例中对html所做的那样,或者可以是闭包。闭包可以包含任何标准操作代码,例如,它可以返回模型或直接呈现内容

    如果没有格式明确匹配*通配符块可用于处理所有其他格式

    有一种特殊格式,所有格式与显式格式的处理方式都不相同。withFormat*通配符块可用

    您不应该添加显式的all块。在本示例中,all格式将触发html交易html是第一个街区,没有*

    withFormat htmlbookList书籍json呈现书籍JSON XML渲染书XML格式
    使用时withFormat确保这是您控制器操作中的最后一次调用,作为withFormat动作使用的方法来指示接下来会发生什么

    使用Accept标头

    每个传入的HTTP请求都有一个特殊的接受标头,定义客户端可以接受的媒体类型或MIME类型。在较旧的浏览器中,通常是

    */*

    只是意味着任何东西,但是更新的浏览器会发送更多有趣的值,例如Firefox发送的值

    文本xml应用程序xml应用程序xhtml xml文本html q纯文本q图像png q

    365bet地区这个特定的接受标头是无用的,因为它表示XML是首选的响应格式,而用户确实期望HTML。这就是为什么365bet地区默认忽略浏览器的接受标头。但是非浏览器客户端通常在其要求上更加具体,可以发送接受标头,例如

    应用程序json

    365bet地区如前所述,365bet地区中的默认配置是忽略浏览器的accept标头,这是通过配置设置完成的grails mime disable接受标头userAgents365bet地区它配置为检测主要渲染引擎并忽略其ACCEPT标头,这使365bet地区内容协商可继续用于非浏览器客户端

    '壁虎', 'WebKit', '急板', '三叉戟']

    例如,如果看到应用程序json上方的accept标头,它将进行设置格式json如您所愿当然,这与withFormat方法与格式尽管URL参数优先,但设置了URL参数

    接受标头的结果为所有为了格式属性

    365bet地区如果使用了accept头但不包含已注册的内容类型,365bet地区将假定浏览器正在发出错误的请求,并将设置HTML格式,请注意,这与其他内容协商模式的工作方式不同,因为它们会激活所有格式

    请求格式与响应格式

    365bet地区从365bet地区开始,有一个单独的概念格式和响应内容类型标头,通常用于检测传入的请求是否可以解析为XML或JSON,而响应格式使用文件扩展名格式参数或ACCEPT标头来尝试向客户端传递适当的响应

    withFormat在控制器上可用,专门处理响应格式如果您希望添加处理请求格式的逻辑,则可以使用单独的方法withFormat可根据要求提供方法

    请求withFormat XML读取XML读取JSON
        }
    }

    使用URI扩展进行内容协商

    365bet地区365bet地区还支持使用URI扩展的内容协商。例如,给出以下URI

    图书清单xml

    这是默认URL映射定义的结果,即

    "/$控制者/$行动?/$ID?(.$格式)?"{

    请注意包含格式路径中的变量如果您不想通过文件扩展名使用内容协商,则只需删除URL映射的这一部分

    "/$控制者/$行动?/$ID?"{

    测试内容协商

    要在单元测试或集成测试中测试内容协商,请参阅测试中您可以操纵传入的请求标头

    虚空testJavascriptOutput定义控制者TestController控制器请求addHeader"接受",
                  "文本javascript文本html应用程序xml文本xml"控制器testAction assertEquals"警惕你好"控制器响应contentAsString

    或者您可以设置format参数来达到类似的效果

    虚空testJavascriptOutput定义控制者TestController控制器参数格式'js'控制器testAction assertEquals"警惕你好"控制器响应contentAsString