2011年11月20日星期日

JavaEE_019:JavaEE6 新特性之八:CDI 1.0

CDI(Context and Dependency Injection)指的是把一个Java类通过依赖注入的方式“注入”到另一个类供其使用。
虽然JavaEE5支持资源注入,但只能支持有限的资源,比如EJB。
在CDI 1.0出现以前,如果你想把一个POJO类“注入”到另一个POJO类中,你只能用Spring之类的框架来完成“注入”。
现在好了,因为CDI 1.0增加以下元注释帮助我们实现了这个功能。

1. @Inject
原来使用@EJB和@Resource的地方都可以使用@Inject替换。
当然,@Inject主要用途还是“依赖注入”POJO类。

2. @Qualifier
用于区别实现同一接口的不同类,比如DefaultCustomer和SpecialCustomer都实现了接口Customer。
为了区分普通用户和白金用户,先创建一个接口Premium,加上元注释@Qualifier。
@Qualifier
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Premium {}

然后在SpecialCustomer类上加上元注释@Premium,表明该用户属于白金用户。
@Premium
public class SpecialCustomer implements Customer {
......

最后在使用时,使用CDI注入:
加上@Premium元注释表明注入SpecialCustomer类,不加则注入DefaultCustomer类。
@Inject // injection point
@Premium // qualifier to obtain an instance of SpecialCustomer
Customer cust;

3. @Named
如果一个类加上了@Named元注释,表明该类可以在JSF中使用EL访问。
比如类LanguageSingleton定义如下:
@Startup
@Singleton
@Named("languages")
public class LanguageSingleton {

// ======================================
// = Attributes =
// ======================================

private Logger logger = Logger.getLogger("org.beginningee6.tutorial");

private Map languages;

// ======================================
// = Lifecycle methods =
// ======================================

@PostConstruct
private void initLanguages() {
languages = new HashMap();
languages.put("EN", "English");
languages.put("FR", "French");
languages.put("DE", "German");
languages.put("ES", "Spanish");
languages.put("FI", "Finnish");
languages.put("IT", "Italian");
languages.put("RU", "Russian");
logger.info("Loaded " + languages.size() + " languages !!!");
}

// ======================================
// = Business methods =
// ======================================

public String getLanguageValue(String code) {
return languages.containsKey(code.toUpperCase()) ? languages.get(code.toUpperCase()) : "UNKNOWN";
}

public String getListOfValues() {
return languages.keySet().toString();
}
}
在JSF中可以这样使用:
<h:outputLabel value="#{languages.listOfValues}"/>


参考文献:
1. http://developer.51cto.com/art/200912/173801.htm
2. http://download.oracle.com/javaee/5/tutorial/doc/bncjk.html
3. http://www.theserverside.com/news/1373391/Dependency-Injection-in-Java-EE-6-Part-1

JavaEE_018:JavaEE6 新特性之七:JAX-RS 1.1

JAX-RS是使用HTTP协议开发RESTful WebService的Java API。
它使用HTTP协议的原生“动词”来对网络资源进行CRUD操作。
JAX-RS 1.0于2008年发布,可以把POJO+Annotations生成RESTful WebService。
JAX-RS 1.1 可以把EJB+Annotations生成RESTful WebService。

举例1:
@Path("/helloworld")
public class HelloWorldResource {

@GET
@Produces("text/plain")
public String sayHello() {
return "Hello World";
}
}

相当于访问:GET http://example.com/helloworld
HTTP Request消息:
GET /helloworld HTTP/1.1
Host: example.com
Accept: text/plain

HTTP Response消息:
HTTP/1.1 200 OK
Date: Wed, 12 Nov 2008 16:41:58 GMT
Server: GlassFish v3
Content-Type: text/plain; charset=UTF-8
Hello World

举例2:
@Path("/users/{userId}")
@Stateless
public class UserResource {

@PersistenceContext
EntityManage em;

@GET @Produces("text/xml")
public String getUser(@PathParam("userId")
String id){

User u = em.find(User.class, id)
...
}
}

JavaEE_017:JavaEE6 新特性之六:Bean Validation 1.0

Bean Validation 允许使用声明式的方式定义验证规则。
Constrain Once, Validate Anywhere
restriction on a bean, field or property
not null, size between 1 and 7, valid email...
Standard way to validate constraints
Integration with JPA 2.0 & JSF 2.0

举例:
public class Address {
@NotNull @Size(max=30,
message="longer than {max} characters")
private String street1;
...
@NotNull @Valid
private Country country;
}

public class Country {
@NotNull @Size(max=20)
private String name;
...
}

创建自己的验证规则类
@Size(min=5, max=5)
@ConstraintValidator(ZipcodeValidator.class)
@Documented
@Target({ANNOTATION_TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface ZipCode {
String message() default "Wrong zipcode";
String[] groups() default {};
}

JavaEE_016:JavaEE6 新特性之五:JSF 2.0(3)

4. AJAX
使用AJAX,可以让Web应用
(1)以异步的方式从服务器获取数据。
(2)局部刷新页面中的某个组件而不影响其它组件。

在JSF中使用AJAX需要引入jsf.js库,当你使用Ajax标签组件时,JSF会自动包括它,然后就可以调用JavaScript API中的函数了。
<f:ajax> 标记指定了以下内容:
(1)event属性:触发 Ajax 调用的事件
(2)execute属性:在服务器上执行的组件
(3)render: 指定在客户机上要局部刷新的组件

举例说明:
<h:selectOneMenu id="menu"
value="#{cc.parent.attrs.location.zoomIndex}"
style="font-size:13px;font-family:Palatino">

<f:ajax event="change" execute="@this" render="map"/>
<f:selectItems value="#{places.zoomLevelItems}"/>

</h:selectOneMenu>

<m:map id="map"...>
可以看出,当改变下拉列表的值时,异步发送请求到服务器端执行相应逻辑,请求返回后,刷新id=map的组件。

JavaEE_015:JavaEE6 新特性之五:JSF 2.0(2)

3. 复合组件
复合组件可以把多个JSF组件组合起来形成一个新的组件,放到共享库中后,可以供其它页面使用。
复合组件也可以有验证器,转换器和监听器,这一点和标准JSF组件一样。
下面是复合组件的定义:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute name="item" required="true"/>
</composite:interface>

<composite:implementation>

<h:panelGrid columns="2">
<h:outputLabel value="Title : " styleClass="alabel" />
<h:inputText value="#{cc.attrs.item.title}" styleClass="ainput"/>

<h:outputLabel value="Price : " styleClass="alabel"/>
<h:inputText value="#{cc.attrs.item.price}" styleClass="ainput"/>

<h:outputLabel value="Description : " styleClass="alabel"/>
<h:inputTextarea value="#{cc.attrs.item.description}" styleClass="atextarea"/>
</h:panelGrid>

</composite:implementation>
</html>

可以看出,xmlns:composite="http://java.sun.com/jsf/composite"声明了复合组件的命名空间。
<composite:interface>标签声明复合组件的使用契约,
<composite:attribute>标签在契约中使用<composite:attribute>标签表示一个属性:item对象。
<composite:implementation>标签定义了复合组件的实现,访问item对象的属性,并用InputText和InputTextarea组合实现。
如果想在契约中指定某个事件,可以使用<composite:actionSource>标签。
<composite:interface>
<composite:actionSource name="loginEvent"/>
</composite:interface>
对应的实现方法代码如下:
<ez:loginPanel>
<f:actionListener for="loginEvent" type="example01.LoginActionListener" />
</ez:loginPanel>
对应的ActionListener代码如下:
import javax.faces.component.UIComponent;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;

public class LoginActionListener implements ActionListener {
public void processAction(ActionEvent event) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getRequestMap().put("loginActionMessage", "Login event happened");
}
}
下面是复合组件实现的片段代码:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:demo="http://java.sun.com/jsf/composite/components">

<ui:composition template="layout.xhtml">

<ui:define name="title">Create a new book</ui:define>

<ui:define name="content">

<h:form style="background-image:url(#{resource['book.png']});">
<demo:newItem item="#{itemBean.book}"/>
.....
可以看出,这里使用了xmlns:demo命名空间,该命名空间最终指向"components";使用demo:newItem索引该组合对象。
这表明在应用程序根目录下的resources目录(resources目录是保留目录)下有一个子目录:components。
在components目录下,有一个名称为newItem.xhtml的文件。
JSF运行时,会根据“复合组件的标签名.xhtml”查找复合组件。

2011年11月19日星期六

JavaEE_014:JavaEE6 新特性之五:JSF 2.0(1)

JSF(JavaServer Faces)是一个服务端组件框架,用于简化Web应用开发。
原来的JSP(JavaServer Pages)不支持一些JSF2.0的新特性,将逐渐被淘汰。
JSF 2.0版本增加了如下新特性:

1. Facelets
Facelets指的是JavaServer Faces View Declaration Language,JSF视图声明语言,是编写Web界面的新标准。
其实在JSF1.0中已经使用了该技术框架,只不过那时还没有正式成为规范。
Facelets通常是使用XHTML编写的(这说明也可以用其它语言编写?比如JDeveloper中的.jsf格式)。
.xhtml页面代码中,禁止添加任何Java代码片段,保证页面代码的整洁度。
而.jsp页面中允许添加Java代码片段,这是非常不好的设计,所以JSP被淘汰了。
从设计角度看,页面只应该负责展示数据,不应该包含任何逻辑。

下面是使用Facelets编写的.xhtml代码片段:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:demo="http://java.sun.com/jsf/composite/components">
.....
<h:form style="background-image:url(#{resource['book.png']});">
<demo:newItem item="#{itemBean.book}"/>

<h:panelGrid columns="2">
<h:outputLabel value="Number of pages : " styleClass="alabel" />
<h:inputText value="#{itemBean.book.nbOfPage}" styleClass="ainput"/>

<h:outputLabel value="Illustrations : " styleClass="alabel"/>
<h:selectBooleanCheckbox value="#{itemBean.book.illustrations}"/>

<h:outputLabel value="Tags : " styleClass="alabel"/>
<h:inputText value="#{itemBean.tags}" styleClass="ainput"/>

<h:outputLabel value="Language code : " styleClass="alabel"/>
<h:inputText value="#{itemBean.languageCode}" styleClass="ainput"/>
</h:panelGrid>

<h:commandButton value="Create a book" action="#{itemBean.doCreateBook}"/>

</h:form>
......
</html>
可以看出,这个页面中引入了JSF、JSTL和Facelets标签库。

2. 页面模板
使用页面模板是为了让其它页面“继承”该模板,节省代码的同时,也保证了页面风格的统一。
定义页面模板使用Facelets标签库中的<ui:insert>,如下所示:
<h:head>
<title>
<ui:insert name="title">Default title</ui:insert>
</title>
</h:head>

<h:outputStylesheet name="styles.css"/>

<h:body styleClass="abody">
<h1>
<ui:insert name="title">Default title</ui:insert>
</h1>
<hr/>
<h:messages style="color:red"/>
<ui:insert name="content">Default content</ui:insert>

<hr/>
<i>Hands-On Lab - Beginning with The Java EE 6 Platform</i>
</h:body>

在页面中,使用<ui:composition>标签指定模板,使用<ui:define>标签指定插入到模板中的内容。
<ui:composition template="layout.xhtml">

<ui:define name="title">Create a new book</ui:define>

<ui:define name="content">

<h:form style="background-image:url(#{resource['book.png']});">
<demo:newItem item="#{itemBean.book}"/>

<h:panelGrid columns="2">
<h:outputLabel value="Number of pages : " styleClass="alabel" />
<h:inputText value="#{itemBean.book.nbOfPage}" styleClass="ainput"/>

<h:outputLabel value="Illustrations : " styleClass="alabel"/>
<h:selectBooleanCheckbox value="#{itemBean.book.illustrations}"/>

<h:outputLabel value="Tags : " styleClass="alabel"/>
<h:inputText value="#{itemBean.tags}" styleClass="ainput"/>

<h:outputLabel value="Language code : " styleClass="alabel"/>
<h:inputText value="#{itemBean.languageCode}" styleClass="ainput"/>
</h:panelGrid>

<h:commandButton value="Create a book" action="#{itemBean.doCreateBook}"/>

</h:form>
......
</ui:define>

</ui:composition>

参考文献:
1. http://developer.51cto.com/art/201001/179049.htm
2. http://www.ibm.com/developerworks/cn/java/j-jsf2fu1/
3. http://www.ibm.com/developerworks/cn/java/j-jsf2fu2/
4. http://www.ibm.com/developerworks/cn/java/j-jsf2fu3/

JavaEE_013:JavaEE6 新特性之四:Managed Beans 1.0

在JavaEE6之前,只有像EJB这样的重量级组件才可以被JavaEE容器管理,轻量级组件POJO类是不能被JavaEE容器管理的。
有了Managed Beans 1.0规范后,轻量级组件POJO类也可以被JavaEE容器管理。
该规范受JSF1.0规范(JavaEE5中的一个规范)中Managed Beans的启发。
于是在JavaEE6中,干脆把Managed Beans从JSF中独立出来,成为直接隶属于JavaEE6的规范之一。
而原来的EJB也就成了一种Managed Bean。

1. Managed Beans 1.0支持如下特性:
(1)资源注入:Injection (@Resource...)
(2)生命周期回调:Life-cycle (@PostConstruct, @PreDestroy)
(3)拦截器:Interceptor (@Interceptor, @AroundInvoke)
一个Managed Bean的基本代码如下:
@javax.annotation.ManagedBean
public class MyPojo {

@Resource
private Datasource ds;

@PostConstruct
private void init() {
....
}

@Interceptors(LoggingInterceptor.class)
public void myMethod() {...}
}

2. Managed Bean定义举例
(1)定义一个POJO类为Managed Bean
@javax.annotation.ManagedBean(value="mybean")
public class MyManagedBean {
...
}

(2)使用生命周期回调的Managed Bean
@javax.annotation.ManagedBean(value="mybean")
public class MyManagedBean {
@PostConstruct
public void setupResources() {
// setup your resources
System.out.println("Setting up resources ...");
}

@PreDestroy
public void cleanupResources() {
// collect them back here
System.out.println("Collecting them back ...");
}

public String sayHello(String name) {
return "Hello " + name;
}
}

3. 调用Managed Bean的方式举例
(1)使用@Resource元注释
@Resource
MyManagedBean bean;
(2)使用@Inject元注释
@Inject
MyManagedBean bean;
(3)使用JNDI
InitialContext ic = new InitialContext();
MyManagedBean bean = (MyManagedBean)ic.lookup("java:app/ManagedBean/mybean");

参考文献:
1. http://bbs.developersky.net/thread-66-1-1.html

2011年11月18日星期五

JavaEE_012:JavaEE6 新特性之三:Servlet3.0(4)

除了前面介绍的三大特性,Servlet3.0还具有以下这些特性。

1. 增强的ServletContext API
ServletContext 支持在运行时动态部署Servlet、Filter、Listener,以及为 Servlet 和过滤器增加 URL 映射等等。
以 Servlet 为例,ServletContext 为动态配置 Servlet 增加了如下方法:
(1)ServletRegistration.Dynamic addServlet(String servletName,Class<? extends Servlet> servletClass)
(2)ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
(3)ServletRegistration.Dynamic addServlet(String servletName, String className)
(4)<T extends Servlet> T createServlet(Class<T> clazz)
(5)ServletRegistration getServletRegistration(String servletName)
(6)Map<String,? extends ServletRegistration> getServletRegistrations()
其中前三个方法的作用是相同的,只是参数类型不同而已。
通过 createServlet() 方法创建的 Servlet,通常需要做一些自定义的配置,然后使用 addServlet() 方法来将其动态注册为一个可以用于服务的 Servlet。
两个 getServletRegistration() 方法主要用于动态为 Servlet 增加映射信息,这等价于在 web.xml( 抑或 web-fragment.xml) 中使用 标签为存在的 Servlet 增加映射信息。
以上 ServletContext 新增的方法要么是在 ServletContextListener 的 contexInitialized 方法中调用,要么是在 ServletContainerInitializer 的 onStartup() 方法中调用。
ServletContainerInitializer 也是 Servlet 3.0 新增的一个接口,容器在启动时使用 JAR 服务 API(JAR Service API) 来发现 ServletContainerInitializer 的实现类,并且容器将 WEB-INF/lib 目录下 JAR 包中的类都交给该类的 onStartup() 方法处理,我们通常需要在该实现类上使用 @HandlesTypes 注解来指定希望被处理的类,过滤掉不希望给 onStartup() 处理的类。

2. HttpServletRequest 对文件上传的支持
此前,对于处理上传文件的操作一直是让开发者头疼的问题,因为 Servlet 本身没有对此提供直接的支持,需要使用第三方框架来实现,而且使用起来也不够简单。
如今这都成为了历史,Servlet 3.0 已经提供了这个功能,而且使用也非常简单。
为此,HttpServletRequest 提供了两个方法用于从请求中解析出上传的文件:

Part getPart(String name)
Collection<Part> getParts()
前者用于获取请求中给定 name 的文件,后者用于获取所有的文件。
每一个文件用一个 javax.servlet.http.Part 对象来表示。该接口提供了处理文件的简易方法,比如 write()、delete() 等。
至此,结合 HttpServletRequest 和 Part 来保存上传的文件变得非常简单,如下所示:
Part photo = request.getPart("photo");
photo.write("/tmp/photo.jpg");
// 可以将两行代码简化为 request.getPart("photo").write("/tmp/photo.jpg") 一行。

另外,开发者可以配合前面提到的 @MultipartConfig 注解来对上传操作进行一些自定义的配置,比如限制上传文件的大小,以及保存文件的路径等。
需要注意的是,如果请求的 MIME 类型不是 multipart/form-data,则不能使用上面的两个方法,否则将抛异常。

3. Configure cookie session name

4. Security with @ServletSecurity

JavaEE_011:JavaEE6 新特性之三:Servlet3.0(3)

特性三:支持异步的Servlet和Filter
Servlet3.0之前不支持异步,也就是说从发送请求给Servlet,到得到响应,用户必须等待Servlet线程结束。
如果Servlet中某个调用比较耗时的话,其中占用的资源会一直得不到释放,如果并发用户数很高的话,可能会引起性能问题。
Servlet3.0支持异步,这样如果Servlet中某个操作比较耗时和耗资源的话,我们可以将其元注释为异步调用。
Servlet线程会启动另外一个线程来异步执行该方法,Servlet线程则返回至容器。
然后,等异步线程处理完毕之后,再生成响应。
也就是说,响应部分可以交给异步线程来实现,因为它也有指向ServletRequest和ServletResponse对象的引用。
在Servlet3.0中,除了Servlet,Filter也支持异步。

1. 配置方式
(1)使用web.xml配置,适用于Servlet和Filter,这里以Servlet为例。
<servlet>
<servlet-name>DemoServlet</servlet-name>
<servlet-class>footmark.servlet.Demo Servlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
(2)使用元注释配置,,适用于Servlet和Filter,这里以Filter为例。
@WebFilter(urlPatterns = "/demo",asyncSupported = true)
public class DemoFilter implements Filter{...}

2. 异步Servlet例子
@WebServlet(urlPatterns = "/demo", asyncSupported = true)
public class AsyncDemoServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("进入Servlet的时间:" + new Date() + ".");
out.flush();

//在子线程中执行业务调用,并由其负责输出响应,主线程退出
AsyncContext ctx = req.startAsync();
new Thread(new Executor(ctx)).start();

out.println("结束Servlet的时间:" + new Date() + ".");
out.flush();
}
}

public class Executor implements Runnable {
private AsyncContext ctx = null;
public Executor(AsyncContext ctx){
this.ctx = ctx;
}

public void run(){
try {
//等待十秒钟,以模拟业务方法的执行
Thread.sleep(10000);
PrintWriter out = ctx.getResponse().getWriter();
out.println("业务处理完毕的时间:" + new Date() + ".");
out.flush();
ctx.complete();
} catch (Exception e) {
e.printStackTrace();
}
}
}

3. 异步监听器
异步监听器用于监听异步处理的事件。
要实现异步监听器,首先需要开发一个Java类,实现接口AsyncListener。
然后注册该监听器,方法如下:
AsyncContext ctx = req.startAsync();
ctx.addListener(new AsyncListener() {
public void onComplete(AsyncEvent asyncEvent) throws IOException {
// 做一些清理工作或者其他
}
...
});
你可以监听四种事件:
(1)当异步线程开始时:调用 AsyncListener的onStartAsync(AsyncEvent event)方法。
(2)当异步线程出错时:调用 AsyncListener的onError(AsyncEvent event)方法。
(3)当异步线程超时时:调用 AsyncListener的onTimeout(AsyncEvent event)方法。
(4)当异步线程结束时:调用 AsyncListener的onComplete(AsyncEvent event)方法。

JavaEE_010:JavaEE6 新特性之三:Servlet3.0(2)

特性二:可插入性支持: 引入Web模块部署描述符片段:web-fragment.xml。
Web模块可以按不同功能划分为多个web-fragment.xml文件,每个文件描述该功能模块的配置。
web-fragment.xml必须放在JAR文件的META-INF目录下,而JAR包一般放在WEB-INF/lib 目录下。
web-fragment.xml内容上跟web.xml没有啥区别,web.xml可以定义的,web-fragment.xml也可以定义。

1. 三种方式配置
以配置Servlet为例(Filter,Listener与之类似),首先编写一个Java类,将其继承HttpServlet。
(1)使用web.xml定义
将该类放在 classes 目录下的对应包结构中,修改 web.xml,在其中增加一个 Servlet 声明。
(2)使用元注释定义
在该类上使用 @WebServlet将该类声明为 Servlet,将该类放在 classes 目录下的对应包结构中,无需web.xml 文件。
(3)使用web-fragment.xml定义
将该类打成JAR包,并且在 JAR 包的 META-INF 目录下放置一个 web-fragment.xml 文件,在其中增加一个 Servlet 声明。
其中 web-fragment.xml 文件定义示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment
xmlns=http://java.sun.com/xml/ns/javaee
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
metadata-complete="true">
<servlet>
<servlet-name>fragment</servlet-name>
<servlet-class>footmark.servlet.FragmentServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>fragment</servlet-name>
<url-pattern>/fragment</url-pattern>
</servlet-mapping>
</web-fragment>

从上面的示例可以看出,web-fragment.xml 与 web.xml 除了在头部声明的 XSD 引用不同之外,其主体配置与 web.xml 是完全一致的。

2. web-fragment.xml加载顺序
一个 Web 应用中可以出现一个 web.xml 文件和多个web-fragment.xml 声明文件,加载顺序规则如下:
web-fragment.xml 包含了两个可选的顶层标签,<name> 和 <ordering>。
<name> 标签的作用是标识当前文件,通常是被其它 web-fragment.xml 文件在定义先后顺序时引用的。
<ordering> 则用于指定先后顺序。
一个简单的示例如下:

<web-fragment...>
<name>FragmentA</name>
<ordering>
<after>
<name>FragmentB</name>
<name>FragmentC</name>
</after>
<before>
<others/>
</before>
</ordering>
...
</web-fragment>

以上片段则表示当前文件必须在 FragmentB 和 FragmentC 之后解析。
<before> 的使用于此相同,它所表示的是当前文件必须早于 <before> 标签里所列出的 web-fragment.xml 文件。
<others/>标签表示除了当前文件之外的其他所有的 web-fragment.xml 文件。

JavaEE_009:JavaEE6 新特性之三:Servlet3.0(1)

与Servlet2.5相比,Servlet3.0增加了若干新特性,以下逐一介绍。

特性一:新增了一些元注释,用于简化 Web应用的开发和部署。

1. metadata-complete
(1)web.xml中的根元素<web-app>属性metadata-complete=true
表示忽略代码中的所有元注释,忽略所有web-fragment.xml,即禁用可插入性,只读取部署描述文件。
(2)web.xml中的根元素<web-app>属性metadata-complete=false
表示启用代码中的所有元注释,启用所有web-fragment.xml,即支持可插入性。

2. @WebServlet
@WebServlet 用于将一个类声明为 Servlet,该元注释的属性如下:
(1)name String 指定 Servlet 的 name 属性,等价于 。如果没有显式指定,则该 Servlet 的取值即为类的全限定名。
(2)value String[] 该属性等价于 urlPatterns 属性。两个属性不能同时使用。
(3)urlPatterns String[] 指定一组 Servlet 的 URL 匹配模式。等价于 标签。
(4)loadOnStartup int 指定 Servlet 的加载顺序,等价于 标签。
(4)initParams WebInitParam[] 指定一组 Servlet 初始化参数,等价于 标签。
(5)asyncSupported boolean 声明 Servlet 是否支持异步操作模式,等价于 标签。
(6)description String 该 Servlet 的描述信息,等价于 标签。
(7)displayName String 该 Servlet 的显示名,通常配合工具使用,等价于 标签。

使用@WebServlet的例子
@WebServlet(urlPatterns = {"/simple"}, asyncSupported = true,
loadOnStartup = -1, name = "SimpleServlet", displayName = "ss",
initParams = {@WebInitParam(name = "username", value = "tom")}
)
public class SimpleServlet extends HttpServlet{ … }

这样在代码中配置元注释后,等价于在web.xml中做了如下配置:
<servlet>
<display-name>ss</display-name>
<servlet-name>SimpleServlet</servlet-name>
<servlet-class>footmark.servlet.SimpleServlet</servlet-class>
<load-on-startup>-1</load-on-startup>
<async-supported>true</async-supported>
<init-param>
<param-name>username</param-name>
<param-value>tom</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SimpleServlet</servlet-name>
<url-pattern>/simple</url-pattern>
</servlet-mapping>

2. @WebFilter
@WebFilter 用于将一个类声明为Filter,该元注释的属性如下:
(1)filterName String 指定过滤器的 name 属性,等价于 <filter-name>
(2)value String[] 该属性等价于 urlPatterns 属性。但是两者不应该同时使用。
(3)urlPatterns String[] 指定一组过滤器的 URL 匹配模式。等价于 <url-pattern> 标签。
(4)servletNames String[] 指定过滤器将应用于哪些 Servlet。取值是 @WebServlet 中的 name 属性的取值,或者是 web.xml 中 <servlet-name> 的取值。
(5)dispatcherTypes DispatcherType 指定过滤器的转发模式。具体取值包括:
(6)ASYNC、ERROR、FORWARD、INCLUDE、REQUEST。
(7)initParams WebInitParam[] 指定一组过滤器初始化参数,等价于 <init-param> 标签。
(8)asyncSupported boolean 声明过滤器是否支持异步操作模式,等价于 <async-supported> 标签。
(9)description String 该过滤器的描述信息,等价于 <description> 标签。
(10)displayName String 该过滤器的显示名,通常配合工具使用,等价于 <display-name> 标签。

使用@WebFilter的例子
@WebFilter(servletNames = {"SimpleServlet"},filterName="SimpleFilter")
public class LessThanSixFilter implements Filter{...}

这样在代码中配置元注释后,等价于在web.xml中做了如下配置:
<filter>
<filter-name>SimpleFilter</filter-name>
<filter-class>xxx</filter-class>
</filter>
<filter-mapping>
<filter-name>SimpleFilter</filter-name>
<servlet-name>SimpleServlet</servlet-name>
</filter-mapping>

3. @WebListener
@WebListener 用于将类声明为监听器,该类需要实现的接口如下(至少实现一个):
(1)ServletContextListener
(2)ServletContextAttributeListener
(3)ServletRequestListener
(4)ServletRequestAttributeListener
(5)HttpSessionListener
(6)HttpSessionAttributeListener

@WebListener的属性只有一个:value。

使用@WebListener的例子:
@WebListener("This is only a demo listener")
public class SimpleListener implements ServletContextListener{...}

这样在代码中配置元注释后,等价于在web.xml中做了如下配置:
<listener>
<listener-class>footmark.servlet.SimpleListener</listener-class>
</listener>

4. @MultipartConfig
@MultipartConfig用于支持对上传文件功能,表示Servlet处理的MIME类型是 multipart/form-data。
@MultipartConfig属性如下:
(1)fileSizeThreshold int 是 当数据量大于该值时,内容将被写入文件。
(2)location String 是 存放生成的文件地址。
(3)maxFileSize long 是 允许上传的文件最大值。默认值为 -1,表示没有限制。
(4)maxRequestSize long 是 针对该 multipart/form-data 请求的最大数量,默认值为 -1,表示没有限制。

参考文献:
1. http://www.ibm.com/developerworks/cn/java/j-lo-servlet30/index.html?ca=drs-cn-0423