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. GNU Radio GRC HackRF实现FM接收

    本文内容.开发板及配件仅限用于学校或科研院所开展科研实验! 淘宝店铺名称:开源SDR实验室 HackRF链接:https://item.taobao.com/item.htm?spm=a1z10.1- ...

  2. 第五章 if语句

    5.2条件测试 使用==判断相当: 使用!=判断不相等: 每条if语句的核心都是一个值为Tre或False的表达式,这种表达式被称为条件测试,如果条件测试的值为Ture,则执行紧跟在if语句后面的代码 ...

  3. NO.8:自学python之路------并行socket网络编程

    摘要 一到放假就杂事很多,这次的作业比较复杂,做了一个周,进度又拖了.不过结果还不错. 正文 粘包 在上一节中,如果连续发送过多数据,就可能发生粘包.粘包就是两次发送的数据粘在一起被接收,损坏了数据的 ...

  4. Trait 是什么东西

    PHP官方手册里面写的内容是 自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait. Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制.Trait 为了减少 ...

  5. [linux] LVM磁盘管理(针对xfs和ext4不同文件系统)

    简单来说就是:PV:是物理的磁盘分区VG:LVM中的物理的磁盘分区,也就是PV,必须加入VG,可以将VG理解为一个仓库或者是几个大的硬盘LV:也就是从VG中划分的逻辑分区如下图所示PV.VG.LV三者 ...

  6. C++:类中的赋值函数

    先来看一个例子: #include<iostream> #include<string> using namespace std; class Student{ public: ...

  7. 【搜索】POJ-2718 全排列+暴力

    一.题目 Description Given a number of distinct decimal digits, you can form one integer by choosing a n ...

  8. 团队作业2 <嗨,你的快递!>需求分析与原型设计

    哦,不,是你的快速(*_*) 第一部分 需求分析 1.1 用户调研 1.1.1调研对象:由于我们的系统是校园快递代取业务,面向的是大学生活,所以本次调研范围都是在校大学生(除了师大学生,也包括了外校的 ...

  9. 开发模式 MVC、MVP、MVVM和MVX框架模式

    MVX框架模式的了解 MVX框架模式:MVC+MVP+MVVM 1.MVC: Model(模型)+View(视图)+controller(控制器),主要是基于分层的目的,让彼此的职责分开.View通过 ...

  10. Linux服务器学习(二)

    昨天简单了解了linux的基础命令,今天学习linux搭建环境(安装文件,配置文件)及权限操作. 一.搭建lnmp环境 lnmp指Linux+Nginx+Mysql+PHP Ubuntu安装文件命令为 ...