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.HttpServletRequestjavax.servlet.http.HttpServletResponse参数,而不是javax.servlet.ServletRequestjavax.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在各种不同方法中定义的HttpServletRequestHttpServletResponse参数,我们可以读取由客户端发送的参数、接受通过表单上传的文件、读取包含在请求正文中的原始数据、读取请求头和操作响应头,并将响应正文返回到客户端。

3.2 使用HttpServletRequest

HttpServletRequest接口是对ServletRequest的扩展。

HttpServletRequest最重要的功能是从客户端发送的请求中获取参数,请求参数有两种不同的形式:

  • 查询参数(URI参数)
  • application/x-www-form-urlencodedmultipart/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-urlencodedapplication/jsontext/plainapplication/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,通过它们都可以向响应中输出数据。

在向响应正文中输出数据时,可能需要设置内容类型或编码格式。可以通过setContentTypesetCharacterEncoding方法进行设置。如果计划在使用getWriter时调用setContentTypesetCharacterEncoding,那么必须在getWriter之前调用setContentTypesetCharacterEncoding,因为这样的getWriter方法返回的writer才能获得正确的字符编码设置。在getWriter调用之后调用的setContentTypesetCharacterEncoding将被忽略。

如果在调用getWriter之前未调用setContentTypesetCharacterEncoding,返回的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的更多相关文章

  1. Java EE javax.servlet中的ServletContext接口

    ServletContext接口 public interface ServletContext (https://docs.oracle.com/javaee/7/api/javax/servlet ...

  2. Java EE之servlet实现用户登录

    1.在连接数据库的JAVA类中添加查询功能: 在这之前有一个连接数据库的方法: Connection conn=null; PreparedStatement stat=null;           ...

  3. Java EE之servlet处理表单提交的请求

    1.在源包下新建一个Servlet页,取名为LoginServlet: package weinidingServlet;                            //该Servlet所 ...

  4. java EE :Servlet 接口

    Servlet 生命周期  : 调用当前 Servlet 类构造函数进行实例化 Servlet 通过调用 init () 方法进行初始化 Servlet 调用 service() 方法来处理客户端的请 ...

  5. Java EE javax.servlet中的RequestDispatcher接口

    RequestDispatcher接口 public interface RequestDispatcher 一.介绍 定义一个对象,从客户端接收请求并将其发送到服务器上的任何资源(例如servlet ...

  6. Java EE javax.servlet中的Servlet接口

    Servlet接口 public interface Servlet 其实现类有:FaceServlet.GenericServlet.HttpServlet 一.介绍 Servlet接口定义了所有s ...

  7. Java EE javax.servlet.http中的HttpSession接口

    HttpSession接口 public interface HttpSession (https://docs.oracle.com/javaee/7/api/javax/servlet/http/ ...

  8. Java EE javax.servlet.http中的HttpRequest抽象类

    HttpRequest抽象类 public abstract class HttpServlet extends GenericServlet 实现的接口有:Serializable, Servlet ...

  9. Java EE javax.servlet中的ServletResponse接口

    ServletResponse接口 public interface ServletResponse 子接口:HttpServletResponse 实现类:HttpServletResponseWr ...

随机推荐

  1. Spring学习(5):DI的配置

    一.  一些概念 应用程序中说的依赖一般指类之间的关系. 泛化:表示类与类之间的继承关系.接口与接口之间的继承关系: 实现:表示类对接口的实现: 依赖:当类与类之间有使用关系时就属于依赖关系,不同于关 ...

  2. Homebrew1.5之后安装PHP和扩展

    Homebrew 1.5 宣布放弃 homebrew/php, 转而使用homebrew/core维护, 详见https://brew.sh/2018/01/19/homebrew-1.5.0/ 于是 ...

  3. PropertyGrid中的枚举显示为中文

    参考http://www.cnblogs.com/yank/archive/2011/09/17/2179598.html 在上述文档的基础上做了改进.从EnumConverter类派生 显示效果: ...

  4. Python序列之列表 (list)

    作者博文地址:http://www.cnblogs.com/spiritman/ 列表是Python中最基本的数据结构,是Python最常用的数据类型.Python列表是任意对象的有序集合,通过索引访 ...

  5. Homebrew -- 安装与使用

    使用 React Native,必须安装的依赖有:Node.Watchman 和 React Native 命令行工具以及 Xcode. 推荐使用Homebrew来安装 Node 和 Watchman ...

  6. Daily Scrum 11.10

    今日完成任务: 1.加入更改头像功能 2.解决不发送激活邮件和重置密码邮件的问题 3.在服务器上部署网站 4.加入匿名提问功能 明日任务: 黎柱金 修改数据库用户表,实现用户积分管理功能 晏旭瑞 解决 ...

  7. TFS任务预览

    不太熟悉TFS任务项的建立. 初步建立及按老师要求分配到个人的任务设置与时间安排如下: (长时间任务可由多人合作完成,具体根据情况迅速调整任务分配) 加上每人需要进行阅读前一小组的代码需要时间2*8= ...

  8. No.1011_第八次团队会议

    罗老师和Bigman助教: 一直以来没看博客页面,我们的博客负责人不是没写博客,而是不小心把博客发到草稿上了.. 请您再次看一下我们的博客,并批评指正! 今天大家的情绪依旧很低落,离第一轮迭代完成距离 ...

  9. 2018-2019-20172329 《Java软件结构与数据结构》第七周学习总结

    2018-2019-20172329 <Java软件结构与数据结构>第七周学习总结 教材学习内容总结 <Java软件结构与数据结构>第十一章-二叉查找树 一.概述 1.什么是二 ...

  10. 基于GUI的小学生四则运算系统

    前言:首先在此感谢我的结对搭档,没有她的帮助和引导绝不会有现在的项目.很高兴和她一起结对完成这个项目.搭档真的是棒棒哒! 一.Coding.Net项目地址: https://git.coding.ne ...