Servlet
- Servlet是一种动态网页技术
- Servlet:server(服务器) applet (小程序),也叫服务器端小程序
- Servlet能够接收浏览器的请求并且给浏览器以应答(响应)
- Servlet解释分为广义和狭义的Servlet
- 广义的servlet的指的是实现了javax.servet.Servlet接口的类
- 狭义的servlet指的是javax.servlet.Servlet接口
Servlet的特征
- Servlet是单例多线程的,只创建一个servlet对象,但是每次请求都会起一个线程并在自己线程栈内存中执行service方法
- 一个 Servlet 实例只会执行一次无参构造器与 init()方法,并且是在第一次访问时执行
- 用户每提交一次对当前 Servlet 的请求,就会执行一次 service()方法
- 一个 Servlet 实例只会执行一次 destroy()方法,在应用停止时执行
- 由于 Servlet 是单例多线程的,所以为了保证其线程安全性,一般情况下是不建议在 Servlet类中定义可修改的成员变量,因为每个线程均可修改这个成员变量,会出现线程安全问题
- 默认情况下,Servlet 在 Web 容器启动时是不会被实例化的
Tomcat启动时实例化servlet实例
在tomcat启动时,默认不会创建servlet实例,如果想要让tomcat在启动时创建servlet实例的话,只需要在web.xml中添加load-on-startup标签即可
<servlet>
<servlet-name>lifeServlet</servlet-name>
<servlet-class>com.monkey1024.servlet.LifeServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>lifeServlet</servlet-name>
<url-pattern>/life</url-pattern>
</servlet-mapping>
添加load-on-startup的作用是,标记是否在 Tomcat启动时创建并初始化这个 Servlet实例。它的值必须是一个整数。
- 当值大于等于 0 时,表示容器在启动时就加载并初始化这个 Servlet,数值越小,该 Servlet的优先级就越高,其被创建的也就越早;
- 当值相同时,容器会自己选择创建顺序。
新建servlet有3种方式:
- 1.实现Servlet接口
- 2.继承GenericServlet
- 3.继承HttpServlet
开发步骤:
- 新建 Dynamic Web Project
- 在项目中添加servlet-api.jar
添加在WEB-INF/lib目录下 - 在src目录下,新建servlet,实现Servlet接口
servlet的访问方式
1.浏览器输入地址
2.超链接
3.form表单
4.window.location.href
浏览器方式:http://ip地址:端口号/项目名/访问路径
servlet生命周期(笔试题)
事物的生命周期指的是事物从创建到消亡的过程。
Servlet从创建到销毁的过程称为Servlet生命周期。
Servlet是单例多线程的
调用构造方法(实例化)---->init(初始化)----->service()–>doGet()|doPost()—>destory()
1次 1次 N次 1次
特别注意:如果servlet重写了service方法,那么service就专门负责处理请求(get|post)
HttpServletRequest
- HttpServletRequest表示浏览器对服务器的请求
- 关于浏览器对服务器的请求都被封装在HttpServletRequest对象
HttpServletResponse
表示服务器对浏览器的响应(应答)
RequestDispatcher
- forward(ServletRequest request, ServletResponse response)
在服务器上将一个请求从一个servlet转到另一个资源 (servlet, JSP文件, 或HTML文件) - include(ServletRequest request, ServletResponse response)
包含一个资源 (servlet, JSP page, HTML文件)内容进一个响应消息
//请求转发方式来实现(地址不变)
request.getRequestDispatcher("a.html").forward(request,response );
//请求包括方式实现同样的效果
request.getRequestDispatcher("b.html").include(request, response);
转发和重定向区别?
- forward 地址栏不变 一次请求 转发之间的servlet共享同一个request对象
- sendRedirect 地址栏会改变 二次请求 servlet之间有各自独立的request对象
ServletConfig (了解)
- ServletConfig表示的是Servlet的配置信息
- ServletConfig对象和servlet配置信息()一一对应
- 当服务器(tomcat)实例化Servlet时,会根据servlet配置信息创建ServletConfig对象
注意 配置初始化参数需要写在<servlet>…</servlet>中
<servlet>
..........
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>username</param-name>
<param-value>password</param-value>
</init-param>
<init-param>
<param-name>key</param-name>
<param-value>value</param-value>
</init-param>
</servlet>
ServletConfig方法
- getInitParameter(java.lang.String name)返回一个包含给定名字的初始化参数,若此参数不存在就返回一个空值。
- getInitParameterNames()返回context的初始化参数的名字 ,用一个字符串对象枚举变量的形式。如果相应的context没有初始化参数,则就返回一个空的枚举变量
- getServletName()返回该servlet实例的名称
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取ServletConfig对象
ServletConfig config = this.getServletConfig();
//获取在web.xml中的配置信息,如果不存在则返回一个空值
String encoding = config.getInitParameter("encoding");
//处理中文乱码问题
response.setContentType("text/html;charset="+encoding);
//打印中文字符
response.getWriter().println("encoding:"+encoding+"<br/>");
//获取所有的ServletConfig的初始化参数
Enumeration<String> initParameterNames = config.getInitParameterNames();
//遍历当前获取到的参数信息
while (initParameterNames.hasMoreElements()) {
String name = (String) initParameterNames.nextElement();
//获取参数值
String value = config.getInitParameter(name);
response.getWriter().println(name+":"+value+"<br/>");
}
//返回该Servlet实例的名字
String servletName = config.getServletName();
response.getWriter().println(servletName);
}
ServletContext
- ServletContext表示一个WEB应用。
- ServletContext是web.xml文件在内存中的表示。
- ServletContext和web.xml一一对应
注意 在web.xml文件中配置全局初始化参数:
<!-- context-param来配置项目的全局初始化参数信息 -->
<context-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</context-param>
<context-param>
<param-name>username</param-name>
<param-value>password</param-value>
</context-param>
<context-param>
<param-name>key</param-name>
<param-value>value</param-value>
</context-param>
ServletContext有效范围
servletContext有效范围是从服务器启动到服务器停止之前,servletContext都有效
ServletContext方法
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取ServletContext对象
ServletContext context = this.getServletContext();
//读取全局全局初始化参数
String encoding = context.getInitParameter("encoding");
//处理响应乱码
response.setContentType("text/html;charset="+encoding);
//获取所有全局初始化参数信息
Enumeration<String> names = context.getInitParameterNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
//获取存储的value值
String value = context.getInitParameter(name);
response.getWriter().println(name+":"+value+"</br>");
}
//移除指定name键值对
context.removeAttribute("key");
String name1 = (String)context.getAttribute("key");
response.getWriter().println(name1);
}
ServletContext可以向map集合一样,以键值对的形式存储数据
会话技术
目前我们是无法获取用户登录状态,servlet提供了2种获取(保存)用户登录状态的方式:
- 1.cookie
- 2.HttpSession
(1)cookie
- Cookie是服务器向浏览器写入的一段字符串,这段字符串由键值对组成:”uname=zhang3”
- Cookie是保存在浏览器上的
注意 存储和取需要在两个servlet里面
// 存储
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//创建cookie
Cookie cookie1 = new Cookie("name1","admin1");
Cookie cookie2 = new Cookie(URLEncoder.encode("用户1","utf-8"),"18");
//设置cookie的有效期(单位/s)
cookie1.setMaxAge(300);
//将cookie对象添加到response
response.addCookie(cookie1);
response.addCookie(cookie2);
//向浏览器打印
response.getWriter().println(cookie1);
}
获取cookie:
//取
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//获取所有cookie
Cookie[] cookies = request.getCookies();
//遍历Cookie数组
for (Cookie cookie : cookies) {
response.getWriter().println(URLDecoder.decode(cookie.getName(),"utf-8")+":"+cookie.getValue()+"</br>");
}
}
(2)HttpSession
- HttpSession表示浏览器与服务器之间的会话(对象)。
- HttpSession是保存在服务器。
- Session默认是30分钟内有效,但是可以在web.xml文件中进行配置有效期:
<!-- 设置session有效时间,以分钟为单位 -->
//方式1:
<session-config>
<session-timeout>1</session-timeout>
</session-config>
//方式2:
//代码设置有效期,秒/单位
session.setMaxInactiveInterval(60);
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取session
HttpSession session = request.getSession();
//2.获取session的id
String id = session.getId();
response.getWriter().print("session_id:"+id+"</br>");
//判断session是新还是旧
boolean b = session.isNew();
response.getWriter().print("boolean:"+b+"</br>");
//向seesion存储键值对
session.setAttribute("age", 18);
//取age
Integer value = (Integer)session.getAttribute("age");
response.getWriter().print("age:"+value+"</br>");
//移除age
session.removeAttribute("age");
//让当前的session失效;失效后再获取session将会出现异常
session.invalidate();
}
Session获取原理
原理:首先服务器先检查浏览器中是否存在会话cookie,如果存在会话cookie,那么会根据会话cookie的值,查找相应的session,然后将查找到的session返回;如果不存在会话cookie,那么首先服务器会先创建session,然后再创建新会话cookie(JSESSION=SESSIONID),将会话cookie发送到浏览器,最后将新建的session返回。
过滤器
Filter译为过滤器。 由于Servlet规范是开放的,借助于公众与开源社区的力量,Servlet规范越来越科学,功能也越来越强大。2000年,Sun公司在Servlet2.3规范中添加了Filter功能,并在Servlet2.4中对Filter进行了细节上的补充。
运行原理:
当客户端向服务器端发送一个请求时,如果有对应的过滤器进行拦截,过滤器可以改变请求的内容、或者重新设置请求协议的相关信息等,然后再将请求发送给服务器端的Servlet进行处理。当Servlet对客户端做出响应时,过滤器同样可以进行拦截,将响应内容进行修改或者重新设置后,再响应给客户端浏览器。在上述过程中,客户端与服务器端并不需要知道过滤器的存在。
在一个Web应用程序中,可以部署多个过滤器进行拦截,这些过滤器组成了一个过滤器链。过滤器链中的每个过滤器负责特定的操作和任务,客户端的请求在这些过滤器之间传递,直到服务器端的Servlet。具体执行流程如下:
实例:
- Filter处理中文乱码问题
- 自定义过滤器需要实现Filter接口
在java Resources下面建立一个util包,在建立一个Filter文件
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//将ServletRequest强转成HttpServletRequest
HttpServletRequest request1=(HttpServletRequest)request;
//将ServletResponse强转成HttpServletResponse
HttpServletResponse response1=(HttpServletResponse)response;
//处理请求乱码
request1.setCharacterEncoding("utf-8");
//处理相应乱码
response1.setContentType("text/html;charset=utf-8");
//判断当前过滤器后面还有没有过滤器,如果有继续执行下一个过滤器
chain.doFilter(request, response);
}
注意配置文件中
<filter>
<display-name>EncodingFilter</display-name>
<filter-name>EncodingFilter</filter-name>
<filter-class>util.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<!-- /* 表示任何请求都交给过滤器处理 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
监听器
web监听器是一种Servlet中的特殊的类,它们能帮助开发者监听web中的特定事件,比如ServletContext,HttpSession,ServletRequest的创建和销毁;变量的创建、销毁和修改等。可以在某些动作前后增加处理,实现监控
Listener,java提供的监听器可以监听的对象包括:
- 1.HttpServletRequest
- 2.HttpSession
- 3.ServletContext
统计网站访问量人数变化
在util包下创建监听文件
public void sessionCreated(HttpSessionEvent arg0) {
//从ServletContext中获取当前在线人数
ServletContext context = arg0.getSession().getServletContext();
Integer count = (Integer)context.getAttribute("count");
if (count==null) {
context.setAttribute("count", 1);
}else{
context.setAttribute("count", count+1);
}
//设置session的有效时间
arg0.getSession().setMaxInactiveInterval(30);
System.out.println("有人上线");
}
/**
* @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
*/
public void sessionDestroyed(HttpSessionEvent arg0) {
System.out.println("有人下线");
ServletContext context = arg0.getSession().getServletContext();
Integer count = (Integer)context.getAttribute("count");
if (count==null || count<=0) {
context.setAttribute("count", 1);
}else{
context.setAttribute("count", count-1);
}
}
网页显示人数:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Integer count = (Integer)request.getSession().getServletContext().getAttribute("count");
response.getWriter().println("当前在线人数:"+count);
}