controllers - niubods/playframework-notes GitHub Wiki

控制器

控制器用以粘合HTTP和模型层,一方面它使用和模型层相同的语言,方便访问和修改模型对象,同时它又和HTTP接口一样,是面向过程和请求/响应的。

控制器综述

一个控制器就是一个java类,放在controllers包或它的子包中,并且是play.mvc.Controller的子类。

控制器中的每一个公共静态方法称为一个动作。

可以在动作方法中定义参数,这些参数会由框架自动从对应的HTTP请求参数中获取。

通常一个动作方法没有return语句,方法会在调用结果方法后结束,例如render(...)就是一个结果方法,它会执行和显示一个模板。

获取HTTP参数

一个HTTP请求可以携带数据,数据可以通过下面几种形式传入:

  • 作为URI的一部分:/clients/1541中的1541
  • 作为查询字符串:/clients?id=1541
  • 作为请求体:通过HTTP表单发送

Play从以上所有形式中提取数据并存入一个Map<String, String[]>对象中。key为参数名。

有几种方法可以在控制器中获取这些请求参数。

使用params map

params对象从任何控制器类中都可以使用,这个对象包含了从当前请求中能找到的所有请求参数。

例如:

String id = params.get("id");

或者让Play为你做类型转换:

Long id = params.get("id", Long.class);

不过下面还有更好的方法

从动作方法的签名中

你可以直接从动作方法的签名中获取HTTP请求参数。Java参数的名字和HTTP参数的名字要一致。

例如在这个请求中:

/clients?id=1451

可以通过在动作方法的签名中定义`id`参数来获取`id`请求参数。

public static void show(String id) {
    System.out.println(id); 
}

也可以使用String之外的其他类型,Play框架会将请求参数转换成正确的Java类型。

public static void show(Long id) {
    System.out.println(id);  
}

如果请求参数是多值的,你可以声明一个数组参数:

public static void show(Long[] id) {
    for(String anId : id) {
        System.out.println(anid); 
    }
}

或者甚至是一个容器类型:

public static void show(List<Long> id) {
    for(String anId : id) {
        System.out.println(anid); 
    }
}

异常
当动作方法中参数的对应的HTTP请求参数没找到时,动作方法中相应的参数会设置为它们的默认值(对象类型为null,基本数值类型为0)。
当对应的值找到了,但是不能正确转换成要求的Java类型时,会向表单验证错误容器中添加一条错误消息,并赋予一个默认值。

HTTP到Java的高级绑定

简单类型

所有本地类型和常见的Java都可以被自动绑定:

int, long, boolean, char, byte, float, double, Integer, Long, Boolean, Char, String, Byte, Float, Double.

注意如果参数在HTTP请求中缺失或自动转换失败,对象类型会设置为null而本地类型会设置为它们的默认值。

Date

Play框架可以自动识别出很多种日期格式并自动转换,如果要自定义日期格式可以使用`@As`注解。

File

文件上传在Play中非常简单,用一个multipart/form-data编码的post请求发送到服务器,然后使用java.io.File类型获取一个文件对象。

创建的文件和原始文件的文件名一致,它保存在一个临时目录中,并且在请求结束的时候会删除。所以你必须将它拷贝到一个安全的地方否则文件会丢失。

POJO对象绑定

Play还可以利用同样简单的的命名转换规则自动绑定任何模型类。

public static void create(Client client ) {
    client.save();
    show(client);
}

JPA对象绑定

你可以使用HTTP到Java的绑定机制自动绑定你的JPA对象。

如果你在请求中包含id,Play会在编辑之前先到数据库加载对应的实例,然后将HTTP请求参数应用其上。这样你就可以直接保存这个对象了。

自定义绑定

@play.data.binding.As

@play.data.binding.NoBinding

play.data.binding.TypeBinder

@play.data.binding.Global

结果类型

一个动作方法必须生成一个HTTP响应,最简单的方法就是发出一个结果对象,一旦发出了一个结果对象,正常的执行流程会被打断,然后方法就返回了。

例如:

public static void show(Long id) {
    Client client = Client.findById(id);
    render(client);
    System.out.println("This message will never be displayed !");
}

这里render(...)方法发出了一个结果对象,阻止了方法继续执行。

返回一些文本内容

使用renderText(...)方法可以发出一个简单结果事件,会向底层的HTTP相应流中直接写入一些文本。

renderText(unreadMessages);

你也可以使用Java标准的格式化语法对你的文本消息进行格式化:

renderText("There are %s unread messages", unreadMessages);

返回一个JSON字符串

可以通过调用renderJSON(...)方法返回一个JSON字符串,参数可以传入一个你自己的JSON字符串,或者传入一个object,Play会使用GsonBuilder对它进行序列化。

返回一个XML字符串

调用renderXML(...)方法可以返回一个XML字符串,参数可以传入一个XML字符串,或者一个org.w3c.dom.Document对象。

返回二进制内容

要提供一个二进制内容,比如放在服务器上的一个文件,可以使用renderBinary

作为附件下载文件

也是使用renderBinary,要提供一个文件名作为第二个参数。

执行一个模板

如果要生成的内容比较复杂,你应该使用模板来产生相应内容。执行一个模板需要调用render(...)方法。

模板的名称是由Play的约定推断出来的,默认的模板是由控制器和动作的名字来决定的。

向模板作用域中添加数据

可以使用renderArgs对象向模板作用域中添加数据。

renderArgs.put("client", client);

在模板执行的时候,会定义一个client变量,在模板中可以这样引用:

<h1>Client ${client.name}</h1>

想模板作用域传数据的更简单的方法

直接将要传入的数据作为render(...)方法的参数:

render(client);  

指定其他模板

重定向到其他URL

动作连锁

自定义web编码

对当前相应自定义web编码

对整个应用指定自定义编码

拦截器

@Before

@After

@Catch

@Finally

控制器的继承

使用@with注解加入更多拦截器

Session和Flash作用域

如果你想跨多个请求保存数据,你可以把它们保存到Session或Flash作用域中。保存在Session中的数据在整个会话中都是可用的,保存在Flash中的数据只能在下次请求时可用。

⚠️ **GitHub.com Fallback** ⚠️