四、Servlet介绍
Servlet入门
前言:
在前面的学习过程中,JavaWeb开发,其实是利用网络和HTTP协议,将服务端的数据,发送给客户端,且可以接收客户端的请求,并且对这个请求作出响应。基于这个原理,早期制定了一套根据这样的逻辑与客户端进行交互的接口,而各个服务器,则根据这个接口作出具体的实现。这样,在服务器端,就运行了一套程序,一套用于接收客户端请求,向客户端作出响应程序,这个程序就被称之为Servlet。
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。根据这点,Servlet本身也是一套规范(接口),也是一个具体运行在服务端程序。
狭义的Servlet是指Java语言实现的一个接口。
广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
由于,Servlet生成Web内容,都是使用Java代码生成,所以,开发WEB异常的麻烦。基于这点,Java在Servlet的基础上,衍生出了JSP模板基础,作为Servlet技术的补充点。所以,JSP与Servlet关系,JSP源于Servlet.
注意:
Servlet是服务器实现的一套规范,其具体的API是在服务器中,所以一般不需要导入任何jar包,一般使用服务器中内置jar包。
1.如何使用Servlet
-
创建类实现Servlet接口,实现相关方法
package com.sxt.controller; import java.io.IOException; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * @ClassName: MyServlet * @Description: 创建一个具体的Servlet * 1. 定义类实现Servlet接口 * 2. 重写相关方法 * @author: Mr.T * @date: 2020年2月11日 下午2:41:11 */ public class MyServlet implements Servlet{ @Override public ServletConfig getServletConfig() { System.out.println("==========config=========="); return null; } @Override public void init(ServletConfig arg0) throws ServletException { System.out.println("==========init=========="); } @Override public String getServletInfo() { return null; } @Override public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException { System.out.println("==========service=========="); } @Override public void destroy() { System.out.println("==========destroy=========="); } }
-
注册Servlet,配置对外访问的地址
程序是在服务器中运行的,如果创建类实现Servlet接口,此时只是创建了一个遵循Servlet规范的类。但是,Servlet本质是一个在服务器中运行的小程序。得通知服务器,我们创建了一个遵循Servlet规范的类,让服务器将这个类装载到Servlet容器中,所以需要进行配置。
在tomcat中,tomcat会默认监视:web.xml.而web.xml,是一个xml文件。xml中标签和节点,可以根据xml约束dtd等进行限定。这样就可以在web.xml中进行相关程序的配置,tomcat就可以对web.xml中的配置信息进行解析。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>07servlet01</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- 注入servlet --> <servlet> <!-- servlet别名 方便使用 --> <servlet-name>chengfusheng</servlet-name> <!-- servlet本质上一个类,包名.类名 类的全路径 --> <servlet-class>com.sxt.controller.MyServlet</servlet-class> <!-- 以上配置是告诉服务器,有一个servlet 可以被使用,servlet的功能是接收客户端的数据 作出响应 所以得配置一个网络地址,便于客户端进行访问 --> </servlet> <!-- 配置网络映射地址 用于客户端访问--> <servlet-mapping> <servlet-name>chengfusheng</servlet-name> <url-pattern>/ergou.do</url-pattern> </servlet-mapping> </web-app>
3.客户端访问Servlet
2.Servelt被调用的流程
servlet被调用的原理.pngservlet调用顺序.png
3.Servlet的三种实现方式
方式一:直接实现Servlet接口,参看上面示例。
方式二:继承GenericServlet
/**
* @ClassName: MyServlet02
* @Description: 实现Servlet的第二种方式
* @author: Mr.T
* @date: 2020年2月11日 下午4:02:12
*/
public class MyServlet02 extends GenericServlet{
/**
* 序列号
* servlet类主要用于与客户进行数据交互.一般需要将数据序列化进行传输。
* 如果没有序列化号,1.安全性存在问题. 2.在实际使用中,很多框架,需要存在需要列号,会出现null的 问题。
*/
private static final long serialVersionUID = -4448635233323484080L;
/**
* service 方法 servlet 提供具体的服务的方法
*/
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
}
}
<!-- 配置servlet -->
<servlet>
<servlet-name>suxiaoxiao</servlet-name>
<servlet-class>com.sxt.controller.MyServlet02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>suxiaoxiao</servlet-name>
<url-pattern>/suxiaoxiao.do</url-pattern>
</servlet-mapping>
方式三:继承HttpServlet
package com.sxt.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @ClassName: MyServlet03
* @Description: servlet的第三种方式
* @author: Mr.T
* @date: 2020年2月11日 下午4:09:18
*/
public class MyServlet03 extends HttpServlet {
private static final long serialVersionUID = -91495684423730465L;
/**
* 重写父类中的service
* 此时 service中的参数:HttpServletRequest HttpServletResponse
* 这个方法的功能是最强大的
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("service");
resp.getWriter().print("Hello HttpServlet");
}
}
<!-- 配置servlet -->
<servlet>
<servlet-name>myServlet03</servlet-name>
<servlet-class>com.sxt.controller.MyServlet03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet03</servlet-name>
<url-pattern>/myServlet03.do</url-pattern>
</servlet-mapping>
注意:
在实际使用中,Servlet一般使用第三种方式,因为第三种方式定制化更强。并且提供了专门根据客户端请求的方法的不同,提共了专门的处理方法。会根据客户端method的值的不同,进行相应的方法调用。
HttpServlet.png4.Servlet的生命周期
servlet的生命周期,其实是指Servlet类的对象的生命周期,是指Servlet类对象的初始化,及Servlet类对象的销毁。
package com.sxt.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
/**
* @ClassName: LifeCycleServlet
* @Description: 此Servlet类,用于演示Servlet的生命周期
* @author: Mr.T
* @date: 2020年2月11日 下午4:45:57
*/
public class LifeCycleServlet extends HttpServlet {
private static final long serialVersionUID = -4411061286729536572L;
/**
* 当servlet 对象创建后 需要对属性进行初始化 可以调用 init
* 且 init 方法只会执行一次
*/
@Override
public void init() throws ServletException {
System.out.println("==============init 出生了=============");
}
/**
* 当有请求,访问当前servlet,那么将有service处理当前请求,每次请求都会调用service
* 有多少次请求,那么service就会被调用多少次
*/
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("=============service 开始打工=================");
}
/**
* destory 方法,当服务器停止,开始释放内存,此时调用destory 方法,且只会调用一次。
*/
@Override
public void destroy() {
System.out.println("=================destory 悄悄的离开了=================");
}
}
注意:
1.生命周期
Servlet中的init方法,只会执行一次,当servlet对象被初始化后执行一次,进行对象属性值的初始化。
Servlet中的service方法,是处理具体的请求的方法,每次请求时都会执行。
Servlet中destory方法,是用于Servlet对象要被销毁时调用的方法。只会执行一次。可以将内存中的数据,在销毁前做一些处理。
2.Servlet生命周期引发的线程安全问题
在Servlet中,每个Servlet默认只会创建一个实例对象,Servlet是单例的。所以,Servlet是非线程安全的。
在使用Servlet时,不要使用成员变量。
3.Servlet的初始化
默认Servlet是在第一被请求时,才会进行Servlet对象的创建,调用init方法,进行属性的初始化。
但是,可以通过在web.xml中配置Servlet的初始化时机,配置信息如下:
<!-- 配置servlet -->
<servlet>
<servlet-name>LifeCycleServlet</servlet-name>
<servlet-class>com.sxt.controller.LifeCycleServlet</servlet-class>
<!--
初始的参数
如果多组参数 使用 多个 init-param 标签
-->
<init-param>
<param-name>key1</param-name>
<param-value>value1</param-value>
</init-param>
<init-param>
<param-name>key2</param-name>
<param-value>value2</param-value>
</init-param>
<!--
配置servlet的初始时机
只要值大于 0 那么,当服务器启动时就会进行该Servlet的初始化 就会创建该Servlet对象
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>LifeCycleServlet</servlet-name>
<url-pattern>/lifeCycle.do</url-pattern>
</servlet-mapping>
@Override
public void init() throws ServletException {
//获取Servlet配置对象
ServletConfig servletConfig = this.getServletConfig();
//通过ServletConfig 对象拿到配置参数
System.out.println(servletConfig.getInitParameter("key1"));
System.out.println(servletConfig.getInitParameter("key2"));
System.out.println(this);
System.out.println("==============init 出生了=============");
}
5.Servlet使用
Servlet主要功能就是接受客户端的请求,对客户端作出响应。而这个功能由Servlet中的service方法实现,所以Servlet使用,就是service方法的使用,service方法,有ServletRequest和ServletResponse.
ServletRequest,是服务器,将所有的请求信息封装在该对象
ServletResponse,是服务器,将响应信息,封装在该对象中。
而HttpServletRequest是ServletRequest的一个子类,HttpServletResponse是ServletResponse的子类。
5.1.HttpServletRequest使用
package com.sxt.controller;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.tribes.util.Arrays;
/**
* @ClassName: ServletMethod
* @Description: 该方法主要用于演示 Servlet中 request 和 response的核心方法
* @author: Mr.T
* @date: 2020年2月11日 下午5:38:10
*/
public class ServletMethod extends HttpServlet {
private static final long serialVersionUID = -6390310195529724055L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//getHttpInfo(req,resp);
getRequestParam(req,resp);
}
/**
* @Title: getHttpInfo
* @author: Mr.T
* @date: 2020年2月11日 下午5:39:36
* @Description: 获取Http请求信息
* @return: void
*/
public void getHttpInfo(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取HTTP请求的method值 : get post 等等
String method = req.getMethod();
System.out.println(method);
//获取HTTP请求的URL地址
StringBuffer url = req.getRequestURL();
System.out.println(url);
//获取请求的资源路径
String uri = req.getRequestURI();
System.out.println(uri);
//获取请求协议
String protocol = req.getProtocol();
System.out.println(protocol);
//获取本地端口
int localPort = req.getLocalPort();
System.out.println(localPort);
//获取请求头 请求头是 key - value
String host = req.getHeader("Host");
System.out.println(host);
}
/**
* @Title: getRequestParam
* @author: Mr.T
* @date: 2020年2月11日 下午5:49:25
* @Description: 获取请求参数
* @param req
* @param resp
* @throws ServletException
* @throws IOException
* @return: void
*/
public void getRequestParam(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求参数编码格式
req.setCharacterEncoding("UTF-8");
//getParameter(name) : 根据name值 获取对应提交的参数
String name = req.getParameter("name");
System.out.println(name);
//getParameterValues(name) :根据name值 获取对应提交的参数,一般用于数组类型的数据,例如复选框
String[] likes = req.getParameterValues("like");
System.out.println("爱好:"+Arrays.toString(likes));
//获取所有的请求参数的name值
Enumeration<String> parameterNames = req.getParameterNames();
while(parameterNames.hasMoreElements()) {
//循环遍历所有的参数的名称
System.out.println(parameterNames.nextElement());
}
//将请求参数封住成一个Map
Map<String, String[]> parameterMap = req.getParameterMap();
System.out.println(parameterMap);
//进行页面跳转 内部转发
req.getRequestDispatcher("index.jsp").forward(req, resp);
}
/**
* @Title: attributeMethod
* @author: Mr.T
* @date: 2020年2月11日 下午6:09:26
* @Description: request 属性相关方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
* @return: void
*/
public void attributeMethod(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 向request 作用域设置属性值
//req.setAttribute(name, o);
//从request 作用域中取值
//req.getAttribute(name)
// 获取request 作用域中所有的属性name值
}
/**
* @Title: scope
* @author: Mr.T
* @date: 2020年2月11日 下午6:11:15
* @Description: 根据request 对象 获取其他作用域
* @param req
* @param resp
* @throws ServletException
* @throws IOException
* @return: void
*/
public void scope(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//根据request 获取与之关联的session
req.getSession();
// 获取application作用域
req.getServletContext();
}
}
5.2.HttpServletResponse使用
/**
* @Title: responseMethod
* @author: Mr.T
* @date: 2020年2月11日 下午6:14:06
* @Description: response 响应对象中的核心方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
* @return: void
*/
public void responseMethod(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应数据的编码
resp.setCharacterEncoding("UTF-8");
//设置响应头信息
resp.addHeader("key11111111111", "value11111222222");
// 获取打印流对象 向客户端输出数据 一般是文本数据
//PrintWriter writer = resp.getWriter();
//writer.print("Hello Servlet");
// 设置Cookie addCookie
//resp.addCookie(cookie);
//获取字节输出流 一般用于文件下载
//ServletOutputStream outputStream = resp.getOutputStream();
//地址跳转 重定向
resp.sendRedirect("index.jsp");
}
}