servlet
生命周期
- 加载Servlet
当Tomcat第一次访问Servlet的时候,Tomcat会负责创建Servlet的实例 - 初始化
当Servlet被实例化后,Tomcat会调用init()方法初始化这个对象
处理服务。当浏览器访问Servlet的时候,Servlet 会调用service()方法处理请求 - 销毁
当Tomcat关闭时或者检测到Servlet要从Tomcat删除的时候会自动调用destroy()方法,让该实例释放掉所占的资源。一个Servlet如果长时间不被使用的话,也会被Tomcat自动销毁 - 卸载
当Servlet调用完destroy()方法后,等待垃圾回收。如果有需要再次使用这个Servlet,会重新调用init()方法进行初始化操作。 - 简单总结:
只要访问Servlet,service()就会被调用。init()只有第一次访问Servlet的时候才会被调用。destroy()只有在Tomcat关闭的时候才会被调用。
创建servlet需要配置web.xml文件
细节
- 已经注册的servlet映射到不同的web应用
- servlet映射可以使用通配符
匹配所有:/*
匹配扩展名:*.jsp
作用:隐藏网站所使用的编程语言
-
servlet为单例:
servlet一旦创建就会驻留在内存中,持续服务直到服务器关闭 -
每次访问servlet对象servlet都会创建新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象
-
线程安全问题
多用户访问同一个servlet时服务器会创建多个进程,并发访问公共资源时会出现线程安全问题。
避免原则:- 如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制synchronized (对象){}
- 如果一个变量不需要共享,则直接在 doGet() 或者 doPost()定义.这样不会存在线程安全问题
-
load-on-startup标签
在servlet标签内配置该元素,服务端启动时就会加载并创建该servlet对象,以及调用init方法
作用:- 为web应用写一个InitServlet,这个servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据
- 完成一些定时的任务【定时写日志,定时备份数据】
-
web访问的任何资源都是在访问servlet
访问静态资源其实是在访问默认的servlet,<url-pattern>
为/。
servletConfig对象
作用:通过此对象可以读取web.xml中配置的初始化参数。
<servlet>
<servlet-name>Demo1</servlet-name>
<servlet-class>Demo1</servlet-class>
<init-param>
<param-name>name</param-name>
<param-value>wz</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Demo1</servlet-name>
<url-pattern>/Demo1</url-pattern>
</servlet-mapping>
在Servlet中获取ServletConfig对象,通过ServletConfig对象获取在web.xml文件配置的参数。
ServletConfig sc = this.getServletConfig();
String value = sc.getInitParameter("name");
ServletContex对象
当Tomcat启动的时候,就会创建一个ServletContext对象。它代表着当前web站点。
作用:
- ServletContext既然代表着当前web站点,那么所有Servlet都共享着一个
ServletContext对象,所以Servlet之间可以通过ServletContext实现通讯。实现Servlet之间通讯就要用到ServletContext
的setAttribute
(String name,Object obj)方法,第一个参数是关键字,第二个参数是你要存储的对象.一个servlet使用setAttribute,另一个使用getAttribute - ServletConfig获取的是配置的是单个Servlet的参数信息,ServletContext可以获取的是配置整个web站点的参数信息
- 利用ServletContext读取web站点的资源文件
- 实现Servlet的转发【用ServletContext转发不多,主要用request转发】。
web站点配置信息
所有servlet都可以使用,可以配置数据库信息
<context-param>
<param-name>name</param-name>
<param-value>zhongfucheng</param-value>
</context-param>
ServletContext servletContext = this.getServletContext();
//通过名称获取值
String value = servletContext.getInitParameter("name");
System.out.println(value);
读取文件
- 文件在webapp根目录下,则直接使用文件名读取
- 在WEB-INF目录下使用SevletContext
//获取到ServletContext对象
ServletContext servletContext = this.getServletContext();
//调用ServletContext方法获取到读取文件的流
InputStream inputStream = servletContext.getResourceAsStream("/WEB-INF/1.png");
getResourceAsStream可以获得根目录下所有资源文件
乱码问题
下面的代码设置了tomcat内部编码为UTF-8,并告诉浏览器响应数据的编码为UTF-8
response.setContentType("text/html;charset=UTF-8");
解决乱码问题就是要保证浏览器解析编码,与响应数据编码一致
重定向与转发
-
转发是服务端操作的,共用同一个request对象
-
重定向是浏览器操作的,地址栏会发生变化
-
用法不同
很多人都搞不清楚转发和重定向的时候,资源地址究竟怎么写。有的时候要把应用名写上,有的时候不用把应用名写上。很容易把人搞晕。记住一个原则:给服务器用的直接从资源名开始写,给浏览器用的要把应用名写上
-
request.getRequestDispatcher("/资源名 URI").forward(request,response)
转发时"/"代表的是本应用程序的根目录【app】
-
response.send("/web应用/资源名 URI");
重定向时"/"代表的是webapps目录。
-
-
转发只能去往当前web应用资源,重定向可以去往任何资源
输出网页头尾
我们在写网页的时候,一般网页的头部和尾部是不需要改变的。如果我们多个地方使用Servlet输出网头和网尾的话,需要把代码重新写一遍。而使用RequestDispatcher的include()方法就可以实现包含网头和网尾的效果了。
request.getRequestDispatcher("/Head").include(request, response);
response.getWriter().write("--------------------------------------------");
request.getRequestDispatcher("/Foot").include(request, response);