Servlet 是 JavaWeb 的三大组件之一,它属于动态资源。Servlet 的作用是处理请求,服务器会把接收到的请求交给 Servlet 来处理,在 Servlet 中需要:
我们先创建一个实例来实现 Servlet 接口:
public class Servlet01 implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
可以看到该实例默认实现了5个方法,我们主要讲解其中的3个。
方法:
service
(ServletRequest request, ServletResponse response):每次处理请求时都会被调用;特征:
web.xml
中配置。
创建一次
,当访问 Servlet 时, 服务器会首先检查该 Servlet 是否创建过,如果创建过直接拿过来用,如果没有才会通过反射来创建该 Servlet 实例。
init()
方法,而且这个方法之后被调用一次,所以一些对 Servlet 的初始化操作可以放在该方法中。
当服务器每次接收到请求时,都会调用 service
方法,该方法是会被多次调用的。
destroy
方法,然后销毁 Servlet,我们可以将一些资源的释放放到该方法中。在 Servlet 中有三个接口类型的参数:
init()
方法的参数,它表示Servlet配置对象,它对应Servlet的配置service()
方法的参数,它表示请求对象,它封装了所有与请求相关的数据,里面全是请求头之类get
方法,它是由服务器创建的;service()
方法的参数,它表示响应对象,里面很多响应的set
方法,在 service() 方法中完成对客户端的响应需要使用这个对象;ServletRequest 和 ServletResponse 是 Servlet 的
service()
方法的两个参数:
一个是请求对象
,可以从 ServletRequest 对象中获取请求数据;
一个是响应对象
,可以使用 ServletResponse 对象完成响应。
service
方法,如果要使用 HTTP 相关内容,那么需要将 ServletRequest 强转成 HttpServletRequest ,这很烦,因为我们经常要这么做,后面有一个类可以解决这个问题。request.setCharacterEncoding(“utf-8”)之后,再通过
getParameter()
方法获取参数值时,那么参数值都已经通过了转码,即转换成了UTF-8编码。所以,这个方法必须在调用 getParameter() 方法之前调用!
setHeader(“Refresh”, “5;url=http://www.baidu.cn”)
,表示 5 秒后自动刷新到http://www.baidu.cn;
setContentType
(String contentType):该方法是 setHeader(“content-type”, “xxx”) 的简便方法,即用来添加名为content-type
响应头的方法。content-type响应头用来设置响应数据的MIME
类型。
-例如要向客户端响应 jpg 的图片,那么可以 setContentType(“image/jepg
”) ,如果响应数据为文本类型,那么还要同时设置编码
-例如setContentType(“text/html;chartset=utf-8
”)表示响应数据类型为文本类型中的html类型,并且该方法会调用 setCharacterEncoding(“utf-8”) 方法;
Servlet 的配置信息,即
web.xml
文件中的<servlet>
元素。
<servlet-name>
通常我们会去继承 HttpServlet 类来完成我们的 Servlet
GenericServlet是Servlet接口的实现类,我们可以通过继承GenericServlet来编写自己的Servlet。
GenericServlet 还实现了ServletConfig 接口,所以可以直接调用getInitParameter()、getServletContext() 等 ServletConfig 的方法。
源代码:
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
public GenericServlet() {
}
public void destroy() {
}
public String getInitParameter(String name) {
return this.getServletConfig().getInitParameter(name);
}
public Enumeration<String> getInitParameterNames() {
return this.getServletConfig().getInitParameterNames();
}
public ServletConfig getServletConfig() {
return this.config;
}
public ServletContext getServletContext() {
return this.getServletConfig().getServletContext();
}
public String getServletInfo() {
return "";
}
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
public void log(String msg) {
this.getServletContext().log(this.getServletName() + ": " + msg);
}
public void log(String message, Throwable t) {
this.getServletContext().log(this.getServletName() + ": " + message, t);
}
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
public String getServletName() {
return this.config.getServletName();
}
}
HttpServlet 类是 GenericServlet 的子类,它提供了对 HTTP 请求的特殊支持,所以通常我们都会通过继承 HttpServlet 来完成自定义的 Servlet 。
service(HttpServletRequest,HttpServletResponse)
方法,这个方法是 HttpServlet 自己的方法,不是从 Servlet 继承来的。在 HttpServlet的service(ServletRequest,ServletResponse) 方法中会把ServletRequest和ServletResponse 强转成 HttpServletRequest 和 HttpServletResponse ,然后调用,所以这样一来就不用我们自己强转了。
覆盖 doGet() 或 doPost()
方法即可。
1、< load-on-startup >
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>cn.lsu.servlet.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
在<servlet>
元素中配置<load-on-startup>
元素可以让服务器在启动时就创建该Servlet,其中<load-on-startup>
元素的值必须是大于等于的整数,它的使用是服务器启动时创建 Servlet 的顺序。
2、< url-pattern >
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<url-pattern>
是<servlet-mapping>
的子元素,用来指定Servlet的访问路径,即URL。
可以在<servlet-mapping>
中给出多个<url-pattern>
,这样它所绑定的所有
的 URL 都是指向这个 Servlet 的。
还可以使用通配符:
<url-pattern>.do</url-pattern>:/abc/def/ghi.do、/a.do,都匹配
<url-pattern>/*<url-pattern>:匹配所有URL;
在 Tomcat 的conf/web.xml
路径下有一个所有的 web.xml
共同的父文件。
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<!-- 这里省略了大概4000多行的MIME类型的定义,这里只给出两种MIME类型的定义 -->
<mime-mapping>
<extension>bmp</extension>
<mime-type>image/bmp</mime-type>
</mime-mapping>
<mime-mapping>
<extension>htm</extension>
<mime-type>text/html</mime-type>
</mime-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
服务器会为每个应用创建一个 ServletContext 对象:
ServletContext 对象的作用 是在整个Web应用
的动态资源之间共享数据
!
ServletConfig
下的 getServletContext();GenericServlet
下的 getServletContext();(包括子类 HttpServlet )在 Servlet 中获取 ServletContext 对象:
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) {
ServletContext context = this.getServletContext();
}
}
ServletContext是JavaWeb四大域对象之一:
所有域对象都有存取数据的功能,因为域对象内部有一个`Map`,用来存储数据
setAttribute
(String name, Object value):用来存储一个对象;getAttribute
(String name):用来获取ServletContext中的数据;1、应用初始化参数
该参数是每个 Servlet 独有的,是局部参数。
2、公共初始化参数
该参数为所有 Servlet 都可用。
可以在 web.xml
中配置:
<web-app ...>
...
<context-param>(为ServletContext设置的公共初始化参数)
<param-name>paramName1</param-name>
<param-value>paramValue1</param-value>
</context-param>
<context-param>
<param-name>paramName2</param-name>
<param-value>paramValue2</param-value>
</context-param>
</web-app>
使用域对象获取:
ServletContext context = this.getServletContext();
String value1 = context.getInitParameter("paramName1");
String value2 = context.getInitParameter("paramName2");
服务器每次收到请求时,都会为这个请求开辟一个新的线程。
request 是 Servlet.service() 方法的一个参数,类型为javax.servlet.http.HttpServletRequest
。在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用 Servlet.service() 方法时传递给 service() 方法,这说明在 service() 方法中可以通过 request 对象来获取请求数据。
request的功能可以分为以下几种:
一个请求会创建一个request对象,如果在一个请求中经历了多个 Servlet ,那么多个 Servlet 就可以使用 request 来共享数据
。
request 的域方法同 ServletContext 的域方法。
setAttribute
(String name, Object value):用来存储一个对象;getAttribute
(String name):用来获取ServletContext中的数据;1、获取请求头数据:
2、获取请求相关的其它方法:
getContextPath()
:返回上下文路径(/项目名),例如:/hellogetRequestURI()
:返回请求URI路径,例如:/hello/oneServlethttp://localhost/hello/oneServlet
,即返回除了参数以外的路径信息;getRemoteAddr()
:返回当前客户端的IP地址;防盗链的应用:
可以使用request.getAttribute(“Referer”)
如果不是当前页面,那么属于盗链,则跳转到当前页面如果是从地址栏直接输入URL,那么Referee返回的是null。
response 是 Servlet # service 方法的一个参数,类型为javax.servlet.http.HttpServletResponse
。在客户端发出每个请求时,服务器都会创建一个 response 对象,并传入给 Servlet.service() 方法。response 对象是用来对客户端进行响应的,这说明在 service() 方法中使用 response 对象可以完成对客户端的响应工作。
response
对象的功能分为以下四种:
response是响应对象,向客户端输出响应正文(响应体) 可以使用response的响应流:
如果响应正文内容为字符(html),那么使用response.getWriter(),如果响应内容是字节(图片等),例如下载时,那么可以使用response.getOutputStream()
在一个请求中,不能同时使用这两个流!
setCharaceterEncoding
(“utf-8”) 来设置。这样可以保证输出给客户端的字符都是使用UTF-8编码的!
setContentType
(“text/html;charset=utf-8”)方法比较好,因为这个方法不只会调用response.setCharaceterEncoding(“utf-8”),还会设置content-type响应头,客户端浏览器会使用 content-type 头来解读响应数据。
缓冲区:
8KB
。也就是说,在响应数据没有输出8KB之前,数据都是存放在缓冲区
中,而不会立刻发送到客户端。当 Servlet 执行结束后,服务器才会去刷新流,使缓冲区中的数据发送到客户端。字节响应流:
将一张图片转为字节流写入到response中
//读取图片,使用commons-io包的方法。
byte[] image = IOUtils.toByteArray(new FileInputStream(this.getServletContext().getRealPath("/images/cat.jpeg")));
response.getOutputStream().write(image);
可以使用 response 对象的setHeader()
方法来设置响应头!使用该方法设置的响应头最终会发送给客户端浏览器!
response.setHeader("Refresh","5; URL=http://www.baidu.cn"):5秒后自动跳转到百度主页。
当你访问
http://www.sun.com
时,你会发现浏览器地址栏中的URL会变成http://www.oracle.com/us/sun/index.html
,这就是重定向了。
重定向是服务器通知浏览器去访问另一个地址,即再发出另一个请求。
1、设置响应码
2、设置Location头
Location
头,指定第二个请求的URL地址。public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setStatus(302);
response.setHeader("Location", "http://www.baidu.cn");
}
}
当访问 AServlet 后,会通知浏览器重定向到百度主页。客户端浏览器解析到响应码为302后,就知道服务器让它重定向,所以它会马上
获取响应头Location,然发出第二个请求。
不过有更方便的方法:
response.sendRedirect()方法会设置响应头为302,以设置Location响应头。
如果要重定向的URL是在同一个服务器内,那么可以使用相对路径,例如:
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendRedirect("/hello/BServlet");
//注意是-/项目名/路径(请求URI)
}
}
GET请求和POST请求的区别:
GET请求:
POST请求:
无论是请求转发还是请求包含,都表示由多个 Servlet 共同来处理一个请求。例如 Servlet1 来处理请求,然后 Servlet1 又转发给 Servlet2 来继续处理这个请求。
在AServlet中,把请求转发到BServlet:
参数是Servlet路径(servlet-mapping
中的url-pattern
)—相当于/项目名
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher rd = request.getRequestDispatcher("/BServlet");
rd.forward(request, response);
}
转发是由服务端
进行的页面跳转:
重定向是由客户端
进行的页面跳转: