??xml version="1.0" encoding="utf-8" standalone="yes"?>
但是有些时候JSF的用还是不是十分方? 其是对于初学者而言, 常常被一些莫明其妙的问题搞得晕头转向.
怿很多初学者都见到q这个Exception?
严重: Servlet.service() for servlet jsp threw exception
javax.servlet.jsp.JspException: Cannot find FacesContext
当我在学习JSF的时?看到q个Exception我找了半天都没有发现我的代码哪里错了(代码不可能出?因ؓ是直接copy的书中的源代?呵呵), 后来不经意间才发现原来访问页面的URL错了, 在JSF配置文g中配|的servlet映射?jsf,所以访问的URL应该?.... index.jsf, 而不?... index.jsp., p么一点疏忽就让h白忙zM半天. 郁闷?
随着学习的深?q种基本错误是很再出现?q出现也可以马上知道问题的Ҏ), 但是JSF其他的一些限制又是让人感到很郁闷? 比如 Form数据的提? JSF规范中ؓ了维护服务端的组件树 只能使用Post提交, 而不可以使用Get. 而GetҎ在很多地方还是非常有用的.
另外q有Faces API使用h不是十分直接的问? 要把一个数据放入到session中就要一大串的操? FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(name, val); ),让h感觉很不?
....
如果你经帔R到这些问? 那么现在我将告诉你一个好消息, 有了Frails q些问题都可以轻而易丄解决?
我们先来看看Frails是什?
在Frails主页上定?http://frails.hexiao.cn/what-is-frails.html
what is frails?
Frails 是基于JSF上的一个开发效率和RoR可以向媲的JavaEE框架 !
Ruby On Rails(RoR)因ؓ在开发webE序的高效性而风行一?可能现在仍然很热), 那些RoR的支持者说, RoR可以比java的开发效率高?0倍以?我们Ҏ观点持怀疑的态度. 我们怿,如果有正的开发方法来支持现在的Java web framework,?Java web开发的效率 不会如此的低?所?我们研究了一下RoR的实现机?来实现我们Java框架中的RoR. 因此, 我们提供一个在开发效率上和RoR可以媲美的JavaEE开发框?-- Frails !
知道了Frails是什么后, 我们再来看看Frails有什么特? 能给JSF带来什么功能上的增?
在Frails主页上列举了Frails的如下主要特? http://frails.hexiao.cn/frails-features.html
Frails(Java Server Faces On Rails)ZJava Server Faces (JSF),q将提供?Hibernate和Spring的支? 主要特征如下:
Frails 让开发者用约?习惯)和注?annotations)来省略在 faces-config.xml 文g?managed-bean ?navigation-rule的配|?
Frails 提供一个更单的Ҏ来?Faces API.
Frails 重定向非 faces hZ?faces h,q样可以避免因ؓURL输入的疏忽导致的异常.
Frails 提供一些预定义?Managed Bean 基类让开发者扩?.
Frails 可以让开发者在 Managed Bean 中用注?Annotation)来支持AOP功能 ,?函数拦截(method interception).
Frails 提供 Managed Bean 属性的injection ?outjection
Frails 中的Hibernate GenericDao 对象提供了基本的 CRUD 函数 ?其他一些有?常用)的数据访问函?
Frails q提供了一些有用的注解(annotations)来简化JSF的开?
Frails 完全支持 jsf 1.1 ?jsf 1.2 规范,q且可以自动的探你使用的版?
Frails 提供了对action Method ?Listener 函数的增?在这些函C现在你可以传递参C.
知道q这么多Frails的东? 那么你不要?如何使用Frails?
q个是很单的. 你只需要在web.xml文g中添加下面的配置:
<filter>
<filter-name>FacesFilter</filter-name>
<filter-class>net.sf.frails.filters.FacesFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FacesFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
然后把你下蝲的frails4jsf1.X.jar 攑ֈc\径中可以用了.
现在可以使用? 你不要? 如果在用过E中我遇C问题, 要到哪里得到帮助?如果我有好的Frails改进要到哪里提议?
关于frails的服务问? 你可以到JavaCafe http://www.hexiao.cn/jsf/ 论坛的Frails专区中取得帮?
ok, q次Frails 介就先到q里, 希望Frails能在你开发Java web app时给你带来一丝清?
资源:
Frails英文主页 http://frails.sf.net
Frails中文主页 http://frails.hexiao.cn
Frails中文论坛 http://www.hexiao.cn/jsf
]]>
"Unableto create the selected preference page
Reason:
Plug-inorg.Maven.ide.eclipsewasunabletoloadclass
org.maven.ide.eclipse.preferences.Maven2PreferencePage"
l过多方查找资料发现, 先安?.0.5 然后升可以解册问题?
不知道ؓ什么要q么ȝ,
]]>
上面的文章介l的比较详细, 也是jsf的一个ajax扩展目, 其实对于使用myfaces的用h说还有个更的选择:使用MyFaces Sandbox 中的 InputSuggestAjax
http://myfaces.apache.org/sandbox/inputSuggestAjax.html
用法如下:
1.创徏一个managed bean:
package test;
import java.util.ArrayList;
import java.util.List;
public class Bean {
//In that function all what you had to do is to
//Specify what will be displayed in the list
//Note that the keyword is the text entered by the user
public List getSuggestedWords(String keyword) {
List list = new ArrayList();
list.add(keyword + " Ahmed Saleh");
list.add(keyword + " Kahki");
list.add(keyword + " Kourany");
list.add(keyword + " Kiki");
list.add(keyword + " Saleh Abouetta");
list.add(keyword + " Hashim");
return list;
}
public String getCurrentValue() {
return currentValue;
}
public void setCurrentValue(String currentValue) {
this.currentValue = currentValue;
}
String currentValue;
}
2. jsp 面代码
<%@ taglib uri="
<%@ taglib uri="
<%@ taglib uri="
<html> <head> <title>Ajax JSF sample (InputSuggestAjax)</title> </head> <body> <f:view> <h:form> <h:outputText value="Enter your name : "/> <s:inputSuggestAjax suggestedItemsMethod="#{bean.getSuggestedWords}" value="#{bean.currentValue}" /> <br /> <h:commandButton action="" value="Submit"/> <br /> <h:outputText value="Your name is #{bean.currentValue}"/> </h:form> </f:view> </body> </html> 3. web.xml配置 <context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>client</param-value> </context-param> //Instead of server make the state saving method on the client to make it works 4. 输出面: 版本为? 1.1.4 CZ代码提供Hazem http://bbs.hexiao.cn/ 如果你不想看到该异常, 也不想保存session. 那么你可以在目部v描述文g?? test.xml,)(instead of just exploding the war) ? <Context> tags中间 加上 :
试试? 译:icess http://blog.matrix.org.cn/page/icess 讨论 如果你听说过 GWT,那么你一定也听说q它的一个核心特性就?AJAX 支持.?GWT? the "X" part,在客L和服务器端来回传递数? 该功能是通过RPC (Remote Procedure Call) 机制实现的而不是?XMLHttpRequest object. 不管q些,你想在服务器端做什么是有你军_? GoogleU它?Server Agnostic". 让我们看看如何添?AJAX 方式的异步通信到我们的E序? 在下个阶D中,我们改变该E序的环?我们d一个用户可以输入姓名的文本?一旦按钮被点击?h会发送到服务器端.服务器将q回出现在弹出窗口的消息.Z跟踪h和响?我们d一个文本标{来昄h的状? Z在服务器和客L传送数?我们使用两个Java beans. – 一个把数据带回服务器端,一个把响应带回客户? . 28. 在JavaSource中创Z?demo.gwt.client.EventData c?内容如下: package demo.gwt.client; 用来在客L到服务器端传送数据的c?发送事?应该l承 G4jsf的 GwtFacesEventc? 29. 创徏另外一个类 demo.gwt.client.ResultGreeting. 内容如下: package demo.gwt.client; 从服务器端带来响应的cd该承G4jsf?GwtFacesResult c? GwtFacesEvent 和GwtFacesResult 都实C com.google.gwt.user.client.rpc.IsSerializable 接口,用来序列化在客户端和服务器端传递的被GWT使用的数? 让我们更新我们的widget c? 30. 打开demo.gwt.client.HelloWidgetEntryPoint 使用下面代码替换? package demo.gwt.client; q里?个重要的部分.1.lg的布局.我们创徏了一个水q面?然后d了一个input box,button,和text label. 2.声明了异步服务和事g,它承至异步模型的AJAXh. ... 我们dClickListener 到button? ?On Click 事g发生?我们创徏q且使用输入的数据填? EventData bean 然后使用异步服务发送该事g.在代码的l后一?我们讄text label的文本ؓ "Loading?,因此? AJAX request 开始的时?用户可以看到变化 . 3.发送事?我们注册了一个回调函? ......... Callback ?Google toolkit中AsyncCallback cȝ一个接?我们实现了两个方?onSucess and onFailure. 在onSuccess情况? 我们d了一个附加的到来的l果.如果我们没有受到一个期望的c?我们标记在状态文本中. 现在我们完成了客L的代?如果你? Hosted Mode (with the "ant shell" command)来启动程? 你将看到 "Request finished, but the result is empty", 因ؓ我们q没有写服务器端代码. Server-Side Coding 在Hosted Mode中的服务器端代码, 在server包中的一个类扮演了一个重要角? 31. 打开JavaSource中的demo.gwt.server.MockHelloWidget java 文g. sendEvent 函数复杂发送响应到客户? 32. 把sendEvent函数替换Z面的内容.: public GwtFacesResult sendEvent(GwtFacesEvent event){ 33. 导入需要的c? import demo.gwt.client.ResultGreeting; The parameter of the method points to the event content that came from the client. What we do here is create the Result bean filling it with a greeting message and then returning. 34.在Hosted Mode中启动ant:
处理JSF的事件和Hosted Mode的代码差不多. 客户端代码不?在服务器?, G4jsf使用 JSF 监听器机制来处理 Ajax events. 35. 打开 WebContent/pages/Base.xhtmlq添加监听器lg声明. <widget:component id="main" buttonLabel="#{bundle.buttonLabel}" gwtListener 元素有两个属? "method"使用JSFEL指向处理?"event"用来定义事gcd. 事gcd是类的全限定?.最后一步是实现该函? 36. 打开demo.gwt.app.GreetingBeand下面的代? public ResultGreeting takeGreeting(EventData event) { 37. 和需要导入的c? import demo.gwt.client.ResultGreeting; 该函数的{(signature )很容易记?该函C用来自于客户端的事g作ؓ他的唯一一个参?q回gؓ 用来q回l果的事件类?type of the method equals is just the type of the class used to return the result).在这个函C,我们合成响应数据q且q回? 38. 创徏war文g,部v? 如果你启动服务器,可以看导:
如你看到的,通过G4JSF使用两种互补的技?GWT and JSF)可以做很多漂亮的事情. 但是,仍然q有很多东西可以q一步添加到G4jsf?作ؓ一个开源项? , G4jsf依靠一个开源社区来支持和开发它.如果你只是用它,那是很好?但是你也可以加入到G4JSFC中来, 帮助G4JSF让他做的更好. Come visit us at: Sergey Smirnov is Senior Product Manager at Exadel where he oversees the development of major products including Exadel Visual Components Platform and Exadel Studio. He has more than 15 years of in-depth development experience, primarily in the area of Web applications. His experience with JSF goes back to the very early days. For two years, he has served as a member of the JSF expert group. In addition to this, he manages a site for JSF-related resources, www.jsftutorials.net. Finally, Sergey is the co-lead of the open source project Ajax4jsf (https://ajax4jsf.dev.java.net). He can be reached at ssmirnov@exadel.com.
]]>
<Manager className="org.apache.catalina.session.PersistentManager"
saveOnRestart="false"/>
q样 tomcat 在关闭的时候就不会保存session资源?
你也可以在server.xml中指定上面的? q也所有的E序都用这个设|了.
]]>AJAX, AJAX, AJAX
Asynchronous Communication in Hosted Mode
Client-Side Coding
import org.ajax4jsf.gwt.client.GwtFacesEvent;
public class EventData extends GwtFacesEvent {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import org.ajax4jsf.gwt.client.GwtFacesResult;
public class ResultGreeting extends GwtFacesResult {
String greetingText;
public String getGreetingText() {
return this.greetingText;
}
public void setGreetingText(String greetingText) {
this.greetingText = greetingText;
}
}
import java.util.Map;
import org.ajax4jsf.gwt.client.ComponentEntryPoint;
import org.ajax4jsf.gwt.client.GwtFacesServiceAsync;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class HelloWidgetEntryPoint extends ComponentEntryPoint {
Label status;
TextBox input;
protected Widget createWidget(final String id) {
Map m = getWidgetParams(id);
final String buttonLabel = (String) m.get("buttonLabel");
HorizontalPanel panel = new HorizontalPanel();
input = new TextBox();
status = new Label("Loaded.");
final GwtFacesServiceAsync service = createFacesService(id);
final AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
if (null != result) {
status.setText("Loaded");
String greeting = ((ResultGreeting)result).getGreetingText();
Window.alert(greeting);
} else {
status.setText("Request finished, but the result is empty");
}
}
public void onFailure(Throwable caught) {
status.setText("Error call :" + caught.getMessage());
}
};
Button btn = new Button(buttonLabel, new ClickListener() {
public void onClick(Widget sender) {
EventData eventData = new EventData();
eventData.setName(input.getText());
service.sendEvent(eventData, callback);
status.setText("Loading...");
}
});
panel.add(input);
panel.add(btn);
panel.add(status);
return panel;
}
}
final GwtFacesServiceAsync service = createFacesService(id);
...
Button btn = new Button(buttonLabel, new ClickListener() {
public void onClick(Widget sender) {
EventData eventData = new EventData();
eventData.setName(input.getText());
service.sendEvent(eventData, callback);
status.setText("Loading...");
}
});
...
:
.........
final AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
if (null != result) {
status.setText("Loaded");
String greeting = ((ResultGreeting)result).getGreetingText();
Window.alert(greeting);
} else {
status.setText("Request finished, but the result is empty");
}
}
public void onFailure(Throwable caught) {
status.setText("Error call :" + caught.getMessage());
}
};
...........
...........
ResultGreeting result = new ResultGreeting();
result.setGreetingText( "Hello " +
((EventData)event).getName() );
return result;
}
import demo.gwt.client.EventData;Adding JSF Listeners for Run-Time Mode
greeting="Hello #{greetingBean.name}!" >
<gwt:gwtListener method="#{greetingBean.takeGreeting}"
event ="demo.gwt.client.EventData"/>
</widget:component>
name = event.getName();
ResultGreeting result = new ResultGreeting();
result.setGreetingText("Hello " + name + " from JSF!");
return result;
}
import demo.gwt.client.EventData;
The Last Word
About the Author
]]>
译:icess http://blog.matrix.org.cn/page/icess 讨论
在我们应用程序的W一个版本中,我们编码标{֭W到E序?在下一个版本中,我们保持该文本与java代码分离.
一U方式是使用GWT来定义label 和message.
13. 打开demo.gwt.client.HelloWidgetEntryPoint.java 文g用下面的代码替换createWidget Ҏ.
protected Widget createWidget(final String id) {
Map m = getWidgetParams(id);
final String buttonLabel = (String) m.get("buttonLabel");
final String greeting = (String) m.get("greeting");
Button btn = new Button(buttonLabel, new ClickListener() {
public void onClick(Widget sender) {
Window.alert(greeting);
}
});
return btn;
}
14. 保存文g.
15. 打开 JavaSource\demo\gwt\public\index.html 文g.
该文件已l包含了一个如何定义参数的CZ,我们只需要修改一下就可以? :
16. 修改为如下的代码:
<html>
<head>
<meta name="gwt:module" content="demo.gwt.HelloWidget">
<meta name="gwt:property" content="viewid=hello">
<meta name="gwt:property" content="action=/gwtFacesServlet">
<title>gwt-jsf integration</title>
</head>
<body bgcolor="white">
<script language="javascript" src="gwt.js"></script>
<iframe id="__gwt_historyFrame"
style="width:0;height:0;border:0"></iframe>
<span id="_id1" class="demo.gwt.HelloWidget">
<span id="_id1:_data" style="display:none;">
<span title="buttonLabel">Say Hello</span>
<span title="greeting">Hello GWT!</span>
</span>
<input type="hidden" id="javax.faces.ViewState"
name="javax.faces.ViewState" value="_id0:_id0" />
</span>
</body>
</html>
17. ?Hosted Mode 中启动ant:
然?如果你想创徏一个war文g,然后部v?你将看不到相同的l果.q是因ؓ public/index.html仅仅在Hosted Mode中其作用.?Run-Time Mode,我们需要?JSF page.
看一下WebContent\pages\Base.xhtml文g.它包含如下代?
<widget:component id="main" />
q实际上是一个GWT widget 的 JSF 包装.
18. 定义lg?buttonLabel" ?greeting" 参数 :
<widget:component id="main" buttonLabel ="Click Me!"
greeting="Hello, GWT and JSF"/>
19. 在Run-Time Mode中运行该目.
看看l果. 然而这是不是太单了, 下面来看看如何? JSF EL来它更动态一?
20.现在关闭XHTML 文g.
21. 在JavaSource 文g夹下创徏demo/gwt/app/bundle/Labels.properties文g,包含下面的内?
#
buttonLabel=Say Hello!
22. 在JavaSource中创Z个类demo.gwt.app.GreetingBean .使用下面的代?
package demo.gwt.app;
public class GreetingBean {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
23. 在WEB-INF/faces-context.xml 中注册该bean.
The faces-context.xml should contain
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.
//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
<managed-bean>
<managed-bean-name>greetingBean</managed-bean-name>
<managed-bean-class>demo.gwt.app.GreetingBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>name</property-name>
<property-class>java.lang.String</property-class>
<value>GWT and JSF</value>
</managed-property>
</managed-bean>
<application>
<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
</application>
</faces-config>
要让EL工作.我们要在lgcMd属性到属性map?
24. 打开demo.gwt.jsf.UIHelloWidget, 扑ֈ getWidgetParameters() Ҏ,使用下面的代码替?
public Map getWidgetParameters() {
HashMap params = new HashMap();
params.put("greeting",getAttributes().get("greeting"));
params.put("buttonLabel",getAttributes().get("buttonLabel"));
return params;
}
25. d下面的import语句:
import java.util.HashMap;
现在回到 pages/Base.xhtml文g?
26. 把资源声明放到该文g的顶?
<f:loadBundle basename="demo.gwt.app.bundle.Labels" var="bundle"/>
27. 修改widget:component的属?
<widget:component id="main" buttonLabel ="#{bundle.buttonLabel}"
greeting="Hello #{greetingBean.name}!" />
现在两个属性都通过el来生了,一个来自于 bundle resource file, 一个来自于 backing bean.
如果你创?部v,启动该程?你可以看到该E序现在使用的按钮标{了:
OK,我们已经在JSF环境中参数化了GWT widget的数? 因此你可以用同LҎ用数据初始化? widget .然而目前这一切看h想一张单ER? one-way ticket).我们q没有提C个非帔R要的斚w .
译:icess http://blog.matrix.org.cn/page/icess 讨论
Google Web Toolkit (GWT) 吸引了一些开发者的注意.因ؓ使用它你可以很容易的dAJAX Web 2.0功能C的程序中. GWT的设计师努力隔绝用户和JavaScript打交?你只要用GWT可以了,不需要知道如何用JS. GWT 通过从java代码来生JS代码的\方式 实现了创建高U客LJS组?client-side JavaScript widgets)的Q?
与此同时, JavaServer Faces (JSF)聚集了愈来愈多的成ؓ通用服务端web框架的要?JSF成功的主要原因是:自顶向下的基于组件的方式来开发webE序. 同时JSF带有自己标准的随时可?out-of-the-box)的UIlg , 它被设计为简单的包含其他lg?it is designed for the easy inclusion of other component libraries).
然?q两Ҏ术是不可思议的他们自己L,他们两个怺l合的非常好(怺互补). GWT 不知道服务端的状? server-side-agnostic),然?JSF'sZlg的结构可以很Ҏ的适应Mlg的渲?在这文章中,我们讨?(首先通过一个step-by-step 的例?一个促q这两个技术互补的新框?
G4jsf 已经成ؓAjax4jsf开源项目的一个子目?(https://ajax4sf.dev.java.net) ,有它来生这U集成库.
GWT和JSF之间看v来是怺竞争的技?而用G4JSF则看h是很自然的互补技?而G4JSF的Q务就是ɘq种互补关系的技术看h更自然一?
库文件包含两个部?
G4jsf 注意了JSF ?GWT 两种技术的发展q程\.对于 GWT, widgets仍然在主机模型中开?q且在?Google browser来调? GWT 目l构包含 /client, /public, ?/server ? q且q在l箋l护.
G4jsf lg开发包(G4jsf CDK)产生的组件包含两个部?一?包含客户端行为的GWT widget .二是负责 GWT widget ?JSF 环境之间的通信问题.
G4jsf CDK 使用Facelets方式来写JSFlg. 它比不同的JSP方式要简? 使用普通的方式要创Z个TLD文g和一个Tagc?使用Facelets的方式是相当直接?
在这文章中,我们一步一步的通过一个简单的"Hello, World" 例子来讲qG4JSF的主要功?我们也创Z个实际的例子,a4j-gwtdemo. 在这?http://livedemo.exadel.com/a4j-gwtdemo/ 可以看到该例?
你可以从Ajax4jsfCZ面上下载到CZ的源代码和war部v文g .?/font>http://code.google.com/webtoolkit/download.html.
2. 保存GWT SDK .
3. 把G4JSF CDK中的 build.properties.sample 重命名ؓ build.properties,打开?把gwt.home改ؓ你的本地GWT ȝ?
例如,你把 Google Web Toolkit SDK 解压?
gwt.home=D:/gwt-windows-1.1.0
4. ~辑,保存文g
初始化工作已l做好了,下面来生项目框?
在刚才的目录下的build文g中有?"create-component" target. 它需要俩个运行参?
out |
产生的项目代码文件存攄目录.路径的最后一部分为项目的名字 |
m odule |
GWT module的全限定? 产生的JSF lgcd有同样的名? |
让我们命名模型ؓ demo.gwt.HelloWidget 保存目的名字ؓ, KickStart, 在D:/workspace/ 文g夹下. (Of course, you can change any of these.)
5.使用下面的命令运行ant:
让我们来ȀzL们的目.我们在标准的GWT Hosted Mode中来看看效果,在下个部分中在servlet container?来允许该例子. 7.打开 JavaSource/demo/gwt/client/HelloWidgetEntryPoint.java文g. 它包含一个 HelloWidgetEntryPoint c? 里面有个q回null的方? 8. 使用下面的代码替换该Ҏ: 9. 保存文g,到ant文g夹下? 10. 使用shell目标启动ant:
Google Toolkit Development shell ?Google browser 启动?在browser中显CZ我们刚才创徏的button.如果你点击button ,一个带问候消息的警告框出C. Google browser包含一? "Compile/Browser" 按钮.如果你点d,你可以在你默认的览器中查看该示? 目前q没有Q何JSF代码搀合进?到此Z我们只是在?"Hosted Mode."你可以在该模式下开发和调试你的 GWT widget . 如果你已l有了开发 GWT的经验了,那么你应该很熟悉它了. G4jsf QDQ 的处理过E和q里是一L. 下一步是在JSF 环境中运行该CZ. 11.使用 "war" target启动ant:
q行该项?可以看到同L效果,但是q行在JSF环境中我们称它ؓ "Run-Time Mode."我们已经? GWT widget 包装为JSF lg?q才是集成的W一? public class HelloWidgetEntryPoint extends ComponentEntryPoint {
protected Widget createWidget(final String id) {
Button btn = new Button("Click me", new ClickListener() {
public void onClick(Widget sender) {
Window.alert("Hello, World");
}
});
return btn;
}
}
Hosted Mode
Run-Time Mode
讨论
]]>
from:R.J. Lorimer
在维护项目的一个普通的d是升库文?例如, 你在使用 commons-collections
在你的项目中,现在使用的是3.1,但是现在 3.2 发布? 你想使用? 所以你需要用新的jar来替换旧的jar库文?在eclipse3.2发布以前你需要做下面的几步来完成?:
[right-click project]->Properties...->Java Build Path->Libraries (tab)来删除类路径中的旧jar文g
q样做是很郁L. 其是你使用一个用很多第三方jar文g的工h(?Hibernate,spring) 当你升q些目?你要做很多上面的改动. 是不是很无趣??
来看看Eclipse 3.2 l我们带来了什么吧.有一个新的特性叫 'Migrate JAR File',用来升jar文g.要用该功能,在要替换的jar文g上右?q入 Build Path
子菜单选择 'Migrate JAR file':
你会看到下面的对话框:
如果你不走运也要Ҏjar文g名的?保持原来的名字不?你可以选中那个复选框..
然后点击finish, 你将看到你的jar文g已经升?
刚好最q几天做的一个东西要知道通信的细? 用的都是httpwatch, 没有和ide集成h,感觉不是很爽. 现在试试q个功能? 呵呵
Did you know that you can use NetBeans to monitor all communication of your web application - between the web browser and the web server? Indeed, you can see all the requests, read the headers, see the request parameters, etc. But not only that, you can actually save these requests and replay them.
This becomes very handy when testing your web application. For example you want to open a page with different parameters so you replay the request with modified (or even new) parameters.
HTTP monitor becomes really handy when working with AJAX. You can see every individual request and response, even though the form wasn't submitted - so you can actually monitor how javascript code requests new XML documents as the user goes through the page. It is quite amazing how much communication there can be between the webpage and server in some AJAX apps. So HTTP monitor can also help you see if you are not doing too many requests to the server.
HTTP monitor is accessible via Window | HTTP monitor. In case of Tomcat the monitor is enabled by default, but in case of Sun appserver it needs to be activated in Server Manager. I do not know about the other servers... please add a comment if you know how you can monitor requests to other appservers.
<filter> <display-name>Ajax4jsf Filter</display-name> <filter-name>ajax4jsf</filter-name> <filter-class>org.ajax4jsf.Filter</filter-class> </filter> <filter-mapping> <filter-name>ajax4jsf</filter-name> <servlet-name>Faces Servlet</servlet-name> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping>
注意. 你可以复制和_脓上面的内容在 README.txt 文g?
d下面的内?
<%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j"%>
C每个使用Ajax功能的JSP面?
让我们来看一个简单的JSF目. 我们仅仅需要一个JSP面,里面包含一个Form和一些JSF标签: <h:inputText> ?<h:outputText>.
我们q个单的E序应该可以让我们输入一些文字到<h:inputText>? 然后发送数据到Server,q在 <h:outputText>中显CServer的响?l我们一个Echo信息).
下面是一个我们需要的面代码 (echo.jsp) :
<%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <html> <head> <title>repeater </title> </head> <body> <f:view> <h:form> <h:inputText size="50" value="#{bean.text}" > <a4j:support event="onkeyup" reRender="rep"/> </h:inputText> <h:outputText value="#{bean.text}" id="rep"/> </h:form> </f:view> </body> </html>
如你看到的,唯一一行于常给JSF面代码不同的就是下面的一?/p>
<a4j:support event="onkeyup" reRender="rep"/>
在这里我们在父标{?<h:inputText>)中添加了一个AJAX 支持. 该支持绑定了JavaScript事g“onkeyup?.因此, 每一ơ该事g发布l父标签?我们的程序将发送一个AJAXh到Server.q意味着我们的受理的bean包含该“text?域中我们输入的最新数?
<a4j:support> 标签的“reRender?属?attribute)定义我们的页面的哪一部分被更? 在这?该页面唯一被更新的部位?<h:outputText> 标签,因ؓ他的ID值和“reRender?的属性值向匚w. 在一个页面中更新多个元素(elements)也是很简单的:仅仅把他们的IDs攑֜ “reRender?属性中可以了.
当然?Zq行q个E序我们q需要一个受理的bean
package demo; public class Bean { private String text; public Bean() { } public String getText() { return text; } public void setText(String text) { this.text = text; } }
下一? 我们需要在faces-config.xml 中注册上面的bean:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd"> <faces-config> <managed-bean> <managed-bean-name>bean</managed-bean-name> <managed-bean-class>demo.Bean</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> <managed-property> <property-name>text</property-name> <value/> </managed-property> </managed-bean> </faces-config>
注意:q里没有M东西直接和Ajax4jsf 有关?
最?不要忘了djar文g和更?web.xml 文g:
<?xml version="1.0"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>a4jEchoText</display-name> <context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>server</param-value> </context-param> <filter> <display-name>Ajax4jsf Filter</display-name> <filter-name>ajax4jsf</filter-name> <filter-class>org.ajax4jsf.Filter</filter-class> </filter> <filter-mapping> <filter-name>ajax4jsf</filter-name> <servlet-name>Faces Servlet</servlet-name> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping> <listener> <listener-class> com.sun.faces.config.ConfigureListener </listener-class> </listener> <!-- Faces Servlet --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class> javax.faces.webapp.FacesServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- Faces Servlet Mapping --> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> <login-config> <auth-method>BASIC</auth-method> </login-config> </web-app>
p样了, 现在你的E序应该可以工作?
前面我没看到了如何用一些基本的markup,和几个示?/p>
( http://www.hexiao.cn/blog/index.php?job=art&articleid=a_20060807_153301 ), q次再来看看几个复杂一点的markup.
下次来看?Form 及其相关的markup的?
[b]Include [/b]是一个和JSP中的include指o功能差不多的markup,用来导入一个文?
可以使用l对和相对\径来导入文g, 该类的用是很简单的.
Java code:
...
add(new Include("header", "header.html"));
add(new Include("footer", "footer.html"));
...
and Html Code:
...
<div>
<div wicket:id="header">header comes here</div>
<div>I am the body!</div>
<div wicket:id="footer">footer comes here</div>
</div>
...
上面可以实C个简单的布局框架.
[b]Panel: [/b]panel有点cM于swing中的panel,用来攄其他markup, panel的用也
是很单的, 如下:
创徏一个mypanelc?
class MyPanel extends Panel {
public MyPanel(String id) {
super(id);
add(new Label("label", "yep, this is from a component
proper"));
add(new AnotherPanel("otherPanel"));
}
}
该类l承与Panel,里面d了两个markup,一个Label,另外一个Panel(Panel可以
无限嵌套). 然后~写对应的html文g. MyPanel.html
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="<head>
<title>Wicket Examples - sample panel</title>
</head>
<body>
<wicket:panel>
<p style="border: 2px dotted #fc0; padding: 5px;">
Here are some panel contents for ya.<br />
Put arbitrairy Wicket components in your Panels,
like this label: <span wicket:id="label" style="background-
color: aqua" >to be replaced</span>, or<br />
even another panel: <span wicket:id="otherPanel"
style="background-color: aqua">also to be replaced</span>.<br />
You can nest panels any deep you want.
</p>
</wicket:panel>
</body>
</html>
下面是用上面的panel的代?
Java code:
...
add(new MyPanel("panel"));
...
Html code:
<span wicket:id="panel">panel contents come here</span>
[b]Fragment:[/b] 当有很多段信息要组l的时?使用很多panel可能是不雅观?q时
可以用Fragment?
CZ如下:
Java code:
...
add(new Fragment("myPanel1", "frag2"));
...
Html code:
...
<span wicket:id="myPanel">Example input (will be removed)</span>
<wicket:fragment wicket:id="frag1">panel
1</wicket:fragment>
<wicket:fragment wicket:id="frag2">panel
2</wicket:fragment>
...
[b]Link:[/b] link是web面中的q接? q里的link可以是一切连??常用?lt;a/>
, button... q里的link 和JSF中的link所拥有的功能一样强?
下面来看几个CZ:
普通的link:
Java code:
...
add(new Link("link1"));
...
Html code:
...
<a href="#" wicket:id="link1">this link is clicked <span
wicket:id="linkLabel1">n</span> times</a>
...
使用不同的html 可以昄Z同的样式,?
button样式的按?
Html code:
<button wicket:id="link2">this button is clicked <span
wicket:id="linkLabel2">n</span> times</button>
or:
<input type="button" wicket:id="link3" value="this button is clicked n
times" />
[b]ExternalLink:[/b] 是link的一U? 特别用来q接到该站点以外的资? CZ: JavaLobby")); Html code: will be replaced</a> [b]PageLink:[/b] 也是link的一U?实现面之间的蟩? CZ: (QuickStart4.this); public Class getPageIdentity(){ ... page</a> [b]BookmarkablePageLink:[/b] 也是link的一U?实现一U可以作Z{收藏的q接,?/p>
是无状态的q接. 可以带参C可以不带参数: CZ: Java code : BookmarkablePage.class));
page parameter argument"); BookmarkablePage.class, parameters)); .... Html code: ... without passing any arguments</a> <p> passing a message argument</a> 讨论: http://bbs.hexiao.cn/thread.php?fid=9 代码下蝲: http://bbs.hexiao.cn/read.php?fid=9&tid=15&fpage=1
Java code:
...
// add a link that goes to javalobby
add(new ExternalLink("externalLink1", "
...
...
<a href="#" target="_new" wicket:id="externalLink1">this body
...
Java code:
...
// 可以有多U方法用该c?下面是一U推荐的Ҏ
add(new PageLink("pageLink", new IPageLink(){
public Page getPage(){
return new NonBookmarkablePage
}
return NonBookmarkablePage.class;
}
}));
Html code:
...
<a wicket:id="pageLink">go to our private/ non bookmarkable
....
...
add(new BookmarkablePageLink("pageLinkNoArgs",
PageParameters parameters = new PageParameters();
parameters.put("message", "This message was passed as a
add(new BookmarkablePageLink("pageLinkWithArgs",
<p>
<a wicket:id="pageLinkNoArgs">go to our bookmarkable page
</p>
<a wicket:id="pageLinkWithArgs">go to our bookmarkable page
</p>
...
允许所需要的cd,到这里下? http://bbs.hexiao.cn/read.php?fid=9&tid=12&fpage=1
]]>
//import java.util.regex.Matcher;
//import java.util.regex.Pattern;
/**
* Decode encode
* @author icess
* @blog http://blog.matrix.org.cn/page/icess
*/
public class EncodeDecode {
final int STATE_COPY_INPUT = 100;
final int STATE_READLEN = 101;
final int STATE_DECODE = 102;
final int STATE_UNESCAPE = 103;
int[] digits = new int[128];
int[][] transformed = new int[3][128];
int[] pick_encoding = { 1, 2, 0, 1, 2, 0, 2, 0, 0, 2, 0, 2, 1, 0, 2, 0, 1,
0, 2, 0, 1, 1, 2, 0, 0, 2, 1, 0, 2, 0, 0, 2, 1, 1, 0, 2, 0, 2, 0,
1, 0, 1, 1, 2, 0, 1, 0, 2, 1, 0, 2, 0, 1, 1, 2, 0, 0, 1, 1, 2, 0,
1, 0, 2 };
int[] rawData = { 0x64, 0x37, 0x69, 0x50, 0x7E, 0x2C, 0x22, 0x5A, 0x65,
0x4A, 0x45, 0x72, 0x61, 0x3A, 0x5B, 0x5E, 0x79, 0x66, 0x5D, 0x59,
0x75, 0x5B, 0x27, 0x4C, 0x42, 0x76, 0x45, 0x60, 0x63, 0x76, 0x23,
0x62, 0x2A, 0x65, 0x4D, 0x43, 0x5F, 0x51, 0x33, 0x7E, 0x53, 0x42,
0x4F, 0x52, 0x20, 0x52, 0x20, 0x63, 0x7A, 0x26, 0x4A, 0x21, 0x54,
0x5A, 0x46, 0x71, 0x38, 0x20, 0x2B, 0x79, 0x26, 0x66, 0x32, 0x63,
0x2A, 0x57, 0x2A, 0x58, 0x6C, 0x76, 0x7F, 0x2B, 0x47, 0x7B, 0x46,
0x25, 0x30, 0x52, 0x2C, 0x31, 0x4F, 0x29, 0x6C, 0x3D, 0x69, 0x49,
0x70, 0x3F, 0x3F, 0x3F, 0x27, 0x78, 0x7B, 0x3F, 0x3F, 0x3F, 0x67,
0x5F, 0x51, 0x3F, 0x3F, 0x3F, 0x62, 0x29, 0x7A, 0x41, 0x24, 0x7E,
0x5A, 0x2F, 0x3B, 0x66, 0x39, 0x47, 0x32, 0x33, 0x41, 0x73, 0x6F,
0x77, 0x4D, 0x21, 0x56, 0x43, 0x75, 0x5F, 0x71, 0x28, 0x26, 0x39,
0x42, 0x78, 0x7C, 0x46, 0x6E, 0x53, 0x4A, 0x64, 0x48, 0x5C, 0x74,
0x31, 0x48, 0x67, 0x72, 0x36, 0x7D, 0x6E, 0x4B, 0x68, 0x70, 0x7D,
0x35, 0x49, 0x5D, 0x22, 0x3F, 0x6A, 0x55, 0x4B, 0x50, 0x3A, 0x6A,
0x69, 0x60, 0x2E, 0x23, 0x6A, 0x7F, 0x09, 0x71, 0x28, 0x70, 0x6F,
0x35, 0x65, 0x49, 0x7D, 0x74, 0x5C, 0x24, 0x2C, 0x5D, 0x2D, 0x77,
0x27, 0x54, 0x44, 0x59, 0x37, 0x3F, 0x25, 0x7B, 0x6D, 0x7C, 0x3D,
0x7C, 0x23, 0x6C, 0x43, 0x6D, 0x34, 0x38, 0x28, 0x6D, 0x5E, 0x31,
0x4E, 0x5B, 0x39, 0x2B, 0x6E, 0x7F, 0x30, 0x57, 0x36, 0x6F, 0x4C,
0x54, 0x74, 0x34, 0x34, 0x6B, 0x72, 0x62, 0x4C, 0x25, 0x4E, 0x33,
0x56, 0x30, 0x56, 0x73, 0x5E, 0x3A, 0x68, 0x73, 0x78, 0x55, 0x09,
0x57, 0x47, 0x4B, 0x77, 0x32, 0x61, 0x3B, 0x35, 0x24, 0x44, 0x2E,
0x4D, 0x2F, 0x64, 0x6B, 0x59, 0x4F, 0x44, 0x45, 0x3B, 0x21, 0x5C,
0x2D, 0x37, 0x68, 0x41, 0x53, 0x36, 0x61, 0x58, 0x58, 0x7A, 0x48,
0x79, 0x22, 0x2E, 0x09, 0x60, 0x50, 0x75, 0x6B, 0x2D, 0x38, 0x4E,
0x29, 0x55, 0x3D, 0x3F };
public EncodeDecode() {
// System.out.println(rawData[0]);
init();
}
public String decode(String encodingString) {
// System.out.println("encodingString : " + encodingString);
String marker = "#@~^";
String at;
String encodingLable = null;
String unEncodingString = "";
int stringIndex = 0;
int scriptIndex = -1;
int unEncodingIndex = 0;
int unEncodinglength = 0;
int state = STATE_COPY_INPUT;
// int statePos = 0;
while (state != 0) {
// System.out.println("in the Swith statePos is :" + statePos +
// "State:" +state);
switch (state) {
case (STATE_COPY_INPUT):
scriptIndex = encodingString.indexOf(marker, stringIndex);
// System.out.println("scriptIndex1"+scriptIndex);
if (scriptIndex != -1) {
unEncodingString += encodingString.substring(stringIndex,
stringIndex + scriptIndex);
scriptIndex += marker.length();
state = STATE_READLEN;
} else {
stringIndex = stringIndex == 0 ? 0 : stringIndex;
unEncodingString += encodingString.substring(stringIndex,
encodingString.length());
state = 0;
}
break;
case (STATE_READLEN):
// System.out.println("scriptIndex"+scriptIndex);
encodingLable = encodingString.substring(scriptIndex,
scriptIndex + 6);
unEncodinglength = decodeBase64(encodingLable);
scriptIndex += (6 + "==".length());
state = STATE_DECODE;
break;
case (STATE_DECODE):
if (unEncodinglength == 0) {
stringIndex = scriptIndex + "DQgAAA==^#~@".length();
unEncodingIndex = 0;
state = STATE_COPY_INPUT;
break;
}
at = encodingString.substring(scriptIndex, scriptIndex + 1);
if (at == "@")
state = STATE_UNESCAPE;
else {
if (at.codePointAt(0) < 0xFF) {
unEncodingString += String
.valueOf((char) transformed[pick_encoding[unEncodingIndex % 64]][at
.codePointAt(0)]);
unEncodingIndex++;
} else {
unEncodingString += at;
}
scriptIndex++;
unEncodinglength--;
break;
}
case STATE_UNESCAPE:
unEncodingString += unescape(encodingString.substring(
++scriptIndex, scriptIndex + 1));
scriptIndex++;
unEncodinglength -= 2;
unEncodingIndex++;
state = STATE_DECODE;
break;
}
}
// System.out.println("unEncodingString : " + unEncodingString);
// Pattern pattern = Pattern.compile("JScript.Encode");
// Matcher matcher = pattern.matcher(unEncodingString);
// if(matcher.find()) {
// System.out.println("unEncodingString 1: " + unEncodingString);
// unEncodingString = unEncodingString.substring(0, matcher.start()) +
// matcher.group() + unEncodingString.substring(matcher.end());
// }
// System.out.println("EncodeDecode.decode : unEncodingString : " + unEncodingString);
return unEncodingString;
}
public int decodeBase64(String string) {
int val = 0;
val += (digits[string.codePointAt(0)] << 2);
val += (digits[string.codePointAt(1)] >> 4);
val += (digits[string.codePointAt(1)] & 0xf) << 12;
val += ((digits[string.codePointAt(2)] >> 2) << 8);
val += ((digits[string.codePointAt(2)] & 0x3) << 22);
val += (digits[string.codePointAt(3)] << 16);
return val;
}
public String unescape(String ch) { // no used, and no test
// System.out.println("dddd");
String escapes = "#&!*$";
String escaped = "\r\n<>@";
if (ch.codePointAt(0) > 126)
return ch;
int index = escapes.indexOf(ch);
if (index != -1)
return escaped.substring(index, index + 1);
return "?";
}
public void init() {
for (int i = 31; i <= 126; i++)
for (int j = 0; j < 3; j++)
transformed[j][rawData[(i - 31) * 3 + j]] = (i == 31) ? 9 : i;
for (int i = 0; i < 26; i++) {
digits['A' + i] = i;
digits['a' + i] = i + 26;
}
for (int i = 0; i < 10; i++)
digits['0' + i] = i + 52;
digits[0x2b] = 62;
digits[0x2f] = 63;
}
/**
* @param args
*/
public static void main(String[] args) {
// new EncodeDecode().decode("<script
// language='JScript.Encode'>#@~^SwAAAA==-mD~DK'B8vZfF~!0FyF/TFFFZXFR!F8)TvZc82qsq98,TfZ+!wF{T;F&q*Z2T!Z1ZAqZFl!bEiyRAAAA==^#~@</script>");
String plantext = new EncodeDecode()
.decode("#@~^SwAAAA==-mD~DK'B8vZfF~!0FyF/TFFFZXFR!F8)TvZc82qsq98,TfZ+!wF{T;F&q*Z2T!Z1ZAqZFl!bEiyRAAAA==^#~@");
System.out
.println(plantext
.equals("var ero='16031B08121C07110518011A06041E1F1D190D020F170C13140E00090B10150A';"));
System.out.println("0".codePointAt(0) + " " + (int) 'a' + " "
+ (int) 'A');
System.out.println("ididgigggi".indexOf("i", 1));
}
}
现在可以得到需要的信息? 呵呵
Eclipse 3.2下蝲: http://www.eclipse.org/downloads/download.php?file=/eclipse/downloads/drops/R-3.2-200606291905/eclipse-SDK-3.2-win32.zip面
CallistoC下? http://www.eclipse.org/callisto/
Eclipse 3.2 - New and Noteworthy
http://download2.eclipse.org/eclipse/downloads/drops/R-3.2-200606291905/new_noteworthy/eclipse-news.html
呵呵, 可能是在做一些后期处理工作给耽搁了吧. 看看wiki上的旉?http://wiki.eclipse.org/index.php/Callisto_Final_Daze ), 如下:
watch eclipse.org servers glow red, especially build server
go have a beer -- to celebrate, if all is well, else, to cry in :)
? 不知道今天可以看到发布不.
在项目的业务属性中,你是不是要经帔R证属性的取D围呢. 惌了解比较优美的解x案吗?
看看Hibernate Validator 是怎么做的?一见到?怿你就会说: Oh God, q就是我需要的.
M获得Matrix授权的网站,转蝲请保留以下作者信息和链接Q?/span>
作者:icess(作者的blog:http://blog.matrix.org.cn/page/icess)
关键字:Hibernate Validator
用Annotations l类或者类的属性加上约?constraint),在运行期查属性值是很优雅的.Hibernate Validator是q样的一个框?该框架是十分Ҏ?像参考文档中宣称的那?,几乎没有什么学习曲U?Validator 是一个验证框?不需要和Hibernate的其他部分绑定就可以使用,只要在你的项目中dHibernate-annotations.jar库就可以?那么下面p我们看看怎么使用?
Person.java c?/font>
/*
* Created on 2006-1-12
Person.java
* @author
*/
package
test.annotation.validator;
import
org.hibernate.validator.Length;
import
org.hibernate.validator.Min;
import
org.hibernate.validator.Valid;
//@Serializability
//试自定义约?/font>
public class
Person {
private
String name;
private int
age;
private
Address address;
public
Person() {}
@Valid
//注意此处
public
Address getAddress() {
return
address;
}
public void
setAddress(Address address) {
this
.address = address;
}
@Min(value =
1
)
public int
getAge() {
return
age;
}
public void
setAge(
int
age) {
this
.age = age;
}
@Length(min =
4
)
public
String getName() {
return
name;
}
public void
setName(String name) {
this
.name = name;
}
}
Address.java c?/font>
/*
* Created on 2006-1-12
Address.java
* @author
*/
package
test.annotation.validator;
import
org.hibernate.validator.Length;
import
org.hibernate.validator.Max;
import
org.hibernate.validator.Min;
public class
Address {
private
String street;
private int
num;
public
Address() {}
@Min(value =
1
)
@Max(value =
100
)
public int
getNum() {
return
num;
}
public void
setNum(
int
num) {
this
.num = num;
}
@Length(min =
3
,max =
8
)
public
String getStreet() {
return
street;
}
public void
setStreet(String street) {
this
.street = street;
}
}
上面是两个用 Validator Annotations 注释?c? 每个属性都?U束限制? 下面看看试的类?
TestValidator.java c?/code>
/*
* Created on 2006-1-12
* @author icerain
*/
package
test.annotation.validator;
import
org.hibernate.validator.ClassValidator;
import
org.hibernate.validator.InvalidValue;
public class
TestValidator {
public void
test() {
Address add =
new
Address();
add.setNum(
0
);
add.setStreet(
"1"
);
Person p =
new
Person();
p.setAddress(add);
p.setAge(
0
);
p.setName(
"ice"
);
/******************Test validator ********/
// 注意该处只验证了Person Z说明 @Valid
注释的?/font>
ClassValidator<Person> classValidator =
new
ClassValidator<Person> (Person.
class
);
InvalidValue[] validMessages = classValidator.getInvalidValues(p);
for
(InvalidValue value : validMessages) {
System.out.println(
"InvalidValue 的长度是:"
+ validMessages.length
+
" . 验证消息? "
+ value.getMessage()
+
" . PropertyPath ?"
+ value.getPropertyPath()
+
" .\n\t PropertyName ? "
+value.getPropertyName()
+
"Value ? "
+ value.getValue()
+
" Bean ? "
+ value.getBean()
+
"\n\t BeanClass ?"
+ value.getBeanClass());
}
}
public static void
main(String[] args) {
new
TestValidator().test();
}
}
E序的输出如?
InvalidValue 的长度是:4 . 验证消息? 必须大于{于 1 . PropertyPath ?age .
PropertyName ? age. Value ? 0 Bean ? test.annotation.validator.Person@dd87b2
BeanClass ?class test.annotation.validator.Person
InvalidValue 的长度是:4 . 验证消息? 长度必须介于 4 ? 2147483647 之间 . PropertyPath ?name .
PropertyName ? name. Value ? ice Bean ? test.annotation.validator.Person@dd87b2
BeanClass ?class test.annotation.validator.Person
InvalidValue 的长度是:4 . 验证消息? 必须大于{于 1 . PropertyPath ?address.num .
PropertyName ? num. Value ? 0 Bean ? test.annotation.validator.Address@197d257
BeanClass ?class test.annotation.validator.Address
InvalidValue 的长度是:4 . 验证消息? 长度必须介于 3 ?8 之间 . PropertyPath ?address.street .
PropertyName ? street. Value ? 1 Bean ? test.annotation.validator.Address@197d257
BeanClass ?class test.annotation.validator.Address
可以看出不满约束的值都被指Z.
同时该句:
ClassValidator<Person> classValidator = new ClassValidator<Person> (Person.class);
我们只验证了 Person. 在Person里面的Address的属?׃?code style="font-family: 'Courier New',Courier; font-size: 10pt;">@Valid Annotations 所?Address的相兛_性也被机联验证了 .
如果 ?/font>
@Valid
Annotations L,l果如下:
InvalidValue 的长度是:2 . 验证消息? 必须大于{于 1 . PropertyPath ?age .
PropertyName ? age. Value ? 0 Bean ? test.annotation.validator.Person@18fef3d
BeanClass ?class test.annotation.validator.Person
InvalidValue 的长度是:2 . 验证消息? 长度必须介于 4 ? 2147483647 之间 . PropertyPath ?name .
PropertyName ? name. Value ? ice Bean ? test.annotation.validator.Person@18fef3d
BeanClass ?class test.annotation.validator.Person
可以看出 没有验证
Address.
当然?
,你还可以只验证一个属?, 没有必要验证整个c?只需要在调用
classValidator.getInvalidValues(p,"age")Ҏ?
加上你要验证的属性就可以?如我们只想验证age 属?把代码改为如下所C?
InvalidValue[] validMessages =
classValidator.getInvalidValues(p,"age"); /
/只验证age
属?/font>
q行l果如下:
InvalidValue 的长度是:1 . 验证消息? 必须大于{于 1 . PropertyPath ?age .
PropertyName ? age. Value ? 0 Bean ? test.annotation.validator.Person@1457cb
BeanClass ?class test.annotation.validator.Person
只是验证?age
属?
怎么?
,很简单吧. 关于 Hibernate Validator 内徏的验证Annotations 大家可以看看 API 或?
参考文?中文版我正在译?误问我?
Blog 获得最C?.
如果你要写自qU束?, 你不用担?,q也是很Ҏ?
MU束有两部分l成: [U束描述W?
x释]the constraint descriptor
(the annotation) 和[U束validator ?实现c] the constraint
validator (the implementation
class).下面我们扩展Hibernate
Test suit 中的一个Test 来讲解一?
首先: 要声明一?/span>
constraint
descriptor .如下:
package
test.annotation.validator;
import
java.lang.annotation.Documented;
import static
java.lang.annotation.ElementType.TYPE;
import static
java.lang.annotation.ElementType.FIELD;
import static
java.lang.annotation.ElementType.METHOD;
import
java.lang.annotation.Retention;
import static
java.lang.annotation.RetentionPolicy.RUNTIME;
import
java.lang.annotation.Target;
import
org.hibernate.validator.ValidatorClass;
/**
* Dummy sample of a bean-level validation annotation
*
*
@author
Emmanuel Bernard
*/
@ValidatorClass(SerializabilityValidator.
class
)
@Target({METHOD,FIELD,TYPE})
@Retention(RUNTIME)
@Documented
public
@interface Serializability {
int
num()
default
11
;
String message()
default
"bean must be serialiable"
;
}
@ValidatorClass(SerializabilityValidator.
class
)
指出?
constraint validator c?
@Target({METHOD,FIELD,TYPE})
@Retention(RUNTIME)
@Documented
q几个我׃用解释了?
Serializability 里面声明了一?message 昄U束的提CZ? num
只是Z说明一个方?在这里面没有实际用途用 .
然后是 实现一?/span>
constraint validator c?该类要实?/span>Validator<ConstraintAnnotation>.q里?/span>SerializabilityValidator.java
如下:
//$Id: SerializabilityValidator.java,v 1.3 2005/11/17 18:12:11 epbernard Exp $
constraint
descriptor 里面的属?如上面我们声明的 num
package
test.annotation.validator;
import
java.io.Serializable;
import
org.hibernate.validator.Validator;
/**
* Sample of a bean-level validator
*
*
@author
Emmanuel Bernard
*/
public class
SerializabilityValidator
implements
Validator<Serializability>, Serializable {
public boolean
isValid(Object value) {
//q里只是Validator
里面?实现验证规则?Ҏ. value 是要验证的?
System.out.println(
"IN SerializabilityValidator isValid:"
+value.getClass()+
": "
+value.toString());
return
value instanceof Serializable;
}
public void initialize(Serializability parameters) {
// 在这里可?取得
System.out.println(
"IN SerializabilityValidator: parameters:"
+ parameters.num() );
}
}
然后在你的类中应用@Serializability
可以约束一个类实现
Serializable
接口? 如下:
在我们的Person.javac?d@Serializability
Annotations ,把Person.java 中的
//@Serializability
//试自定义约?注释Lok?
InvalidValue 的长度是:3 . 验证消息?
bean must be serialiable
. PropertyPath ?null .
PropertyName ? null. Value ?
test.annotation.validator.Person@1a73d3c Bean ?
test.annotation.validator.Person@1a73d3c
BeanClass ?class
test.annotation.validator.Person
q行l果如下:
现在把Personcd?
java.io.Serializable 接口 则没有出?验证错误消息.
消息的国际化也是很简单的,?/span>
Serializability
中的message 改ؓ以{}扩住?属性文件的Key可以了
public
@interface Serializability {
int
num()
default
11
;
String message()
default
"{Serializable}";
//"bean must be serialiable";
//消息的国际化
}
然后~辑资料文g. 注意 该资源文件中要包?Hibernate Validator 内徏的资? 可以在该org\hibernate\validator\resources
包里面的资源文g基础上修?,在打包里?q样可以了.
自己打包可能不太方便.你可以把该包里面的文件复制出?然后攑ֈ你自q目包下在自q? 该测试中 我是攑֜
test\resources 包下?
然后?
资源文g中添?
Serializable = '''''' q么一? 样例如下:
#DefaultValidatorMessages.properties
(DefaultValidatorMessages_zh.properties 不再列出^_^)
#下面?Hibernate Validator 内徏的国际化消息
validator.assertFalse= assertion failed
validator.assertTrue= assertion failed
validator.future= must be a future date
validator.length= length must be between {min} and {max}
validator.max= must be less than or equal to {value}
validator.min= must be greater than or equal to {value}
validator.notNull= may not be null
validator.past= must be a past date
validator.pattern= must match "{regex}"
validator.range= must be between {min} and {max}
validator.size= size must be between {min} and {max}
#下面是自定义的消?/font>
Serializable= Bean not Serializable //加上自己定义的国际化消息.
在构?/span>
ClassValidator
时要M 资源文g 如下:(在测试类?
ClassValidator<Person>
classValidator = new ClassValidator<Person> (Person.class,ResourceBundle.getBundle("test.resources.DefaultValidatorMessages"));//加蝲资源
q样可以了 . 当然
你还可以 更改 Hibernate Validator 的消?不是在上面的资源文g中直接修?/font>
validator.length
= ... {等
) ,
q记?Validator 注释中有?message 元素? 你以前用的都是默认?现在你可以该Z自己定义的了.
?validator.length
我把他改?"该字W串的长度不W合规定范围范围".
在资源文件中d一行键值属性对(key定义?"myMsg")如下:
myMsg=该字W串的长度不W合规定范围范围
q且q要?/font> @Length 注释中提供message的引用的key 如下 @Length(min = 4,message = "{ myMsg }")
再一ơ运行测?
,我们可以看C面两条自定义l定的消息了 .如下:
InvalidValue 的长度是:3
. 验证消息?/font>: Bean 不是
?Serializable . PropertyPath ?null .
PropertyName ? null. Value ? test.annotation.validator.Person@1bd4722
Bean ? test.annotation.validator.Person@1bd4722
BeanClass ?class test.annotation.validator.Person
InvalidValue 的长度是:3 . 验证消息?/font>:
该字W串的长度不W合规定范围范围 . PropertyPath ?name
.
PropertyName ? name. Value ? ice Bean ?
test.annotation.validator.Person@1bd4722
BeanClass ?class test.annotation.validator.Person
怎么?比你惌的简单吧.
OK
上面我们讨论?
Hibernate Validator 的主要用? 但是 该框架有什么用? ^_^
看到q里其实不用我在多说?大家都知道怎么?什么时候用. 作ؓ一介l性文章我q是在此l出一个最常用的例子吧,更好的用方式大家慢慢挖掘吧.
比如 : 你现在在开发一个h力资?HR)pȝ (其实是我们ERP评的一个作?^_^), 里面要处理大量的数据,其是在输入各种资料?? 登记员工信息. 如果你公司的员工的年龄要求是18 -- 60 那么你所输入的年龄就不能出q个范围. 你可能会说这很容易啊 , 不用Validator可以解军_.q保持数据前验证可以啦 如if ( e.getAge() > 60 || e.getAge() < 18 ) ........ l出错误信息 然后提示重新输入不就OK?用得着 兴师动众的来个第三方框架?
是啊 当就验证q一个属性时, 没有必要?! 但是一个真正的HR pȝ,会只有一个属性要验证? 恐怕要有N多吧
你要是每一个都那样 写一D验证代?是不是很烦啊 ,况且也不方便代码重用. 现在考虑一? Validator 是不是更高效?拦截?U束q例?属?可以直接得?国际化的消息 可以把该消息昄C个弹出对话框?提示更正 !
Validator的用处不只这一U?,你可以想到如何用?! Ƣ迎发表你的高见!!
OK 到此 我们?Hibernate Validator 之旅p先告一D落?. 希望q是令你心旷怡的一ơ寒冬之?
把你学到的应用到你的目中吧,一定会提高你的生率的. 怿?,没错的?^_^ !