第九章(cyy)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第三部分进阶阶段
第九章高级指南----------------------------------------------------------------------------------------------------------------------
9.1 JPA支持
JPA Support
Play provides a set of very useful helpers to simplify the management of your JPA entities.
Play提供了一套非常实用的帮助类来简化对JPA实体的管理。
Starting the JPA entity manage 启用JPA实体管理
Play will automatically start the Hibernate entity manager when it finds one or more classes annotated with the @javax.persistence.Entity annotation. However, make sure that you have correctly configured a JDBC datasource or it will fail.
Play 会自动寻找标有@javax.persistence.Entity 注解的类,@javax.persistence.Entity 注解的作用是通知Play对当前类进行实体管理,默认情况下Play对注解的类通过Hibernate 实体管理器进行管理。
当然,这个的前提是你必须正确配置JDBC 数据源,否则Play将无法进行实体管理。
Obtaining the JPA entity manager 获得JPA实体管理器
When the JPA entity manager is started you can get it from the application code, using the JPA helper. For example:
当JPA实体管理器启动后,在程序代码中就可以通过JAP帮助类来取得被管理的实体。
例如:
Transaction management 事务管理
Play will automatically manage transactions for you. It will start a transaction for each HTTP request and commit it when the HTTP response is sent. If your code throws an exception, the transaction will automatically rollback.
If you need to force transaction rollback from the application code, you can use
the JPA.setRollbackOnly() method.
Play会为你自动的进行事务管理。
在每次的HTTP请求中Play都会启动一个事务,然后在发送HTTP响应时提交事务。
如果在请求响应过程中你的代码中抛出了一个异常,事务则会自动回滚。
如果你需要强制从应用程序代码回滚事务,你可以调用JPA.setRollbackOnly() 方法来通知JPA不要提交当前事务。
The play.db.jpa.Model support class play.db.jpa.Model 帮助类
This is the main helper class for JPA. If you make one of your JPA entities extend
the play.db.jpa.Model class, it will give you a lot of helper methods to simplify the JPA access.
For example, look at this Post model object:
这是Play中最主要的JPA帮助类。
如果使JPA实体类继承play.db.jpa.Model 类,它会提供给你大量的辅助方法,从而简化对JPA的访问。
例如,观察下面Post模型对象:
The play.db.jpa.Model class automatically provides an autogenerated Long id field. We think that it’s generally a good idea to keep an auto-generated Long id as primary key for JPA models (the technical primary key) and manage your functional primary key using another field.
Note that we have used the fact that Play automatically considers the Post class’public members
as properties. So we don’t need to write all setter/getter methods for this object.
play.db.jpa.Model类默认包含了一个自增长的长整型id字段。
这通常是一个比较好的方案,让一个自增长的长整型id作为JPA模型的主键(技术主键),而用另一个字段管理功能主键。
注意在Play中默认会把成员变量的访问权限设置为public,从而无需定义大量的setter/getter 方法。
Finding objects 查找对象
The play.db.jpa.Model gives you several ways to find data. For example:
play.db.jpa.Model类提供多种方法查找数据。
例如:
Find by ID 通过ID查找
The simplest way to find an object.
最简单的方式查找对象。
Find all 查找所有对象
This is the simplest way to retrieve all posts, but you can do the same using:
没有比这个更简单的方式检索所有posts对象,同时你也可以用下面的方式来检索:
This allows you to paginate results:
下面的方式允许你对查询结果进行分页:
or even,
乃至,
Find using a simplified query 通过简单查询语句查找
That allow you to create very expressive finders, but will only work for simple queries.
通过下面的方式可以创建非常明了的查询器,但是只支持一些简单的查询。
Find using a JPQL query 通过JPQL查询
You can use a JPQL query:
你可以通过JPQL查询:
or even a part of:
或者只是部分条件查询:
You can even specify only the order by statement:
你甚至可以只声明order by 条件来查询:
Counting objects 统计对象
You can easily count objects.
你可以调用count( ) 方法很容易的统计出查询到的对象数量。
Or even count using a query:
甚至你可以直接对count()方法指定条件来统计目标对象数量:
Explicit save 对象保存
Hibernate maintains a cache of Objects that have been queried from the database. These Objects are referred to as persistent Objects as long as the EntityManager that was used to fetch them is still active. That means that any changes to these Objects within the bounds of a transaction are automatically persisted when the transaction is committed. In standard JPA, these updates are implicit within the transaction’s boundary; you don’t have to explicitly call any method to persist the values.
Hibernate 会把从数据库中查询到的结果以对象缓存方式维护起来。
在实体管理器查询匹配中这些对象一直作为持久对象存在。
这意味着在事务过程中任何对象的改变在提交事务时都会自动的持久化到数据库中。
在JPA规范中,对象的修改都是默认与事务过程一致的,这样你无需显示的调用任何方法来持久化修改后的值。
The main downside is that we must manage all of our Objects manually. Instead of telling the EntityManager to update an Object (which would be far
more intuitive), we must tell the EntityManager which Objects NOT to update. We do this by calling refresh(), which essentially rolls back a single entity. We do this just prior to calling commit on the transaction or when we realize the Object shouldn’t be updated.
我们必须手动的管理所有对象这是非常让人头疼的。
与其通知实体管理器更新一个对象,我们还不如告诉实体管理体哪些对象不需要更新。
通过调用refresh( ) 通知实体管理器重新读取单独的实体。
我们必须在事务提交之前调用refresh(),当对象对象不需要更新到数据库时。
Here is a common use case, when editing a persistent object after a form submit:
下面是在提交表单后,处理持久化对象的常规使用案例:
From what I’ve seen, most developers are not aware of this, and forget to discard the object state in case of errors, assuming that the object will not be saved without an explicit call to save().
大部分开发者没有意识到上面出现的情况,当程序出现错误时,我们是不希望这时的对象状态被持久化的,但通常我们会忘记通知实体管理器忽滤当前对象,以为只要没有显示调用save( )时对象就不会被持久化,其实不然。
So that’s exactly what we’ve changed in Play. All the persistent objects extending the
JPASupport/JPAModel will not be saved without an explicit call to the save() method. So you can actually rewrite the previous code as:
幸运的是Play的改进了处理过程,所有继承自JPASupport/JPAModel的持久化对象需要显示的调用save()来保存对象。
所以你可以重写前面的代码:
This is far more intuitive. Moreover since it could be tedious to explicitly call save() on a large object graph, the save() call is automatically cascaded to the relationships annotated with
the cascade=CascadeType.ALL attribute.
显示的调用save()方法在大量对象操作中看上去是比较繁琐,通过在注解中声明
cascade=CascadeType.ALL 属性,save()方法会自动被关联到关系中。
More about generic typing problems 泛型问题
The play.db.jpa.Model defines a set of generic methods. These generic methods use a type parameter to specify the method’s return type. When using those methods, the concrete type to be used as return value is derived from the invocation context using type inference.
play.db.jpa.Model 定义了大量的泛型方法。
这些泛型方法通过泛型参数来指定方法的返回类型。
当我们调用这些方法时,根据执行上下文的类型返回具体的类型。
For example, the findAll method is defined as:
例如,findAll 方法的定义:
And you use it as:
使用方法:
Here the Java compiler resolves the actual type of T using the fact that you assign the method result to a List<Post>. So T is resolved as a Post type.
事实上是由你在方法返回结果中指定List<Post>来通知Java编译器解析器确切的T 类型。
所以在这里T 被解析为Post 类型。
Unfortunately, this doesn’t work if the generic method’s return value is directly used as a parameter for another method invocation or used in a loop. So the following code fails with a compiler error saying “Type mismatch: cannot convert from element type Object to Post”:
不幸的是,如果我们无法直接在循环参数中指定泛型方法返回值类型。
所以下面的代码无法通过编译,提示“Type mismatch: cannot convert from element type Object to Post”类型转换错误。
Of course you can resolve this issue using a temporary local variable, as:
当然你可以通过指定一个中间变量来解决:
But wait, there is a better way. You can use a practical but somewhat unknown Java language feature, which makes the code shorter while more readable at the same time:
但是,这里有更好的解决方法。
你可以使用一个实用的却鲜有人知的Java 语言特性,这样在使代码更简短的同时更具可读性。
9.2数据验证
Validations ensure that the data has certain values or meets specific requirements. You can use validation to verify that your models are correct before saving them to the database, or use them directly on HTTP parameters to validate a simple form.
数据验证(Validations)用来保证数据是确定类型的值或满足特定的要求。
你可以使用数据验证来验证将要保存到数据库之前的模型,或直接验证HTTP表单参数。
How does it work? 如何运行?
Each request has it own Validation object which collects errors. From a controller, you access it directly using the validation variable. You can still access a subset of the API using
the play.data.validation.Validation class’ static methods.
每个请求都有绑定一个Validation对象用来收集错误信息。
从controller中你可以通过validation变量访问Validation对象。
你仍然可以通过API的子集play.data.validation.Validation 类的静态方法来访问。
The validation object maintains a collection of play.data.validation.Error objects. Each error has two properties:
▪The key. This helps you to determine which data element caused the error. The key value can be set arbitrarily but when Play generates errors, it uses default conventions that follow the Java variables’ names.
▪The message. This contains the error’s textual description. The message can be a plain message or refer to a key from a message bundle (typically for internationalization support).
Let’s see how to validate a simple HTTP parameter:
验证对象维护了play.data.validation.Error的对象集合。
每个error有两个属性:
key:帮助你确定是哪些数据元素引起的error。
key可任意设定,但是当Play生成error时,通常使用默认约定的方式:按照Java变量名称。
message:包含了错误的文字描述。
message可以是纯信息或指向消息包(message bundle)中的一个key(通常为了国际化支持)。
让我们来看看如何验证一个简单的HTTP参数:
This code checks that the name variable is correctly set. If not, the corresponding error is added to the current errors collection.
You can repeat this operation for each validation you need:
程序代码检查了name变量是否被正确的设置。
如果没有,相应的错误被添加到当前错误集合中。
你可以重复这个操作为每个需要验证的参数:
Retrieving error messages 检索错误信息
At the end of the validation you can check if any errors have been created and display them:
在验证的结尾你可以检查是否有errors产生,并显示他们:
Assuming that name and age are null, this would display:
假定name和age都为空,将会显示下面信息:
Default messages are keys that refer to the message bundle. So in the conf/messages file you will have:
默认的messages和keys将关联到消息包。
所以在conf/messages 文件中会有:
You can change this default message and override it for each application language. The %s placeholder will be replaced by the error key. You can override using the error.message(String field)method.
For example:
你可以更改默认的错误信息,并且会被不同语言的错误信息覆盖。
%s占位符将被替换成错误的key。
你可以通过error.message(String field)方法重写错误信息。
例如:
You can also specify a different message for each check:
你可以为每次验证指定不同的错误信息:
Displaying errors in the template 在模板中显示错误
In most cases you want to display the error messages in the view template. You can access them in the template using the errors object. Some tags help you to display the errors:
Let’s see a sample:
在大多数情况下你需要把错误信息显示在视图模板中。
通过errors对象你可以在模板中获得错误信息。
结合标签可以帮助你显示错误信息:
让我们看下面一个例子:
and now the template:
But in a real application you want to redisplay the original form. So you will have two actions: one to display the form and another one to handle the POST.
Of course the validation will occur in the second action and if some error occurs you will have to redirect to the first action. In this case you need a special trick to keep your errors during the redirect. Use the validation.keep() method. This will save the errors collection for the next action.
Let’s see a real sample:
但在实际应用中要重新显示原来的表单。
所以你需要有两个操作:一个是显示表单,另一个是处理POST。
当然,验证将发生在第二个操作,如果一些错误发生,你必须重定向到第一个操作。
在这种情况下,你需要一个特殊的技巧能在重定向中保持错误信息。
使用validation.keep()方法可以在下一个操作中依旧保持错误信息的集合。
让我们看一个真实的示例:
And the view/Application/index.html template: view/Application/index.html模板中:
You can create a better user experience by displaying each error message next to the field that generated the error:
你可以在未通过验证字段旁显示错误信息来提供更好的用户体验:
Using annotations 使用注解
You can use annotations to do the same thing: 你可以使用注解来验证:
Validating objects 对象验证
Using annotations you can easily add constraints to your model objects. Let’s rewrite the previous example using a User class.
First the User class:
使用注解你可以方便地添加限制到你的模型对象。
让我们使用User类重写前面的例子。
首先是User 类:
Then the modified hello action: 然后修改hello 行为方法:
And finally the modified form: 最后修改表单:
Custom validation 自定义验证
Can’t find the validator you need in the play.data.validation package? Write your own. You can use the generic @CheckWith annotation to bind your own Check implementation.
For example:
在使用验证器之前你需要加载play.data.validation包。
定义检查器后,你需要通过@ CheckWith 注解来绑定自定义验证器。
例如:
9.3应用模块
Using Play modules
A Play application can be assembled from several application modules. This allows you to reuse application components across several application or split a large application into several smaller applications.
一个Play应用程序可以由多个应用模块组装而成。
这使得你可以在多个应用程序中重用应用程序组件或者把一个大型应用程序分割成几个较小的应用程序。
What is a module? 模块是什么?
A module is just another Play application; however some differences exist in the way resources are loaded for an application module:
A module does not have a conf/application.conf file.
▪ A module can have a conf/routes file, but these routes will not be loaded automatically.
▪All files are first searched for in the main application path, then in all loaded modules.
▪ A module can contain plain Java code packaged as a JAR file in the module/lib directory.
▪Everything in a module is optional.
You can create a module with the play new-module command.
在Play中一个模块就相当于一个应用,但模块在应用程序资源加载方式上是存在一些区别的:
▪模块不需要conf/application.conf 配置文件。
▪模块可以有conf/routes配置文件,但路由配置文件不会被自动加载。
▪加载文件时首先在主程序路径下搜索,然后到所有已加载模块路径下搜索。
▪在模块的module/lib目录下可以包含JAR格式的Java代码归档文件
▪JAR文件。
▪在模块中一切都是可选的。
你可以在命令行中输入play new-module创建一个新模块。
How to load a module from an application 如何在程序中加载模块
The default modules installation path is in the $PLAY_HOME/modules directory. This way all modules are automatically available to all applications run with the framework.
If you want to load external modules from an application, just declare external modules in the application.conf file in the main application.
默认的模块安装路径是$PLAY_HOME/modules。
这样在框架下所有模块默认将提供给所有的应用程序中运行。
如果你想在应用程序中加载外部模块,只需要在主应用程序下的application.conf配置文件中声明需要加载的外部模块。
You can also create a standalone project that contains all modules needed by your application. You just need to copy all modules into the same directory as your application.
Let’s say you have a large application with a CMS component, a forum component, a directory component and using the GWT module. You can create a project using this layout:
你还可以创建一个独立的项目,在程序中你可以包含所需的所有模块。
你只需要复制应用程序中的所有模块到同一个目录中。
如果你有一个大型应用程序需要包含一个CMS组件,一个论坛组件,和一个目录组件,并且使用了GWT模块。
你可以使用下面的目录结构创建项目:
Here main is the directory of your main application (created using the play new command), gwt is a module installed from the modules repository, and cms, forum and directory are modules created using the play new-module command.
Now from the main application configuration file (my-project/main/conf/application.conf), you can load these modules using:
这里main 是主程序目录(使用play new命令创建),gwt是从模块库中安装的模块,使用play new-module命令创建cms, forum, directory模块。
然后,在主程序配置文件(my-project/main/conf/application.conf)中,你可以通过下面配置加载这些模块:
When you run the main application (using play run my-project/main) it will load all these modules in memory as a larger application.
当你运行主程序时(使用play run my-project/main命令),Play会加载所有需要的模块到内存中。
Load default routes from modules 模块路由加载
A module can provide a default routes file. You can load it in the main application routes file, using a special route declaration:
每一个模块都可以提供默认的路由配置。
你可以主程序的路由配置中加载模块路配置,如通过下面声明方式定义路由:
You can even load routes from all available modules:
你甚至可以从所有可用的模块中加载路由配置:
Using the module repository 应用模块库
The module repository identifies all modules contributed by the community. A module can have several versions. You have to check the module’s documentation for which version you need to use for your framework version.
You can also browse the module repository using the play list-modules command.
模块库包含了所有已认定的由社区贡献的模块。
一个模块可能有多个不同版本,所以在使用过程中你需要查看当前模块的版本来确定是否符合当前框架的版本。
你也可以通过play list-modules命令来浏览模块库。
You can install a module using the play install {module}-{version} command. For example, to install the Scala support to the framework, use:
你需要通过play install {module}-{version} 命令来安装模块。
例如,安装让框架支持Scala语言的模块:
By convention the head version is the unstable version of the module. You can also install the default version of a module by omitting the version information. For example:
按照约定,head标识的模块是不稳定版本。
当然你也可以在命令中省略版本信息,Play会安装默认版本的模块。
例如:
Modules installed this way are downloaded to the /modules directory of your framework installation. You can change the installation path using the --path option:
这种方式默认把模块安装到/modules目录下。
你可以设置–path选项更改安装路径:
Contributing a new module to the module repository 提交一个新的模块到模块库
First you need to have an OpenID. It will help us to authenticate you as author of your modules. Then send us a module registration request on the Google Group.
Please tell us:
▪More about your module. What is it?
▪Your module name. It must match the [a-zA-Z]+ regular expression.
▪ A short description of the module.
▪Your project home page.
▪Your OpenID.
▪Your module must be hosted somewhere with the source code available and a way to report bugs. If you don’t have any idea, github, Google Code and Launchpad are good choices.
To release your module, simply use the play build-module command. Then connect to the module repository and upload the generated package.
You can of course use the offical Google Group to provide help and share information about your work.
首先你需要有一个OpenID。
我们通过OpenID验证模块作者。
然后在Google Group中发送给我们注册模块的请求。
告诉我们更多模块的信息:
▪它是什么?
▪你的模块的名称。
命名必须符合[a-zA-Z]+正则表达式。
▪模块的简短描述。
▪模块的项目主页。
▪你的OpenID。
▪你的模块需要托管在可以存放源代码和反馈bugs的平台。
如果你没有什么想法,github,Google Code和Launchpad都是不错的选择。
当需要发布模块时,只需使用play build-module命令。
然后Play会自动连接到模块库并且上传生成的包。
当然你可以使用Play官方的Google Group提供模块帮助同时分享你的工作信息。
9.4配置Log
Configure logs
The Play logger is built on Log4j. Since most Java libraries use Log4j or a wrapper able to use Log4j as a backend, you can easily configure logging that is well-suited to your application.
Play logger是建立在Log4j之上的。
目前大部分的Java库都直接使用了Log4j或者在后端封装了Log4j,你可以在程序中非常容易地配置日志记录。
Logging from your application
Play provides a default logger with the class play.Logger. This class uses Log4j to write messages and exceptions to a logger named “play”.
Logging from your application is easy:
Play提供了一个play.Logger类作为默认的记录器。
这个类通过Log4j记录消息和异常到play 命名的logger。
记录程序日志非常简单:
The play.Logger class’ methods support easy formatting through the standard Java formatter syntax: play.Logger类支持标准的Java格式化语法进行格式化。
You can still use Log4j directly to create alternative loggers for specific needs:
特定需求下,您仍然可以直接使用Log4j来创建其他记录器:
Configure log levels
You can configure the play logger’s log level. Just define this key in the application.conf file:
通过修改application.conf配置来更改play logger的日志级别定义:
You can change this value without restarting the server. Note that this level only applies to messages generated by the application.
If you need to fully configure Log4j, create a log4j.properties file in the conf/ directory. Since this directory is the first element of the classpath, this file will be the default used by all libraries.
The default Log4j configuration is the following:
你可以更改此值而无需重新启动服务器。
请注意,此日志级别配置只针对于应用程序产生的消息。
如果需要充分配置log4j,你可以在conf /目录下创建一个log4j.properties文件。
由于conf 目录是在classpath路径配置中的第一个元素,所以这个配置文件将有可能会被其他库使用。
默认Log4j的配置如下:
Copy this file and update it for your specifics needs!
你可以复制默认配置并在这基础上修改。
9.5配置文件管理
Manage application.conf in several environments
When you work in a team, different developers will use different configuration keys in
their application.conf. For example, the log level, some database configuration… This generally leads to recurrent conflicts when you commit the file using your VCS.
Furthermore, different deployment environments – e.g. dev, test, staging and production – need different configurations.
当你在团队开发中,不同的开发人员将使用不同的application.conf配置项。
例如,日志级别,一些数据库配置... 在通过VCS(版本控制系统)提交的你的文件时,这通常会导致经常性的冲突。
此外,不同的部署环境- 例如dev, test, staging and production 都需要不同的配置。
The framework ID
To resolve this problem, Play allows you to give an ID to each framework installation. Use the play tool’s id command to define this ID:
如何来解决这个问题,Play允许你在安装时给每个框架的设定一个ID。
使用Play id命令来定义这个ID:
You can then prefix your configuration keys with the framework ID for which the configuration option is intended:
然后在配置中你可以使用ID做为配置项的前缀来区别配置:
Framework ID can be set from the command line
You can specify the framework ID to use for a particular command directly from the command line. For example to run an application in production mode you can use:
您直接在命令行中使用特定的命令来指定的框架ID。
例如,通过下面命令让程序运行在产品模式下:
with these line defined in the application.conf file:
application.conf中的定义:
It should be compatible with all commands using the framework ID information. The default ID is still defined using the play id command.
它应当与所有使用框架ID信息的命令兼容。
默认ID仍然是通过play id命令定义。
By the way, play test is then equivalent to:
顺便说一下,play test命令相当于:
9.6国际化
Setting up i18n
Internationalization is a means of adapting your application to different languages to allow for regional differences. Follow these steps to enable internationalization in your application.
国际化意味着你的应用程序可以适应不同地区的语言。
按照下面这些步骤,使你的应用程序的实现国际化。
Only use UTF-8!
Play supports only one encoding: UTF-8. Since encoding problems can be weird and difficult to deal with, we made the choice to support only one encoding. UTF-8 allows you to display all characters for all languages.
Be sure to be consistent with UTF-8 usage throughout your application:
▪Edit all your source files as UTF-8
▪Define proper encoding headers in HTTP
▪Set your HTML meta tags to UTF-8
▪If you use a database, configure it to use UTF-8, and always connect to it using UTF-8
Play只支持UTF-8一种编码。
编码问题一直是让人头痛的事情,Play的解决方案是只提供一种编码支持。
而且使用UTF - 8可以显示所有语言的所有字符。
务必在你的应用程序一致使用UTF – 8编码:
▪以UTF - 8编码方式编辑所有的源文件
▪在HTTP headers中定义适当的编码
▪设置HTML meta标签为UTF – 8
▪如果你使用了一个数据库,将其配置为UTF - 8,并且始终以UTF – 8编码方式连接Note
The UTF-8 encoding issue is the reason why most of the Play configuration files, even though they are Java properties files, are not named *.properties. Java imposes the requirement that properties files must be encoded with iso-8859-1. Play configuration files must be UTF-8 encoded. Need we say more?
Externalize your messages
To support i18n you have to externalize all messages in your application.
Create a file named messages in the application’s conf/ directory. This file is really just a Java properties file.
为了支持i18n,你必须让你的messages外部化。
在程序的conf/ 目录创建下一个名为messages文件。
这个文件实际上就是一个Java属性文件。
Then you can define a specific message file for each language used in your application. Just add the ISO language code as a file extension.
然后你可以为不同语言指定不同的message文件。
以ISO语言代码作为message文件的扩展名。
For example, the message file containing the corresponding French translations is conf/messages.fr:
例如,conf/messages.fr 文件是对应法国的message文件。
Define languages supported by the application
In the conf/application.conf file, define a list of supported languages:
在conf/application.conf 中设置程序支持的语言列表。
On the first request from a new user, Play will guess the default language to use. It does so by parsing the HTTP Accept-language header. It will then save the chosen language in a PLAY_LANG cookie. So the next request will use the same language.
在用户在第一请求中,Play通过解析HTTP header 中Accept-language 信息识别用户使用的语言。
然后Play会把识别到语言信息保存到PLAY_LANG cookie。
所以在下次请求中Play会使用上次使用的语言。
From your application code your can retrieve the current language for the user by accessing
the ng object:
在你的程序代码中你可以使用ng对象获得当前使用的语言:
If you want to permanently change the user language, use the change() method:
使用change() 方法你可以改变用户语言:
The new value will be saved back to the user’s languag e cookie.
新的值会保存在用户的language cookie。
Retrieve localized messages
From the application code, you can retrieve messages defined in message files. From Java, use
the play.i18n.Messages object.
在程序代码中,你可以使用play.i18n.Messages获取在message文件中的定义。
We support message formatting through the standard Java formatting syntax. You can also define dynamic content in your messages:
Play使用标准的Java格式化语法支持格式化消息。
这样你可以再定义动态的消息内容:
and
From a template you can use the special &{…} syntax to display localized messages:
在模板文件中使用&{…}语法来显示本地化消息文件:
or using dynamic content:
动态内容显示方式:
9.7使用缓存
Use a cache
To create high-performance systems, sometimes you need to cache data. Play has a cache library and will use memcached when used in a distributed environment.
为了创建高性能的系统,这时你需要缓存数据。
Play默认包含了一个缓存库,并在分布式环境中使用了memcached缓存数据。
If you don’t configure memcached, Play will use a standalone cache that stores data in the JVM heap. Caching data in the JVM application breaks the “share nothing” assumption made by Play: you can’t run your application on several servers, and expect the application to behave consistently. Each application instance will have a different copy of the data.
如果你没有配置memcached,Play将使用一个将数据存储在JVM堆中的独立缓存。
但将数据缓存在不同服务器的JVM中却打破了Play “share nothing”的期望:你不能把你的应用程序运行在多个服务器上,并且期望程序能够运行一致。
因为每个程序实例都拥有自己不同的数据副本。
It is important to understand that the cache contract is clear: when you put data in a cache, you can’t expect that data to remain there forever. In fact you shouldn’t. A cache is fast, but values expire, and the cache generally exists only in memory (without persistent backup).
重要的是要明确缓存的有效期:当你把数据放在缓存中,你不能指望这些数据永远不会消失。
事实上你也不应该让缓存永远存在。
缓存是非常快的,意味着会过期,并且缓存通常只存在于内存中(没有持久化备份)。
So the best way to use the cache is to repopulate it when it doesn’t have what you expect:
因此当你期望从缓存中获取数据时却缓存又已经过期时的最好的办法就是,在获取数据后重新把数据重新放入缓存中:
The cache API
The cache API is provided by the play.cache.Cache class. This class contains the set of methods to set, replace, and get data from the cache. Refer to the memcached documentation to understand the exact behavior of each method.
Some examples:。