[有书共读]Java Web高级编程
JavaWeb高级编程 -- 篇3
在Java EE平台中,Servlet用于接收和响应终端用户的请求。Servlet在Java EE API规范中的定义如下:
Servlet是一个运行在Web服务器中的Java小程序。Servlet将会接收和响应来自Web客户端的请求,使用HTTP进行通信。
创建Servlet
Servlet是所有Web应用程序的核心类,它是唯一的既可以直接处理和响应用户请求,也可以将处理工作委托给应用中的其它部分的类。
除非某些过滤器提前终止了客户端的请求,否则所有的请求都将被发送到某些Servlet中。
所有的Servlet都实现了javax.servlet.Servlet接口,但通常不是直接实现的。Servlet只是一个简单接口,它包含了初始化并销毁Servlet和处理请求的方法。
多数情况下,Servlet都继承自javax.servlet.GenericServlet。GenericServlet仍然是一个不依赖于具体协议的Servlet,它只包含一个抽象的service方法,但它同时也包含了几个辅助方法用于日志操作和从应用和Servlet配置中获取信息。
作为响应HTTP请求的java.servlet.http.HttpServlet,它继承了GenericServlet,并实现了只接受HTTP请求的service方法。然后它提供了响应每种HTTP方法类型的方法的空实现。
我们之后的Servlet将总是继承HTTPServlet。它的方法接收的是javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse参数。
eg:
import javax.servlet.http.HttpServlet; public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest r,HttpServletResponse ,re) throws ServletException,IOException{ response.getWriter().println("Hello, World") } }
以上,该Servlet即能够对GET请求做出响应,并在响应主体中显示出“Hello, World”。
初始化和销毁方法
@Override public void init() throws ServletException{ ... } @Override public void destroy(){ ... }
在Web容器启动Servlet时,会调用Servlet的init方法,有时也会在部署应用程序时调用该方法。
在容器关闭Servlet时,会调用destroy方法。
配置可部署的Servlet
在web-INF目录中创建web.xml文件,并对Servlet进行配置,使它可以正确地部署到服务器中。
向描述符中添加Servlet
如在web.xml中添加部署描述:
<?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>
示例中,<display-name></display-name>描述的为应用程序在应用服务器中显示的名字。<web-app></web-app>中version特性描述应用程序使用的Servlet API版本。
在该例中,init方法将在web应用程序启动后,第一个请求到达Servlet时调用,但是如果init需要花费过长时间来完成工作,则会导致第一个请求的时间被延长很多,因此我们可以在Servlet配置中进行调整,以让它在Web应用启动之后立即启动。
<servlet> <servlet-name>helloServlet</servlet-name> <servlet-class>com.wrox.HelloServlet</servlet-class> <load-on-start-up>1</load-on-start-up> </servlet>
如上,在<load-on-start-up>标签中设置1,使得Web容器在应用程序启动之后,立即启动Servlet。如果多个Servlet配置都包含了该标签,它们的启动顺序将按照标签内的值的大小顺序启动,1表示第一个启动,数字越大表示启动越晚。如果出现值相同的情况,则按照它们出现在配置文件中的顺序来启动。
使用配置文件来告诉Servlet来应该对哪些请求URL做出响应:
<servlet-mapping> <servlet-name>helloServlet</servlet-name> <url-pattern>/greeting</url-pattern> </servlet-mapping>
使用如上配置之后,所有访问应用程序相对URL/greeting的请求都将由helloServlet处理。
Web容器通过这种方式关联两个配置。
Servlet类的service方***处理所有到达的请求。最终,它必须根据所使用的协议解析并处理到达请求中的数据,然后返回客户端可接受的响应。
了解doGet、doPost和其他方法
HttpServletRequest接口是对ServletRequest的扩展,它将提供关于收到请求的额外的与HTTP协议相关的信息。它指定了多个可以获得HTTP请求的详细信息的方法。它也允许设置请求特性。
HttpServletREquest最重要的功能:从客户端发送的请求中获取参数。
请求参数有两种不同的形式:查询参数(也成为URI参数)、以application/x-www-form-urlencoded或multipart/form-data编码的请求正文。所有的请求方法都支持查询参数,它们被添加在HTTP请求的第一行数据中,如:
GET /index.jsp?productId=123456789&category=Book HTTP/1.1
例子中包含两个查询参数:productId和category。
方法getParameter将返回参数的单个数值。如果参数有多个数值,getParameter将返回第一个值,而getParameterValues将返回参数的值的数组。如果参数只有一个值,则返回只有一个值的数组。方法getParameterMap将返回一个包含了所有参数名值对的java.util.Map<String,String[]>,而getParameterNames方法将返回所有可用参数的名字的枚举。
方法getInputStream将返回一个javax.servlet.ServletInputStream,而方法getReader将返回一个java.io.BufferedReader,它们都可用于读取请求内容。如果请求内容是基于字符编码的,使用BufferedReader是最简单的方式,请求数据是二进制的,必须使用ServletInputStream,这样才可以访问字节格式的请求内容。永远不应该在同一请求上同时使用这两种方法。
HttpServletResponse继承了ServletResponse接口,提供了对响应中与HTTP协议相关的属性的访问。可以使用响应对象完成设置响应头、编写响应正文、重定向请求、设置HTTP状态码以及将Cookies返回到客户端等任务。
方法getOutputStream返回一个javax.servletServletOutputStream,而方法getWriter将返回一个java.io.PrintWriter,通过对它们都可以向响应中输出数据。
我们可以在Servlet中重写doGet和doPost方法来分别处理get和post请求。
需要注意的是,我们应该在Servlet的声明上进行注解,如:
@WebServlet{ name = "helloServlet", urlPatterns = {"/greeting","/wazzup"}, loadOnStartup = 1 } public class HelloServlet extends HttpServlet { ... }
如上所示,可以代替编写对用的XML。
<b>使用初始化参数配置应用程序</b>
虽然在Servlet类上的注解代替了在部署描述符文件中的Servlet声明和映射,但是存在其它的一些配置必须通过部署描述符才能完成。上下文初始化参数就是其中之一。在web.xml文件中使用<context-param》标签声明上下文初始化参数。
声明初始化参数举例:
<context-param> <param-name>setting</param-name> <param-value>value</param-value> </context-param>
在Servlet代码的任何地方都能够轻松获得和使用初始化参数,使用代码举例:
ServletContext sc = this.getServletContext(); sc.getInitParameter("setting");
或者:
定义:
<servlet> <servlet-name>...</servlet-name> <servlet-class>...</servlet-class> <init-param> <param-name>setting</param-name> <param-value>hello</param-value> </init-param> </servlet>
使用:
ServletConfig sc = this.getServletConfig(); sc.getInitParameter("setting");
Web应用程序是天然的多线程应用程序。Web容器中通常会包含某种类型的线程池,它们被称为连接池或执行池。当容器收到请求时,它将在池中寻找可用的线程。如果找不到可用的线程,并且线程池已经达到了最大线程数,那么该请求将被放入一个队列等待获得可用的线程。
#读书笔记##Java#