一.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效果如下图
可以看出,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文件
里面添加上这些
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里面的代码内容