blob: 4246d237886d72a3f7c6fb9549cfa29942898549 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= Java EE 应用程序入门指南
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: Java EE 应用程序入门指南 - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, Java EE 应用程序入门指南
本文档简要介绍了作为 Java Enterprise Edition 6 (Java EE 6) 规范一部分引入的某些功能。为了说明这些新功能,本教程介绍了如何创建简单的 Java EE Web 应用程序,其中包含实体类的 EJB 3.1 无状态会话 Bean Facade。将使用 IDE 中的向导生成实体类和会话 Bean。向导生成的代码使用在条件 API 中定义的查询,该 API JPA 2.x 的一部分并包含在 Java EE 6 规范中。然后,将创建一个用于访问会话 Facade 的命名受管 Bean,并且还创建一个表示层,它使用 JSF 2.x 中所指定的 Facelets 视图框架。
本教程基于 Adam Bien 发布的博客帖子link:http://www.adam-bien.com/roller/abien/entry/simplest_possible_jsf_2_ejb[+尽可能简单的 JSF 2/EJB 3.1/JPA 组件 - 使用 WAR 部署+]。您可以在 Adam Bien 的 Kenai 项目 link:http://kenai.com/projects/javaee-patterns[+Java EE 模式和最佳做法+]中找到其他 Java EE 示例,他撰写的书籍“现实的 Java EE 模式 - 反思最佳做法”可通过以下网址下载:link:http://press.adam-bien.com[+http://press.adam-bien.com+]。
*教程练习*
* <<Exercise_1,创建 Web 应用程序项目>>
* <<Exercise_2,创建实体类和会话 Facade>>
* <<Exercise_2a,创建实体类>>
* <<Exercise_2b,创建会话 Facade>>
* <<Exercise_3,创建 JSF 受管 Bean JSF 页>>
* <<Exercise_3a,创建受管 Bean>>
* <<Exercise_3b,修改索引页>>
* <<Exercise_3c,创建结果页>>
* <<Exercise_4,运行项目>>
* <<Exercise_5,下载解决方案项目>>
*要学习本教程,您需要具备以下软件和资源。*
|===
|软件或资源 |要求的版本
|link:https://netbeans.org/downloads/index.html[+NetBeans IDE+] |7.2、7.3、7.4、8.0、Java EE 版本
|link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[+Java 开发工具包 (JDK)+] |版本 7 或 8
|GlassFish Server Open Source Edition |3.x4.x
|===
*先决条件*
本文档假定您具备以下技术的一些基本知识或编程经验:
* Java 编程
* NetBeans IDE
您可以下载link:https://netbeans.org/projects/samples/downloads/download/Samples/JavaEE/SimpleEE6App72.zip[+已完成项目的 zip 档案文件+]。
== 创建 Web 应用程序项目
在本练习中,将创建一个简单的 Web 应用程序。在创建 Web 应用程序时,请将 GlassFish Server 指定为目标 Java EE 容器。GlassFish Server Java EE 兼容,并包含此应用程序中所需的 JSF 2.x 库。
"New Project"(新建项目)向导中,可以选择 "Java EE 6 Web" "Java EE 7 Web" 作为 Java EE 版本。Java EE 6 Web Java EE 7 Web 是小型 Java EE 配置文件,其中包含完整 Java EE 平台的一部分。Java EE Web 配置文件设计用于不需要高级 Java EE 技术的 Web 应用程序,例如远程接口支持、完整 EJB 3.1 规范以及 Java 消息服务 (JMS) API
Web 配置文件支持企业 Web 应用程序中经常使用的事务处理和持久性管理。可以将 Java EE Web 配置文件用于使用具有本地接口或没有接口的会话 Bean Web 应用程序。如果应用程序使用远程接口,则需要使用完整 Java EE 配置文件。
1. 从主菜单中选择 "File"(文件)> "New Project"(新建项目)(Ctrl-Shift-N 组合键;在 Mac 上为 ⌘-Shift-N 组合键)。
2. "Java Web" 类别中选择 "Web Application"Web 应用程序),然后单击 "Next"(下一步)。
3. 键入 *SimpleEE6App* 作为项目名称并设置项目位置。
4. 取消选中 "Use Dedicated Folder"(使用专用文件夹)选项(如果该选项处于选中状态)。单击 "Next"(下一步)。
(在本教程中,我们将项目库复制到一个专门的文件夹中,因为需要与其他用户或项目共享库。)
. 选择 "GlassFish Server",并将 "Java EE Version"Java EE 版本)设置为 "Java EE 6 Web" "Java EE 7 Web"。单击 "Next"(下一步)。
image::images/newappwizard.png[title="新建项目向导中的 "Server and Settings"(服务器和设置)面板"]
. "Frameworks"(框架)窗格中选择 "JavaServer Faces"。单击 "Finish"(完成)。
默认情况下,如果要开发 Java EE Web 应用程序并将其部署到 GlassFish Server 中,IDE 将选择 JSF 2.x 库。默认 JSF 库的版本取决于随 GlassFish Server 捆绑提供的版本。JSF 2.x 库允许将 Facelets 作为页面语言,并且还提供了 JSF 1.2 JSP 支持。
image::images/newappwizard2.png[title="新建项目向导中的 "Frameworks"(框架)面板"]
单击 "Finish"(完成),此时 IDE 将创建项目并在 "Projects"(项目)窗口中打开该项目。IDE 自动创建 ``index.xhtml`` 页,并在编辑器中打开该页。
== 创建实体类和会话 Facade
在此部分,将创建一个实体类,并为该实体类创建会话 Facade。实体类是一种简单的传统 Java 对象 (POJO),可通过 ``@Entity`` 标注将这种简单的 Java 类标识为实体。从 Java EE 5 规范开始,可以将实体类作为持久性对象来表示数据库中的表。通过使用 Java 持久性 API,您可以在 Web 应用程序中使用持久性,而无需创建 EJB 模块。
该应用程序中的实体类的会话 Facade 是无状态会话 BeanEnterprise JavaBean (EJB) 3.1 体系结构作为 Java EE 6 规范的一部分引入,使您无需使用业务接口即可创建会话 Bean,而在 EJB 3.0 中则要求使用此类接口。此外,Java EE 6 规范允许您可以直接将 EJB 组件打包到 WAR 档案中。由于不需要创建作为 JAR 档案打包到 EAR 档案中的单独 EJB 模块,这就简化了较小 Web 应用程序的开发过程。不过,对于分布到不同计算机的大型企业应用程序,仍需要创建 EAR 档案以便将业务逻辑与表示层分开。
有关在 IDE 中使用 EJB 3.1 的更多信息,请参见link:javaee-entapp-ejb.html[+使用 EJB 3.1 创建企业应用程序+]教程。
有关实体类的更多详细信息,请参见 link:http://download.oracle.com/javaee/7/tutorial/doc/[+Java EE 7 教程+]中的 link:http://docs.oracle.com/javaee/7/tutorial/doc/persistence-intro.htm[+Java 持久性 API 简介+]一章。
有关会话 Bean 的更多信息,请参见 link:http://download.oracle.com/javaee/7/tutorial/doc/[+Java EE 7 教程+]中的link:http://docs.oracle.com/javaee/7/tutorial/doc/ejb-intro002.htm[+什么是会话 Bean?+]一章。
=== 创建实体类
在本练习中,将使用新建实体类向导创建简单的持久性实体类。您还会使用该向导创建持久性单元,以定义应用程序中使用的数据源和实体管理器。将在类中添加一个字段以表示表中的数据,并为新字段生成 getter setter
实体类必须具有一个主键。在使用向导创建实体类时,IDE 将默认生成 ``id`` 字段,并使用 ``@Id`` 标注来标注该字段以将其声明为主键。IDE 还会添加 ``@GeneratedValue`` 标注并指定主 id 字段的键生成策略。
在项目中使用 Java 持久性可以大大简化应用程序的开发,因为不需要配置部署描述符为持久性字段或属性提供对象关系映射信息。您可以使用标注直接在简单的 Java 类中定义这些属性。
实体持久性是通过 EntityManager API 来管理的。EntityManager API 用于处理持久性上下文,而每个持久性上下文是一组实体实例。开发应用程序时,您可以在类中使用标注来指定实体实例的持久性上下文实例。然后通过容器处理实体实例的生命周期。
要创建实体类,请执行以下步骤。
1. 右键单击项目节点,然后选择 "New"(新建)> "Other"(其他)。
2. "Persistence"(持久性)类别中,选择 "Entity Class"(实体类)。单击 "Next"(下一步)。
3. 键入 *Message* 作为类名。
4. 键入 *entities* 作为包名。
5. 选择 "Create Persistence Unit"(创建持久性单元)。单击 "Next"(下一步)。
6. 选择数据源(例如,如果要使用 JavaDB,则选择 ``jdbc/sample`` )。
在安装 IDE GlassFish Server 时, ``jdbc/sample`` 的数据源将与 IDE 资源包捆绑在一起;但如果要使用不同的数据库,则可以指定不同的数据源。
您可以保留其他默认选项(持久性单元名称、EclipseLink 持久性提供器)。确保持久性单元将使用 Java 事务 API,并且已将 "Table Generation Strategy"(表生成策略)设置为 "Create"(创建),以便在部署应用程序时将创建基于实体类的表。
. 在新建实体类向导中单击 "Finish"(完成)。
单击 "Finish"(完成),此时 IDE 将创建实体类并在编辑器中打开该类。您可以看到 IDE 生成了 id 字段 ``private Long id;`` 并使用 ``@Id`` ``@GeneratedValue(strategy = GenerationType.AUTO)`` 标注该字段。
. 在编辑器中,将 ``message`` 字段(以粗体显示)添加到 ``id`` 字段下面。
[source,java]
----
private Long id;
*private String message;*
----
. 在编辑器中右键单击,选择 "Insert Code"(插入代码)(Alt-Insert 组合键;在 Mac 上为 Ctrl-I 组合键),然后选择 "Getter and Setter"Getter Setter)。
. "Generate Getters and Setters"(生成 getter setter)对话框中,选择 ``message`` 字段,然后单击 "Generate"(生成)。
IDE 将为 ``message`` 字段生成 getter setter 方法。
image::images/getters-dialog.png[title="创建持久性单元向导"]
. 保存所做的更改。
实体类表示数据库中的表。在运行此应用程序时,将自动创建 Message 的数据库表。该表包含 ``id`` ``message`` 列。
如果在 XML 编辑器中查看持久性单元,则可以看到应用程序将使用 Java 事务 API (JTA) ( ``transaction-type="JTA"`` )。这指定了在持久性上下文中管理实体生命周期的责任将指定给容器。这可减少所需的代码,因为实体生命周期是由容器而不是应用程序管理的。有关使用 JTA 管理事务的更多信息,请参见 link:http://www.oracle.com/technetwork/java/javaee/jta/index.html[+Java 事务 API+] 文档。
=== 创建会话 Facade
在本练习中,将使用向导为 Message 实体创建无状态会话 FacadeEJB 3.1. 规范指出,会话 Bean 的业务接口现在是可选的。在此应用程序中,访问该 Bean 的客户端是本地客户端,您可以选择使用本地接口或无接口视图公开该 Bean
要创建会话 Bean,请执行以下步骤。
. 右键单击项目节点,然后选择 "New"(新建)> "Other"(其他)。
. "Enterprise JavaBeans" 类别中选择 "Session Beans for Entity Classes"(实体类的会话 Bean)。单击 "Next"(下一步)。
. 选择 ``Message`` 实体,然后单击 "Add"(添加)。单击 "Next"(下一步)。
. 键入 *boundary* 作为包名。单击 "Finish"(完成)。
请注意,无需为会话 Bean 创建业务接口。相反,在此应用程序中,将使用无接口视图向本地受管 Bean 公开该 Bean
image::images/sessionwizard.png[title="实体类的会话 Bean 向导"]
单击 "Finish"(完成),此时 IDE 将会生成会话 Facade ``MessageFacade.java`` ``AbstractFacade.java`` ,然后在编辑器中打开文件。正如在生成的代码中所看到的一样, ``@Stateless`` 标注用于将 ``MessageFacade.java`` 声明为无状态会话 Bean 组件。 ``MessageFacade.java`` 用于扩展 ``AbstractFacade.java`` ,该类包含业务逻辑,用于管理事务。
[source,java]
----
@Stateless
public class MessageFacade extends AbstractFacade<Message> {
@PersistenceContext(unitName = "SimpleEE6AppPU")
private EntityManager em;
----
在使用向导为实体创建 Facade 时,IDE 将默认添加 ``PersistenceContext`` annotation 标注 ( ``@PersistenceContext(unitName = "SimpleEE6AppPU")`` ),以便将实体管理器资源注入会话 Bean 组件并指定持久性单元名称。在本示例中,将显式声明持久性单元的名称;但如果应用程序只有一个持久性单元,则该名称是可选的。
IDE 还会在 ``AbstractFacade.java`` 中生成相应的方法以创建、编辑、删除和查找实体。实体管理器 API 定义了用于与持久性上下文交互的方法。您可以看到 IDE 生成了一些常用的默认查询方法,可使用这些方法查找实体对象。 ``findAll`` ``findRange`` ``count`` 方法使用条件 API 中定义的方法来创建查询。条件 API JPA 2.x 规范的一部分,它包含在 Java EE 6 规范中。
== 创建 JSF 受管 Bean JSF
在此部分,将使用 JavaServer Faces (JSF) 2.x JSF 页所使用的受管支持 Bean 创建应用程序的表示层。JSF 2.x 规范支持将 Facelets 作为基于 JSF 的应用程序的首选视图技术。从 JSF 2.x 开始,您还可以在源代码中使用 ``@ManagedBean`` 标注将类声明为受管 Bean。您不再需要在 ``faces-config.xml`` 文件中添加实体以声明 JSF 受管 Bean。可以在 JSF 页中使用 Bean 名称访问受管 Bean 中的方法。
有关 IDE 中的 JavaServer Faces 2.x 规范支持的详细信息,请参见 link:../web/jsf20-support.html[+NetBeans IDE 中的 JSF 2.x 支持+]。
有关 JavaServer Faces 2.x 规范的详细信息,请参见 Java EE 7 教程中的 link:http://docs.oracle.com/javaee/7/tutorial/doc/jsf-intro.htm[+JavaServer Faces 技术+]一章。
=== 创建受管 Bean
在本练习中,将创建一个用于访问会话 Facade 的简单 JSF 受管 BeanJSF 2.x 规范允许在 Bean 类中使用标注以将类标识为 JSF 受管 Bean,以及指定范围和 Bean 名称。
要创建受管 Bean,请执行以下步骤。
1. 右键单击项目节点,然后选择 "New"(新建)> "Other"(其他)。
2. "JavaServer Faces" 类别中选择 "JSF Managed Bean"JSF 受管 Bean)。单击 "Next"(下一步)。
3. 键入 *MessageView* 作为类名。
在调用受管 Bean 中的方法时,将使用 Bean 名称 ``MessageView`` 作为 JSF ``index.xhtml`` 中的 ``inputText`` ``commandButton`` 的值。
. 键入 *my.presentation* 作为包名。
. 键入 *MessageView* 作为将用于受管 Bean 的名称。
NOTE: 在使用此向导创建受管 Bean 时,默认情况下 IDE 将会根据该 Bean 类的名称为该 Bean 指定名称,名称以小写字母开头。出于本教程和演示之目的,您要为 Bean 明确指定以小写字母开头的名称。在 JSF 页中引用 Bean 时,您要使用 ``MessageView`` 而不是 ``messageView`` 。如果尚未明确指定名称,则应在 JSF 页中使用默认的 ``messageView``
. "Scope"(范围)设置为 "request"(请求)。单击 "Finish"(完成)。
image::images/newjsfbean.png[title="新建 JSF 受管 Bean 向导"]
单击 "Finish"(完成),此时 IDE 创建 Bean 类并在编辑器中打开该类。在 "Projects"(项目)窗口中,将会看到以下文件。
image::images/projectswindow.png[title="显示文件结构的 "Project"(项目)窗口"]
在编辑器中,您可以看到 IDE 添加了 ``@ManagedBean`` ``@RequestScoped`` 标注以及 Bean 名称。
[source,java]
----
@ManagedBean(name="MessageView")
@RequestScoped
public class MessageView {
/** Creates a new instance of MessageView */
public MessageView() {
}
}
----
现在,将添加 ``@EJB`` 标注,以使用依赖关系注入获取对 MessageFacade 会话 Bean 的引用。此外,还要调用在 Facade 中公开的 ``findAll`` ``create`` 方法。在键入这些方法时,IDE 的代码完成功能可为您提供帮助。
1. 在编辑器中右键单击,选择 "Insert Code"(插入代码)(Alt-Insert 组合键;在 Mac 上为 Ctrl-I 组合键),然后在弹出式菜单中选择 "Call Enterprise Bean"(调用企业 Bean)。
2. "Call Enterprise Bean"(调用企业 Bean)对话框中选择 "MessageFacade"。单击 "OK"(确定)。
image::images/callbean.png[title=""Call Enterprise Bean"(调用企业 Bean)对话框"]
在单击 "OK"(确定)时,IDE 将添加以下代码(以粗体显示)以注入该 Bean
[source,java]
----
public class MessageView {
/** Creates a new instance of MessageView */
public MessageView() {
}
// Injects the MessageFacade session bean using the @EJB annotation
*@EJB
private MessageFacade messageFacade;*
}
----
. 添加以下代码以创建新实例。
[source,java]
----
/** Creates a new instance of MessageView */
public MessageView() {
this.message = new Message();
}
----
. 在该类中添加以下代码。
[source,java]
----
// Creates a new field
private Message message;
// Calls getMessage to retrieve the message
public Message getMessage() {
return message;
}
// Returns the total number of messages
public int getNumberOfMessages(){
return messageFacade.findAll().size();
}
// Saves the message and then returns the string "theend"
public String postMessage(){
this.messageFacade.create(message);
return "theend";
}
----
. 在编辑器中右键单击并选择 "Fix Imports"(修复导入)(Alt-Shift-I 组合键;在 Mac 中为 ⌘-Shift-I 组合键),然后保存您的更改。
您可以在编辑器中使用代码完成以帮助键入代码。
请注意, ``postMessage`` 方法将返回 "theend" 字符串。JSF 2.x 规范允许在使用 Facelets 技术的应用程序中使用隐式导航规则。此应用程序中,没有在 ``faces-config.xml`` 中配置任何导航规则。导航处理程序将尝试在应用程序中查找合适的页面。在这种情况下,在调用 ``postMessage`` 方法时,导航处理程序将尝试查找名为 ``theend.xhtml`` 的页面。
=== 修改索引页
在本练习中,将对 ``index.xhtml`` 页面进行简单的更改以添加一些 UI 组件。将在窗体中添加输入文本字段和按钮。
1. 在编辑器中打开 ``index.xhtml``
2. 修改该文件,在 ``<h:body>`` 标记之间添加以下简单窗体。
[source,xml]
----
<h:body>
*<f:view>
<h:form>
<h:outputLabel value="Message:"/><h:inputText value="#{MessageView.message.message}"/>
<h:commandButton action="#{MessageView.postMessage}" value="Post Message"/>
</h:form>
</f:view>*
</h:body>
----
在键入代码时,JSF 代码完成功能可为您提供帮助。
image::images/jsfcodecompletion1.png[title="源代码编辑器中的代码完成"]
NOTE: 如果将代码复制并粘贴到文件,您将会在 ``<f:view>`` 所在行旁边的左旁注中看到一条警告。您可以将插入光标放在该行中,然后按 Alt-Space 组合键以打开有关如何解决错误的提示。该提示告知您需要添加 ``xmlns:f="http://xmlns.jcp.org/jsf/core"`` 库声明。
. 保存所做的更改。
``inputText`` ``commandButton`` 组件将在命名 JSF 受管 Bean ``MessageView`` 中调用方法。 ``postMessage`` 方法返回 "theend",导航处理程序将查找名为 ``theend.xhtml`` 的页面。
=== 创建结果页
在本练习中,将创建 JSF ``theend.xhtml`` 。当用户在 ``index.xhtml`` 中单击 "Post Message" 按钮并在 JSF 受管 Bean 中调用 ``postMessage`` 方法时,将显示该页面。
. 右键单击项目节点,然后选择 "New"(新建)> "Other"(其他)。
. "JavaServer Faces" 类别中选择 "JSF Page"JSF 页)。单击 "Next"(下一步)。
. 键入 *theend* 作为文件名。
. 确认选择了 "Facelets" 选项。单击 "Finish"(完成)。
image::images/result-jsf-page.png[title="在新建 JSF 文件向导中创建 theend JSF 文件"]
. <h:body> 标记之间键入以下内容以修改该文件。
[source,xml]
----
<h:body>
*<h:outputLabel value="Thanks! There are "/>
<h:outputText value="#{MessageView.numberOfMessages}"/>
<h:outputLabel value=" messages!"/>*
</h:body>
----
在开始键入时,IDE 自动在文件中为 JSF 元素添加 ``xmlns:h="http://xmlns.jcp.org/jsf/html"`` 标记库定义。
== 运行应用程序
现在,已完成了应用程序的编码工作。您可以在浏览器中测试应用程序。
1. "Projects"(项目)窗口中右键单击项目节点,然后选择 "Run"(运行)。
在选择 "Run"(运行)时,IDE 构建和部署应用程序,并在浏览器中打开 ``index.xhtml``
. 在文本字段中键入消息。单击 "Post Message"
image::images/browser1.png[title="浏览器中的应用程序"]
在单击 "Post Message" 时,该消息将保存到数据库中,然后检索并显示消息数。
image::images/browser2.png[title="显示结果的浏览器中的应用程序"]
== 下载解决方案项目
您可以采用下列方法下载本教程中使用的样例项目。
* 下载link:https://netbeans.org/projects/samples/downloads/download/Samples/JavaEE/SimpleEE6App72.zip[+已完成项目的 zip 档案文件+]。
* 通过执行以下步骤从 NetBeans 样例检出项目源代码:
1. 从主菜单中选择 "Team"(团队开发)> "Subversion" > "Checkout"(检出)。
2. "Checkout"(检出)对话框中,输入以下资源库 URL
``https://svn.netbeans.org/svn/samples~samples-source-code``
单击 "Next"(下一步)。
. 单击 "Browse"(浏览)以打开 "Browse Repository Folders"(浏览资源库文件夹)对话框。
. 展开根节点并选择 *samples/javaee/SimpleEE6App*。单击 "OK"(确定)。
. 指定用于存储源代码的本地文件夹(本地文件夹必须为空)。
. 单击 "Finish"(完成)。
单击 "Finish"(完成),此时 IDE 会将本地文件夹初始化为 Subversion 资源库,并检出项目源代码。
. 在完成检出操作后将会显示一个对话框,在该对话框中单击 "Open Project"(打开项目)。
NOTE: 需要 Subversion 客户端检出源代码。有关安装 Subversion 的更多信息,请参见 link:../ide/subversion.html[+NetBeans IDE 中的 Subversion 指南+]中有关link:../ide/subversion.html#settingUp[+设置 Subversion+] 的部分。
link:/about/contact_form.html?to=3&subject=Feedback:%20Getting%20Started%20with%20Java%20EE%206%20Applications[+发送有关此教程的反馈意见+]
== 另请参见
有关使用 NetBeans IDE 开发 Java EE 应用程序的更多信息,请参见以下资源:
* link:javaee-intro.html[+Java EE 技术简介+]
* link:../web/jsf20-support.html[+NetBeans IDE 中的 JSF 2.x 支持+]
* link:../../trails/java-ee.html[+Java EE Java Web 学习资源+]
可以在 link:http://download.oracle.com/javaee/7/tutorial/doc/[+Java EE 7 教程+]中找到使用 Java EE 技术开发应用程序的详细信息。
要发送意见和建议、获得支持以及随时了解 NetBeans IDE Java EE 开发功能的最新开发情况,请link:../../../community/lists/top.html[+加入 nbj2ee 邮件列表+]。