Java EE之Servlet
1.创建Servlet类
Servlet在Java EE API规范中的定义:
Servlet是一个运行在Web服务器中的Java小程序。Servlet将会接收和响应来自Web客户端的请求,使用HTTP(超文本传输协议)进行通信。
Servlet是所有Web应用程序的核心类。
运行应用程序的Web容器将会有一个或多个内建的Servlet。这些Servlet将用于处理JavaServer Pages、显示目录列表和访问静态资源。
所有的Servlet都实现了javax.serlvet.Servlet接口,但通常不是直接实现的。Servlet只是一个简单接口,它包含了初始化并销毁Servlet和处理请求的方法。
在大多数情况下,Servlet都继承自javax.servlet.GenericServlet。GenericServlet仍然是一个不依赖于具体协议的Servlet,它只包含了一个抽象的service方法。
作为响应HTTP请求的java.servlet.http.HttpServlet,它继承了GenericServlet,并实现了只接受HTTP请求的service方法。然后,它提供了响应每种HTTP方法类型的方法的空实现。
HttpServlet的方法接受的是javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse参数,而不是javax.servlet.ServletRequest和javax.servlet.ServletResponse,这样它就可以轻松访问Servlet服务所处理的请求中的HTTP特定的特性。
package com.wrox;
import javax.servlet.http.HttpServlet;
public class HelloServlet extends HttpServlet
{
}
//为了可以编译该代码,需要将Java EE Servlet API库添加到编译类路径上。
任何未重写的HTTP Servlet方法都将返回一个HTTP状态405作为响应。如果一个Servlet不处理任何请求,当然它就是无用的。
//重写doGet()方法
package com.wrox;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@SuppressWarnings("serial")
public class HelloServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
//下面没有调用PringtWriter的close方法。一般来说,在Java中只需要关闭自己创建
//的资源即可。Web容器创建了该资源,所以它也会负责关闭该资源。
response.getWriter().println("Hello, World!");
}
}
注意,不需要担心任何原生HTTP请求或响应的细节。Web容器将会处理请求的解释,并从套接字(socket)中读取请求头和参数。在Servlet的方法返回之后,Web容器还将格式化响应头和主体,并写回套接字中。
使用初始化方法和销毁方法
@Override
public void init() throws ServletException
{
System.out.println("Servlet " + this.getServletName() + " has started.");
}
@Override
public void destroy()
{
System.out.println("Servlet " + this.getServletName() + " has stopped.");
}
GenericServlet实现了javax.servlet.Servlet接口中的init(ServletConfig config)
方法,所以不需要在自己的init方法实现中调用super.init(servletConfig)
。
可以使用init方法读取属性文件,或者使用JDBC连接数据库。init方法将在Servlet启动时调用。
如果将Servlet配置为在Web应用程序部署和启动时自动启动,那么它的init方法也将会被调用。否则,init方法将在第一次请求访问它接收的Servlet时调用。
同样地,destroy在Servlet不再接受请求之后立即调用。这通常发生在Web应用程序被停止或卸载,或者Web容器关闭时。总是应该使用destroy方法清理Servlet持有的资源。
2.配置可部署的Servlet
部署描述符将指示Web容器如何部署应用程序。尤其是它定义了应用程序中所有的监听器、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">
<display-name>Hello World Application</display-name>
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.wrox.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/greeting</url-pattern>
</servlet-mapping>
</web-app>
上面的配置中<servlet>
和<servlet-mapping>
标签内的<servlet-name>
标签应该一致。Web容器通过这种方式关联这两个配置。
可以将多个URL映射到相同的Servlet:
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/greeting</url-pattern>
<url-pattern>/salutation</url-pattern>
<url-pattern>/wazzup</url-pattern>
</servlet-mapping>
下面的<load-on-startup>1</load-on-startup>
指示Web容器在应用程序启动之后立即启动Servlet。如果多个Servlet配置都包含了该标签,它们将按照标签内的值的大小顺序启动。如果两个或多个Servlet的<load-on-startup>
配置相同,那么将按照它们在描述符文件中的出现顺序启动。
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.wrox.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
3.了解doGet、doPost和其他方法
3.1 在service方法执行的过程中
service方法的实现是非常复杂的,而且随着Web容器的不同,service方法的实现也会随之变化。
扩展HttpServlet的优点在于我们不需要担心其中的任何细节问题。
通过使用HttpServlet在各种不同方法中定义的HttpServletRequest和HttpServletResponse参数,我们可以读取由客户端发送的参数、接受通过表单上传的文件、读取包含在请求正文中的原始数据、读取请求头和操作响应头,并将响应正文返回到客户端。
3.2 使用HttpServletRequest
HttpServletRequest接口是对ServletRequest的扩展。
HttpServletRequest最重要的功能是从客户端发送的请求中获取参数,请求参数有两种不同的形式:
- 查询参数(URI参数)
- 以application/x-www-form-urlencoded或multipart/form-data编码的请求正文
public interface ServletRequest {
//...
//getParameter方法将返回参数的单个值,如果参数有多个值,就返回第一个值。
public String getParameter(String name);
//getParameterNames方法返回所有可用参数的名字的枚举。
public Enumeration<String> getParameterNames();
//getParameterValues方法返回参数的值的数组,如果参数只有一个值,就返回只有一个元素的数组。
public String[] getParameterValues(String name);
//getParameterMap方法返回一个包含了所有参数名值对的 java.util.Map<String, String[]>
public Map<String, String[]> getParameterMap();
//...
}
有几个方法可用于帮助决定HTTP请求内容的类型、长度和编码。
方法getContentType
将返回请求的MIME(多用途互联网邮件扩展)内容类型,例如 application/x-www-form-urlencoded、application/json、text/plain或application/zip等。
MIME内容类型描述了数据的类型。
方法getContentLength
返回请求正文的长度,以字节为单位。
方法getCharacterEncoding
将返回请求内容的字符编码。
public interface HttpServletRequest extends ServletRequest {
//...
//返回客户端用于创建请求的完整URL,包含协议(http或https)、服务器名称、端口号和服务器路径,但不包括查询字符串
public StringBuffer getRequestURL();
//它只返回URL中的服务器路径部分
public String getRequestURI();
//它只返回用于匹配Servlet映射的URL部分
public String getServletPath();
//返回指定名字的头数据
public String getHeader(String name);
//返回请求头中所有头数据的名字的枚举
public Enumeration<String> getHeaderNames();
//如果有某个特定的头的值一直是数字,那么可以调用该方法返回一个数字。
public int getIntHeader(String name);
//对于可以表示有效时间戳的头数据,该方法将返回一个Unix时间戳。
public long getDateHeader(String name);
//...
}
3.3 使用HttpServletResponse
HttpServletResponse接口继承了ServletResponse,HttpServletResponse可以设置响应头、编写响应正文、重定向请求、设置HTTP状态码以及将Cookies返回到客户端等任务。
方法getOutputStream
将返回一个javax.servlet.ServletOutputStream
,而方法getWriter
将返回一个java.io.PrintWriter
,通过它们都可以向响应中输出数据。
在向响应正文中输出数据时,可能需要设置内容类型或编码格式。可以通过setContentType
和setCharacterEncoding
方法进行设置。如果计划在使用getWriter
时调用setContentType
和setCharacterEncoding
,那么必须在getWriter
之前调用setContentType
和setCharacterEncoding
,因为这样的getWriter
方法返回的writer才能获得正确的字符编码设置。在getWriter
调用之后调用的setContentType
和setCharacterEncoding
将被忽略。
如果在调用getWriter
之前未调用setContentType
和setCharacterEncoding
,返回的writer将使用容器的默认编码。
方法sendRedirect
将客户端重定向至另一个URL。
4.使用参数和接受表单提交
@WebServlet(
name = "helloServlet",
urlPatterns = {"/greeting", "/salutation", "/wazzup"},
loadOnStartup = 1
)
public class HelloServlet extends HttpServlet
{
private static final String DEFAULT_USER = "Guest";
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
//获取名为"user"的参数
String user = request.getParameter("user");
if(user == null)
user = HelloServlet.DEFAULT_USER;
//将响应的内容类型设置为text/html,将字符编码设置为UTF-8
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
//从响应中获得一个PrintWriter,并输出一个兼容于HTML5的文档
PrintWriter writer = response.getWriter();
writer.append("<!DOCTYPE html>\r\n")
.append("<html>\r\n")
.append(" <head>\r\n")
.append(" <title>Hello User Application</title>\r\n")
.append(" </head>\r\n")
.append(" <body>\r\n")
.append(" Hello, ").append(user).append("!<br/><br/>\r\n")
.append(" <form action=\"greeting\" method=\"POST\">\r\n")
.append(" Enter your name:<br/>\r\n")
.append(" <input type=\"text\" name=\"user\"/><br/>\r\n")
.append(" <input type=\"submit\" value=\"Submit\"/>\r\n")
.append(" </form>\r\n")
.append(" </body>\r\n")
.append("</html>\r\n");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
//接收表单提交,将请求委托给doGet方法。
this.doGet(request, response);
}
//...
接受多值参数的例子:
@WebServlet(
name = "multiValueParameterServlet",
urlPatterns = {"/checkboxes"}
)
public class MultiValueParameterServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.append("<!DOCTYPE html>\r\n")
.append("<html>\r\n")
.append(" <head>\r\n")
.append(" <title>Hello User Application</title>\r\n")
.append(" </head>\r\n")
.append(" <body>\r\n")
.append(" <form action=\"checkboxes\" method=\"POST\">\r\n")
.append("Select the fruits you like to eat:<br/>\r\n")
.append("<input type=\"checkbox\" name=\"fruit\" value=\"Banana\"/>")
.append(" Banana<br/>\r\n")
.append("<input type=\"checkbox\" name=\"fruit\" value=\"Apple\"/>")
.append(" Apple<br/>\r\n")
.append("<input type=\"checkbox\" name=\"fruit\" value=\"Orange\"/>")
.append(" Orange<br/>\r\n")
.append("<input type=\"checkbox\" name=\"fruit\" value=\"Guava\"/>")
.append(" Guava<br/>\r\n")
.append("<input type=\"checkbox\" name=\"fruit\" value=\"Kiwi\"/>")
.append(" Kiwi<br/>\r\n")
.append("<input type=\"submit\" value=\"Submit\"/>\r\n")
.append(" </form>")
.append(" </body>\r\n")
.append("</html>\r\n");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String[] fruits = request.getParameterValues("fruit");
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.append("<!DOCTYPE html>\r\n")
.append("<html>\r\n")
.append(" <head>\r\n")
.append(" <title>Hello User Application</title>\r\n")
.append(" </head>\r\n")
.append(" <body>\r\n")
.append(" <h2>Your Selections</h2>\r\n");
if(fruits == null)
writer.append(" You did not select any fruits.\r\n");
else
{
writer.append(" <ul>\r\n");
for(String fruit : fruits)
{
writer.append(" <li>").append(fruit).append("</li>\r\n");
}
writer.append(" </ul>\r\n");
}
writer.append(" </body>\r\n")
.append("</html>\r\n");
}
}
5.使用初始化参数配置应用程序
5.1 使用上下文初始化参数
在部署描述符中添加上下文初始化参数:
<context-param>
<param-name>settingOne</param-name>
<param-value>foo</param-value>
</context-param>
<context-param>
<param-name>settingTwo</param-name>
<param-value>bar</param-value>
</context-param>
在Servlet代码的任何地方都可以轻松获得和使用这些参数。
@WebServlet(
name = "contextParameterServlet",
urlPatterns = {"/contextParameters"}
)
public class ContextParameterServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
ServletContext c = this.getServletContext();
PrintWriter writer = response.getWriter();
writer.append("settingOne: ").append(c.getInitParameter("settingOne"))
.append(", settingTwo: ").append(c.getInitParameter("settingTwo"));
}
}
应用程序中的所有Servlet都将共享这些初始化参数。在所有的Servlet中它们的值都是相同的。有时需要使某个设置只作用于某一个Servlet,那么就需要使用Servlet初始化参数。
5.2 使用Servlet初始化参数
public class ServletParameterServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
//从ServletConfig对象中获取初始化参数
ServletConfig c = this.getServletConfig();
PrintWriter writer = response.getWriter();
writer.append("database: ").append(c.getInitParameter("database"))
.append(", server: ").append(c.getInitParameter("server"));
}
}
部署描述符中的配置:
<servlet>
<servlet-name>servletParameterServlet</servlet-name>
<servlet-class>com.wrox.ServletParameterServlet</servlet-class>
<init-param>
<param-name>database</param-name>
<param-value>CustomerSupport</param-value>
</init-param>
<init-param>
<param-name>server</param-name>
<param-value>10.0.12.5</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>servletParameterServlet</servlet-name>
<url-pattern>/servletParameters</url-pattern>
</servlet-mapping>
考虑到多线程安全的问题:永远不要在静态或实例变量中存储请求或响应对象。任何属于请求的对象和资源都只应该被用作本地变量和方法参数。
参考:《Java Web高级编程》第3章
Java EE之Servlet的更多相关文章
- Java EE javax.servlet中的ServletContext接口
ServletContext接口 public interface ServletContext (https://docs.oracle.com/javaee/7/api/javax/servlet ...
- Java EE之servlet实现用户登录
1.在连接数据库的JAVA类中添加查询功能: 在这之前有一个连接数据库的方法: Connection conn=null; PreparedStatement stat=null; ...
- Java EE之servlet处理表单提交的请求
1.在源包下新建一个Servlet页,取名为LoginServlet: package weinidingServlet; //该Servlet所 ...
- java EE :Servlet 接口
Servlet 生命周期 : 调用当前 Servlet 类构造函数进行实例化 Servlet 通过调用 init () 方法进行初始化 Servlet 调用 service() 方法来处理客户端的请 ...
- Java EE javax.servlet中的RequestDispatcher接口
RequestDispatcher接口 public interface RequestDispatcher 一.介绍 定义一个对象,从客户端接收请求并将其发送到服务器上的任何资源(例如servlet ...
- Java EE javax.servlet中的Servlet接口
Servlet接口 public interface Servlet 其实现类有:FaceServlet.GenericServlet.HttpServlet 一.介绍 Servlet接口定义了所有s ...
- Java EE javax.servlet.http中的HttpSession接口
HttpSession接口 public interface HttpSession (https://docs.oracle.com/javaee/7/api/javax/servlet/http/ ...
- Java EE javax.servlet.http中的HttpRequest抽象类
HttpRequest抽象类 public abstract class HttpServlet extends GenericServlet 实现的接口有:Serializable, Servlet ...
- Java EE javax.servlet中的ServletResponse接口
ServletResponse接口 public interface ServletResponse 子接口:HttpServletResponse 实现类:HttpServletResponseWr ...
随机推荐
- Spring学习(5):DI的配置
一. 一些概念 应用程序中说的依赖一般指类之间的关系. 泛化:表示类与类之间的继承关系.接口与接口之间的继承关系: 实现:表示类对接口的实现: 依赖:当类与类之间有使用关系时就属于依赖关系,不同于关 ...
- Homebrew1.5之后安装PHP和扩展
Homebrew 1.5 宣布放弃 homebrew/php, 转而使用homebrew/core维护, 详见https://brew.sh/2018/01/19/homebrew-1.5.0/ 于是 ...
- PropertyGrid中的枚举显示为中文
参考http://www.cnblogs.com/yank/archive/2011/09/17/2179598.html 在上述文档的基础上做了改进.从EnumConverter类派生 显示效果: ...
- Python序列之列表 (list)
作者博文地址:http://www.cnblogs.com/spiritman/ 列表是Python中最基本的数据结构,是Python最常用的数据类型.Python列表是任意对象的有序集合,通过索引访 ...
- Homebrew -- 安装与使用
使用 React Native,必须安装的依赖有:Node.Watchman 和 React Native 命令行工具以及 Xcode. 推荐使用Homebrew来安装 Node 和 Watchman ...
- Daily Scrum 11.10
今日完成任务: 1.加入更改头像功能 2.解决不发送激活邮件和重置密码邮件的问题 3.在服务器上部署网站 4.加入匿名提问功能 明日任务: 黎柱金 修改数据库用户表,实现用户积分管理功能 晏旭瑞 解决 ...
- TFS任务预览
不太熟悉TFS任务项的建立. 初步建立及按老师要求分配到个人的任务设置与时间安排如下: (长时间任务可由多人合作完成,具体根据情况迅速调整任务分配) 加上每人需要进行阅读前一小组的代码需要时间2*8= ...
- No.1011_第八次团队会议
罗老师和Bigman助教: 一直以来没看博客页面,我们的博客负责人不是没写博客,而是不小心把博客发到草稿上了.. 请您再次看一下我们的博客,并批评指正! 今天大家的情绪依旧很低落,离第一轮迭代完成距离 ...
- 2018-2019-20172329 《Java软件结构与数据结构》第七周学习总结
2018-2019-20172329 <Java软件结构与数据结构>第七周学习总结 教材学习内容总结 <Java软件结构与数据结构>第十一章-二叉查找树 一.概述 1.什么是二 ...
- 基于GUI的小学生四则运算系统
前言:首先在此感谢我的结对搭档,没有她的帮助和引导绝不会有现在的项目.很高兴和她一起结对完成这个项目.搭档真的是棒棒哒! 一.Coding.Net项目地址: https://git.coding.ne ...