java_web_2
主要内容:Tomcat、servlet;JSP、MVC、cookie&session ; EL&JSTL ; filter&listener学习目标1. Tomcat & Servlet能够理解WEB动态资源概念能够安装、启动和关闭Tomcat服务器掌握运用Tomcat服务器部署WEB项目的三种方式能够说出Servlet的编写流程能够说...
主要内容:Tomcat、servlet;JSP、MVC、cookie&session ; EL&JSTL ; filter&listener
文章目录
学习目标
1. Tomcat & Servlet
- 能够理解WEB动态资源概念
- 能够安装、启动和关闭Tomcat服务器
- 掌握运用Tomcat服务器部署WEB项目的三种方式
- 能够说出Servlet的编写流程
- 能够说出Servlet的生命周期
- 能够使用注解开发Servlet
- 能够理解HTTP协议请求内容的格式
- 能够处理HTTP请求参数的乱码问题
- 能够使用Request对象获取HTTP协议请求头的值
2. cookie& session
- 能够说出会话的概念
- 能够说出两种会话技术的区别
- 能够创建、发送、接收、删除cookie
- 能够说出cookie执行的原理
- 能够获取session对象、添加、删除、获取session
- 能够说出session执行的原理
- 能够说出session的创建、销毁机制
3. EL && JSTL
- 能够说出el表达式的作用
- 能够使用el表达式获取javabean的属性
- 能够使用jstl标签库的if标签
- 能够使用jstl标签库的foreach标签
5. filter & listener
- 能够说出过滤器的作用
- 能够编写过滤器
- 能够说出过滤器声明周期相关方法
- 能够根据过滤路径判断指定的过滤器是否起作用
- 能够理解什么是过滤器链
- 能够完成filter完成用户登录验证案例
- 能够理解动态代理对类的方法进行增强
- 能够了解listener概念
day13 Tomcat&Servlet
1. web服务器软件
1. 服务器
安装了服务器软件的计算机
2. 服务器软件
接收用户的请求,处理请求,做出响应
web服务器软件:接收用户的请求,处理请求,做出响应
- 在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目
- web容器
3. 常见java相关的web软件
- webLogic: oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费
- webSphere: IBM
- JBOSS: JBOSS公司
- Tomcat: Apache基金组织,中小型,支持少量javaEE规范servlet/jsp,开源的,免费的
4. javaEE:
java语言在企业级开发中使用的技术规范的综合,一共规定了13项大的规范。
2. Tomcat
目录结构
- /bin:存放Windows或Linux平台上启动和关闭Tomcat的脚本文件。
- /conf:存放Tomcat的各种全局配置文件,其中最重要的是server.xml。
- /lib:存放Tomcat以及所有Web应用都可以访问的JAR文件。
- /logs:存放Tomcat执行时产生的日志文件。
- /work:存放JSP编译后产生的Class文件。
- /webapps:Tomcat的Web应用目录,默认情况下把Web应用放在这个目录下
各类日志
运行日志,主要记录运行过程中的一些信息,尤其是一些异常错误日志信息
访问日志,它记录访问的时间、IP地址、访问的路径等相关信息。
- catalina.***.log 主要是记录Tomcat启动过程的信息,在这个文件可以看到启动的JVM参数以及操作系统等日志信息。
- localhost.**.log 主要记录Web应用在初始化过程中遇到的未处理的异常,会被Tomcat捕获而输出这个日志文件
- localhost_access_log.**.txt 存放访问Tomcat的请求日志,包括IP地址以及请求的路径、时间、请求协议以及状态码等信息
1. 安装卸载相关
- 下载
- 安装
- 卸载
- 启动
bin/startup.bat
,双击运行该文件即可- 访问:浏览器输入:
http://localhost:8080
http:别人的ip:8080
- 关闭
- 正常关闭
ctrl+c
或者打开shutdown.bat
- 暴力关闭 直接点close
- 正常关闭
- 配置
启动可能遇到的问题:
- 黑窗口一闪而过:
- 原因:没有正确配置JAVA_HOME环境变量,或者CATALINA_HOME之类的环境变量错误
- 解决方案:正确配置JAVA_HOME环境变量,或者在CMD命令行启动,会报相应的错
- 或者编辑
startup.bat
,在末尾加一个pause
- 启动报错
- 暴力:找到占用的端口号,并且找到对应的进程,杀死该进程
netstat -ano
- 温柔:修改自己的端口号
conf/server.xml
<Connector port="8888" protocol="HTTP/1.1"
- 一般会将tomcat的默认端口号修改为80。80端口号是http协议的默认端口号。
- 暴力:找到占用的端口号,并且找到对应的进程,杀死该进程
2. 配置 部署项目的方式
直接将项目放到webapps目录下
(使用的较多,方便,针对小项目)
/hello:
项目的访问路径–> 虚拟目录- 简化部署:将项目打包为war包,再将war包放到webapps目录下
- war包会自动解压缩
配置conf/server.xml文件
(强烈不建议使用)
在<Host>
标签体中配置 <Context docBase="D:/hello" path="/hehe" />
docBase 项目存放的位置,path虚拟目录
热部署
在conf/Catalina\localhost创建任意名称的xml文件,在文件中编写
<Context docBase="D:\hello">
- 虚拟目录:xml文件的名称 热部署,想删除,修改扩展名为xxx_bat即可
3. 静态项目和动态项目
1. java动态项目的目录结构
一般,我们以web应用程序的方式部署servlet,而根据servlet规范,web应用程序有一定的目录结构,在这个目录下分别放置servlet的类文件、配置文件和静态资源,servlet容器通过读取配置文件,找到并加载servlet。
-- 项目的根目录
-- WEB-INF目录
-- web.xml:web项目的核心配置文件
-- classes目录: 放置字节码文件的目录
-- lib目录: 放置依赖的jar包
2. Tomcat 集成到idea
集成到idea,常见javaEE的项目,部署项目
热部署,如何集成到idea
3. Servlet
1. 概念:
运行在服务器端的小程序
servlet就是一个接口,定义了java类被浏览器访问到(tomcat识别)的规则
一个Java类,要想被浏览器访问到(Tomcat识别到),必须实现servlet接口
我们自己定义一个类,实现Servlet接口,复写方法
2. 快速入门
-
创建javaEE项目
-
定义一个类,实现servlet接口
public class ServletDemo01 implements Servlet
-
实现接口中的抽象方法
-
配置servlet
<!--配置servlet--> <servlet> <servlet-name>demo1</servlet-name> <servlet-class>cn.itcast.web.servlet.ServletDemo01</servlet-class> </servlet> <servlet-mapping> <servlet-name>demo1</servlet-name> <url-pattern>/demo1</url-pattern> </servlet-mapping> </web-app>
3. 执行原理
- 当服务器接收到客户端浏览器的请求后,会解析请求url路径,获取访问的servlet的资源路径
- 查找web.xml文件,是否有对应的
<url-pattern>
标签体内容 - 如果有,则再找对应的
<servlet-class>
全类名 - Tomcat会将字节码文件加载进内存
Class.forName("全类名")
,并且创建其对象cls.newInstance()
- 调用service方法
Servletconfig类
作用是封装servlet的初始化参数,在web.xml给servlet配置的参数,在程序中通过getServletConfig方法获取这些参数。
4. servlet的生命周期
1. 被创建
执行init方法,只执行一次
- servlet什么时候被创建?
- 默认情况,第一次被访问时,创建
- 可以配置指定servlet的创建时机
- 在servlet标签下配置
指定servlet的创建时机
- 第一次被访问时,创建
<load-on-startup>
值为负数 - 在服务器启动时,创建
<load-on-startup>
值为0或者正数
servlet的init方法,只执行一次,说明一个servlet在内存中只存在一个对象,servlet是单例的
- 多个用户同时访问时,可能存在线程安全问题
- 解决:尽量不要在servlet中定义成员变量,即使定义成员变量,也不要对值进行修改
可能在init方法中初始化一些资源,如spring MVC的DispatcherServlet在init方法里创建自己的spring容器。
2. 提供服务
执行service方法,执行多次
3. 被销毁
执行destroy方法,只执行一次
只有服务器正常关闭时,才会执行,一般用于释放资源
5. servlet3.0
好处:支持注解配置,可以不需要web.xml
步骤:
- 创建JavaEE项目,选择Servlet版本3.0以上,可以不创建web.xml
- 定义一个类,实现servlet接口
- 复写方法
- 在类上使用@WebService注解,进行配置
@WebServlet("资源路径")
6. IDEA与Tomcat的相关配置
- IDEA会为每一个Tomcat部署的项目单独建立一份配置文件
- 查看控制台的log:“C:\Users\Lenovo.IntelliJIdea2018.3\system\tomcat_javaweb2”
- 工作空间项目 和 Tomcat部署的web项目
- Tomcat真正访问的是“Tomcat部署的web项目”,而“Tomcat部署的web项目”对应着“工作空间项目”的web目录下的所有资源
- WEB-INF目录下的资源不能被浏览器直接访问
7. servlet相关配置
- urlpattern: servlet访问路径
- 一个servlet可以定义多个访问路径:
@WebServlet({"/d4","/dd4","/ddd4"})
- 路径定义规则:
- /xxx: 路径匹配 “/demo1”
- /xxx/xxx : 多层路径,目录结构 “/user/demo1”
*.do
: 扩展名匹配 *.action 为什么写.do
呢?
- 优先级:
绝对匹配 /xxx > /* > *.do
- 一个servlet可以定义多个访问路径:
[外链图片转存失败(img-DbFgY8Kl-1563071065997)(img\url_pattern.png)]
servlet的体系结构
genericServlet类:将servlet接口中其他方法做了默认空实现,只将service()方法作为抽象
将来定义servlet类时,可以继承GenericServlet,实现service()方法即可
HttpServlet: 对http协议的封装,简化操作
- 定义继承
Ctrl+H
查看继承
GenericServlet类:
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();//调用init()方法,将init()方法里的方法体内容输出
}
public void init() throws ServletException {
}
Servlet接口:
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
public abstract class HttpServlet extends GenericServlet
为什么GenericServlet重写了Servlet的init方法后,自己又写了个空参的init()方法
ServletContext
Servlet规范里定义了ServletContext这个接口来对应一个Web应用。Web应用部署好后,Servlet容器在启动时会加载Web应用,并为每个Web应用创建唯一的ServletContext对象。你可以把ServletContext看成是一个全局对象,一个Web应用可能有多个Servlet,这些Servlet可以通过全局的ServletContext来共享数据,这些数据包括Web应用的初始化参数、Web应用目录下的文件资源等。由于ServletContext持有所有Servlet实例,你还可以通过它来实现Servlet请求的转发
day14-18 HTTP
1. 概念
Hyper Text Transfer Protocol
超文本传输协议
传输协议:定义了客户端和服务器端通信时,发送数据的格式
特点:
- 基于TCP/IP的高级协议
- 默认端口:80
- 基于请求/响应模型的:一次请求对应一次响应
- 无状态的:每次请求之间相互独立,不能交互数据
历史版本
- 1.0:每一次请求都会响应都会建立新的连接
- 1.1:复用连接
发展史:
- 0.9版本:只能传输HTML,只支持get命令,基于TCP
- 1.0版本:1996年,不仅可以传输HTML的文本,
- 1.1版本:1997年,增加持久连接
- 2.0版本:做了多工的处理
在java开发中不管用线程,数据库,网路请求,建立的连接,都是宝贵的,不要随意乱用和浪费
2. request
1. request消息数据格式
[外链图片转存失败(img-IHOzOqME-1563071065999)(img\图一 HTTP协议的请求部分.bmp)]
1. 请求行
请求方式 请求url 请求协议/版本
GET /login.html HTTP/1.1
2. 请求头
客户端浏览器告诉服务器一些信息
请求头名称:请求头值
常见的请求头:
- User-Agent: 浏览器告诉服务器,我访问你使用的浏览器版本信息
- 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
- Referer:
http://localhost/login.html
- 告诉服务器,我(当前请求)从哪里来
- 作用:1. 防盗链 2. 统计工作
3. 请求空行
空行,分隔post请求头和请求体
4. 请求体(正文)
封装POST请求消息的请求参数的
字符串格式
POST /login.html HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
2. request对象
1. request对象和response对象的原理
- request和response对象是由服务器创建的,我们来使用它们
- request对象是来获取请求消息,response对象是来设置响应消息
- Tomcat服务器会根据请求url中的资源路径,创建对应的servletDemo1的对象
- Tomcat服务器,会创建request和response对象,request对象中封装请求消息数据
- Tomcat将request和response对象传递给service方法,并且调用service方法
- 程序员,可以通过request对象获取请求消息数据,通过response对象设置响应消息数据
- 服务器再给浏览器做出响应之前,会从response对象中拿程序员设置的响应消息数据
2. request对象的继承体系结构
ServletRequest --接口
|
HttpServletRequest -- 接口
|
org.apache.catalina.connector.RequestFacade类实现
3. request功能
1. 获取请求行消息数据
获取请求行数据 GET /day14/demo1?name=zhangsan HTTP/1.1
- 获取请求方式 GET
String getMethod()
- 获取虚拟目录 /day14
String getContextPath()
- 获取Servlet路径 /demo1
String getServletPath()
- 获取get方式请求参数 name=zhangsan
String getQueryString()
- 获取请求URI: /day14/demo1
String getRequestURI()
/day14/demo
String getRequestURL()
http://localhost/day14/demo
- 获取协议及版本:HTTP/1.1
String getProtocol
- 获取客户机的IP地址:
String getRemoteAddr()
2. 获取请求头数据
方法:
String getHeader(String name)
通过请求头的名称获取请求头的值Enumeration<String> getHeaderNames()
获取所有的请求头名称
3. 获取请求体数据
请求体:只有post请求方式,才有请求体,在请求体中封装post请求的请求参数
步骤:
- 获取流对象
- BufferedReader getReader() : 获取字符输入流,只能操作字符数据
- ServletInputStream getInputStream(): 获取字节输入流,可以操作所有数据,在文件上传知识点讲解
- 再从流对象中拿数据
4. 其他功能
4.1获取请求参数通用方式
String getParameter(String name)
根据参数名称获取参数值String[] getParameterValues(String name)
根据参数名称获取参数值的数组,常见复选框Enumeration<String> getParameterNames()
获取所有请求的参数名称Map<String, String[]> getParameterMap()
获取所有参数的map集合
- 中文乱码问题:
- get方式:Tomcat 8已经将get方式乱码问题解决了
- post方式:会乱码
- 解决:在获取参数之前,设置request的编码方式
request.setCharacterEncoding("utf-8");
4.2 请求转发
一种在服务器内部的资源跳转方式
请求次数:代表的是浏览器到服务器端的次数,不包含服务器内部跳转
- 步骤:
- 通过request对象获取请求转发器对象:
RequestDispatcher getRequestDispatcher(String path)
- 使用RequestDispatcher对象来进行转发:
forward(ServletRequest request,ServletResponse response)
- 通过request对象获取请求转发器对象:
- 特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器内部资源中
- 转发是一次请求
4.3 共享数据
- 域对象:一个有作用范围的对象,可以在范围内共享数据
- request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
- 方法:
void setAttribute(String name,Object obj)
存储数据Object getAttribute(String name)
通过键获取值void removeAttribute(String name)
通过键移除键值对
4.4 获取ServletContext
ServletContext getServletContext()
3. request案例
1. 用户登录案例需求:
1.编写login.html登录页面
username & password 两个输入框
2.使用Druid数据库连接池技术,操作mysql,day14数据库中user表
3.使用JdbcTemplate技术封装JDBC
4.登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您
5.登录失败跳转到FailServlet展示:登录失败,用户名或密码错误
2. 分析
3. 开发步骤
-
创建项目,导入HTML项目,配置文件,jar包
-
创建数据库环境
CREATE DATABASE day14; USE day14; CREATE TABLE USER( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32) UNIQUE NOT NULL, PASSWORD VARCHAR(32) NOT NULL );
-
创建包
cn.itcast.domain
创建类User
-
创建包
cn.itcast.dao
创建类UserDao
操作数据库,提供login的方法 -
创建工具吧
con.itcast.util
创建JDBCUtils工具类,使用Druid连接池,获取连接池对象和连接对象public class JDBCUtils { private static DataSource ds; static { try { // 加载配置文件 Properties pro = new Properties(); InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"); pro.load(in); // 初始化连接池对象 ds = DruidDataSourceFactory.createDataSource(pro); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } // 获取连接池对象 public static DataSource getDataSource(){ return ds; } // 获取连接connection对象 public static Connection getConnection() throws SQLException { return ds.getConnection(); } }
-
完善UserDao的方法
public class UserDao { // 声明JDBCTemplate对象共用 private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 登录方法
* @param loginUser 只有用户名和密码
* @return user包含用户全部数据,没有,返回null值
*/
public User login(User loginUser){
try {
// 1. 编写SQL
String sql = "select * from user where username = ? and password = ?";
// 2. 调用query方法
User user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (DataAccessException e) {
e.printStackTrace();//记录日志
return null;
}
}
}
7. 测试方法,看Dao代码运行是否正常,创建包`cn.itcast.test`,测试类`UserDaoTest`
```java
public class UserDaoTest {
@Test
public void testLogin(){
// 创建登录用户对象
User loginUser = new User();
loginUser.setUsername("superbaby");
loginUser.setPassword("123111");
// 查看数据库是否有该对象
UserDao dao = new UserDao();
User user = dao.login(loginUser);
System.out.println(user);
}
}
发现问题,如果用户名密码不一致,会出现异常,不应该抛出异常,应该返回null,用try/catch包裹(ctrl+alt+t
)
-
编写
cn.itcast.web.servlet.LoginServlet
类@WebServlet("/loginServlet") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置编码 request.setCharacterEncoding("utf-8"); // 获取请求参数 String username = request.getParameter("username"); String password = request.getParameter("password"); // 封装user对象 User loginUser = new User(); loginUser.setUsername(username); loginUser.setPassword(password); // 调用Dao的login方法 UserDao dao = new UserDao(); User user = dao.login(loginUser); // 判断user if(user == null){ //登录失败 //转发 request.getRequestDispatcher("/failServlet").forward(request,response); }else{ // 登录成功 // 存储数据 request.setAttribute("user",user); request.getRequestDispatcher("/successServlet").forward(request,response); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
-
编写成功和失败的跳转页面
@WebServlet("/failServlet") public class FailServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 给页面写一句话 // 设置编码 response.setContentType("text/html;charset=utf-8"); // 输出 response.getWriter().write("登录失败,用户名或密码错误"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取request域中共享的user对象
User user =(User) request.getAttribute("user");
if (user!=null) {
// 给页面写一句话
// 设置编码
response.setContentType("text/html;charset=utf-8");
// 输出
response.getWriter().write("登录成功,"+user.getUsername()+"欢迎您!");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
### 4. 错误日志
问题:登录后跳转找不到网页,转不到loginServlet的页面
解决方法:部署的问题,在idea该项目的部署中,将虚拟目录改为`/day14_test`,之前误改为`/day14`
### 5. 优化
使用Apache的BeanUtils包封装loginUser对象,修改部分如下
```java
/*// 获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
// 封装user对象
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);*/
// 2. 获取所有请求参数
Map<String, String[]> map = request.getParameterMap();
// 3. 创建User对象
User loginUser = new User();
// 3.2 使用BeanUtils封装
try {
BeanUtils.populate(loginUser,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
6. BeanUtils工具类
简化数据封装,用于封装JavaBean,原理:内省机制
1. Javabean
标准的java类
要求:
- 类必须被public修饰
- 必须提供空参构造器
- 成员变量必须使用private修饰
- 提供公共setter和getter方法
功能:封装数据
2. 概念
成员变量
属性:setter和gettter方法截取后的产物
例如:getUsername() --> Username --> username
3. 方法
- setProperty(“key”) 属性名 != 成员变量
- getProperty()
- populate(Object obj, Map map) 将map集合的键值对信息,封装到对应的javabean对象。
4. response
响应消息:
服务器端发送给客户端的数据
数据格式:
- 响应行
- 组成:协议/版本 响应状态码 状态码描述
- 响应状态码:见下个标题
- 响应头
- 格式: 头名称:值
- 常见的响应头:
- Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
- Content-disposition: 服务器告诉客户端以什么格式打开响应体数据
- 值1: in-line; 默认值,在当前页面内打开
- 值2: attachment;filename=xxx 以附件形式打开响应体,文件下载
- 响应空行
- 响应体: 传输的数据
响应字符串格式
headers:
HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Content-Length: 101
Date: Sat, 09 Mar 2019 04:35:22 GMT
response:
<html>
<head>
<title>response</title>
</head>
<body>
hello, response
</body>
</html>
响应状态码
服务器告诉客户端浏览器本次请求和响应的一个状态
状态码都是3位数字
分类:
-
1xx: 服务器接收客户端消息,但没有接收完成,等待一段时间后,发送1xx状态码
-
2xx:成功 代表:200
-
3xx: 重定向 代表:302(重定向),304(访问缓存)
-
4xx: 客户端错误
代表:
- 404(请求路径没有对应的资源)
- 405(请求方式没有对应的doXxx方法)
-
5xx: 服务器端错误 代表:500(服务器内部出现异常)
5. response对象
1. 功能
设置响应消息
1. 设置响应行
- 格式:HTTP/1.1 200 OK
- 设置状态码:
setStatus(int sc)
2. 设置响应头
setHeader(String name, String value)
3. 设置响应体
使用步骤:
- 获取输出流
- 字符输出流:
PrintWriter getWriter()
- 字节输出流:
ServletOutputStream getOutputStream()
- 字符输出流:
- 使用输出流,将数据输出到客户端浏览器
2. 案例
1. 重定向
资源的跳转方式
代码实现
// 访问responseDemo01会自动跳转到/responseDemo02资源
/* // 1. 设置状态码为302
response.setStatus(302);
// 2. 设置响应头location
response.setHeader("location","/day15_response/responseDemo02");*/
// 简单的重定向方法
response.sendRedirect("/day15_response/responseDemo02");
重定向redirect的特点:
- 地址栏发生变化
- 重定向可以访问其他站点(服务器)的资源
- 重定向是两次请求
转发forward的特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器内部资源中
- 转发是一次请求
路径写法
-
相对路径:通过相对路径不可以确定唯一资源
- 如:
./index.html
- 不以
/
开头,以.
开头路径 - 规则:找到当前资源和目标资源之间的相对位置关系
./
: 当前目录../
:后退一级目录
- 如:
-
绝对路径:通过绝对路径可以确定唯一资源
-
如:
http://localhost:8080/day15_response/responseDemo02
-
以
/
开头的路径 -
规则:判断定义的路径是给谁用的,判断请求将来从哪里发出
- 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
- 建议虚拟目录动态获取:
request.getContextPath()
<a>,<form>
重定向…
- 建议虚拟目录动态获取:
- 给服务器使用:不需要加虚拟目录
- 转发路径
- 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
-
2. 服务器输出字符数据到浏览器
步骤:
- 获取字符输出流
- 输出数据
注意:
-
乱码问题:
PrintWriter pw = response.getWriter();
获取的流的默认编码格式为ISO-8859-1- 设置该流的默认编码
- 告诉浏览器响应体使用的编码
// 简单的形式,设置编码,在获取流之前设置 response.setContentType("text/html;charset=utf-8");
3. 服务器输出字节数据到浏览器
步骤:
-
获取字节输出流
-
输出数据
response.setContentType("text/html;charset=utf-8"); // 1. 获取字节输出流 ServletOutputStream sos = response.getOutputStream(); sos.write("你好".getBytes("utf-8"));
4. 验证码
本质:图片
目的:防止恶意表单注册
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int width = 100;
int height = 50;
// 1. 创建一个对象,在内存中图片(验证码图片对象)
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 2. 美化图片
// 2.1 填充背景色
Graphics g = image.getGraphics();// 画笔对象
g.setColor(Color.pink);
g.fillRect(0,0,width,height);
// 2.2 画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width-1,height-1);
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
// 生成随机角标
Random random = new Random();
for (int i = 1; i <= 4; i++) {
int index = random.nextInt(str.length());
// 获取字符
char ch = str.charAt(index);
// 2.3 写验证码
g.drawString(ch+"",width/5*i,height/2);
}
// 2.4 画干扰线
g.setColor(Color.gray);
// 随机生成坐标点
for (int i = 0; i < 10; i++) {
int x1 = random.nextInt(width);
int x2 = random.nextInt(width);
int y1 = random.nextInt(height);
int y2 = random.nextInt(height);
g.drawLine(x1,y1,x2,y2);
}
// 3. 将图片输出到页面展示
ImageIO.write(image, "jpg", response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
6. ServletContext对象
1. 概念
代表整个web应用,可以和程序的容器(服务器)来通信。
2. 功能
- 获取MIME类型
- 域对象:共享数据
- 获取文件的真实(服务器)路径
MIME类型
在互联网通信过程中定义的一种文件数据类型
格式: 大类型/小类型 text/html
image/jpeg
域对象
共享数据
setAttribute(String name,Object value)
getAttribute(String name)
removeAttribute(String name)
ServletContext
对象范围:所有用户所有请求的数据
获取文件的真实(服务器)路径
方法:String getRealPath(String path)
String realPath = servletContext.getRealPath("/b.txt");// Web目录下的文件
String c = servletContext.getRealPath("/WEB-INF/c.txt");// WEB-INF目录下的文件
String a = servletContext.getRealPath("/WEB-INF/classes/c.txt");//src目录下的文件
7. response案例
需求:
文件下载
- 页面显示超链接
- 点击超链接后弹出下载提示框
- 完成图片文件下载
步骤
- 定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename
- 定义Servlet
- 获取文件名称
- 使用字节输入流加载文件进内存(需要获取文件真实路径)
- 指定response的响应头:
content-disposition:attachment;filename=xxx
- 将数据写出到response输出流
问题
问题1. :为什么直接拖视频文件到img目录下,没有真正复制到out\artifacts\day15_response_war_exploded\img
问题2:中文文件问题:
解决思路:
- 获取客户端使用的浏览器版本信息
- 根据不同的版本信息,设置filename的编码方式不同
@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置request的编码方式
request.setCharacterEncoding("utf-8");
// 1. 获取请求参数
String filename = request.getParameter("filename");
// 2. 使用字节输入流加载文件进内存
// 2.1 找到文件的服务器路径
String realPath = this.getServletContext().getRealPath("/img/" + filename);
// 2.2 用字节流关联
FileInputStream fis = new FileInputStream(realPath);
// 3. 设置response响应头
// 3.1 设置response响应头的类型 content-type
String mimeType = this.getServletContext().getMimeType(filename);
// 3.2 设置响应头的打开方式 content-disposition
// 解决中文文件名问题
// 1. 获取user-agent请求头
String agent = request.getHeader("user-agent");
// 2. 使用工具类方法编码文件名即可
String fileName = DownLoadUtils.getFileName(agent, filename);
response.setHeader("content-disposition","attachment;filename="+fileName);
// 4. 将输入流的数据写到输出流
ServletOutputStream os = response.getOutputStream();
byte[] buff = new byte[1024*8];
int len;
while((len=fis.read(buff))!=-1){
os.write(buff,0,len);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
day16 cookie&session
1. 会话技术
1. 概念
一次会话中包含多次请求和响应。
一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止。
2. 功能
在一次会话的范围内的多次请求间,共享数据
3. 方式
- 客户端会话技术:cookie
- 服务器端会话技术:session
2. cookie
1. 概念
客户端会话技术,将数据保存到客户端
2. 快速入门
使用步骤:
- 创建cookie对象,绑定数据
new Cookie(String name,String value)
- 发送Cookie对象
response.addCookie(Cookie cookie)
- 获取Cookie,拿到数据
Cookie[] request.getCookies()
3. 实现原理
基于响应头set-cookie
和请求头cookie
实现
cookie应用场景
访问京东商城,购物,看上了一个商品加入购物车(并未登录的情况下),可以将商品信息通过cookie的方式存储到浏览器端,在结算的时候,查询所有的cookie,列出我们的商品
4. cookie的细节
4.1 一次可不可以发送多个cookie?
- 可以
- 可以创建多个cookie对象,使用response调用多次addCookie方法发送cookie即可
4.2 cookie在浏览器中保存多长时间?
默认情况下,当浏览器关闭后,cookie数据被销毁
持久化存储:setMaxAge(int seconds)
- 正数:将cookie数据写到硬盘的文件中,持久化存储。cookie存活时间
- 负数:默认值
- 零:删除cookie数据
4.3 cookie能不能存中文?
- 在tomcat8之前,cookie中不能直接存储中文数据
- 需要将中文数据转码,一般采用URL编码(%E3)
- 在tomcat8之后,cookie支持中文数据
4.4 cookie的共享问题?
假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能否共享?
- 默认情况下cookie不能共享
setPath(String path)
:设置cookie的获取范围,默认情况下设置当前的虚拟目录- 如果想共享,则可以将path设置为"/"
不同的tomcat服务器间cookie共享问题?
setDomain(String path)
: 如果设置一级域名相同,那么多个服务器之间cookie可以共享setDomain(".baidu.com")
,那么tieba.baidu.com
和news.baidu.com
中cookie可以共享
扩展:
- 如果我的项目,,没有给cookie设置path,但是我的虚拟目录也是"/",能否共享cookie
- 能,不调用setPath("/")如果虚拟目录本身就是/,依然可以共享所有项目,但是如果调用getPath(),获取的路径为null
5. cookie的特点
- cookie存储数据在客户端浏览器
- 浏览器对于单个cookie的大小有限制(4kb)以及对于同一个域名下的总cookie数也有限制(20个)
作用:
- cookie一般用于存储少量的不太敏感的数据
- 在不登录的情况下,完成服务器对客户端的身份识别
day16 JSP
1. 入门学习
1. 概念
Java Server Pages
:java服务器端页面
可以理解为:一个特殊的页面,其中既可以指定定义HTML标签,又可以定义java代码
用于简化书写
目前的传统项目中JSP仅仅作为页面展示+servlet+数据共享(request,ServletContext,page,session)
2. 原理
本质上就是一个Servlet,第一次访问该JSP的时候,翻译成一个.java .class 继承HttpJSPBase ---- HttpServlet
3. JSP的脚本
JSP定义java代码的方式
<% 代码 %>
: 定义的java代码,在service方法中,service方法中可以定义什么,该脚本中就可以定义什么<%! 代码 %>
: 定义的java代码,在JSP转换后的java类的成员位置,一般不用<%= 代码 %>
: 定义的java代码,会输出到页面上,输出语句中可以定义什么,该脚本就可以定义什么
4. 内置对象
1. 概念
在jsp页面中不需要获取和创建,可以直接使用的对象
jsp一共有9个内置对象
今天学习3个:
- request
- response
- out:字符输出流对象。可以将数据输出到页面上。和response.getWrter()类似
在tomcat服务器真正给客户端做出响应之前,会先找response缓冲区数据,
response.getWriter()数据输出永远在out.write()之前,尽量不要用response.getWrter()输出!
入门案例
修改cookie案例为jsp
<%@ page import="java.net.URLDecoder" %>
<%@ page import="static cn.itcast.cookie.CookieTest.getTime" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>itcast</title>
</head>
<body>
<%
// 设置request的编码方式
request.setCharacterEncoding("utf-8");
// 1. 获取cookie
Cookie[] cookies = request.getCookies();
boolean flag = false;
if(cookies!=null && cookies.length>0){
for (Cookie cookie : cookies) {
String name = cookie.getName();
if("lastTime".equals(name)){
// 不是第一次,欢迎回来,您上次访问时间为:显示时间字符串
flag = true;
String value = cookie.getValue();
// 取出来后要URL解码
String value1 = URLDecoder.decode(value, "utf-8");
%>
<h1>欢迎回来,您上次访问时间为:<%= value1 %></h1>
<%
// 修改cookie的value
value = getTime();
cookie.setValue(value);
cookie.setMaxAge(60*60*24*30);
response.addCookie(cookie);
break;
}
}
}
if(cookies==null || cookies.length==0 || flag==false){
Cookie cookie = new Cookie("lastTime",getTime());
cookie.setMaxAge(60*60*24*30);
response.addCookie(cookie);
// 首次登陆
%>
<h1>您好,欢迎您首次访问。</h1>
<%
}
%>
</body>
</html>
2. session
1. 概念
服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中,HttpSession
2. 快速入门
1. 获取HttpSession对象
HttpSession session = request.getSession();
2. 使用Httpsession对象
Object getAttribute(String name)
void setAttribute(String name, Object value)
void removeAttribute(String name)
3. 原理
session的实现依赖于cookie
4. 细节
1. 当客户端关闭后,服务器不关闭,两次获取的session是否为同一个?
- 默认情况下,不是
- 如果需要相同,可以创建cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存
HttpSession session = request.getSession();
Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
2. 客户端不关闭,服务器关闭后,两次获取到的session是同一个吗?
- 不是同一个,但是要确保数据不丢失
- session的钝化
- 在服务器正常关闭之前,将session对象序列化到硬盘
- session的活化
- 在服务器启动后,将session文件转化为内存中的session对象即可
3. session什么时候被销毁?
-
服务器关闭
-
session对象调用invalidate()
-
session默认失效时间30分钟
选择性配置修改
<session-config> <session-timeout>30</session-timeout> </session-config>
5. session 的特点
- session用于存储一次会话的多次请求的数据,存在服务器端
- session可以存储任意类型,任意大小的数据
session和cookie的区别
- session存储数据在服务器端,cookie在客户端
- session没有数据大小限制,cookie有
- session数据安全,cookie相对不安全
3. JSP深入
1. 指令
作用
用于配置JSP页面,导入资源文件
格式
<%@ 指令名称 属性名1=属性值1 属性名2=属性值2 ... %>
分类
-
page:配置JSP页面的
ContentType
:等同于response.setContentType()
- 设置响应体的MIME类型以及字符集
- 设置当前jsp页面的编码(只能是高级的IDE才能生效,低级的需要设置pageEncoding属性设置当前页面的字符集)
import
:导包errorPage
:当前页面发生异常后,会自动跳转到指定的错误页面isErrorPage
:标识当前页面是否是错误页面true
:是,可以使用内置对象exceptionfalse
:否,默认值,不可以使用内置对象exception
-
include:页面包含的,导入页面的资源文件
<%@include file="top.jsp"%>
-
taglib:导入资源
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
prefix为前缀
2. 注释
1. HTML注释
<!-- -->
只能注释HTML代码片段
2. jsp注释:推荐使用
<%-- --%>
:可以注释所有
3. 内置对象
在jsp页面中不需要创建,直接使用的对象
一共有9个
变量名 | 真实类型 | 作用 |
---|---|---|
pageContext | PageContext | 当前页面共享数据,还可以获取其他八个内置对象 |
request | HttpServletRequest | 一次请求访问的多个资源(转发) |
session | HttpSession | 一次会话的多个请求间 |
application | ServletContext | 所有用户间共享数据 |
response | HttpServletResponse | 响应对象 |
page | Object | 当前页面(Servlet)的对象 this |
out | JspWriter | 输出对象,数据输出到页面上 |
config | ServletConfig | servlet的配置对象 |
exception | Throwable | 异常对象 |
day17 MVC
1. MVC
1. jsp演变历史
- 早期只有servlet,只能使用response输出标签数据,非常麻烦
- 再后来有jsp,简化了servlet的开发,如果过度使用jsp,在jsp中既写大量的java代码,又写HTML标签,造成难以维护,难以分工协作
- 再后来,java的web开发,借鉴MVC开发模式,使得程序的设计更加合理
2. MVC
1. 概念
-
M: Model 模型。 javabean
- 完成具体的业务操作,如:查询数据库,封装对象
-
V:View 视图 JSP
-
展示数据
数据存储在哪里? 数据库,内存(四大域对象),本地
-
-
C: Controller 控制器 servlet
- 获取用户的输入
- 调用模型
- 将数据交给视图进行展示
2. 优缺点
优点:
- 耦合性低,方便维护,利于分工协作
- 重用性高
缺点:使得项目结构变得复杂,对开发人员要求高
2. EL表达式
1. 概念
Expression Language 表达式语言
2. 作用
替换和简化jsp页面中java代码的编写
3. 语法
${表达式}
4. 注意
jsp默认支持el表达式的,如果要忽略el表达式
- 设置jsp中page指令中:
isELIgnore="true"
忽略当前jsp页面的所有的el表达式 \${表达式}
:忽略当前这个el表达式
5. 作用
- 运算
- 获取值
运算符
- 算数运算符:
+ - * / (div) %(mod)
- 比较运算符:
> < >= <= == !=
- 逻辑运算符:
&&(and) ||(or) !(not)
- 空运算符: empty
- 功能: 用于判断字符串、集合、数组对象是否为null并且长度是否为0
${empty list}
获取值
-
el表达式只能从域对象中获取值
-
语法:
${域名称.键名}
:从指定域中获取指定键的值- 域名称:
pageScope
-->pageContext
requestScope
-->request
sessionScope
-->session
applicationScope
–>application(servletContext)
- 例子:在request域中存储了
name=张三
- 获取:
${requestScope.name}
- 域名称:
${键名}
:表示依次从最小的域中查找是否有该键对应的值,直到找到为止- 获取对象、list集合、map集合的值
- 对象:
${域名称.键名.属性名}
- 本质上会去调用对象的getter方法
- List集合:
${域名称.键名[索引]}
- map集合
${域名称.键名.属性名}
${域名称.键名["key名称"]}
- 对象:
<h1>获取list集合中的map集合中的user对象中的birthday</h1> ${requestScope.list[0].user.birStr}
-
隐式对象
- el表达式中有11个隐式对象,知道4个域对象和pageContext即可
- pageContext:获取jsp其他八个内置对象
${pageContext.request.contextPath}
:动态获取虚拟目录
3. JSTL
1. 概念
JavaServer pages Tag Library
JSP标准标签库
是由Apache组织提供的开源的免费的jsp标签 <标签>
2. 作用
用于简化和替换jsp页面上的java代码
3. 使用步骤
- 导入JSTL相关jar包
- 引入标签库: taglib指令
<%@ taglib %>
- 使用标签
4. 常用标签
1. if
相当于java代码的if语句
- 属性:
- test:必须属性,接收boolean表达式
- 如果表达式为true,则显示if标签体内容,如果为false,不显示标签体内容
- 一般情况,test属性值会结合el表达式一起使用
- test:必须属性,接收boolean表达式
- 注意:
c:if
标签没有else情况,想要else情况,可以再定义一个c:if
标签
2. choose
相当于java代码的switch语句
- 使用choose标签声明 相当于switch语句
- 使用when标签做判断 相当于case
- 使用otherwise标签做其他情况的声明 相当于default
3. foreach
相当于java代码的for语句
- 完成重复操作
for(int i=0;i<10;i++)
属性:begin:开始值;end:结束值;var:临时变量;step:步长;
varStatus:循环状态对象;index:容器中元素的索引,从0开始;count:循环次数,从1开始
-
遍历容器
List<User> list; for(User user: list){}
属性:item:容器对象;var:容器中元素的临时变量
4. 三层架构
软件设计架构
- 界面层(表示层):用户看得见的界面。用户可以通过界面上的组件和服务器进行交互
- 业务逻辑层:处理业务逻辑
- 数据访问层:操作数据存储文件
案例:用户信息列表展示
-
需求:用户信息的增删改查操作
-
设计
-
技术选型:Servlet+JSP+MySQL+JDBCTemplate+Druid+BeanUtils+tomcat
-
数据库设计:
create database day17; -- 创建数据库 use day17; -- 使用数据库 create table user( -- 创建表 id int primary key auto_increment, name varchar(20) not null, gender varchar(5), age int, address varchar(32), qq varchar(20), email varchar(50) );
-
开发:
- 环境搭建
- 创建数据库环境
- 创建项目,导入需要的jar包
- 编码
- 环境搭建
-
测试
-
部署运维
-
添加用户:
同登录类似?输入参数,获取参数,判断是否存在同名的,是,原页面返回用户名已存在,否,添加进数据库,添加成功后,进入登录页面,显示欢迎你,xxx
day18 扩展机制
1. 扩展机制之Filter
1. 概念
生活中的过滤器:净水器,空气净化器等
web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能
过滤器的作用:
一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤…
2. 快速入门
-
步骤:
- 定义一个类,实现接口Filter
- 复写方法
- 配置拦截路径
- web.xml
- 注解
-
代码:
@WebFilter("/*") // 访问所有资源之前,都会执行该过滤器 public class FilterDemo01 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filterDemo01被执行了。。。"); // 放行 filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }
3. 过滤器细节:
1. web.xml配置
<filter-name>demo1</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo01</filter-class>
</filter>
<filter-mapping>
<filter-name>demo1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>-->
2. 过滤器执行流程
- 执行过滤器
- 执行放行后的资源
- 回来执行过滤器放行代码下的代码
3. 过滤器生命周期方法
- init: 在服务器启动后,会创建Filter对象,然后调用init方法,只执行一次
- doFilter:每一次请求被拦截资源时,会执行,执行多次
- destroy:在服务器关闭后,filter对象被销毁,如果服务器是正常关闭,则会执行destroy方法。用于释放资源。
4. 过滤器配置详解
- 拦截路径配置
- 具体的资源路径:
/index.jsp
只有访问index.jsp资源时,过滤器才会被执行 - 目录拦截:
/user/*
访问/user
下的所有资源时,过滤器都会被执行 - 后缀名拦截:
*.jsp
访问所有后缀名为jsp资源时,过滤器都会被执行 - 拦截所有资源:
/*
访问所有资源时,过滤器都会被执行
- 具体的资源路径:
- 拦截方式配置 资源被访问的方式
- 注解配置:
- 设置
dispatcherTypes
属性- REQUEST 默认值 浏览器直接请求
- FORWORD 转发访问资源
- INCLUDE 包含访问资源(了解)
- ERROR 错误跳转资源(了解)
- ASYNC 异步访问资源(了解)
- 设置
- web.xml配置
- 设置
<dispatcher></dispatcher>
标签即可
- 设置
- 注解配置:
5. 过滤器链FilterChain(配置多个过滤器)
执行顺序:如果有两个过滤器,过滤器1 和过滤器2
- 过滤器1
- 过滤器2
- 资源执行
- 过滤器2
- 过滤器1
先后顺序:
- 注解配置:按照类名的字符串比较规则比较,值小的先执行 如A B
- web.xml配置:
<filter-mapping>
谁定义在上边,谁先执行
4. 案例
增强对象的功能
设计模式:一些通用的解决固定问题的方式
- 装饰模式
- 代理模式
- 概念
- 真实对象:被代理的对象
- 代理对象
- 代理模式:代理对象代理真实对象,达到增强真实对象功能的
- 实现方式
- 静态代理:有一个类文件描述代理模式
- 动态代理:在内存中形成代理类
- 实现步骤
- 代理对象和真实对象实现相同的接口
- 代理对象=Proxy.newInstance();
- 使用代理对象调用方法
- 增强方法
- 增强方式:
- 增强参数列表
- 增强返回值类型
- 增强方法体逻辑
- 增强参数列表
- 实现步骤
- 概念
5. 动态代理
demo:
public class ProxyTest{
public static void main(String[] args) {
Lenovo lenovo = new Lenovo();
SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("sales")){
// 增强参数
double money = (double) args[0];
money = money * 0.85;
System.out.println("专车接你");
// 使用真实对象调用该方法
String obj = (String) method.invoke(lenovo, money);
System.out.println("免费送货...");
// 增强返回值
return obj+"和鼠标垫";
}else{
Object obj = method.invoke(lenovo, args);
return obj;
}
}
});
String computer = proxy_lenovo.sale(8000);
System.out.println(computer);
}
}
2. 扩展机制之listener
概念:web三大组件之一
当Web应用在Servlet容器中运行时,Servlet容器内部会不断的发生各种事件,如Web应用的启动和停止、用户请求到达等。 Servlet容器提供了一些默认的监听器来监听这些事件,当事件发生时,Servlet容器会负责调用监听器的方法
事件监听机制
- 事件 :一件事情
- 事件源 :事件发生的地方
- 监听器 :一个对象
- 注册监听:将事件、事件源、监听器绑定在一起。 当事件源上发生某个事件后,执行监听器代码
例子
- Spring就实现了自己的监听器,来监听ServletContext的启动事件,目的是当Servlet容器启动时,创建并初始化全局的Spring容器
- ServletContextListener:监听ServletContext对象的创建和销毁
方法:
void contextDestroyed(ServletContextEvent sce) :ServletContext对象被销毁之前会调用该方法
void contextInitialized(ServletContextEvent sce) :ServletContext对象创建后会调用该方法
步骤:
- 定义一个类,实现ServletContextListener接口
- 复写方法
- 配置
@WebListener
filter和listener的区别
- Filter是干预过程的,它是过程的一部分,是基于过程行为的。
- Listener是基于状态的,任何行为改变同一个状态,触发的事件是一致的
扩展
springMVC容器、spring容器和servlet容器的关系
Tomcat&Jetty在启动时给每个Web应用创建一个全局的上下文环境,这个上下文就是ServletContext,其为后面的Spring容器提供宿主环境。
Tomcat&Jetty在启动过程中触发容器初始化事件,Spring的ContextLoaderListener会监听到这个事件,它的contextInitialized方法会被调用,在这个方法中,Spring会初始化全局的Spring根容器,这个就是Spring的IoC容器,IoC容器初始化完毕后,Spring将其存储到ServletContext中,便于以后来获取。
Tomcat&Jetty在启动过程中还会扫描Servlet,一个Web应用中的Servlet可以有多个,以SpringMVC中的DispatcherServlet为例,这个Servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个Servlet请求。
Servlet一般会延迟加载,当第一个请求达到时,Tomcat&Jetty发现DispatcherServlet还没有被实例化,就调用DispatcherServlet的init方法,DispatcherServlet在初始化的时候会建立自己的容器,叫做SpringMVC 容器,用来持有Spring MVC相关的Bean。同时,Spring MVC还会通过ServletContext拿到Spring根容器,并将Spring根容器设为SpringMVC容器的父容器,请注意,Spring MVC容器可以访问父容器中的Bean,但是父容器不能访问子容器的Bean, 也就是说Spring根容器不能访问SpringMVC容器里的Bean。说的通俗点就是,在Controller里可以访问Service对象,但是在Service里不可以访问Controller对象。
更多推荐
所有评论(0)