Servlet的单例模式
当多个客户端请求在同一时刻同时访问一个Servlet时该怎么办 ?
为每个请求都创建一个Servlet对象
- 不存在多线程并发访问的问题,但是会造成内存的巨大压力
- 频繁的创建和销毁对象会占用大量cpu资源
只创建一个Servlet对象,同时被多个线程共享
- 多线程并发问题可通过编程方式解决
编程验证Servlet的单例特性
多次请求该地址,count一直累加,说明只创建一个对象
@WebServlet("/count")
public class CountServlet extends HttpServlet {
private int count;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("charset=utf-8");
PrintWriter out = response.getWriter();
out.write("<h3>当前计数器:" + (count++) + "</h3>");
out.flush();
out.close();
}
}
Servlet生命周期的三个方法
- 1、init(),初始化对象,执行一次
- 2、service(),提供服务,多次使用
- 3、destroy(),销毁对象,只执行一次
@WebServlet(value = "/count", initParams = {@WebInitParam(name = "name", value = "张三")
, @WebInitParam(name = "sex", value = "男")})//servlet对象初始化参数,私有参数
public class CountServlet extends HttpServlet {
private int count;
/**
* 多次调用提供请求服务
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.write("<h3>当前计数器:" + (count++) + "</h3>");
out.flush();
out.close();
}
/**
* 销毁对象的方法
* 只执行一次
*/
@Override
public void destroy() {
System.out.println("servlet 对象销毁");
}
/**
* 生命周期的初始化方法
* 只执行一次
*/
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
}
小结
- servlet生命周期:
- 单例模式,一个servlet类只创建一个对象,在客户端第一次请求时在服务器创建,用来处理客户端请求。
- 内存不足或者服务器关闭时销毁
- request生命周期:
- 多例模式,每次请求创建一个对象,当请求到达服务器时由服务器创建,当服务器响应结束后返回客户端时销毁。
- session生命周期
- 客户端请求服务器调用getSession方法时由服务器创建,有效期超时或者服务器关闭销毁。
- context生命周期
- 单例模式:服务器启动时创建,服务器关闭时销毁。
- Cookie生命周期
- 服务器响应客户时由服务器创建,响应结束后返回返回客户端浏览器保存对象。
- 如果设置有效期,有效期结束后由浏览器删除,默认是关闭服务器则删除。
ServletConfig对象
由tomcat创建并传递给init函数
由HttpServlet的init函数负责保存在成员变量中
用于读取程序员配置在web.xml中的配置信息
初始化参数由一个名字和一个值组成 。
在Servlet中通过继承下来的getServletConfig()方法获得ServletConfig对象
通过servletConfig对象的getInitParameter(“”)获得web.xml中的配置信息
(系统自动创建Servlet对象,自动调用getServletConfig()方法来获取对象)
语法:
<servlet>
<servlet-name></servlet-name>
<servlet-class></servlet-class>
<init-param>
<param-name>fileName</param-name>
<param-value>data.properties</param-value>
</init-param>
</servlet>
实例:
类名
类的全限定名(指定到那个类)
键值对(存值)
<!--配置servlet名称和对应的类-->
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>servlet.TestServlet</servlet-class>
<!--键值对的方式进行初始化-->
<init-param>
<param-name>age</param-name>
<param-value>50</param-value>
</init-param>
<init-param>
<param-name>weight</param-name>
<param-value>75</param-value>
</init-param>
</servlet>
或者用注解的方式
value代表地址,默认可以不写。initParams 内存放键值对。
@WebServlet(value = "/count", initParams = {@WebInitParam(name = "name", value = "张三")
, @WebInitParam(name = "sex", value = "男")})//servlet对象初始化参数,私有参数
重定向的工作原理
执行流程:
- 客户端发送请求到到Servlet A
- Servle tA响应客户端,并命令其发送请求到Servlet B
- 客户端发送请求到Servlet B
- Servlet B响应客户端
请求转发的工作原理
执行流程:
- 客户端发送请求到Servlet A
- Servlet A将请求转发给Servlet B
- Servlet B响应客户端
请求转发与重定向的区别
请求转发是在服务器内部实现的,重定向要返回客户端,由浏览器发起第二次请求。
请求转发时,浏览器的地址不会变,重定向时地址栏的地址会发生变化。
请求转发时两个servlet处于一个请求当中,使用的是一个request对象,重定向时两个servlet处于两个不同的请求当中,不共享一个request对象
请求转发只能在相同应用中使用,重定向可以定向到其他应用中
中文乱码产生的原因
当用户提交表单时,浏览器会按照浏览器默认的字符集对表单中的字符进行编码
- 中文操作系统 :gb2312(GBK)
- 英文操作系统 :iso-8859-1
Java语言使用的是unicode字符集(utf-8) , 当浏览器的编码和utf-8产生冲突时,中文就编程了乱码
解决办法 :使用函数request.setCharacterEncoding( “浏览器字符集”) ;
- 该函数会告知tomcat,浏览器采用的字符集,然后tomcat会按照规则将该字符集转化为java需要的utf-8字符集
- 该函数必须在request.getParameter(“”)之前调用
应答乱码的解决办法
果在应答时不指明应答内容的字节编码,浏览器会按照默认编码进行解析。如果浏览器的默认编码与utf-8不一致时,就会出现中文乱码
解决办法 :在产生应答结果之前,指明应答内容的编码方式
- 即使用函数response.setCharacterEncoding(“utf-8”);
- 如果应答字符集和java默认字符集不一致,tomcat会在应答输出之前将数据转化为指定字符集
GET和POST
GET和POST是HTTP协议中浏览器发送请求的两种方式 :
GET :
- 在地址栏中直接输入URL发送请求
- 通过点击超级链接发送请求
- 提交method=“get”的表单
- 表单的默认提交方式也是get .
POST
- 提交method=“post”的表单
GET与POST的区别
Get方式发送请求时,客户端参数在地址栏中能够显示,POST不显示
GET方式能够发送的最大数据长度有限制,具体数值取决于浏览器对URL最大值的限制,POST没有最大值得限制
- GET和POST解决中文乱码的方式不一致 :
- POST : request.setCharacterEncoding( “” );
- GET :修改tomcat下conf/server.xml 70行 加URIEncoding= “utf-8”
GET与POST的处理方法
在同一个servlet中,可以对两种方式提交的请求进行分开处理
不要覆盖service(…)方法
覆盖doGet 与 doPost 两个方法 。
doGet与doPost的方法声明与service一致
- 当用户用get方式调用Servlet时,执行doGet方法
- 当用户使用post方式调用servlet时,执行doPost方法
对于servlet而言,如果对POST和GET的处理没有区别的话就可以直接覆盖service方法,如果有必要分别处理的话则覆盖doGet和doPOST
Web应用的目录结构
TOMCAT安装目录/
|- conf :配置文件
|- bin : 可执行文件
|- lib : 被所有应用共享的jar文件
|- webapps :所有web应用
|- appA
|- appB
|- WEB-INF
| |- web.xml
| |- classes :本应用的所有类文件
| |- lib : 本应用所有jar文件
|- 静态 资源 ( html,css,js , css … )
Filter
Filter称作过滤器
如果一个Servlet配置了过滤器,那么请求在到达Servlet之前先要经过过滤器的处理
作用:适合进行登陆验证,字符集转化等工作。
- 过滤器,对所有请求过滤,只有满足过滤条件的请求才能达到servlet服务
- 单例模式,一个filter类只创建一个对象,默认是服务器启动时创建,关闭销毁。
- 生命周期:
- 0、对象创建,创建一次
- 1、初始化,执行一次
- 2、对象过滤服务,每次过滤都执行,根据条件是否过滤
- 3、对象销毁,执行一次,服务器关闭执行
编写Filter
implements Filter
doFilter(ServletRequest,ServletResponse,FilterChain)过滤过程
ServletRequest,ServletResponse要进行类型强转
FilterChain: 用于连接Filter与Servlet,可以通过chain.doFilter(…)将请求转给浏览器真正要访问的Servlet
init() : Filter初始化时调用
destroy() :Filter销毁时创建
实例
/**
* 过滤器,对所有请求过滤,只有满足过滤条件的请求才能达到servlet服务
* 单例模式,一个filter类只创建一个对象,默认是服务器启动时创建,关闭销毁。
* 生命周期:
* 0、对象创建,创建一次
* 1、初始化,执行一次
* 2、对象过滤服务,每次过滤都执行,根据条件是否过滤
* 3、对象销毁,执行一次,服务器关闭执行
*/
@WebFilter(value = "/*")// /* 代表所有地址
public class EncodingFilter implements Filter {
/**
* 构造对象
*/
public EncodingFilter() {
System.out.println("filter对象创建");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter对象初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filter对象过滤");
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//统一设置字符编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//放行请求
filterChain.doFilter(request,response);
}
@Override
public void destroy() {
System.out.println("filter对象销毁");
}
}
配置filter
配置xml文件
<filter>
<filter-name></filter-name>
<filter-class></filter-class>
</filter>
<filter-mapping>
<filter-name></filter-name>
<url-pattern>/admin/*</url-pattern>
<!--重要】此处配置的并不是Filter自身的URL,而是Filter负责过虑的URL。也就是说,凡是对/admin下所有资源的访问,都要经过这个Filter的过滤
-->
</filter-mapping>
使用注解
@WebFilter(value = “/*”)//过滤所有的请求
Filter的执行顺序
- 如果存在多个过滤器,执行顺序:
- 1、如果在web.xml配置,根据顺序从上往下过滤
- 2、如果是注解方式,根据类名字母的ascii的顺序执行
- 3、配置文件的过滤器优先执行
- 销毁过程也是这个顺序
补充函数
StringBuffer url = request.getRequestURL();//返回全路径
System.out.println("url:" + url);
String uri = request.getRequestURI();//返回除去host(域名或者ip)部分的路径
System.out.println("uri:" + uri);
String contextPath = request.getContextPath();//返回工程名部分,如果工程映射为/,此处返回则为空
System.out.println("contextPath:" + contextPath);
String scheme = request.getScheme();//返回当前链接使用的协议
System.out.println("scheme:" + scheme);
String serverName = request.getServerName();//可以返回当前页面所在的服务器的名字;
System.out.println("serverName:" + serverName);
int serverPort = request.getServerPort();//以返回当前页面所在的服务器使用的端口
System.out.println("serverPort:" + serverPort);
String queryString = request.getQueryString();//获取传递的参数
System.out.println("queryString:" + queryString);
例如在浏览器上的请求地址:
http://localhost:8080/server_0316/login.html?name=zhangsan&age=20
url:http://localhost:8080/server_0316/login.html
uri:/server_0316/login.html
contextPath:/server_0316
scheme:http
serverName:localhost
serverPort:8080
queryString:name=zhangsan&age=20
Listener
Listener 称作监听器,当web应用中某一特定事件发生时会调用相应的Listener :
常用Listener :
ServletContextListener :监听ServletContext的创建和销毁
HttpSessionListener : 监听HttpSession对象的创建和销毁
也需要配置之后才能使用:
web.xml配置
<listener>
<listener-class>类全限定名</listener-class>
</listener>
注解
@WebListener
ServletContextListener
用于监听SerlvetContext的创建于销毁
implements ServletContextListener
contextInitialized(ServletContextEvent )
当servletContext创建时调用
可以通过ServletContextEvent获得ServletContext对象
event.getServletContext();
contextDestroyed(ServletContextEvent)
当servletContext销毁时调用
实例
/**
* 监听上下文对象创建和销毁
*/
@WebListener
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("服务器启动创建上下文");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("服务器销毁关闭上下文");
}
}
HttpSessionListener
用于监听Session对象的创建于销毁
implements HttpSessionListener
sessionCreated(SessioEvent) 用于监听session的创建
sessionDestroyed(SessionEvent) 监听Sessiond的销毁
可以通过SessionEvent来获得刚刚创建或销毁的session对象
event.getSession();
实例
web.xml配置
<!--配置会话的,创建、销毁监听-->
<listener>
<listener-class>listener.MyHttpSessionListener</listener-class>
</listener>
public class MyHttpSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("会话创建");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("会话销毁");
}
}