JavaWeb学习三(细解Servlet和ServletContext)

时间:2022-07-12 13:08:59

一.Servlet细节

1.Servlet与线程安全

因为一个类型的Servlet只有一个实例对象,那么就有可能,会出现一个Servlet同时处理多个请求,那么Servlet线程不安全,但效率高,但也存在线程安全问题

  • 不要在Servlet中创建成员,创建局部变量即可
  • 可以创建无状态成员 ,User user=new User();
  • 可以创建有状态的成员,但状态必须是只读的User方法内不能有set

2.让服务器在启动时就创建Servlet

<load-on-startup>0</load-on-startup>//在<servlet>中配置<load-on-startup> 其中给出一个非负整数
public class AServlet extends HttpServlet {

@Override
public void init() throws ServletException {
System.out.println("Servlet已经创建成功");
}

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}

<servlet>
<servlet-name>AServlet</servlet-name>
<servlet-class>cn.st.web.servlet.AServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/AServlet</url-pattern>
</servlet-mapping>

访问此Servlet效果如下图
JavaWeb学习三(细解Servlet和ServletContext)
可以看出,servlet是服务器启动完成前就创建了

3.<url-pattern>

  • <url-pattern><servlet-mapping>的子元素,用来指定Servlet的访问路径,即URL,它必须是以/开头
(1).可以在<servlet-mapping>中给出多个<url-pattern>
 <servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/AServlet</url-pattern>
<url-pattern>/BServlet</url-pattern>
</servlet-mapping>

访问以AServlet或者以BServlet结尾的都可以

  • 说明一个Servlet绑定两个URL,无论访问/AServlet还是/BServlet,都是访问的AServlet
(2).还可以在<url-pattern>中使用通配符,所谓通配符就是星号,星号可以匹配任何URL前缀和后缀

使用通配符可以命名一个Servlet绑定一组URL,例如

a.路径
  <servlet>
<servlet-name>BServlet</servlet-name>
<servlet-class>cn.st.web.servlet.BServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BServlet</servlet-name>
<url-pattern>/BServlet/*</url-pattern>
</servlet-mapping>

/servlet/a,/servlet/b都匹配/servlet/*

b.扩展名
 <servlet>
<servlet-name>BServlet</servlet-name>
<servlet-class>cn.st.web.servlet.BServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

/abc/deg/ghi.do,/a.do都匹配

c.啥都匹配
 <servlet>
<servlet-name>BServlet</servlet-name>
<servlet-class>cn.st.web.servlet.BServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

匹配所有URL

4.web.xml文件的继承

每个完整的javaweb应用中都需要有web.xml,但我们不知道所有的web.xml都有一个共同的父文件,在tomcat下的conf\web.xml中的内容,相当于写到了每个项目的web.xml中,它是所有web.xml的共同的”父类”

<servlet-name>default</servlet-name> //它的优先级最低,如果一个请求没有人处理,那么它就来处理,返回404
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> //当访问路径不存在时,会执行该Servlet,其实我们在访问index.html时也在执行这个Servlet

5.Servlet与反射

Tomcat在对于web.xml中<servlet-class>这里采用了反射的机制来实现的,其实对于以后很多web项目,配置底层是通过反射实现的会有很多很多的,所以我们要打好基础!!!!!

Class.forName(servlet的class);
getMethod("servlet",ServletRequest.class,ServletResponse.class);
invoke方法

二.ServletContext

1.ServletContext概述

  • 一个项目只有一个ServletContext对象
  • 我们可以在N多个Servlet中来获取这唯一的对象,使用它可以给多个Servlet传递数据
  • 与天地同寿,这个对象在Tomcat启动时就创建,在Tomcat关闭时才会死去

ServletContext对象的作用是在整个web应用的动态资源之间共享数据!例如在AServlet中向ServletContext对象中保存一个值,然后在BServlet中就可以获取这个值,这就是共享数据了!

2.获取ServletContext

获取ServletContext一共有4种方法,如下:

  • ServletConfig getServletContext
  • GenericServlet getServletContext
  • HttpSession getServletContext
  • ServletContextEvent getServletContext

在Servlet中获取ServletContext对象:

  • 在void init(ServletConfig config)中:
ServletContext context=config.getServletContext();

在GenericeServlet或HttpServlet中获取ServletContext对象

  • GenericServlet类有getServletContext()方法,所以可以直接使用this.getServletContext()来获取
public class BServlet extends HttpServlet {



public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context1=this.getServletConfig().getServletContext();
ServletContext context2=this.getServletContext();
System.out.println(context1==context2);
}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}

访问这个Servlet打印出true,证明了在一个项目中只有一个ServletContext对象

3.域对象的功能

(1).域对象的定义
  • 就是用来在多个Servlet中传递数据
  • 域对象必须有要存数据功能
  • 域对象必须有取数据功能
(2).javaweb四大域对象
  • ServletContext
  • PageContext
  • ServletRequest
  • HttpSession
(3).ServletContext对于存储数据的方法
  • void setAttribute(String name,Object value):用来存储一个对象,也可以称之为存储一个域属性,Map存储
  • Object getAttribute(String name):用来获取ServletContext中的数据
  • void removeAttribute(String name):用来移除ServletContext中的域属性
  • Enumeration getAttributeNames():获取所有域属性名称

4.获取应用初始化参数

  • Servlet也可以获取初始化参数,但它是局部的参数,也就是说,一个Servlet只能获取自己的初始化参数,不能获取别人的,即初始化参数只为一个Servlet准备
  • 可以配置公共的初始化参数,为所有Servlet所用,这需要使用ServletContext
 <servlet>
<servlet-name>BServlet</servlet-name>
<servlet-class>cn.st.web.servlet.BServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BServlet</servlet-name>
<url-pattern>/BServlet</url-pattern>
</servlet-mapping>

<context-param>
<param-name>context-name</param-name>
<param-value>context-value</param-value>
</context-param>
public class BServlet extends HttpServlet {



public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context=this.getServletContext();
String name=context.getInitParameter("context-name");
System.out.println(name);

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}

访问这个Servlet控制台打印出

context-value

5.获取资源相关的方法

  • ServletContext().getRealPath(String name):它得到的是有盘符的路径
public class BServlet extends HttpServlet {



public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String path=getServletContext().getRealPath("/index.jsp");
System.out.println(path);
}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}

访问此Servlet,控制台打印

E:\javaweb_work\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\javaweb2\index.jsp
  • ServletContext().getResourceAsStream(String name):获取资源的路径后,再创建出输入流对象
public class BServlet extends HttpServlet {



public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

InputStream io=getServletContext().getResourceAsStream("/index.jsp");

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}
  • ServletContext().getResourcePaths(String name):获取当前路径下所有资源的路径,返回的是一个Set集合
public class BServlet extends HttpServlet {



public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

Set<String> set=getServletContext().getResourcePaths("/WEB-INF");
for(String path:set) {
System.out.println(path);
}

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}

控制台打印

/WEB-INF/lib/
/WEB-INF/classes/
/WEB-INF/web.xml

6.练习:访问量统计

一个项目中所有的资源被访问都要对访问量进行累加!创建一个int类型的变量,用来保存访问量,然后保存到ServletContext的域中,这样可以保存所有得Servlet都可以访问到!

  • 最初时 ServletContext中没有保存访问量相关的属性
  • 当本站第一次被访问时 创建一个变量 设置其值为1 保存到ServletContext终
  • 当以后访问 就可以从ServletContext中获取这个变量 然后在其基础之上加1
public class BServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

ServletContext application=getServletContext();
Integer count=(Integer)application.getAttribute("count");
if(count==null) {
count=1;
}else {
count++;
}
response.setContentType("text/html;charset=utf-8");//防止乱码
response.getWriter().print("你已经访问了"+count+"次");
application.setAttribute("count",count);
}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}

7.获取类下的资源

  • 获取类路径资源,类路径对一个javaweb项目而言就是WEB-INF下面的classer和WEB-INF/lib每个jar包

在这个包下新建一个a.txt文件

JavaWeb学习三(细解Servlet和ServletContext)

里面添加上这些

JavaWeb学习三(细解Servlet和ServletContext)

public class BServlet extends HttpServlet {



public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

ClassLoader classLoader=this.getClass().getClassLoader();
//得到ClassLoader,先得到Class,再得到ClassLoader
InputStream io=classLoader.getResourceAsStream("cn/st/web/servlet/a.txt");
//调用其getResourceAsStream(),得到InputStream
String result=IOUtils.toString(io);//要导入io包
System.out.println(result);
}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}

控制台打印出txt里面的东西了

public class BServlet extends HttpServlet {



public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

ClassLoader classLoader=this.getClass().getClassLoader();
InputStream io=classLoader.getResourceAsStream("cn/st/web/servlet/a.txt");
String result=IOUtils.toString(io);
System.out.println(result);

Class class1=this.getClass();
InputStream io2=class1.getResourceAsStream("/../../index.jsp");
String result2=IOUtils.toString(io2);
System.out.println(result2);
}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}

控制台不仅打印出了txt中的内容,还打印出了index.jsp里面的代码内容