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 ...
随机推荐
- GNU Radio GRC HackRF实现FM接收
本文内容.开发板及配件仅限用于学校或科研院所开展科研实验! 淘宝店铺名称:开源SDR实验室 HackRF链接:https://item.taobao.com/item.htm?spm=a1z10.1- ...
- 第五章 if语句
5.2条件测试 使用==判断相当: 使用!=判断不相等: 每条if语句的核心都是一个值为Tre或False的表达式,这种表达式被称为条件测试,如果条件测试的值为Ture,则执行紧跟在if语句后面的代码 ...
- NO.8:自学python之路------并行socket网络编程
摘要 一到放假就杂事很多,这次的作业比较复杂,做了一个周,进度又拖了.不过结果还不错. 正文 粘包 在上一节中,如果连续发送过多数据,就可能发生粘包.粘包就是两次发送的数据粘在一起被接收,损坏了数据的 ...
- Trait 是什么东西
PHP官方手册里面写的内容是 自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait. Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制.Trait 为了减少 ...
- [linux] LVM磁盘管理(针对xfs和ext4不同文件系统)
简单来说就是:PV:是物理的磁盘分区VG:LVM中的物理的磁盘分区,也就是PV,必须加入VG,可以将VG理解为一个仓库或者是几个大的硬盘LV:也就是从VG中划分的逻辑分区如下图所示PV.VG.LV三者 ...
- C++:类中的赋值函数
先来看一个例子: #include<iostream> #include<string> using namespace std; class Student{ public: ...
- 【搜索】POJ-2718 全排列+暴力
一.题目 Description Given a number of distinct decimal digits, you can form one integer by choosing a n ...
- 团队作业2 <嗨,你的快递!>需求分析与原型设计
哦,不,是你的快速(*_*) 第一部分 需求分析 1.1 用户调研 1.1.1调研对象:由于我们的系统是校园快递代取业务,面向的是大学生活,所以本次调研范围都是在校大学生(除了师大学生,也包括了外校的 ...
- 开发模式 MVC、MVP、MVVM和MVX框架模式
MVX框架模式的了解 MVX框架模式:MVC+MVP+MVVM 1.MVC: Model(模型)+View(视图)+controller(控制器),主要是基于分层的目的,让彼此的职责分开.View通过 ...
- Linux服务器学习(二)
昨天简单了解了linux的基础命令,今天学习linux搭建环境(安装文件,配置文件)及权限操作. 一.搭建lnmp环境 lnmp指Linux+Nginx+Mysql+PHP Ubuntu安装文件命令为 ...