Servlet
概述
Servlet是用java编写的服务器端程序 ,能够生成动态web内容 ,即Servlet是运行在Web服务器(如Tomcat),使用java编写的小应用程序
广义Servlet:实现了这个Servlet接口的类 (一般指广义)
狭义:java语言实现的一个接口
作用
渲染的是浏览器 ,通过浏览器客户端去访问Servlet .
接收浏览器请求并响应数据给浏览器
Servlet开发步骤
- 创建一个类去实现
javax.servlet.Servlet
接口 - 实现接口中的所有方法
- 在service方法处理请求和响应数据
- 配置Servlet访问地址 (让浏览器去访问) 通过web.xml配置 或者注解
为什么在service方法中处理请求和相应数据 ? 因为每一次请求都经过service方法
为什么要配置Servlet ?因为我们要找到它才能去访问它
public class ServletDemo implements Servlet {
public ServletDemo(){
//对象时单例的
System.out.println("ServletDemo.create");
}
//当Servlet被创建后,紧接着调用init方法来进行初始化
@Override
public void init(ServletConfig servletConfig) throws ServletException {
//init 只被调用一次 使用场景:可以在该方法进行一些初始化并耗时的操作
System.out.println("ServletDemo.init");
}
//每次请求,都会执行Servlet方法
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//每次请求都调用service方法 使用场景:处理每次的请求和相应
System.out.println("ServletDemo.service");
}
//当servlet退出服务的时候,服务器正常关闭 ,不正常关闭的时候不会调用该方法
@Override
public void destroy() {
System.out.println("ServletDemo.destroy");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
}
- 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_4_0.xsd"
version="4.0">
<!--1.servlet 和servlet-mapping 是一对 ,必须同时存在
2. servlet-name 这个标签体中的内容必须保持一致 ,一般使用Servlet类的名称
3.servlet-class这个标签体的内容必须使用Servlet这个类的全限定名
4.url-pattern这个标签体的内容,必须以 / 开头-->
<servlet>
<servlet-name>ServletDemo</servlet-name>
<servlet-class>cn.k.servlet.ServletDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
Servlet的生命周期
类的生命周期: 创建对象 --> 运作–>销毁
了解Servlet的生命周期构成
- Servlet对象是谁创建的 ,怎么创建的?
1.Servlet对象 是由Tomcat(服务器)创建的
2.创建Servlet对象,我们并没有去自己new一个对象 ,所以它是通过反射来创建的.
在web.xml中,我们配置了 类的全限定名 ,所以可以通过字节码来通过反射 创建真实对象 Class.forName("类的全限定名").newInstance(); 需要有公共无参构造
- Servlet对象是什么时候创建的?
默认情况下,通过浏览器 第一次访问服务器的时候,servlet被创建
- Servlet对象是什么时候销毁的?
服务器正常关闭或者重启时销毁
Servlet接口中生命周期方法
- 构造方法 : 对象实例化时执行,必须要有公共无参构造方法
void init(ServletConfig servletConfig)
:只被调用一次,可以在该方法进行一些初始化并耗时的操作void service(ServletRequest servletRequest, ServletResponse servletResponse)
:每次请求都会被执行void destroy()
:当servlet退出服务的时候,服务器正常关闭 ,不正常关闭的时候不会调用该方法
请求流程
http://localhost:8080/one/hello
访问项目路径 :/one
资源路径: /hello
浏览器发送请求,Tomcat接收到请求,解析请求地址并获取到要访问的项目和资源路径
以web.xml为例
-
启动Tomcat服务器会先扫描项目 ,解析web.xml文件加载进缓存,获取每一个Servlet的servlet-class访问地址(全限定类名)和url-pattern装进Map集合url-pattern作为key,servlet-class作为value ,从而获取到了一个map集合Map(String,String),
-
当服务器开始访问类的全限定名时,又会临时加载一个缓存,将servlet-class 作为key和 真实对象 作为value放进另一个map集合中Map(String,Object),
-
当访问类的全限定名时,会先判断map集合中value(真实对象)是否存在,如果没有存在,则通过反射 class.forName(“全限定类名”).newInstance来创建Servlet真实对象 ,servlet对象被创建后 Tomcat创建servletConfig调用init()来进行初始化 ,再创建servletRequst对象和servletResponse对象,如果本来存在了servlet对象 就不会调用init()了 ,所以Servlet是单例的
-
调用service方法,将servletRequst对象和servletResponse对象传递进来,通过response对象返回输出到浏览器,在浏览器中显示出来
Servlet的继承体系
继承GenericServlet
@WebServlet(value = "/hello1")
public class ServletDemo02 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
}
}
继承HttpServlet
如果Servlet使用的是Http协议,选择继承HttpServlet类
@WebServlet(value = "/hello1" )
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
继承HttpServlet 必须要重写 protect void service方法 ,不然报错405,不能调用父类super的service方法
ServletConfig对象
作用:用来封装Servlet初始化的时候的一些配置信息
为什么要配置初始化参数:能够解决硬编码的缺点,可以写在web.xml中,后期方便修改与维护
例如 :
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
通过 getInitParameter(“参数名”) ,得到value
loadOnStartup属性
让web容器启动的时候创建并初始化Servlet ,loadOnStartup =-1是默认值
@WebServlet(value = "/hello1" ,loadOnStartup = 1)
取值范围1到10 ,值越小越先加载
通配符
通配符格式 | 说明 |
---|---|
/* | 匹配所有的访问地址,必须一/开头 |
/目录名/* | 匹配目录下的所有地址 |
*.扩展名 | 匹配某个扩展名结尾的访问地址 *.html等 |
映射细节
servlet-name 不能用default 和jsp
优先级
**/**开头的优先级大于扩展名结尾 ,匹配原则:精准匹配
请求对象
HttpServletRequest
HttpServletRequest接口的实现类称为请求对象,请求对象封装了所有的请求信息(请求行,请求头,请求体)
常用方法
-
String getMethod()
:获得请求方式GET和POST -
String getRequestURI() :统一资源标识符,代表一个资源名字
-
StringBuffer getRequestURL() :统一资源定位符,代表一个可以访问地址
-
String getContextPath()
:获得上下文路径(项目名path) -
String getProtocol() :获得协议和版本
-
String getParameter(String name) :通过参数名得到参数值
注意:
URI ():统一资源标识符 : /request
UPL():统一资源定位符 : http://localhost:8080/request
//@WebServlet("/request")
public class HttpServletRequestDemo extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//必须放在service方法的第一行 处理的是post请求的乱码
req.setCharacterEncoding("utf-8");
//获取请求行的信息
//请求方式
System.out.println("req.getMethod() = " + req.getMethod());
//项目的映射路径
System.out.println("req.getContextPath() = " + req.getContextPath());
//协议
System.out.println("req.getProtocol() = " + req.getProtocol());
//获取请求头的信息 根据名字获取
System.out.println("req.getDateHeader(\"User-Agent\") = " + req.getDateHeader("User-Agent"));
//表单里接收的数据,都是以字符串的形式
//获取请求体中的数据 getParameter()只能获取一个value
String name = req.getParameter("name");
//获取多个value 可以使用 getParameterValues()
//使用getParameterMap()
Map<String, String[]> parameterMap = req.getParameterMap();
parameterMap.entrySet().forEach(x->System.out.println(x.getKey()+":"+ Arrays.toString(x.getValue())));
}
}
请求参数乱码问题
req.setCharacterEncoding(“utf-8”) 代码位置放在第一行
响应对象
什么是响应对象HttpServletResponse对象?
服务器响应数据给浏览器,响应数据中有(响应行,响应头,响应体),HttpServletRespouse对象封装了操作这些数据的方法.
方法
PrintWriter getWriter() :如果服务器端返回的是字符的文本数据,使用这个方法