最近学到了JavaWeb阶段,随手进行总结:
一、Servlet介绍
1.Servlet概述
Servlet是JavaEE规范之一,是一个运行在web服务端的java小程序,它可以用于接收和响应客户端的请求。
2.Servlet的实现方法
1.实现Servlet接口
需要重写Servlet接口中所有的抽象方法
2.继承GenericServlet
只需要重写Service()方法
3.继承HttpServlet
只需要重写doGet()和doPost()方法
3.Servlet的执行过程
浏览器输入url,敲回车访问服务器,整个资源的查找过程:
通过浏览器发送请求,请求首先到达Tomcat服务器,然后Tomcat服务器会解析请求url,然后根据url中的虚拟目录在部署的应用列表 找到相应的web应用。接下来,找到web.xml配置文件,在web.xml中,根据<servlet-mapping>中的<servlet-name>找到<servlet>中的<servlet-name>,根据<servlet-name>找到<servlet-class>具体的Servlet文件,找到后执行service方法或者doGet()/doPost()方法,最后由Servlet响应给客户端浏览器。
总结:浏览器——>Tomcat服务器——>我们的应用——>应用中的web.xml——>FirstServlet——>响应浏览器
4.Servlet的细节
Servlet:接口
--GenericServlet:抽象的实现类
--HttpServlet:抽象的子类
二、Servlet-HttpServlet
这里着重讲HttpServlet,因为在用的最多的就是继承HttpServlet
1.HttpServlet的优势
HttpServlet做了Http协议相关的细节封装,可以简化程序员的开发,并且继承了HttpServlet后,只需要重写doGet/doPost方法,这里先做一下简单介绍,后面会详细讲解
2.Servlet的生命周期
Servlet的生命周期分为三个阶段,分别是init、service、destroy
init:在Servlet对象创建的时候(浏览器第一次访问的时候)执行,只会执行一次;一般用来做加载资源等初始化动作
service:每次浏览器访问资源,都会执行一次,提供服务。 执行多次
destroy:在Servlet对象销毁(tomcat正常关闭)之前执行,只会执行一次;一般用来做释放资源等动作
3.Servlet的线程安全问题
3.1 Servlet产生线程安全问题的原因
回顾多线程安全问题产生原因:
1.多线程程序
2.多个线程共享资源
3.多个线程同时对共享资源进行增删改的操作
而tomcat提供的Servlet:
1.tomcat是一个多线程程序,每一次用户请求,tomcat都会使用一个子线程来提供服务
2.多次请求,访问同一个Servlet类(一个Servlet类,在内存中只有一个对象),使用的都是同一个Servlet对象,成员变量也是同一份;
3.多个请求都会修改同一份成员变量
示例:
/**
* 演示Servlet的线程安全问题:
* 示例需求:
* 模拟网上看书的翻页功能。
* (类似的有浏览商品的翻页,浏览论坛帖子的翻页)
* @author
* @Company
*/
public class ServletDemo4 extends HttpServlet {
/**
* 我们讨论的是类成员的线程安全问题,所以要定义一个类成员
*/
//定义浏览书籍的页码,都是从第一页开始的
private int currentPage = 1;
/**
* 真正翻页看书的功能
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取当前要看的书名(此处我们今天先来用以下,明天来着重讲解请求和响应对象)
String bookName = req.getParameter("bookName");
//2.输出书名和当前页码
System.out.println("您看的是:"+bookName+",当前页码是:"+currentPage);
//3.执行翻页
currentPage++;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
理想状态下,用户每次请求都来看自己该看的页码,但是结果并不是,所以它是线程不安全的。
3.2解决Servlet线程安全问题
1.不声明成员变量(推荐);
2.加同步代码块
4.Servlet不同映射方式
第一种:指名道姓的方式
此种方式,只有和映射配置一模一样时,Servlet才会接收和响应来自客户端的请求。
第二种:/开头+通配符的方式
此种方式,只要符合目录结构即可,不用考虑结尾是什么。
第三种:通配符+固定格式结尾
此种方式,只要符合固定结尾格式即可,其前面的访问URI无须关心(注意协议,主机和端口必须正确)
拓展:多路径映射Servlet
在web.xml配置Servlet,可以配置多个不同的路径,实现同一个Servlet来执行不同的代码
public class ServletDemo7 extends HttpServlet {
/**
* 根据不同的请求URL,做不同的处理规则
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取当前请求的URI
String uri = req.getRequestURI();
uri = uri.substring(uri.lastIndexOf("/"),uri.length());
//2.判断是1号请求还是2号请求
if("/servletDemo7".equals(uri)){
System.out.println("ServletDemo7执行1号请求的业务逻辑:商品单价7折显示");
}else if("/demo7".equals(uri)){
System.out.println("ServletDemo7执行2号请求的业务逻辑:商品单价8折显示");
}else {
System.out.println("ServletDemo7执行基本业务逻辑:商品单价原价显示");
}
}
/**
* 调用doGet方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
在web.xml中配置Servlet
<!--配置ServletDemo7-->
<servlet>
<servlet-name>servletDemo7</servlet-name>
<servlet-class>com.itheima.web.servlet.ServletDemo7</servlet-class>
</servlet>
<!--映射路径1-->
<servlet-mapping>
<servlet-name>servletDemo7</servlet-name>
<url-pattern>/demo7</url-pattern>
</servlet-mapping>
<!--映射路径2-->
<servlet-mapping>
<servlet-name>servletDemo7</servlet-name>
<url-pattern>/servletDemo7</url-pattern>
</servlet-mapping>
<!--映射路径3-->
<servlet-mapping>
<servlet-name>servletDemo7</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
5.Servlet的创建时机
Servlet默认创建时机:浏览器第一次访问创建
可以设置Servlet在服务器启动加载时就创建:
在web.xml中的servlet标签中:
<load-on-startup>正整数</load-on-startup>即可
<!--配置ServletDemo3-->
<servlet>
<servlet-name>servletDemo3</servlet-name>
<servlet-class>com.itheima.web.servlet.ServletDemo3</servlet-class>
<!--配置Servlet的创建顺序,当配置此标签时,Servlet就会改为应用加载时创建
配置项的取值只能是正整数(包括0),数值越小,表明创建的优先级越高
-->
<load-on-startup>1</load-on-startup>
</servlet>
6.默认Servlet
默认Servlet是由服务器提供的一个Servlet,它配置在Tomcat的conf目录下的web.xml中,它的映射路径是<url-pattern>/<url-pattern>
,我们在发送请求时,首先会在我们应用中的web.xml中查找映射配置,找到就执行,这块没有问题。但是当找不到对应的Servlet路径时,就去找默认的Servlet,由默认Servlet处理。所以,一切都是Servle。
三、ServletConfig
1.ServletConfig概述
1.1基本概念
它是Servlet的配置参数对象,在Servlet规范中,允许为每个Servlet都提供一些初始化配置。所以,每个Servlet都一个自己的ServletConfig。它的作用是在Servlet初始化期间,把一些配置信息传递给Servlet。
1.2生命周期
由于它是在初始化阶段读取了web.xml中为Servlet准备的初始化配置,并把配置信息传递给Servlet,所以生命周期与Servlet相同。这里需要注意的是,如果Servlet配置了<load-on-startup>1</load-on-startup>
,那么ServletConfig也会在应用加载时创建
1.3配置ServletConfig
使用<servlet>
标签中的<init-param>
标签来配置。Servlet的初始化参数都是配置在Servlet的声明部分的。并且每个Servlet都支持有多个初始化参数,并且初始化参数都是以键值对的形式存在的
<!--配置ServletDemo8-->
<servlet>
<servlet-name>servletDemo8</servlet-name>
<servlet-class>com.itheima.web.servlet.ServletDemo8</servlet-class>
<!--配置初始化参数-->
<init-param>
<!--用于获取初始化参数的key-->
<param-name>encoding</param-name>
<!--初始化参数的值-->
<param-value>UTF-8</param-value>
</init-param>
<!--每个初始化参数都需要用到init-param标签-->
<init-param>
<param-name>servletInfo</param-name>
<param-value>This is Demo8</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo8</servlet-name>
<url-pattern>/servletDemo8</url-pattern>
</servlet-mapping>
1.4常用方法
/**
* 演示Servlet的初始化参数对象
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public class ServletDemo8 extends HttpServlet {
//定义Servlet配置对象ServletConfig
private ServletConfig servletConfig;
/**
* 在初始化时为ServletConfig赋值
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
this.servletConfig = config;
}
/**
* doGet方法输出一句话
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.输出ServletConfig
System.out.println(servletConfig);
//2.获取Servlet的名称
String servletName= servletConfig.getServletName();
System.out.println(servletName);
//3.获取字符集编码
String encoding = servletConfig.getInitParameter("encoding");
System.out.println(encoding);
//4.获取所有初始化参数名称的枚举
Enumeration<String> names = servletConfig.getInitParameterNames();
//遍历names
while(names.hasMoreElements()){
//取出每个name
String name = names.nextElement();
//根据key获取value
String value = servletConfig.getInitParameter(name);
System.out.println("name:"+name+",value:"+value);
}
//5.获取ServletContext对象
ServletContext servletContext = servletConfig.getServletContext();
System.out.println(servletContext);
}
/**
* 调用doGet方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
四、ServletContext
1、ServletContext概述
ServletContext对象,它是应用上下文对象。每一个应用有且只有一个ServletContext对象。它可以实现让应用中所有Servlet间的数据共享。
2、ServletContext生命周期
出生——活着——死亡
出生: 应用一加载,该对象就被创建出来了。一个应用只有一个实例对象。(Servlet和ServletContext都是单例的)
活着:只要应用一直提供服务,该对象就一直存在。
死亡:应用被卸载(或者服务器挂了),该对象消亡。
3、域对象概念
域对象的概念,它指的是对象有作用域,即有作用范围。域对象的作用,域对象可以实现数据共享。不同作用范围的域对象,共享数据的能力不一样。在Servlet规范中,一共有4个域对象。今天我们讲解的ServletContext就是其中一个。它也是我们接触的第一个域对象。它是web应用中最大的作用域,叫application域。每个应用只有一个application域。它可以实现整个应用间的数据共享功能。
4、获取ServletContext
public class ServletDemo9 extends HttpServlet {
//定义Servlet配置对象ServletConfig
private ServletConfig servletConfig;
/**
* 在初始化时为ServletConfig赋值
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
this.servletConfig = config;
}
/**
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取ServletContext对象
ServletContext servletContext = servletConfig.getServletContext();
System.out.println(servletContext);
}
/**
* 调用doGet方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
4、配置ServletContext
<!--配置应用初始化参数-->
<context-param>
<!--用于获取初始化参数的key-->
<param-name>servletContextInfo</param-name>
<!--初始化参数的值-->
<param-value>This is application scope</param-value>
</context-param>
<!--每个应用初始化参数都需要用到context-param标签-->
<context-param>
<param-name>globalEncoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
暂时只总结到这里,在后续学习还会继续总结,希望大家多多指导!