admin管理员组文章数量:1122852
play
play基本命令play new 项目名 创建新的play应用play eclipsify 项目名 将play应用转化为Eclipse项目play run 启动当前路径下的play应用(需要在play应用的根目录下使用)(会打印输出信息,阻塞当前进程)play start 启动当前路径下的play应用(需要在play应用的根目录下使用)play stop 停止当前路径下的play应用(需要在play应用的根目录下使用)创建一个play应用打开命令行,进入需要创建项目的路径play new 项目名What is the application name? [xxx] 回车就行这样就在当前目录创建了一个play应用搭建一个play框架的eclipse项目打开命令行,进入需要创建项目的路径cmd --> play new 项目名What is the application name? [xxx] 回车就行cmd --> play eclipsify 项目名打开eclipse,导入项目问题:解决调试错误打开/eclipse/项目名称.launch搜索并删除 -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n修改引用的play.jar为相对路径(团队合作)<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xdebug -Dplay.debug=yes -Dplay.id= -Dapplication.path="${project_loc:dosql}" -Djava.endorsed.dirs="-javaagent:"/lib/play-1.2.3.jar""/>要注意项目名称(${project_loc:dosql})和play.jar包版本play应用目录规范app 应用文件夹controllers 控制器所在包 models 模型所在包views 页面所在文件夹Application 正常页面所在文件夹errors 错误页面所在文件夹test 测试文件夹,存放测试代码 conf 配置文件文件夹application.conf 主配置文件routes 路由配置文件messages 国际化配置文件dependencies.ymllib 依赖jar文件public 静态文件文件夹images 图片文件夹javascripts js文件夹stylesheets 样式表文件夹eclipse eclipse启动文件(eclipse应用中存在)路由语法配置Play路由器使用的配置文件为conf/routes路由配置总是从HTTP方法开始,URI作为中间部分,最后的元素是Java调用。在路由文件中可以使用#进行注释:格式: HTTP方法(大写) URI表达式 要调用的方法如: GET /clients Application.indexHTTP方法HTTP协议支持GET,POST,PUT,DELETE,HEAD方法,用于指定客户请求服务器的动作可使用*号匹配所有请求方式* /clients Application.indexURI表达式可使用{}匹配动态内容/clients/{id}匹配 /clients/12121 或 /clients/toto并且匹配的部分,控制器可以在HTTP参数map中获取该值可使用正则 格式: /clients/{<正则>id}例: /clients/{<[0-9]+>id} 匹配 id为数字的值?请求路径后的/的有无是有区别的,可使用?消除区别例: /clients/?注意: URI除了尾斜线不允许有其他可选的部分。Java调用控制器规则控制器需作为play.mvc.Controller的子类定义在controllers包中控制器中必须存在指定的Action方法必须声明为public static void方法一般格式类的全限定名称.方法名如果包名为controllers,则可以省略例: Application.index 表示将执行 controllers.Application类中的无参方法index404表示匹配的url将被忽略指定静态参数GET /home Application.page(id:'home')GET /pages/{id} Application.page则如果路径为/home,则会调用page方法,并将参数id的值设为"home"静态资源文件夹格式: staticDir:路径例 GET /public/ staticDir:public当客户端请求/public/*路径时,Play会从应用的public文件夹中获取相应的静态资源。这些资源将直接响应给客户端,并不需要服务器做进一步加工处理文件格式: staticFile:路径例 GET /home staticFile:/public/html/index.html当客户端通过GET方法请求/home时,服务器将不做任何处理直接把/public/html目录下面的index.html文件返回给客户端。变量和脚本与模板中的使用方法类似,在routes文件中可以使用${...}作为变量表达式,使用%{...}作为脚本表达式例%{ context = play.configuration.getProperty('context', '') }%GET ${context} Secure.login优先级从上往下进行匹配,将执行最先匹配到的方法控制层概述Play的控制层位于/app/controllers包中控制器需要继承play.mvc.Controller控制器中,每个以public static声明,返回值为void的方法称为ActionPlay会自动将HTTP请求参数转化为与之相匹配的Action方法参数(路由)Action以调用结果方法来终止执行,即render系列的方法获取HTTP参数保存参数play会自动将请求中的参数保存起来包括 路由中的动态部分,查询字符串 和 请求体中的参数和值使用params字段获取play.mvc.Controller超类中定义了params字段,可通过get和getAll方法获得请求中的值public String get(String key)public String get(String key,Class<?> clazz) //可进行类型转换public String[] getAll(String key)在Action中定义同名参数获取play自动在调用Action时将值放入到同名参数中,注意如果Action与HTTP之间的参数无法匹配,Play会将该参数设置为默认值(通常情况下对象类型为null,原始数据类型为0)。参数类型转换简单类型Play可以实现所有Java原生的简单数据类型的自动转换,主要包括:int,long,boolean,char,byte,float,double,Integer,Long,Boolean,Char,String,Float,Double。日期类型如果HTTP参数字符串符合以下几种数据格式,框架能够自动将其转换为日期类型yyyy-MM-dd'T'hh:mm:ss’Z' // ISO8601 + timezoneyyyy-MM-dd'T'hh:mm:ss" // ISO8601yyyy-MM-ddyyyyMMdd'T'hhmmssyyyyMMddhhmmssdd'/'MM'/'yyyydd-MM-yyyyddMMyyyyMMddyyMM-dd-yyMM'/'dd'/'yy可以通过@As注解,指定特定格式的日期,例如public static void articlesSince(@As("dd/MM/yyyy") Date from) 文件类型(文件上传)只需在Action方法添加一个File类型的参数,参数名称要和页面提交的表单名称相同即可前台<form action="/Application/save" method="post" enctype="multipart/form-data"><input name="imageFile" type="file"><br><input type="submit" value="提交"></form>后台public static void save(File imageFile) {File file = new File("lib/"+imageFile.getName());imageFile.renameTo(file);}数组和集合类型需要注意的是Map类型,如果一个name提交了多个值,则多个值用逗号分隔POJO对象前台表单名称 参数名.属性名则自动填充到指定参数的属性中可以指定多层注意如果参数可以匹配但不能正确进行数据转换,那么Play会先生成错误并添加到验证器的error对象集合中,然后将参数设置为默认值。结果返回返回文本内容 renderText(CharSequence pattern, Object... args)还可以通过Java标准的格式化语法对输出的文本进行处理renderText("There are %s","张三")返回JSONrenderJSON(Object o)返回xmlrenderXml(Object o)返回二进制内容不是作为附件renderBinary(InputStream is)作为附件renderBinary(InputStream is,String fileName)返回模板render(Object... args)如果一个参数的没有,则返回 app/views/当前控制器类名/当前action名称.html第一个参数如果是字符串并且是局部变量(不是没有引用),则为模板地址,否则为传递的数据后面的参数为传递的数据,只允许传递局部变量,否则被忽略模板的地址为相对路径, 例 Application/index.html 表示 /app/viewx/下的Application/index.htmlrenderTemplate(String templateName, Object... args)renderTemplate(String templateName, Map<String,Object> args)renderTemplate(Map<String,Object> args) //使用默认模板注意当调用结果方法后,后面的代码不会被执行到为模板传递数据可以使用renderArg字段renderArgs.put("client", "张三");在页面获取 ${client}可以追加到render的参数中render();传递的数据必须是局部变量,否则被忽略,模板中可访问的变量与Java局部变量的名称一致重定向redirect(String url)设置编码(默认utf-8)为当前响应设置编码response.encoding = "ISO-8859-1"为当前请求设置编码1. 在form标签中添加属性 accept-charset="ISO-8859-1" 通知浏览器当form表单提交的时候采用何种编码格式2. 在form标签中添加表单元素(隐藏域) name为"_charset_" 通知服务端的Play采用何种编码方式<form action="@{application.index}" method="POST" accept-charset="ISO-8859-1"><input type="hidden" name="_charset_" value="ISO-8859-1"></form>定义全局编码格式在application.conf配置文件中修改application.web_encoding属性Action链Play的每次HTTP请求只能调用一个Action,如果需要调用其他的Action,那么必须将浏览器重定向到相应的URL调用控制器中其他Action方法也可以实现重定向,框架会拦截该调用并生成正确的HTTP重定向。拦截器概述控制器中可以定义拦截方法(也可称之为拦截器),为控制器及其子类的所有Action提供服务拦截器方法不能定义为public,但必须是static,并通过有效的拦截标记进行注解@Before使用@Before注解的方法会在每个Action调用之前执行属性unless 使用unless参数列出需要排除的方法only 使用only参数把需要拦截的方法列举出来unless和only参数对@After,@Before以及@Finally注解都适用例:@Before(unless="login")static void checkAuthentification() {if(session.get("user") == null) login();}@After使用@After注解的方法会在每个Action调用之后执行@Catch如果有Action方法抛出了异常,那么使用@Catch注解的方法就会执行抛出的异常会以参数的形式传递到@Catch注解的方法中例:@Catch(IllegalStateException.class)public static void logIllegalState(Exception e) {System.out.print(e);}属性value 拦截的异常类型的Class对象priority 多个@Catch指定优先级@Finally@Finally注解的方法总是在每个Action调用之后执行(无论Action是否成功执行)@with使用@with注解调用其他控制器中已经定义好的拦截方法在类声明上使用,相当于本类定义了那么多拦截方法Session和Flash作用域在Play开发中,如果需要在HTTP请求之间保存数据,可以将数据保存在Session或者Flash内。保存在Session中的数据在整个用户会话中都是有效的,而保存在Flash的数据只对下一次请求有效。Session和Flash作用域中的数据都是采用Cookie机制添加到随后的HTTP响应中的(并没有存储在服务器上的),所以数据大小非常有限(不能超过4K),而且只能存储字符串类型的数据。如果需要在特定的会话中缓存一些数据,那么可以使用Play内置的缓存机制模板模板语法概述表达式 ${…}标签 #{tagName /}引用 @{…} 或者 @@{…}国际化 &{…}注释 *{...}*脚本 %{...}%表达式 ${…}例: ${client.name}首先需要向模板注入对象client,之后就可以在模板中输出client对象的name属性如果不能确定向模板注入的client对象是否为null,可以使用如下Groovy快捷语法:<h1>Client ${client?.name}</h1>此时,只有client不为null的情况下,才进行client.name的输出。标签 #{tagName /}概述标签是能够附带参数调用的模板片段如果标签只有一个参数,按照约定,参数的名称为arg,并且该参数名是可以省略的例如,可以使用#{script}标签加载JavaScript文件#{script 'jquery.js' /}Play模板中的标签必须是闭合的#{script 'jquery.js'/} 或#{script 'jquery.js'}#{/script}内置标签#{script} 引入外部js文件参数arg 要引入的js文件例#{script 'jquery.js' /}#{list} 迭代集合参数items 要遍历的集合as 变量的名称例#{list items:client.accounts, as:'account' }<li>${account}</li>#{/list}引用 @{…}或者@@{…}在模板中使用@{…}引用 可以通过路由器逆向生成URL<a href="@{Clients.showAccounts(client.id)}">All accounts</a>调用了Clients控制器中的showAccounts Action方法,并传递了client.id参数@@{…}引用的使用语法与@{…}相同,只不过生成的是绝对URL(尤其适用于邮箱)国际化 &{…}首先需要在conf/messages文件中进行国际化定义clientName=The client name is %s之后在模板中就可以通过&{...}显示该国际化信息了<h1>&{'clientName',client.name}</h1>注释 *{…}*使用*{…}*标记的内容会被模板引擎忽略脚本 %{…}%脚本是更加复杂的表达式集合,能够声明一些变量或者定义一些语句也可以直接使用out内置对象输出动态内容%{fullName = client.name.toUpperCase()+' '+client.forname;out.print('<h1>'+fullName+'</h1>');}%<h1>Client ${fullName}</h1>转义模板引擎默认对所有的动态表达式进行转义如果模板中变量${title}的内容为<h1>Title</h1>,在页面输出时会自动进行转义${title} --> <h1>Title</h1>可以通过调用扩展方法raw(),以非转义的形式在页面中输出${title.raw()} --> <h1>Title</h1>如果需要显示大量的非转义HTML内容,可以使用#{verbatim /}标签#{verbatim}${title} --> <h1>Title</h1>#{/verbatim}模板继承#{extends /} 和 #{doLayout /}标签进行继承#{get} 和 #{set}标签在模板与父模板之间进行参数传递例 父模板simpledesign.html<html><head><title>#{get 'title' /}</title><link rel="stylesheet" type="text/css" href="@{'/public/stylesheets/main.css'}" /></head><body><h1>#{get 'title' /}</h1>#{doLayout /}<div class="footer">Built with the play! framework</div></body></html>说明#{get 'title' /} 表示在子模板中设置值#{doLayout /} 起到占位的作用,其他所有继承于此模板的页面内容都将显示在#{doLayout /}所占的页面区块子模板#{extends 'simpledesign.html' /}#{set title:'A decorated page' /}This content will be decorated.说明#{extends 'xxx' /} 继承与某个模板#{set title:'xxx' /} 向父模板传递值内置标签常用#{extends}子模板可以通过#{extends}标签继承已经定义好的装饰模板示例#{extends 'main.html'/}<h1>Some code</h1>#{doLayout /}表示父模板中在标签处可以插入子模板的内容示例<div id="content">#{doLayout /}</div>#{set},#{get}#{set}标签用于设置可以在模板中使用的变量。#{get}标签的作用是获取由#{set}标签定义的值在Play的模板中,通过get/set机制,可以使父模板和子模板间进行通信示例#{set email:'china@oopsplay.org'} 设置了模板变量email的值#{get 'email'} 获取email的值可以在#{set}标签体内定义变量的值示例#{set 'title'}Profile of ${user.login}#{/set}可以在#{get}标签体内设置当变量不存在时的缺省值,如下例当title变量不存在时,会显示Homepage。示例<head><title>#{get 'title'}Homepage #{/} </head>#{script}用于生成一个<script>元素,可以引入/public/javascripts目录下的JavaScript文件。无需在地址前加上默认父目录/public/javascripts。示例#{script 'jquery-1.5.1.min.js' /}#{stylesheet}可以引入/public/stylesheets目录下的CSS文件示例#{stylesheet 'default.css' /}#{if},#{ifnot}#{ifnot}执行时具体的作用与#{if !condition}等价示例#{if user.countryCode == 'en' }Connected user is ${user}#{/if}#{else},#{elseif}#{else}标签通常与#{if}标签配合使用示例#{if user}Connected user is ${user}#{/if}#{else}Please log in#{/else}#{else}标签也可以与#{list}标签一起使用,当使用#{list }标签进行迭代的集合为空时,可以执行#{else}标签中的内容示例#{list items:task, as:'task'}<li>${task}</li>#{/list}#{else}Nothing to do...#{/else}#{list}遍历集合示例<ul>#{list items:products, as:'product'}<li>${product}</li>#{/list}</ul>#{list items:0..10, as:'i'}${i}#{/list}预定义变量,名称为 循环变量_XXX,下面用note代表循环变量note_index:表示当前对象在集合中的序号。note_isFirst:表示是否是集合中的第一个对象。note_isLast:表示是否是集合中的最后一个对象。note_parity:表示当前对象在集合中序号的奇偶值,可能是even或odd。#{include}在当前模板中导入另一个模板,并且当前模板中的所有变量对导入的模板透明。示例<div id="tree">#{include 'tree.html' /}</div>#{verbatim}使输出内容不转义(默认转义)示例#{verbatim}${'&'}#{/verbatim}表单#{authenticityToken /}可以防止跨站请求伪造,同时也能消除刷新提交和后退提交所带来的困扰会为服务器和客户端表单生成相同的随机令牌,并以隐藏的input输入域的形式嵌入表单,一起提交到服务器在表单中加入即可,相当于<input type="hidden" name="authenticityToken" value="1c6d92fed96200347f06b7c5e1a3a28fa258ef7c">验证错误信息#{ifError},#{ifErrors}#{ifError}标签可以判断指定的作用域中是否有action添加的验证错误的信息#{ifErrors}只要模板中有任何的验证错误信息,都可以将其输出示例#{ifError 'user.name'}<p>User name is invalid: #{error 'user.name' /}<p>#{/ifError}--------------------------------#{ifErrors}<p>Error(s) found!</p>#{/ifErrors}#{error},#{errorClass},#{errors}#{error}标签的作用是输出验证后的错误消息示例#{error 'user.name'/}#{errorClass}标签的作用是如果存在指定的验证错误消息,则标签在解析时将被替换为文本hasError,一般在class中使用示例<input name="name" class="#{errorClass 'name'/}">相当于<input name="name" class="${errors.forKey('name') ? 'hasError' : ''}">#{errors}标签可以遍历当前的验证错误对象集合,其使用方式与 #{list}非常类似,循环体中使用的对象变量名称是${error}示例<ul>#{errors}<li>${error}</li>#{/errors}</ul>内置函数格式化日期${new Date(1275910970000).format('dd MMMM yyyy hh:mm:ss')}格式化数字${42.format('000.00')}字符串转义escape(),escapeHtml() 对字符串进行转义处理raw() 跳过模板对字符串的自动转义处理urlEncode() 将URL查询字符串中用到的特殊符号转义输出数组操作(字符串数组)contains(string) 判断数组中是否包含指定元素内置对象所有添加到renderArgs作用域的对象,都会以变量的形式注入模板。默认的内置对象errors 验证错误信息结果集,对应play.data.validation.Validation.errors()flash Flash作用域,对应play.mvc.Scope.Flashlang 当前使用的语言,对应play.i18n.Langmessages 消息映射变量,对应play.i18n.Messagesout 引用页面输出流,对应java.io.PrintWriterparams 当前参数变量,对应play.mvc.Scope.Paramsplay Play框架类,对应play.Playrequest 当前请求对象,对应play.mvc.Http.Requestsession Session作用域,对应play.mvc.Scope.Session域模型属性模拟在Play中把属性变量声明为public,并可以不提供set/get方法,可以使用等号为属性赋值运行时Play会自动生成相应的getXxx/setXxx方法(将声明为public的字段都视为属性)使用等号为属性进行赋值,也会在程序加载时自动转换为set方法如果存在自己定义的get/set方法,则play会优先选择手动编写的方法数据库配置在conf/application.conf文件中添加db.url=jdbc:mysql://localhost/testdb.driver=com.mysql.jdbc.Driverdb.user=rootdb.pass=123456可选配置方言jpa.dialect=<dialect>获取Connection对象Connection conn = play.db.DB.getConnection();conn.createStatement().execute("select * from products");数据持久化Play的持久层框架采用的是Hibernate,使用Hibernate(通过JPA)自动地将Java对象持久化到数据库在实体类上增加@javax.persistence.Entity注解后,Play会自动为其开启JPA实体管理器。得到实体管理器EntityManager em = JPA.em();Play提供的play.db.jpa.Model类提供了对模型自己进行增删改查的便捷方法,可以使用实体类继承Job异步处理概述Job就是需要在指定的时刻或者时间段内执行的任务,通常由作业调度程序来执行调度和管理。需要继承play.jobs.Job类,没有返回值就重写doJob方法,有返回值就重写doJobWithResult方法job必须在单独的一个文件中,不能有同级的类,job不能访问其它类的方法?在类声明上添加注解(开发模式先访问一下才会开始执行)@OnApplicationStart 在应用程序启动时执行@OnApplicationStop 在应用程序停止时执行@Every 周期性执行任务,例@Every("1h"),可选单位d,h,min,mn,s (min和mn都为分钟)@On 在具体的某个时间点执行,例@On("0 0 12 * * ?")CRON表达式@On标签中使用的是Quartz库的CRON表达式。CRON表达式是由7个子表达式组成的字符串,每个子表达式都描述了单独的日程细节。这些子表达式用空格分隔,分别表示:Seconds 秒Minutes 分钟Hours 小时Day-of-Month 一个月中的某一天Month 月Day-of-Week 一周中的某一天Year 年(可选)具体CRON表达式的例子:"0 0 12 ? * WED",表示“每周三的中午12:00”。手动调用job创建实现类的对象,并使用now()方法即可,可返还一个结果,默认为异步执行,如果想阻塞线程,可以调用结果的get方法every(str)可手动启动job,并指定间隔时间JPA支持启用JPA实体管理Play会自动查找标记为javax.persistence.Entity注解的类@javax.persistence.Entity注解的作用是通知Play对当前实体类进行管理获得JPA实体管理器JPA.em()事务管理Play会自动进行事务管理,在每次发送HTTP请求时自动开启事务,发送HTTP响应完毕后提交事务。Play为事务管理控制提供了注解的支持。如果需要将Action声明为只读事务,可以在Action方法上标记@play.db.jpa.Transactional(readOnly=true)注解;如果执行当前方法时无需开启事务,可以在Action方法上标记@play.db.jpa.NoTransaction;如果当前控制器中所有方法都无需开启事务,可以直接在控制器上标明@play.db.jpa.NoTransaction。数据验证使用验证器进行数据验证框架为每个请求绑定了验证器。应用代码中可以通过以下三种方式对数据进行验证1.使用APIpublic static void hello(String name) {validation.required(name); //验证name参数是否被赋值}2.在方法中添加注解public static void hello(@Required String name){}3.在定义域模型时添加注解public class User extends Model {@Requiredpublic String name; //为User的name属性添加@Required验证} //直接使用@Valid注解对POJO参数进行验证public static void save(@Valid User user) { }当验证不通过时,验证器会将错误以play.data.validation.Error的形式保存,因此每个验证器以集合的形式维护了一系列的error对象。每个error对象有key和message两个属性:key:该属性帮助我们标识引起错误的元素。key的值可以任意设定,默认与验证的数据同名。message:验证消息,用于描述验证不通过的错误信息。message可以是纯文本或指向消息包(message bundle)的key(通常为了支持国际化)。在验证结束后我们可以检查是否有error产生,并将验证消息打印出来public static void hello(String name, Integer age) {validation.required(name);validation.required(age);validation.min(age, 0);if(validation.hasErrors()) { for(Error error : validation.errors()) {System.out.println(error.message());}}}方法说明error.message() 返回此error对象的messageerror.message(str) 设置此error对象的key,然后返回此对象的message(如果没有在配置文件中找到指定key,则直接返回key)设置错误消息提示如果validation.required(name);校验失败,则error.message()的值为"Required",可以自定义错误消息提示Play提供了三种方式自定义错误消息提示:在项目的conf/messages文件中自定义某一类错误校验的提示消息在项目的conf/messages文件中自定义错误校验的提示消息,并为error设置key直接为error设置message自定义某一类错误校验的提示消息在conf/messages中修改不带参数: validation.required=Please enter a value 含有参数: validation.required=%s is required # %s自动替换为 error.key自定义错误验证消息(手动使用)在conf/messages中添加validation.required.em = You must enter the %s!使用(三种方法都可以)1.使用API设置keyvalidation.required(manualKey).message("validation.required.em")2.使用注解设置keypublic static void hello(@Required(message="validation.required.em") String name) { } 3.JavaBean的属性中设置keypublic class Person extends Model { @Required(message = "validation.required.em")public String name; } public static void hello(@Valid Person person) {} 直接为error设置message使用方法与自定义错误验证消息相同,只是不在conf/messages文件中添加配置原因error.message(str)方法的作用为 返回此对象的message,如果没有在配置文件中找到指定key,则直接返回key所以,通过error.message(str)方法设置key的值,并且不在配置文件中添加配置.相当于直接设置了message的值注意在conf/message文件中配置时,如果消息提示中,需要获取 验证方式的参数使用 %2$s %3$s 依次获取(数字为 %2$d %3$d)如范围验证validation.range=Not in the range %2$d through %3$d在页面显示错误消息提示示例#{ifErrors}<h1>Oops...</h1>#{errors}<li>${error}</li>#{/errors}#{/ifErrors}#{else}Hello ${name}, you are ${age}.#{/else}完整示例控制器提供两个action方法,一个用于返回表单(index),一个用于接收提交的表单内容(hello)public static void index() {render();}public static void hello(String name, Integer age) {validation.required(name);validation.required(age);validation.min(age, 0);if(validation.hasErrors()) {params.flash(); // 将HTTP参数保存在Flash作用域中validation.keep(); // 在下一个请求中保持错误信息的集合index();}render(name, age);}页面#{form @Application.hello()}<div>Name: <input type="text" name="name" value="${flash.name}" /><span class="error">#{error 'name' /}</span></div><div>Age: <input type="text" name="age" value="${flash.age}" /> <span class="error">#{error 'age' /}</span></div><div><input type="submit" value="Say hello" /> </div>#{/form}内置验证方式required 验证是否为空equals 验证两个值是否相等range 验证是否在给定的两个数值范围内phone 验证是否为合法的电话号码email 验证E-mail地址是否合法url 验证是否为合法的URLmatch 验证是否匹配给定的正则表达式max 验证数值大小是否大于给定的值min 验证数值大小是否小于给定的值maxSize 验证字符串长度是否大于给定的值minSize 验证字符串长度是否小于给定的值future 验证是否为相对未来的时间past 验证是否为相对过去的时间ipv4Address 验证是否为符合ipv4规则的IP地址ipv6Address 验证是否为符合ipv6规则的IP地址isTrue 验证String或者Boolean类型变量是否为true自定义验证步骤自定义实现类,继承Check类,重写isSatisfied方法使用@CheckWith注解,在注解中传递实现类的class对象示例public class User {@Required@CheckWith(MyPasswordCheck.class)public String password;static class MyPasswordCheck extends Check {public boolean isSatisfied(Object user, Object password) {return notMatchPreviousPasswords(password);}}}缓存概述缓存是用来避免频繁到服务器端获取数据而建立的一个存取更快的临时存储器。缓存的容量相对较小,但执行速度非常快,其主要作用为:存储系统经常访问的数据。存储耗时较长的计算结果。当我们在使用缓存时,必须明确其自身特性:缓存存在于内存中(不进行持久化),只是用于存放暂时性的数据,时间一到就会过期。因此缓存并不是一个安全的存储器,不能保证数据可以永久存在。如果发现数据在缓存中已过期,需要重新获取数据,并再次放入缓存与Session对象不同,缓存中的内容是独立的,不会绑定任何特定的用户。所以一般使用session.getId作为key将数据存入缓存APICache.get(id, Product.class)Cache.set("product_"+id, product, "30mn");Cache.delete("product_"+id);Cache.safeGet(id, Product.class)Cache.safeSet("product_"+id, product, "30mn");Cache.safeEelete("product_"+id);注意:带safe前缀的方法是阻塞的,而标准方法是非阻塞的delete方法会立即返回结果,并没有等待缓存对象是否被真正地物理删除。因此,如果程序执行期间发生了错误(例如IO错误),缓存对象可能仍然存在,并没有被删除。如果操作需要确保缓存对象被删除,可以使用safeDelete方法,该方法是阻塞式的,并返回一个布尔值标识对象是否被成功删除。示例public static void showProduct(String id) {Product product = Cache.get(id, Product.class);if(product == null) {product = Product.findById(id);Cache.set("product_"+id, product, "30mn");}render(product);}public static void addProduct(String name, int price) {Product product = new Product(name, price);product.save();showProduct(id);}public static void editProduct(String id, String name, int price) {Product product = Product.findById(id);product.name = name;product.price = price;Cache.set("product_"+id, product, "30mn");showProduct(id);}public static void deleteProduct(String id) {Product product = Product.findById(id);product.delete();Cache.delete("product_"+id);allProducts();}配置Memcached如果项目要启用Memcached,需要在application.conf中打开Memcached开关,并设置Memcached的守护进程地址:memcached=enabledmemcached.host=127.0.0.1:11211我们还可以指定多个守护进程地址,使之连接到同一个分布式缓存:memcached=enabledmemcached.1.host=127.0.0.1:11211memcached.2.host=127.0.0.1:11212常用Play.applicationPath.getPath() 获得项目路径Request.current() 获取request对象Response.current() 获取response对象
本文标签: play
版权声明:本文标题:play 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1687949197a160907.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论