对java的重要三组件再次看了一遍。
ps: hugo new posts//post_2/S_L_F.md
Java三剑客&Tomcat
Servlet
1.Servlet必须封装在WAR(web应用程序式保存文档)或者Web模组中,才能部署到应用程序式(web)服务器。
2.由1.可得,Servlet程序由web服务器调用(对其进行生命周期的管理)。当应用加载一个Servlet的时候,从初始化到销毁,期间会发生一系列的事件(Servlet的生命周期事件或方法)。
3.可以支持动态网页内容,同时对多个用户端提供服务。
容器指Tomcat
Servlet的生命周期
-
Servlet构造器:Servlet的加载
-
init初始化:Servlet的实例化,
- 对于一个Servlet,init方法只能调用一次。无论有多少客户机访问Servlet,都不会重复执行init()。
- init方法有一个类型为ServletConfig的参数,Servlet容器通过这个参数向Servlet传递配置信息,通过ServletConfig对象获取描述Servlet运行环境的ServletContext对象,使用该对象,Servlet可以和它的Servlet容器进行通信。
- Servlet初始化之后,将一直存在于容器中(内存马的基础)
- 1.客户端发送GET请求,调用Servlet的doGet方法进行处理并响应
- 2.客户端发送POST请求,调用Servlet的doPost方法处理并响应
- 3.service方法处理用户请求。
- 每当由一个对HttpServlet对象的请求,该对象的service方法就调用且获得请求对象ServletRequest和响应对象ServletResponse作为参数。
- Servlet对象通过ServletRequest对象(得到客户端的相关信息和请求信息,处理之后,调用ServletResponse对象的方法设置响应信息。
- destroy销毁:在web工程停止的时候调用,Servlet的销毁
一个总结:
-
在正常情况下,Servlet只会初始化一次,而处理服务会调用多次,销毁也只会调用一次;
-
但是如果一个Servlet长时间不使用的话,也会被容器自动销毁,
-
而如果需要再次使用时会重新进行初始化的操作,即在特殊情况下初始化可能会进行多次,销毁也可能进行多次。
## Servlet的任务
- 将请求封装为ServletRequest对象,包含请求头、参数等各种信息
- 在service中接收参数,并进行处理
- 请求处理完成后,通过**转发(Forward)或者重定向(Redirect)**到某个页面
## Servlet容器(Tomcat为例)
### Tomcat容器4个等级(由高到低)(结合图看):
(其实目前4张图片,三张都在说同一件事)
容器的生命周期
(和Servlet的生命周期大同小异)
- 加载与实例化:容器启动时,读取web.xml中内容,容器中无实例化Servlet对象,则实例化一个(创建web.xml指定的ServletConfig对象,并将其作为参数来进行下一步的Servlet对象的init方法调用)。
- ServletConfig对象和Servlet实例的关系:
- 每个Servlet实例对应一个ServletConfig对象,由容器创建,并进行相关联
- ServletConfig储存Servlet初始化参数
- ServletConfig对象可以获取ServletContext对象(整个web应用程序的上下文)
- ServletContext是容器给每一个web应用程序创建的一个全局对象(资源)(该程序的所有Servlet都可以访问),提供一系列方法,Servlet用来进行与容器的交互,belike 获取初始化参数、读取资源文件之类的.
-
初始化:调用Servlet对象的init进行初始化,详情参考上面的Servlet的生命周
-
处理请求:same
-
销毁:容器移除一个Servlet就调用其destroy方法(完全残忍)
## Servlet的线程安全
point:
- Problem:Servlet是单实例多线程的,也就是,一个类一个实例多个线程(访问)
- 如果存在可以修改的成员变量,就存在多个线程同时访问和修改这些变量,导致数据竞争(数据不一致)、死锁等问题。
- 无可修改的成员变量
- 每次请求都是独立的,不会受到之前的请求的影响
- 好处是:易于维护
## 实现
客户端通过URL地址访问web服务器中的资源,Servlet程序映射到一个URL地址上
在web.xml中的映射实现,例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<servlet>// 注册Servlet
<servlet-name>FirstServlet</servlet-name> //设置Servlet类一个逻辑名称,用于在容器内进行标识
<servlet-class>FirstServlet</servlet-class> //Servlet的类名,就是写了实现代码的类的名字
</servlet>
<servlet-mapping> //用于映射上面的Servlet的对外访问路径
<servlet-name>FirstServlet</servlet-name> //设置引用的Servlet名称,也就是上面那个的名称
<url-pattern>/FirstServlet</url-pattern> //servlet对外的访问路径,当访问/FirstServlet的时候,就会将请求转发到指定的Servlet类
</servlet-mapping>
|
ps:转发:客户端只发送一次请求,在服务端进行转发,可以共享数据,浏览器URL不变。
一个简单的例子:
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
//web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-class>Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
//Servlet1.java
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// 扩展 HttpServlet 类
public class Servlet1 extends HttpServlet {
private String message;
public void init() throws ServletException
{
// 执行必需的初始化
message = "Hello World";
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// 设置响应内容类型
response.setContentType("text/html");
// 实际的逻辑是在这里
PrintWriter out = response.getWriter();
out.println("<h1>" + message + "</h1>");
}
public void destroy()
{
// 什么也不做
}
}
|
注意一下,IDEA需要映射URL到这个项目的deploy名
belike this is http://localhost:8080/ServletDemo2_war/hello
然后
Filter
详细点is,请求到达Servlet之前进行过滤、响应从Servlet发出后进行过滤。
Filter本身并不申请请求对象和响应对象,只提供过滤功能。
## Filter的执行顺序
如果定义了多个Filter,且同一个请求会被多个Filter进行处理,那么顺序就来自于web.xml中的顺序,从上到下执行。
-
Filter接口中有一个doFilter方法,当Filter配置好对哪个资源进行拦截的时候,服务器就会在每次调用该资源之前先调用doFilter方法(执行一段代码)
-
调用doFilter方法的时候,会传递一个filterChain对象(提供一个doFilter方法)
-
如果调用filterChain对象的doFilter方法,那么服务器就会调用web资源的service方法——该资源被访问。(在调用目标资源之前,执行一段代码,与上面的同理)
## Filter生命周期
- 容器启动时,根据web.xml中的filter声明进行实例化
- 容器启动时执行,只会执行一次
- 调用FilterConfig进行初始化filter,类似ServlertConfig
- 利用FilterConfig可以得到ServletContext对象,以及在web.xml中的filter的初始化参数
- 容器启动时执行,只会执行一次
- 类似Servlet的service方法
- 客户端请求资源,容器匹配到filter-mapping所指url-pa,则按照声明的顺序依次调用这些filter的doFilter方法
- 容器调用其destroy方法进行销毁,被销毁的filter使用的资源也会被释放
## 创建Filter
IDEA提供了三剑客的模板class,所以直接使用+修改修改
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
//Filter1.java
package com.test.Filters;
import javax.servlet.*;
import java.io.IOException;
import java.util.*;
public class Filter1 implements Filter{
public void init(FilterConfig config) throws ServletException {
String site = config.getInitParameter("site");
System.out.println("name of website: " + site);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("I got a bad idea...");
chain.doFilter(request, response);
}
public void destroy(){
System.out.println("Destroy!!!");
}
}
//web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>DisplayHeader</servlet-name>
<servlet-class>com.test.Servlets.DisplayHeader</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayHeader</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<filter>
<filter-name>FilterTest</filter-name>
<filter-class>com.test.Filters.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterTest</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
|
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
//DisplayHeader.java,直接搬的菜鸟教程的。
package com.test.Servlets;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/DisplayHeader")
//扩展 HttpServlet 类
public class DisplayHeader extends HttpServlet {
// 处理 GET 方法请求的方法
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// 设置响应内容类型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "HTTP Header 请求实例";
String docType =
"<!DOCTYPE html> \n";
out.println(docType +
"<html>\n" +
"<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n"+
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<table width=\"100%\" border=\"1\" align=\"center\">\n" +
"<tr bgcolor=\"#949494\">\n" +
"<th>Header 名称</th><th>Header 值</th>\n"+
"</tr>\n");
Enumeration headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
String paramName = (String)headerNames.nextElement();
out.print("<tr><td>" + paramName + "</td>\n");
String paramValue = request.getHeader(paramName);
out.println("<td> " + paramValue + "</td></tr>\n");
}
out.println("</table>\n</body></html>");
}
// 处理 POST 方法请求的方法
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
|
## Filter如何filter something
重点是url-pattern
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<filter>
<filter-name>FilterTest</filter-name>
<filter-class>com.test.Filters.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterTest</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
|
重点是url-pattern
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<filter>
<filter-name>FilterTest</filter-name>
<filter-class>com.test.Filters.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterTest</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
|
重点是filter-mapping
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<filter>
<filter-name>FilterTest</filter-name>
<filter-class>com.test.Filters.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterTest</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>FilterTest</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
|
重点是url-pattern
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<filter>
<filter-name>FilterTest</filter-name>
<filter-class>com.test.Filters.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterTest</filter-name>
<url-pattern>/folder_name/*</url-pattern>
</filter-mapping>
|
重点是filter-mapping中的servlet-name
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<filter>
<filter-name>FilterTest</filter-name>
<filter-class>com.test.Filters.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterTest</filter-name>
<servlet-name>DisplayHeader</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>DisplayHeader</servlet-name>
<servlet-class>com.test.Servlets.DisplayHeader</servlet-class>
</servlet>
|
重点是url-pattern
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<filter>
<filter-name>FilterTest</filter-name>
<filter-class>com.test.Filters.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterTest</filter-name>
<url-pattern>/a.html</url-pattern>
</filter-mapping>
|
## Filter应用场景
-
统一POST请求中文字符编码
-
控制浏览器缓存页面中的静态资源
1. 动态页面中引入一些图片orCSS(静态资源),为减轻服务器的压力,使用Filter控制浏览器缓存这些文件
- 实现URL级别的权限认证
1. 将执行敏感操作的Servlet映射到一些特殊目录中,同时用Filter将这些目录保护起来,限制只有某些权限的用户才能访问,从而在系统中实现一种URL级别的权限功能。
- 实现用户自动登录
1. 用户成功登录后发送名为user的COOKIE(值为用户名和md5后的密码)给客户端
2. 用Filter检查用户是否带有该COOKIE
1. 有,调用dao查询cookie的值和数据库是否匹配
2. 匹配,则向session中存入user对象——登录标识,实现自动登录
## 缺省Servlet URL绕过Filter
有点子看不懂原文在说个什么……
在对资源使用Filter的时候,有两种方式来指定要应用的Filter:
- 这个模式必须和web.xml中的<servlet-mapping>
元素定义的模式匹配
- 这个名称必须和web.xml中的<servlet>
元素中定义的名称匹配
但大多数服务器会使用一个激活器Servlet为Servlet提供一个默认的URL访问路径:
http://host/WebAppPrefix/servlet/ServletName
用户可以通过该URL直接访问Servlet,也就是绕开Filter
Listener
一般给按钮增加监听器——点击按钮,触发一项监听事件
Listener类型
- HttpSessionListener:监听Session的创建与销毁
- ServletReuqestListener:监听request的创建与销毁
- ServletContextListener:监听Context的创建与销毁
这个只是一个笼统的例子(IDEA官方模板)
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
package com.test.Listeners;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
@WebListener
public class ListenerforServletContext implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener {
public ListenerforServletContext() {
}
@Override
public void contextInitialized(ServletContextEvent sce) {
/* This method is called when the servlet context is initialized(when the Web application is deployed). */
System.out.println("ServletContext对象创建");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
/* This method is called when the servlet Context is undeployed or Application Server shuts down. */
System.out.println("ServletContext对象销毁");
}
@Override
public void sessionCreated(HttpSessionEvent se) {
/* Session is created. */
System.out.println(se.getSession() + "创建成功。");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
/* Session is destroyed. */
System.out.println("Session销毁。");
}
@Override
public void attributeAdded(HttpSessionBindingEvent sbe) {
/* This method is called when an attribute is added to a session. */
}
@Override
public void attributeRemoved(HttpSessionBindingEvent sbe) {
/* This method is called when an attribute is removed from a session. */
}
@Override
public void attributeReplaced(HttpSessionBindingEvent sbe) {
/* This method is called when an attribute is replaced in a session. */
}
}
|
然后其他的配置:
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
|
//web.xml
<!-- 对ServletContext和Request的listener的注册 -->
<listener>
<listener-class>com.test.Listeners.ListenerforServletContext</listener-class>
</listener>
//web.xml文件中注册监听器
<!--注册针对HttpSession对象进行监听的监听器-->
<listener>
<description>HttpSessionListener监听器</description>
<listener-class>me.gacl.web.listener.MyHttpSessionListener</listener-class>
</listener>
<!-- 配置HttpSession对象的销毁时机 -->
<session-config>
<!--配置HttpSession对象的1分钟之后销毁 -->
<session-timeout>1</session-timeout>
</session-config>
```
![Untitled](../post_3/S_L_Fpics/Untitled%205.png)
<hr>
|