《Play for Java》学习笔记(四)Controller

play的一大优势是可以将HTTP映射到JAVA API代码(Type-safe mapping from HTTP to an idiomatic Scala or Java API),完美的实现了RestFul架构。

Play使用 Controllers来实现MVC结构,如下图所示,Controller是用来连接服务器业务逻辑(business logic)和前台浏览器HTTP请求(HTTP requests)的桥梁。

一、Actions, Controllers and Results

  • controller其实是一个继承了父类play.mvc.Controller的类,在该类中定义了多个action的方法,该类位于controllers包中,如下图

  • 每个action是一个JAVA方法,用于处理HTTP的请求并将处理结果发还给用户(Action可以看作是一个处理请求数据并产生一个结果放回给客户端的简单Java方法)
  • 每个action方法的返回值类型均为Result(play.mvc.Result),每个Result均对应一个HTTP请求(HTTP response)代表Http响应发送到客户端,即play.mvc.Results类提供了多个helpers来产生标准的HTTP回应,如ok()构建了一个200状态的相应,它包含一个text/plain的响应体
  • Results即结果。最简单的莫过于包含一个状态码、一组HTTP头和一个Http体的被发送到web客户端的Http Resul。这些Results被play.mvc.Result定义,play.mvc.Results 类提供了一些帮助产生标准Http Results的方法,下面的代码示例创建了各种Results:
public static Result index() {
    return ok("Hello world!");
}
//------------------------------------------------
Result ok = ok("Hello world!");
Result notFound = notFound();
Result pageNotFound = notFound("<h1>Page not found</h1>").as("text/html");
Result badRequest = badRequest(views.html.form.render(formWithErrors));
Result oops = internalServerError("Oops");
Result anyStatus = status(488, "Strange response type");
//------------------------------------------------------
// 重定向同样是简单的Results,把浏览器重定向到一个新的URL也不过是一种简单的result,不同的是这些result 类型没有响应体 public static Result index() { return redirect("/user/home"); } //-------------303----------------------------------- public static Result index() { return temporaryRedirect("/user/home"); }
//-------------TODO Result-----------------------------------
return TODO;

 (Status code: ok  -- 200, error, redirect, 404)

如何使用Result

如在controller中

public static Result list() {
    ...
    return ok(list.render(products));
}

 在模板中

<a href="@routes.Products.newProduct()" class="btn"> 

 二、HTTP routing(wire URLs to action methods)——绑定HTTP参数到JAVA方法(action)里的参数

  • 路由route是将每一个进来的Http请求转换成一个Action调用(action是contoller类里的静态的、公共的方法)的组件。
  • 一个Http请求在MVC框架中被视为一个事件,这一事件包含了两个主要的信息块:     请求路径和Http方法(get,post...)
  • 路由在conf/routes文件中被定义,并且会被编译,也就是说你能直接在浏览器中看到路由错误

路由route用于传送HTTP请求到JAVA的controller的action代码中,route、controller和action的关系如下图

route的语法书写规定如下:

其中:

1、The HTTP method——Http方法指任何被Http所支持的方法

GET, POST, PUT, DELETE, HEAD

2、URI pattern

  • 静态路径:   GET       /clients/all         controllers.Clients.list()
  • 动态路径:   GET      /product/:ean     controllers.Products.details(ean: String)
    • 带默认值的动态路径:        GET    /clients                                  controllers.Clients.list(page: Integer ?= 1)
    • 带固定值的路径:             GET    /                                            controllers.Application.show(page = "home")
    • 带可选项的动态路径:        GET  /api/list-all              controllers.Api.list(version ?=null)—— /api/list-all?version=3.0(???)
    • 带正则表达式的动态路径: GET    /product/$ean<[0-9]{13}>     controllers.Products.details(ean: Long) ——使用$id<regex>
    • 带可捕捉多个用/分隔的URI路径的动态路径:  GET  /files/*name  controllers.Application.download(name) ————如:GET /files/images/logo.png, name部分代表了 images/logo.png

3、反向路径:

说明: 没搞明白,以后补充

4路由优先级

多个路由匹配同一个请求的时候就会产生冲突,这时候第一个路由会被使用。

三、处理HTTP响应

1、Play的Result的默认content type和字符集

  • 默认的Content-Type是text/plain如: Result textResult = ok("Hello World!"); 返回 text/plain
  • 默认的字符集为 utf-8
  • 修改为application/json, 如: Result jsonResult = ok(jerksonObject);

2. 设置content type
    Result htmlResult = ok("<h1>Hello World!</h1>").as("text/html");
   或

public static Result index() {
  response().setContentType(text/html; charset=iso-8859-1"); 
return ok("<h1>Hello World!</h1>");
}

3. 设置HTTP response头信息

public static Result index() {
  response().setContentType("text/html");
  response().setHeader(CACHE_CONTROL, "max-age=3600");
  response().setHeader(ETAG, "xxx");
  return ok("<h1>Hello World!</h1>");
}

4.将content type设置为返回JSON格式

public static Result index(){
  Map<String, String> itworks = new HashMap<String, String>();  
  itworks.put("message","It works");      
  return ok(plays.libs.Json.toJson(itworks));
}

返回结果为:     

四、Scope

有了controller和route,我们可以从接受用户的输入数据,并将处理结果返回给用户。现在我们开始讨论储存数据的有效范围和时间——scope

  • play不保存任何服务器段的数据,数据要么保存在服务器,要么保存在客户端
  • 和J2EE有所不同,play有四种scope,如下图所示

(Session scope,Flash scope,Request scope,Response scope)

  • 如果要保持跨多个Http请求的数据,可以把他们保存在Session或者Flash作用域中。保存在Session中的数据在整个用户会话中可用,保存在Flash作用域中的数据仅在下个请求中可用。
  •  Session和Flash数据没有在服务器上储存,而是使用cookies在后续的Http请求之间传递(而是使用cookies被添加到后续的每个Http请求中),理解这一点很重要。也就是说数据大小受限制了(最大到4KB),并且只能存储字符。

 1. Context对象

  • Play中所有scope均存放在Context对象中,Context是一个final static类,其子对象有Request, Response, Session, 和Flash。
  • 我们可以使用current()方法获取当前的scope,然后进入Play的各个scope

 2. scope类型

1) request scope

该scope不能用于存储数据对象,只是用来进入当前请求的数据,如用HTML的表单的数据就是通过request scope提交的。

2)response scope
该scope不能用于存储数据对象,只是用来设置响应的content类型的,如设置响应的类型为XML:
     Context.current().response().setContentType("application/xml");

另外response对象还可以用来设置和删除Cookies

  • response().setCookie("theme","blue");
  • response().discardCookies("theme");

如根据Cookie设置主题

public static Result index() {
    if ("blue".equals(cookies("theme").value())){
    // Do something
    }
    ....
}

3) session scope

  • 只要客户端浏览器没有关闭,存储在session中是数据均不会消失。
  • 需要说明的是sessions不是存储在服务器端的,在每一次HTTP请求的时候添加上的。
  • sessions使用Cookie机制,使用数据大小是4kB,而且只能存储字符串

   3.1) 存储数据到session

   3.2) 在controller中使用session

4)flash scope

  • flash scope的生命周期位于两个请求之间, 这就是说当进行重定向的时候存储在flash scope的数据的有效的。
  • flash作用域的工作方式和Session很相似,但是有两点是不同的:
    • 数据仅保持在一个请求中
    • 数据未被签名,因此用户可以修改Flash cookie的数据

注意:Flash作用域仅应该被用于在简单的非Ajax应用中传递成功/失败消息。因为其数据仅仅传递给下一个请求,但是在复杂的web应用中它无法确保请求的顺序。总之,Flash作用域受到竞争条件限制。

有和没有flash的对比如下所示:

五、数据的安全性

针对存储在客户端的数据的安全性问题,play提供了一个Cookie key来确保用户无法修改Cookie数据。这个Cookie key存放在conf/application.conf文件中,如

    application.secret="FuqsIcSJlLppP8s?UpVYb5CvX1v55PVgHQ1Pk"

说明:  如果你的应用程序有多个实例,程序之间需要共享secret key(如两个服务器必须有相同的secret key),否则另一个程序无法验证数据

  • Use flash scope—— Flash scope is ideal for passing messages to the user (when a redirect is involved).
  • Use action methods——This is the entry point for your business logic. Keep them short and delegate all business logic to your business models.
  • Simple data binding is URL-centric data mapping to your action methods

转载于:https://www.cnblogs.com/JoannaQ/p/3637432.html

猜你喜欢

转载自blog.csdn.net/weixin_34006965/article/details/93057239