1. Overview
1.概述
Servlets are plain Java classes that run in a servlet container.
Servlets是在Servlet容器中运行的普通Java类。
HTTP servlets (a specific type of servlet) are first class citizens in Java web applications. The API of HTTP servlets is aimed at handling HTTP requests through the typical request-processing-response cycle, implemented in client-server protocols.
HTTP servlet(一种特殊类型的servlet)是Java网络应用程序中的第一等公民。HTTP servlet的API是旨在通过典型的请求-处理-响应周期来处理HTTP请求,在客户-服务器协议中实现。
Furthermore, servlets can control the interaction between a client (typically a web browser) and the server using key-value pairs in the form of request/response parameters.
此外,servlets可以使用请求/响应参数形式的键值对来控制客户端(通常是Web浏览器)和服务器之间的互动。
These parameters can be initialized and bound to an application-wide scope (context parameters) and a servlet-specific scope (servlet parameters).
这些参数可以被初始化,并被绑定到一个应用程序范围(上下文参数)和一个Servlet特定范围(Servlet参数)。
In this tutorial, we’ll learn how to define and access context and servlet initialization parameters.
在本教程中,我们将学习如何定义和访问上下文和Servlet初始化参数。
2. Initializing Servlet Parameters
2.初始化Servlet参数
We can define and initialize servlet parameters using annotations and the standard deployment descriptor — the “web.xml” file. It’s worth noting that these two options are not mutually exclusive.
我们可以使用注解和标准部署描述符–“web.xml”文件来定义和初始化Servlet参数。值得注意的是,这两个选项并不相互排斥。
Let’s explore each of these options in depth.
让我们深入探讨这些选项中的每一个。
2.1. Using Annotations
2.1.使用注解
Initializing servlets parameters with annotations allows us to keep configuration and source code in the same place.
用注解初始化servlets参数使我们能够将配置和源代码放在同一个地方。
In this section, we’ll demonstrate how to define and access initialization parameters that are bound to a specific servlet using annotations.
在这一节中,我们将演示如何使用注解来定义和访问与特定Servlet绑定的初始化参数。
To do so, we’ll implement a naive UserServlet class that collects user data through a plain HTML form.
为此,我们将实现一个天真的 UserServlet类,通过一个普通的HTML表单收集用户数据。
First, let’s look at the JSP file that renders our form:
首先,让我们看一下渲染我们的表单的JSP文件。
<!DOCTYPE html>
<html>
<head>
<title>Context and Initialization Servlet Parameters</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h2>Please fill the form below:</h2>
<form action="${pageContext.request.contextPath}/userServlet" method="post">
<label for="name"><strong>Name:></label>
<input type="text" name="name" id="name">
<label for="email"><strong>Email:></label>
<input type="text" name="email" id="email">
<input type="submit" value="Send">
</form>
</body>
</html>
Note that we’ve coded the form’s action attribute by using the EL (the Expression Language). This allows it to always point to the “/userServlet” path, regardless of the location of the application files in the server.
请注意,我们通过使用EL(表达式语言)对表单的action属性进行编码。这允许它始终指向“/userServlet”路径,而不管服务器中的应用程序文件的位置如何。
The “${pageContext.request.contextPath}” expression sets a dynamic URL for the form, which is always relative to the application’s context path.
“${pageContext.request.contextPath}”表达式为表单设置一个动态URL,它总是相对于应用程序的上下文路径。
Here’s our initial servlet implementation:
这是我们最初的Servlet实现。
@WebServlet(name = "UserServlet", urlPatterns = "/userServlet", initParams={
@WebInitParam(name="name", value="Not provided"),
@WebInitParam(name="email", value="Not provided")}))
public class UserServlet extends HttpServlet {
// ...
@Override
protected void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
forwardRequest(request, response, "/WEB-INF/jsp/result.jsp");
}
protected void processRequest(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("name", getRequestParameter(request, "name"));
request.setAttribute("email", getRequestParameter(request, "email"));
}
protected void forwardRequest(
HttpServletRequest request,
HttpServletResponse response,
String path)
throws ServletException, IOException {
request.getRequestDispatcher(path).forward(request, response);
}
protected String getRequestParameter(
HttpServletRequest request,
String name) {
String param = request.getParameter(name);
return !param.isEmpty() ? param : getInitParameter(name);
}
}
In this case, we’ve defined two servlet initialization parameters, name and email, by using initParams and the @WebInitParam annotations.
在这种情况下,我们通过使用initParams和@WebInitParam注解,定义了两个servlet初始化参数:name和email。
Please note that we’ve used HttpServletRequest’s getParameter() method to retrieve the data from the HTML form, and the getInitParameter() method to access the servlet initialization parameters.
请注意,我们使用了HttpServletRequest的getParameter()方法来检索HTML表单中的数据,以及getInitParameter()方法来访问Servlet初始化参数。
The getRequestParameter() method checks if the name and email request parameters are empty strings.
getRequestParameter()方法检查name和email请求参数是否是空字符串。
If they are empty strings, then they get assigned the default values of the matching initialization parameters.
如果它们是空字符串,那么它们会被分配到匹配的初始化参数的默认值。
The doPost() method first retrieves the name and email that the user entered in the HTML form (if any). Then it processes the request parameters and forwards the request to a “result.jsp” file:
doPost()方法首先检索用户在HTML表单中输入的姓名和电子邮件(如果有的话)。然后,它处理请求参数并将请求转发到“result.jsp”文件。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>User Data</title>
</head>
<body>
<h2>User Information</h2>
<p><strong>Name:> ${name}</p>
<p><strong>Email:> ${email}</p>
</body>
</html>
If we deploy our sample web application to an application server, such as Apache Tomcat, Oracle GlassFish or JBoss WidlFly, and run it, it should first display the HTML form page.
如果我们将我们的示例Web应用程序部署到应用服务器上,例如Apache Tomcat, Oracle GlassFish或JBoss WidlFly,并运行它,它应该首先显示HTML表单页。
Once the user has filled out the name and email fields and submitted the form, it will output the data:
一旦用户填写了姓名和电子邮件字段并提交了表格,它将输出数据。
User Information
Name: the user's name
Email: the user's email
If the form is just blank, it will display the servlet initialization parameters:
如果该表格只是空白,它将显示servlet的初始化参数。
User Information
Name: Not provided
Email: Not provided
In this example, we’ve shown how to define servlet initialization parameters by using annotations, and how to access them with the getInitParameter() method.
在这个例子中,我们展示了如何通过使用注解来定义servlet初始化参数,以及如何用getInitParameter()方法来访问它们。
2.2. Using the Standard Deployment Descriptor
2.2.使用标准部署描述符
This approach differs from the one that uses annotations, as it allows us to keep configuration and source code isolated from each other.
这种方法与使用注释的方法不同,因为它允许我们将配置和源代码相互隔离。
To showcase how to define initialization servlet parameters with the “web.xml” file, let’s first remove the initParam and @WebInitParam annotations from the UserServlet class:
为了展示如何用“web.xml”文件定义初始化servlet参数,我们首先从initParam和@WebInitParam注释中删除UserServlet类。
@WebServlet(name = "UserServlet", urlPatterns = {"/userServlet"})
public class UserServlet extends HttpServlet { ... }
Next, let’s define the servlet initialization parameters in the “web.xml” file:
接下来,让我们在“web.xml”文件中定义Servlet的初始化参数。
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<servlet>
<display-name>UserServlet</display-name>
<servlet-name>UserServlet</servlet-name>
<init-param>
<param-name>name</param-name>
<param-value>Not provided</param-value>
</init-param>
<init-param>
<param-name>email</param-name>
<param-value>Not provided</param-value>
</init-param>
</servlet>
</web-app>
As shown above, defining servlet initialization parameters using the “web.xml” file just boils down to using the <init-param>, <param-name> and <param-value> tags.
如上所示,使用“web.xml”文件定义servlet初始化参数,只需使用<init-param>,<param-name>和<param-value>标签。
Furthermore, it’s possible to define as many servlet parameters as needed, as long as we stick to the above standard structure.
此外,只要我们坚持上述标准结构,就可以根据需要定义尽可能多的servlet参数。
When we redeploy the application to the server and rerun it, it should behave the same as the version that uses annotations.
当我们把应用程序重新部署到服务器并重新运行时,它的行为应该与使用注解的版本相同。
3. Initializing Context Parameters
3.初始化上下文参数
Sometimes we need to define some immutable data that must be globally shared and accessed across a web application.
有时我们需要定义一些必须在整个网络应用中全局共享和访问的不可变的数据。
Due to the data’s global nature, we should use application-wide context initialization parameters for storing the data, rather than resorting to the servlet counterparts.
由于数据的全局性,我们应该使用应用程序范围内的上下文初始化参数来存储数据,而不是求助于Servlet的对应参数。
Even though it’s not possible to define context initialization parameters using annotations, we can do this in the “web.xml” file.
尽管不可能使用注解来定义上下文初始化参数,但我们可以在“web.xml”文件中这样做。
Let’s suppose that we want to provide some default global values for the country and province where our application is running.
假设我们想为我们的应用程序所运行的国家和省份提供一些默认的全局值。
We can accomplish this with a couple of context parameters.
我们可以通过几个上下文参数来实现这一点。
Let’s refactor the “web.xml” file accordingly:
让我们对“web.xml”/em>文件进行相应的重构。
<web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<context-param>
<param-name>province</param-name>
<param-value>Mendoza</param-value>
</context-param>
<context-param>
<param-name>country</param-name>
<param-value>Argentina</param-value>
</context-param>
<!-- Servlet initialization parameters -->
</web-app>
This time, we’ve used the <context-param>, <param-name>, and <param-value> tags to define the province and country context parameters.
这一次,我们使用了<context-param>, <param-name>, 和<param-value>标签来定义province和country语境参数。
Of course, we need to refactor the UserServlet class so that it can fetch these parameters and pass them on to the result page.
当然,我们需要重构UserServlet类,以便它能够获取这些参数并将它们传递给结果页面。
Here are the servlet’s relevant sections:
下面是servlet的相关部分。
@WebServlet(name = "UserServlet", urlPatterns = {"/userServlet"})
public class UserServlet extends HttpServlet {
// ...
protected void processRequest(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("name", getRequestParameter(request, "name"));
request.setAttribute("email", getRequestParameter(request, "email"));
request.setAttribute("province", getContextParameter("province"));
request.setAttribute("country", getContextParameter("country"));
}
protected String getContextParameter(String name) {-
return getServletContext().getInitParameter(name);
}
}
Please notice the getContextParameter() method implementation, which first gets the servlet context through getServletContext(), and then fetches the context parameter with the getInitParameter() method.
请注意getContextParameter()方法的实现,它首先通过getServletContext()获得Servlet上下文,然后用getInitParameter()方法获取上下文参数。
Next, we need to refactor the “result.jsp” file so that it can display the context parameters along with the servlet-specific parameters:
接下来,我们需要重构“result.jsp”文件,以便它能够在显示上下文参数的同时显示特定服务的参数。
<p><strong>Name:> ${name}</p>
<p><strong>Email:> ${email}</p>
<p><strong>Province:> ${province}</p>
<p><strong>Country:> ${country}</p>
Lastly, we can redeploy the application and execute it once again.
最后,我们可以重新部署应用程序并再次执行它。
If the user fills the HTML form with a name and an email, then it will display this data along with the context parameters:
如果用户在HTML表单中填写了姓名和电子邮件,那么它就会将这些数据与上下文参数一起显示出来。
User Information
Name: the user's name
Email: the user's email
Province: Mendoza
Country: Argentina
Otherwise, it would output the servlet and context initialization parameters:
否则,它将输出Servlet和上下文初始化参数。
User Information
Name: Not provided
Email: Not provided
Province: Mendoza
Country: Argentina
While the example is contrived, it shows how to use context initialization parameters to store immutable global data.
虽然这个例子是设计好的,但它展示了如何使用上下文初始化参数来存储不可变的全局数据。
As the data is bound to the application context, rather than to a particular servlet, we can access them from one or multiple servlets, using the getServletContext() and getInitParameter() methods.
由于数据被绑定到应用程序上下文,而不是特定的Servlet,我们可以使用getServletContext()和getInitParameter()方法从一个或多个Servlet访问它们。
4. Conclusion
4.结论
In this article, we learned the key concepts of context and servlet initialization parameters and how to define them and access them using annotations and the “web.xml” file.
在这篇文章中,我们学习了上下文和Servlet初始化参数的关键概念,以及如何使用注释和“web.xml”文件来定义它们和访问它们。
For quite some time, there has been a strong tendency in Java to get rid of XML configuration files and migrate to annotations whenever possible.
在相当长的一段时间里,在Java中一直有一种强烈的趋势,即摆脱XML配置文件,尽可能地迁移到注解。
CDI, Spring, Hibernate, to name a few, are glaring examples of this.
CDI、Spring、Hibernate等等,都是这方面的明显例子。
Nevertheless, there’s nothing inherently wrong with using the “web.xml” file for defining context and servlet initialization parameters.
尽管如此,使用“web.xml”文件来定义上下文和Servlet初始化参数本身并没有什么问题。
Even though the Servlet API has evolved at pretty fast pace toward this tendency, we still need to use the deployment descriptor for defining context initialization parameters.
尽管Servlet API已经以相当快的速度向这个趋势发展,我们仍然需要使用部署描述符来定义上下文初始化参数。
As usual, all the code samples shown in this article are available over on GitHub.
像往常一样,本文中显示的所有代码样本都可以在GitHub上找到。