本章节,将进入javaWeb开发技术中,最核心的部分,我们将使用最原始的技术上构建Web系统,这部分原始的技术在实际开发的中并不会直接使用,通常都是使用基于此技术封装的框架。简单的说就是,它是JavaWeb的本质,是每个Java程序员都应该理解和掌握的内容。
web(World Wide Web)即全球广域网,也称为万维网,它是一种基于超文本和HTTP的、全球性的、动态交互的、跨平台的分布式图形信息系统。是建立在Internet上的一种网络服务,为浏览者在Internet上查找和浏览信息提供了图形化的、易于访问的直观界面,其中的文档及超级链接将Internet上的信息节点组织成一个互为关联的网状结构。
通俗的说 就是网站。
在Sun的Java Servlet规范中,对Java Web应用作了这样定义:“Java Web应用由一组Servlet、HTML页、类、以及其它可以被绑定的资源构成。它可以在各种供应商提供的实现Servlet规范的 Servlet容器(Tomcat) 中运行。”Java Web应用中可以包含Servlet、JSP、实用类、静态文档如HTML、图片等描述Web应用的信息(web.xml).
通俗的说 就是用Java相关技术(比如 _servlet jdbc jsp _等 )开发的web应用。
那JavaEE有是什么呢?
Java语言在企业级开发中使用的技术规范的总和,一共规定了13项大的规范。
1、JDBC(java Database Connectivity)2、JNDI(Java Name and Directory Interface)3、EJB(Enterprise JavaBean)4、RMI(RemoteMethod Invoke)5、Java IDL(接口定义语言)/CORBA6、JSP(Java Server Pages)7、Java Servlet、8、XML(Extensible Markup Language)9、JMS(Java Message Service)10、JTA(Java Transaction Architecture)11、JTS(Java Transaction Service):12、JavaMail13、JAF(JavaBeans Activation Framework)
简单的说 就是JavaEE 包含 JavaWeb 。


C/S 对比 B/S
优点:
- cs 体验好,流畅。
- bs 无需升级维护,(服务器更新即可)。
缺点:
- cs 更新麻烦
- 体验没有客户端好。(对应企业系统这都不重要)


Web应用服务器 = 硬件 + 软件
一个Web站点就是一个资源集合,无论是一个网页,一张图片,一个样式文件,视频…,都是资源,网站就是提供这些资源展现给用户,这些资源都被服务器管理了起来。这些资源都是可以被访问到了( 当然服务器也可以限制访问 )。
目前最为流行的Tomcat服务器是Apache-Jarkarta开源项目中的一个子项目,是一个小型、轻量级的支持JSP和Servlet 技术的Web服务器,也是初学者学习开发JSP应用的首选。
下载地址 https://tomcat.apache.org/download-80.cgi
版本选择问题:
Tomcat 作为 javaweb运行的容器,它与JavaEE中的各种技术版本存在 关联对应。

解压到指定的目录,就完成了安装,需要保证本地有JAVA_HOME环境。
tomcat 这个软件就是用java语言开发,它的运行需要jre,所以需要保证本地有 JRE_HOME 或者 JAVA_HOME。
如果没有JAVA_HOME环境变量,则启动不了。
Neither the JAVA_HOME nor the JRE_HOME environment variable is defined At least one of these environment variable is needed to run this program

双击执行 bin/startup.bat4
测试访问 浏览器地址栏 : http://localhost:8080/

双击执行 bin/shutdown.bat
修改 conf/logging.properties
java.util.logging.ConsoleHandler.encoding = GBK // 47行
配置文件修改都必须重启 ,然后才有效果
修改 conf/server.xml
<Connector port="9090" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
port 可以自己定义 80端口 http协议默认端口,访问时可以不输入端口号。
修改 conf/tomcat-users.xml
<role rolename="manager-gui"/>
<user username="tomcat" password="12345" roles="manager-gui"/>



Web工程结构
import java.util.Date;
/**
* 编写第一个Servlet
*/
public class MyServletPage extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// req : 携带请求数据
// resp: 携带响应数据
resp.getWriter().print("");
resp.getWriter().print("");
resp.getWriter().print("" );
resp.getWriter().print("我的第一个动态网页 ");
resp.getWriter().print("");
resp.getWriter().print("");
resp.getWriter().print(" "+ new Date() +" ");
resp.getWriter().print("");
resp.getWriter().print("");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--1. 注册动态资源-->
<servlet>
<servlet-name>ABC</servlet-name>
<servlet-class>servlet.MyServletPage</servlet-class>
</servlet>
<!--2.给动态资源配置请求url-->
<servlet-mapping>
<servlet-name>ABC</servlet-name>
<url-pattern>/user/zmf</url-pattern>
</servlet-mapping>
</web-app>
配置必须 以斜杠 / 开头 否则服务器启动 报错 。
自己命名,但是不可重复, 也不可重复。

http://localhost/myfristweb_war_exploded/zmf
结果


请求消息格式

响应消息格式

Get和Post区别
get:
- 请求数据走地址栏( 地址栏可以看见发送的数据 ) 不安全。
- 数据量有限制 不同浏览器实现可能不同。1024字节
post:
- 数据走后台(正文)地址栏不可见,安全。
- 数据量没有限制。
文档类型用于声明响应文档的格式,方便浏览器解析和处理。
状态码用于说明本次请求响应的状态,不同的情况对应不同的状态码。

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
Sun对于动态资源(动态Web页面)最原始的抽象,是一个接口,定义了5个抽象方法,这些抽象方法,表示的是一个Servlet的声明周期。
通用的Servlet,它是Servlet接口的普通(通用)实现类,可以理解为对Servlet接口做了简单实现。
它是 GenericServlet 子类 ,基于Http协议实现,和Http协议绑定,全面支持Http协议的一切规范和要求,提供了处理Http请求的方法。
============================继承 HttpServlet========================================
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("执行GET");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("执行Post");
}
}
============================继承 GenericServlet========================================
public class MyServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
System.out.println("执行方法");
}
}
============================直接实现 Servlet接口========================================
public class MyServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {}
@Override
public ServletConfig getServletConfig() {return null;}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("执行方法");
}
@Override
public String getServletInfo() { return null;}
@Override
public void destroy() {}
}
ABC
servlet.MyServlet
ABC
/hello
@WebServlet("/hello")
public class MyServlet extends HttpServlet {
}
通常情况下,动态资源的作用就是接收来自前段页面的请求,同时获得请求中的数据,这些数据都是name=value的形式。通过下面的方法可以根据name 获取对应的 value。
前端发送数据
前端发送数据的形式常见的有3种,①表单 ②超链接 ** ** ③ajax (后面单独专题)
<form action="动态资源url" method="post|get" >
<input name="username" />
<input name="password" />
.......
form>
<a href='动态资源url?id=123&age=100&age=45' > 删除 a>
超链接请求默认为get请求方式。?后为查询字符串多个值用&连接。比如 /xxx.do?name=kangkang&age=10
后端接收数据★★
获取单个数据值
获取多个数据值(复选框)
Servlet 对于前端的请求方式和方法 不关心 , 取值的方法是相同的。
// 防止请求数据乱码
req.setCharacterEncoding("UTF-8");
这里必须注意,必须在获取数据前也就是getParameter() 前执行,否则无效。
// 防止响应数据乱码
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
这里必须注意 ①必须在输出数据前设置,否则无效 ②响应类型根据实际设置,不一定全是 text/html。
1创建工程
_ 02Servlet-Jdbc_
2引入jar包和工具类
3工具类与配置文件
自己封装的工具类代码

4编写实体类
/**
* 实体类
*/
public class Teacher {
private Integer id;
private String name;
private String level;
private Integer gender;
private Double cost;
private String state;
private Date practice_date;
private String information;
。。。。。。。。。。。。
}
5编写Dao
/**
* 技师持久化功能接口
*/
public interface TeacherDao {
/**
* 查全部
* @return
* @throws SQLException
*/
List<Teacher> selectAll() throws SQLException;
/**
* 根据ID 查一个
* @param id
* @return
* @throws SQLException
*/
Teacher selectById( int id ) throws SQLException;
/**
* 录入技师
* @param teacher
* @return
* @throws SQLException
*/
int insert( Teacher teacher ) throws SQLException;
/**
* 根据ID删除技师
* @param id
* @return
* @throws SQLException
*/
int delete(int id) throws SQLException;
}
===============================================================
/**
* 技师表持久化功能具体实现
*/
public class TeacherDaoImpl implements TeacherDao {
@Override
public List<Teacher> selectAll() throws SQLException {
String sql = "select * from technician ";
return JdbcUtil.query(sql, new BeanListHandler<>(Teacher.class));
}
@Override
public Teacher selectById(int id) throws SQLException {
String sql = "select * from technician where id=? ";
return JdbcUtil.query(sql,new BeanHandler<>(Teacher.class),id);
}
@Override
public int insert(Teacher t) throws SQLException {
String sql = "insert into technician(`name`,`level`,`gender`,`information`,`state`,`cost`,`practice_date`) values(?,?,?,?,?,?,?) ";
return JdbcUtil.update(sql,t.getName(),t.getLevel(),t.getGender(),t.getInformation(),t.getState(),t.getCost(),t.getPractice_date());
}
@Override
public int delete(int id) throws SQLException {
String sql = "delete from technician where id=?";
return JdbcUtil.update(sql,id);
}
}
6编写Service
/**
* 技师功能接口
*/
public interface TeacherService {
/**
* 查询全部技师
* @return
* @throws Exception
*/
List<Teacher> findAllTeacher() throws Exception;
/**
* 添加一个技师
* @param t
* @return
* @throws Exception
*/
int add( Teacher t ) throws Exception;
/**
* 根据id删除技师信息
* @param id
* @return
* @throws Exception
*/
int delete( int id ) throws Exception;
}
===============================================
/**
* 业务逻辑实现
*/
public class TeacherServiceImpl implements TeacherService {
//需要Dao协助
private TeacherDao teacherDao = new TeacherDaoImpl();
@Override
public List<Teacher> findAllTeacher() throws Exception {
try{
return teacherDao.selectAll();
}finally {
JdbcUtil.close(null,null,JdbcUtil.getConnection());
}
}
@Override
public int add(Teacher t) throws Exception {
try{
return teacherDao.insert(t);
}finally {
JdbcUtil.close(null,null,JdbcUtil.getConnection());
}
}
@Override
public int delete(int id) throws Exception {
try{
return teacherDao.delete(id);
}finally {
JdbcUtil.close(null,null,JdbcUtil.getConnection());
}
}
}
7编写Servlet
package com.qfedu.wash.servlet;
import com.qfedu.wash.entity.Teacher;
import com.qfedu.wash.service.TeacherService;
import com.qfedu.wash.service.impl.TeacherServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/teacher/list.do")
public class QueryTeacherServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.处理乱码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//2.获得前端数据(有可能发也可能不发)
//3. 业务逻辑协助
TeacherService teacherService = new TeacherServiceImpl();
try {
List<Teacher> allTeacher = teacherService.findAllTeacher();
//遍历结果并输出给客户端
resp.getWriter().println("");
resp.getWriter().println("");
resp.getWriter().println("编号 ");
resp.getWriter().println("姓名 ");
resp.getWriter().println("性别 ");
resp.getWriter().println("等级 ");
resp.getWriter().println("费用 ");
resp.getWriter().println("从业日期 ");
resp.getWriter().println("信息 ");
resp.getWriter().println("操作 ");
resp.getWriter().println(" ");
for (Teacher teacher : allTeacher) {
resp.getWriter().println("");
resp.getWriter().println("" +teacher.getId()+ " ");
resp.getWriter().println("" +teacher.getName()+ " ");
resp.getWriter().println("" +teacher.getGender()+ " ");
resp.getWriter().println("" +teacher.getLevel()+ " ");
resp.getWriter().println("" +teacher.getCost()+ " ");
resp.getWriter().println("" +teacher.getPractice_date()+ " ");
resp.getWriter().println("" +teacher.getInformation()+ " ");
resp.getWriter().println("删除 ");
resp.getWriter().println(" ");
}
resp.getWriter().println("
");
resp.getWriter().println(" 继续添加 ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
8测试
localhost:8080/teacher/list.do
请求转发,指的是Servlet接收到请求后,经过部分处理后,再次把请求转到其它Servlet或者视图去的过程。它是服务器内部的一个行为,只能转发到本站资源。地址栏不变化,转发前后是一次请求。转发后使用的就是 转发前的 请求 响应对象。
req.getRequestDispatcher( String url ).forword( HttpServeltRequest req, HttpServlet response )
请求重定向,指的是Servlet接收到请求后,**处理完请求 ,**然后立即响应客户端,发送302状态码,和一个重定向地址。客户端立即请求新地址。它是客户端行为,地址栏改变,可以跳转到任意资源。
resp.sendRedirect(String url)

作用域,简单说就是一块内存空间,这个空间可以存放数据,这个空间的数据结构就是一个Map。 数据以name=value 形式存储。Value是Object类型。name 是 String 类型。
//存(转发前)
req.setAttribute("date", new Date() );
req.setAttribute("ip", req.getRemoteAddr() );
//取(转发后)
resp.getWriter().println(req.getAttribute("date"));
resp.getWriter().println(req.getAttribute("ip"));
由于转发前后是同一个Request 所以,可以使用 Request域来传数据。
思考重定向如何传参数呢?
URL重写
通过 在重定向地址后面携带数据。
resp.sendRedirect("/page/success.do?date=xxx&ip=xxxx");
如果数据是中文的,需要使用 xxx=URLEncoder.encode(“中文数据”, “utf-8”);编码后发送。
success.do 取数据
req.getParameter("date")
req.getParameter("ip")
会话指的是客户端与服务端多次交互的连接抽象。Http 无状态短连接,客户端与服务端,一次请求和响应后,就立马断开了,这就导致了,服务器记不住客户端,实际上这是不行的,我们需要把客户端与服务端的多次通信过程,视为在一个连接中,要实现这种方案,就是会话保持,会话管理。

简单理解就是 客户端与服务器的多次通信过程的集合 就是会话。
可以使用Cookie存储简单键值对信息,存储在浏览器本地,由服务器负责 存和取,减轻服务端保存数据的压力,这些数据,不是重要数据,通常是存储的是用户的行为偏好。典型的,比如记住账号密码 商品推荐 临时购物车 ,切记Cooke存在客户端
Cookie ck = new Cookie( "hobby","Ball");
ck.setMaxAge(60*5); //正数:存活时间 s秒 0删除cookie 负值:存在再浏览器内存中,关闭就没了
resp.addCookie(ck);
Cookie[] cookies = req.getCookies();
if( cookies!=null ){
for ( Cookie ck :cookies ){
resp.getWriter().println(ck.getName()+":"+ ck.getValue()+":"+ck.getPath());
}
}
HttpSession的实例表示的就是一个会话,Session 作用域,简单说就是一块内存空间,这个空间可以存放数据,这个空间的数据结构就是一个Map。 数据以name=value 形式存储。Value是Object类型。name 是 String 类型,这个空间是HttpSession 对象的空间,服务端 ,每个客户端都有一个,相互隔离。切记Session存在服务器端
Session 与 Cookie 的关系,Session需要使用cookie作为通信凭证。
Session 生命周期
tomcat 服务本质上是实现了Servlet 规范的一个容器,支持Servlet程序执行,众多的Servlet被部署到容器中,Tomcat 通过 Context(上下文)对网站进行隔离,一个网站就是一个Context, 也就是Context对应一个Web应用。在JavaWeb程序中 ServletContext 就是一个表示一个Web应用。 
获得ServletContext对象
全局作用域,也是一块内存空间,是整个网站的空间,所有用户都可以使用,由于是全局的,生命周期和网站一样,要谨慎使用,一般都不用,网站全局的配置信息。Sevlet 有三大作用域。作为域通常存在下面3个方法管理数据。
有时候整个项目会需要一些初始化信息,或者全局配置信息,这时就可以把数据配置在配置文件中,在程序中通过API来获取数据。
web.xml
<context-param>
<param-name>OSparam-name>
<param-value>Windows7param-value>
context-param>
<context-param>
<param-name>Javaparam-name>
<param-value>123param-value>
context-param>
读取方法
String os = context.getInitParameter("OS");
String os = context.getInitParameter("Java");
HttpServletRequest : 请求域: 生命周期同request对象。转发传值。
HttpSession: 会话域:每个浏览器的空间,用于保存用户 状态信息。比如用户标识
ServletContext: 全局域,整个网站的空间,保存全局信息,比如网站的配置信息。
所谓Servlet生命周期就是指Servlet从生到死的各个阶段,主要分为 ① 创建 ②初始化 ③服务 ④销毁 几个阶段
如果我们需要在生命周期时间点上 做事情。就需要预留生命周期钩子( 回调 ),Servlet 提供了以下几种回调钩子
public interface Servlet {
// 初始化
void init(ServletConfig var1) throws ServletException;
// 处理请求(服务)
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
// 销毁
void destroy();
ServletConfig getServletConfig(); // 获得Servlet配置信息
String getServletInfo(); // 获得Servlet信息
}
HttpServlet实现的过程中把 Service细分为doGet doPost
/**
* 测试生命周期
*/
@WebServlet("/life.do")
public class LifeServlet extends HttpServlet {
public LifeServlet() {
System.out.println("构造器....");
}
@Override
public void init() throws ServletException {
System.out.println("初始化....");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("服务....");
}
@Override
public void destroy() {
System.out.println("销毁....");
}
}
第一请求Servlet 创建并初始化再调用服务,以后每次请求只调用服务方法,最后容器卸载web应用调用销毁。
_构_造器 执行1次
_init() _ 执行1次
service() 执行N次
destory() 执行1次
Servlet 被设计为一个单例(多线程)模式,一个Servlet一旦被创建就一直驻留在内存,提供服务,直到销毁,每个请求服务器开启一个单独的线程处理。所以Servlet是线程不安全的,尽量避免使用实例变量。或者实在要使用实例变量用ThreadLocal包装,或者实现SingleThreadModel 。
SingleThreadModel 可以使Servlet编程单线程模式。
配置Servlet 初始化参数
<servlet>
<servlet-name>LifeServletservlet-name>
<servlet-class>servlet.LifeServletservlet-class>
<init-param>
<param-name>numparam-name>
<param-value>998param-value>
init-param>
<init-param>
<param-name>nameparam-name>
<param-value>tomparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>LifeServletservlet-name>
<url-pattern>/life.dourl-pattern>
servlet-mapping>
@WebServlet( value = "/life.do",
initParams = { @WebInitParam(name = "num",value = "888"),
@WebInitParam(name = "name",value = "jack")})
在Serlvet代码中读取
@Override
public void init(ServletConfig config) throws ServletException {
String num = config.getInitParameter("num");
String name = config.getInitParameter("name");
System.out.println("初始化...."+num+" "+name);
}
配置Servlet 创建时机
希望服务器启动就立即加载并初始Serlvet
<servlet>
<servlet-name>LifeServletservlet-name>
<servlet-class>servlet.LifeServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>LifeServletservlet-name>
<url-pattern>/life.dourl-pattern>
servlet-mapping>
@WebServlet( value = "/life.do", loadOnStartup = 1 )
loadOnStartup = 1 数字越大优先级越高
通常我们会有一个疑问,就是我们重写了doGet 和 doPost 以后,我们并没有调用,只要浏览器请求,它就执行了。那么,它是什么时候调用的呢?谁调用的呢?
// 理解回调原理
//Tomcat{
// run( Servlet xx ){
// //服务器 接收客户端 tcp 连接
// ServerSocker xx = new ServerSocker(8080)
// Socket soket =xx.accetp();
// //服端 通过 io流读取客户数据
// InputStream is = socket.getInputStreamt();
// String username = is.read()
// String passowrd = is.read()
// //服务端构造 请求 和 响应对象
// HttpServletRequest req = new HttpServletRequest();
// HttpServletResponse resp = new HttpServletResponse();
// req.setParameter( "username",username )
// req.setParameter( "passowrd",passowrd )
// //服务端调用 服务方法
// //做个事情
// if(method=="get")
// {
xx.doGet(req,resp)
// }
// if(method=="post")
// {
xx.doPost(req,resp)
// }
//销毁(调用钩子)
// xx.destory();
// // 断开操
// }
//}
通过上面的伪代码,我们可以这样理解,是tomcat 监听客户端连接,接收到浏览器数据后,自己把数据封装到请求对象和响应对象中,然后创建了我们提供的Serlvet 对象,然后调用doGet 或者doPost方法,由于多态,实际执行的就是我们提供了方法逻辑了,简单的说,我们编写的Servlet 就是提供了回调代码。由于这部份代码tomcat无法完成封装( 因为不同的客户端请求服务端做的事情都不一样 ) 。
Filter 是JavaWeb 中的过滤器,所谓过虑器,就是可以对请求做预处理,在请求每抵达目标资源前做一些操作。比如 设置编码呀 验证权限呀 参数校验呀 连接黑名单 等等。 这种思想就是 想把目标方法中一些与业务逻辑无关的代码,提到过滤器中提前处理。

实现一个Filter接口并重写3个抽象方法其中只需要关注 doFilter() 方法。
public class AFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("AFilter 初始化");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
System.out.println("执行过虑");
chain.doFilter(req,resp);//放行(把请求往下一级传递)
System.out.println("FilterA完成过虑");
}
@Override
public void destroy() {
System.out.println("AFilter 销毁");
}
}
执行完过虑 希望传递到下一级, 通过 FilterChain 过虑链 放行。
过滤器的作用是对请求做预处理。
xml配置
<filter>
<filter-name>AFilterfilter-name>
<filter-class>filter.AFilterfilter-class>
filter>
<filter-mapping>
<filter-name>AFilterfilter-name>
<url-pattern>/user/*url-pattern>
filter-mapping>
url-pattern 配置需要连接的 请求路径 *是一个通配符
多个Filter 注册顺序决定了执行顺序。
注解配置 (掌握)
@WebFilter(value="/user/*")
public class AFilter implements Filter {
......
注解配置没有直接控制 优先级的配置, 通过Filter类名决定优先级,默认安装字母顺序。
启动网站理解创建并初始化,以后只要请求满足自己的url-patten 则直接过虑, tomcat 容器卸载应用时,执行销毁方法。
思考? 为什么Filter 必须是随着网站的启动而初始化
补充: 如果使用处理编码问题,导致静态资源乱码可以只用一下方式处理,在tomcat 的conf/web.xml中 做如下配置 指定默认servlet的读取静态文件的编码方式。
<servlet>
<servlet-name>defaultservlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServletservlet-class>
..........
<init-param>
<param-name>fileEncodingparam-name>
<param-value>utf-8param-value>
init-param>
............
<load-on-startup>1load-on-startup>
servlet>
监听器,可以实现对 域(HttpServletRequest, HttpSession, ServletContext)对象生命周期,以及域中数据变化_,做监控。它的作用就可以建立一种事件机制,如果一旦这些对象状态发生改变,我们可以感知到。可以做出响应的处理。 比如 _早期Spring 框架整合Web项目时,需要监听网站加载完成然后创建Spring容器。
HttpSession
_HttpSessionListener 生命周期监听 _
_HttpSessionAttributeListener 属性变化监听 _
HttpServletRequest
ServletRequestListener 生命周期监听
ServletRequestAttributeListener 属性变化监听
以HttpSession为例,编写一个JAVA类实现 相关接口。
@WebListener
public class MySessionListener implements HttpSessionListener, HttpSessionAttributeListener {
// 监听Session 创建
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
System.out.println("session 创建了");
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
System.out.println("session 销毁了");
}
@Override
public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("添加数据");
}
@Override
public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("移除数据");
}
@Override
public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("修改数据");
}
}
注解配置
@WebListener
public class MySessionListener implements HttpSessionListener, HttpSessionAttributeListener {
......
XML 配置
<listener>
<listener-class>listener.MySessionListenerlistener-class>
listener>