JavaWeb——Servlet转发与重定向的区别,过滤器与监听器

转:

JavaWeb——Servlet转发与重定向的区别,过滤器与监听器
原创 等一次另眼相看 最后发布于2019-04-10 19:12:21 阅读数 121 收藏
展开

文章目录

转发与重定向
本质区别
过滤器Filter
过滤器可以做什么
过滤器示例——处理中文乱码
filter的三种典型应用:
监听器Listener
监听器示例——统计在线人数

转发与重定向

https://blog.csdn.net/meiyalei/article/details/2129120

Servlet中转发:

// 转发NewServelt
request.getRequestDispatcher("NewServelt").forword(request,response);

1
2

Servelt重定向:

// 重定向到NewServlet
response.sendRedirect("NewServlet");

1
2

jsp页面中转发:

<jsp:forword page = "NewServelt">

1

jsp页面重定向:

<%response.sendRedirect("new.jsp");%>

1

本质区别

转发是服务器行为,重定向是客户端行为。

转发过程:客户浏览器发送http请求----》web服务器接受此请求–》调用内部的一个方法在容器内部完成请求处理和转发动作----》将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。

重定向过程:客户浏览器发送http请求----》web服务器接受后发送302状态码响应及对应新的location给客户浏览器–》客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址----》服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。

过滤器Filter

过滤器是Servlet中最令人激动的特性之一,当浏览器发送请求给服务器时,服务器会先执行过滤器,然后才访问web资源。服务器响应请求,在web资源抵达浏览器之前,也会途径过滤器。
过滤器可以做什么

你可以把过滤器想象成一张过滤网,服务器与浏览器的信息交互都要经过过滤器以保证满足标准。使用过滤器可以过滤一些敏感字符串,可以避免中文乱码,可以进行权限验证(比如规定只有带session和cookie的浏览器才可以访问资源)等等。
过滤器的出现使得一些棘手的问题得以解决,最通俗的体现就在于处理中文乱码,我们都知道,只有使用utf-8编码才能使得全世界各地的字符得以正确显示。不使用过滤器的话我们就需要在所有的servlet和jsp中对编码加以声明,代码的重复率相当高。
过滤器示例——处理中文乱码

只要java类实现了Filter接口就可以成为过滤器。
一个标准的过滤器:

新建Servlet实现Filter接口,重写其方法:

package com.xx.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

// 实现Filter接口就可以称之为过滤器
public class EncodingFilter implements Filter {
// 构造方法
public EncodingFilter() {
// TODO Auto-generated constructor stub
}

// 销毁方法,与Servlet中的destory方法类似
public void destroy() {
// TODO Auto-generated method stub
}

// doFilter方法,在这里实现过滤器功能
// 它有三个参数(ServletRequest,ServletResponse,FilterChain)
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

// 我们把处理中文乱码的代码放在这里就可以了
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");

// pass the request along the filter chain
// 在Java中使用了链式结构来管理过滤器。把所有的过滤器都放在FilterChain里边
// 如果符合条件,就执行下一个过滤器(如果没有过滤器了,就执行目标资源)。
chain.doFilter(request, response);
}

// 初始化方法,和destory方法都只执行一次
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

Filter部署

和Servlet一样,过滤器需要部署在服务器上:
第一种方式:在web.xml文件中部署

<filter>
<display-name>EncodingFilter</display-name>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.xx.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

1
2
3
4
5
6
7
8
9

<filter>用于注册过滤器
<filter-name>用于为过滤器指定一个名字,该元素的内容不能为空
<filter-class>用于指定过滤器的完整的限定类名
<filter-mapping>用于设置一个Filter所负责拦截的资源
<filter-name>子元素用于设置filter的注册名称。该值必须是在元素中声明过的过滤器的名字
一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
<url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
<servlet-name>指定过滤器所拦截的Servlet名称。
<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher>子元素用来指定 Filter 对资源的多种调用方式进行拦截。

dispatcher小结
<dispatcher>子元素可以设置的值及其意义:

REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。

filter的三种典型应用:

可以在filter中根据条件决定是否调用chain.doFilter(request, response)方法,即是否让目标资源执行
在让目标资源执行之前,可以对requestresponse作预处理,再让目标资源执行
在目标资源执行之后,可以捕获目标资源的执行结果,从而实现一些特殊的功能

监听器Listener

监听器其实就是一个实现了特定接口普通java程序,这个程序专门用来监听一个java对象的方法调用或者属性改变,当被监听的对象的事件发生后,监听器就会立即捕捉到,并做以响应的处理。
我们把被监听的对象称作事件源。在Servlet规范中定义了多种类型的监听器,我们可以使用监听器来监听 ServletContext,HttpSession和HttpServletRequest这三个作用域对象。监听的内容分为:监听域对象的创建和销毁,监听域对象的属性变化
ServletContext HttpSession HttpServletRequest
域对象的创建和销毁 ServeltContextListener HttpSessionListener ServeltRequestListener
域对象属性的变化 ServeltContextAttributeListener HttpSessionAttributeListener ServeltRequestAttributeListener

我们可以根据实际要求去实现不同的接口以监听目标事件源。

监听器的部署,写在web.xml文件当中:

<listener>
<listener-class>com.xx.listener.CountOnlineUserListener</listener-class>
</listener>

1
2
3

监听器示例——统计在线人数

我们先来新建一个简单的登录页面:

<html>
<head>
<meta charset="UTF-8">
<style type="text/css">
body{text-align:center;}
span{ color:red; font-size:200% }
hr{ margin-bottom:30px }
</style>
</head>
<body>
<span> 登录 </span>
<hr color="red"/>
<form action="LoginServlet" method="post">
<table border="1" bordercolor="blue" width="40%" cellspacing="0" align="center">
<tr>
<td>用户名:</td>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"/></td>
</tr>
<tr align="center">
<td colspan="2">
<input type="submit" value="登陆"/> <input type="reset" value="重置"/>
</td>
</tr>
</table>
</form>
</body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

看下效果:
在这里插入图片描述
现在来新建LoginServlet:

package com.xx.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Servlet implementation class LoginServlet
*/
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 模拟登陆后在首页显示当前在线人数
String username = request.getParameter("username");
String password = request.getParameter("password");
// 拿到用户输入的用户名和密码后,我们自然是拿去和数据库中的数据做校验
// 我们假设校验成功,然后跳转到首页页面
response.sendRedirect("IndexServlet");
}

/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

这是IndexServlet:

package com.xx.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
* Servlet implementation class Index
*/
public class Index extends HttpServlet {
private static final long serialVersionUID = 1L;

/**
* @see HttpServlet#HttpServlet()
*/
public Index() {
super();
// TODO Auto-generated constructor stub
}

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContextType("text/html;charset=utf-8");
HttpSession session = request.getSession();
response.getWriter().println("当前在线人数是:" + session.getServletContext().getAttribute("count"));
}

/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

监听器来监听session:

package com.xx.listener;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
* Application Lifecycle Listener implementation class CountOnlineUserListener
*
*/
public class CountOnlineUserListener implements HttpSessionListener {

/**
* Default constructor.
*/
public CountOnlineUserListener() {
// TODO Auto-generated constructor stub
}

/**
* @see HttpSessionListener#sessionCreated(HttpSessionEvent)
*/
public void sessionCreated(HttpSessionEvent se) {
// TODO Auto-generated method stub
// 有用户登录,session就会被创建
HttpSession session = se.getSession()
// ServletContext的作用范围:整个web应用范围内,我们就用它来存在线人数
Integer count = (Integer)session.getServletContext().getAttribute("count");
// 设置session的有效期
session.setMaxInactiveInterval(300);
// 第一个人登陆,此时count应该为null,且count>=0
if (count == null || count <= 0) {
session.getServletContext().setAttribute("count", 1);
} else {
session.getServletContext().setAttribute("count", count + 1);
}
}

/**
* @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
*/
public void sessionDestroyed(HttpSessionEvent se) {
// TODO Auto-generated method stub
// session失效了,意味着这个人下线了,我们把count-1
Integer count = (Integer) se.getSession().getServletContext().getAttribute("count");
se.getSession().getServletContext().setAttribute("count", count - 1);

}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

这样就完成了对session的监听,如果用户从浏览器登录的话,服务器就会自动创建session,那么这边就可以监听到,并且给count+1,当session被销毁后,就会给count-1。
————————————————
版权声明:本文为CSDN博主「等一次另眼相看」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44238142/java/article/details/89034560

原文地址:https://www.cnblogs.com/libin6505/p/12674131.html