*5.ServletConfig
现在只会开发一个servlet。
但是我们还看到了resq对象。resp对象。这写对象都是和servl开发相关的对象。这几天我们都会讲。
先讲第一个与servlet开发相关的对象——servletConfig!
ServletConfig -- 代表当前Servlet在web.xml中的配置信息
那这个对象又有哪些方法呢?
String getServletName() -- 获取当前Servlet在web.xml中配置的名字
String getInitParameter(String name) -- 获取当前Servlet指定名称的初始化参数的值
Enumeration getInitParameterNames() -- 获取当前Servlet所有初始化参数的名字组成的枚举
ServletContext getServletContext() -- 获取代表当前web应用的ServletContext对象
其实上面这个方式已经在他的父类,Gernericservlet里面实现啦!
获取初始化参数。
有什么用呢?数据库的用户名密码。编码gbk,utf-8.这些都是我们不想写死在程序里面的。
*6.ServletContext1
讲完servletconfig对象之后,我们在讲servletcontext对象。
ServletContext -- 代表当前web应用
唯一性。一个servlecontext对象代表一个web应用。
我们可以用servletconfig对象来回去servletcontext对象。
那servletcontext对象有什么用呢? 1.做为域对象可以在整个web应用范围内共享数据
下面的一个例子:
1.做为域对象可以在整个web应用范围内共享数据
域对象:在一个可以被看见的范围内共享数据用到对象
作用范围:整个web应用范围内共享数据
生命周期:当服务器启动web应用加载后创建出ServletContext对象后,域产生。当web应用被移除出容器或服务器关闭,随着web应用的销毁域销毁。
void setAttribute(String,Object);
Object getAttribute(String);
void removeAttribute(String);
web开发里,有4大作用域,今天是第一个。
2.用来获取web应用的初始化参数
配个某一个servlet对象的初始化参数,值在摸一个servlet内有效。
2.用来获取web应用的初始化参数
请求参数 parameter --- 浏览器发送过来的请求中的参数信息
初始化参数 initparameter --- 在web.xml中为Servlet或ServletContext配置的初始化时带有的基本参数
域属性 attribute --- 四大作用于中存取的键值对
接下来是将servletcontext的第三个功能:
*7.ServletContext2
实现Servlet的转发
重定向: 302+locatin
缓存:304/307
请求转发 : 服务器内部进行资源流转
*请求转发是一次请求一次响应实现资源流转.请求重定向两次请求两次响应.
这里请求转发 我们就可以用servletcontext来实现。
servletcontext第四个功能: 4.加载资源文件
假设运行的时候需要用到配置文件。
如果发布环境换了呐?
最终解决方案:
在Servlet中读取资源文件时:
如果写相对路径和绝对路径,由于路径将会相对于程序启动的目录--在web环境下,就是tomcat启动的目录即tomcat/bin--所有找不到资源
如果写硬盘路径,可以找到资源,但是只要一换发布环境,这个硬盘路径很可能是错误的,同样不行.
为了解决这样的问题ServletContext提供了getRealPath方法,在这个方法中传入一个路径,这个方法的底层会在传入的路径前拼接当前web应用的硬盘路径从而得到当前资源的硬盘路径,这种方式即使换了发布环境,方法的底层也能得到正确的web应用的路径从而永远都是正确的资源的路径
this.getServletContext().getRealPath("config.properties")
*8.Response_输出数据
一、response
ServletResponse -- 通用的response提供了一个响应应该具有最基本的属性和方法
|
|-HttpServletResponse -- 在ServletResponse的基础上针对于HTTP协议增加了很多强化的属性和方法
注意下面的区别:
m
乱码?
解决方案呢?
注意下面的对比:
接下来,我们使用字符输出来。
细节:
为什么呢?
-------------------Day03课堂笔记-----------------------------
一、Servlet
1.sun提供的一种动态web资源开发技术.本质上就是一段java小程序.可以将Servlet加入到Servlet容器中运行.
*Servlet容器 -- 能够运行Servlet的环境就叫做Servlet容器. --- tomcat
*web容器 -- 能够运行web应用的环境就叫做web容器 --- tomcat
2.
写一个类实现sun公司定义的Servlet接口
将写好的类配置到tomcat中的web应用的web.xml中,(配置对外访问路径)
3.Servlet的调用过程/生命周期
4.Servlet的继承结构
Servlet接口 -- 定义了Servlet应该具有的基本方法
|
|--GenericServlet --通用基本Servlet实现,对于不常用的方法在这个实现类中进行了基本的实现,对于Service设计为了抽象方法,需要子类去实现
|
|--HttpServlet --在通用Servlet的基础上基于HTTP协议进行了进一步的强化:实现了GenericServlet中的Service方法,判断当前的请求方式,调用对应到doXXX方法,这样一来我们开发Servlet的过程中只需继承HttpServlet ,覆盖具体要处理的doXXX方法就可以根据不同的请求方式实现不同的处理.一般不要覆盖父类中的Service方法只要覆盖doGet/doPost就可以了
5.Servlet的细节
(1)一个<servlet>可以对应多个<serlvet-mapping>,从而一个Servlet可以有多个路径来访问
(2)url-partten中的路径可以使用*匹配符号进行配置,但是要注意,只能是/开头/*结尾或*.后缀这两种方式
~由于*的引入,有可能一个路径被多个urlpartten匹配,这是优先级判断条件如下:
哪个最像找哪个
*.后缀永远匹配级最低
(3)<serlvet>可以配置<load-on-startup>可以用来指定启动顺序
(4)缺省Servlet:如果有一个Servlet的url-partten被配置为了一根正斜杠,这个Servlet就变成了缺省Serlvet.其他Servlet 都不处理的请求,由缺省Servlet来处理.
其实对于静态资源的访问就是由缺省Servlet来执行
设置404页面500页面等提示页面也是由缺省Servlet来执行
通常我们不会自己去配置缺省Servlet
(5)线程安全问题
由于默认情况下Servlet在内存中只有一个对象,当多个浏览器并发访问Servlet时就有可能产生线程安全问题
解决方案:
加锁--效率降低
SingleThreadModel接口 -- 不能真的防止线程安全问题
最终解决方案:在Servlet中尽量少用类变量,如果一定要用类变量则用锁来防止线程安全问题,但是要注意锁住内容应该是造成线程安全问题的核心代码,尽量的少锁主内容,减少等待时间提高servlet的响应速度
二、ServletConfig -- 代表当前Servlet在web.xml中的配置信息
String getServletName() -- 获取当前Servlet在web.xml中配置的名字
String getInitParameter(String name) -- 获取当前Servlet指定名称的初始化参数的值
Enumeration getInitParameterNames() -- 获取当前Servlet所有初始化参数的名字组成的枚举
ServletContext getServletContext() -- 获取代表当前web应用的ServletContext对象
三、ServletContext -- 代表当前web应用
1.做为域对象可以在整个web应用范围内共享数据
域对象:在一个可以被看见的范围内共享数据用到对象
作用范围:整个web应用范围内共享数据
生命周期:当服务器启动web应用加载后创建出ServletContext对象后,域产生。当web应用被移除出容器或服务器关闭,随着web应用的销毁域销毁。
void setAttribute(String,Object);
Object getAttribute(String);
void removeAttribute(String);
2.用来获取web应用的初始化参数
请求参数 parameter --- 浏览器发送过来的请求中的参数信息
初始化参数 initparameter --- 在web.xml中为Servlet或ServletContext配置的初始化时带有的基本参数
域属性 attribute --- 四大作用于中存取的键值对
3.实现Servlet的转发
重定向 : 302+Location
请求转发 : 服务器内不进行资源流转
*请求转发是一次请求一次响应实现资源流转.请求重定向两次请求两次响应.
4.加载资源文件
在Servlet中读取资源文件时:
如果写相对路径和绝对路径,由于路径将会相对于程序启动的目录--在web环境下,就是tomcat启动的目录即tomcat/bin--所有找不到资源
如果写硬盘路径,可以找到资源,但是只要一换发布环境,这个硬盘路径很可能是错误的,同样不行.
为了解决这样的问题ServletContext提供了getRealPath方法,在这个方法中传入一个路径,这个方法的底层会在传入的路径前拼接当前web应用的硬盘路径从而得到当前资源的硬盘路径,这种方式即使换了发布环境,方法的底层也能得到正确的web应用的路径从而永远都是正确的资源的路径
this.getServletContext().getRealPath("config.properties")
如果在非Servlet环境下要读取资源文件时可以采用类加载器加载文件的方式读取资源
Service.class.getClassLoader().getResource("../../../config.properties").getPath()
-------------------Day03笔记-----------------------------
一、Servlet概述
1.sun公司提供的动态web资源开发技术。本质是上一段java小程序,要求这个小程序必须实现Servlet接口,以便服务器能够调用。
2.开发Servlet的两个步骤
*实验:Servlet的快速入门
(1)步骤一:写一个java程序实现Servlet接口(此处直接继承了默认实现类GenericServlet)
package cn.itheima;
import java.io.*;
import javax.servlet.*;
public class FirstServlet extends GenericServlet{
public void service(ServletRequest req, ServletResponse res) throws ServletException, java.io.IOException{
res.getOutputStream().write("My FirstServlet!".getBytes());
}
}
(2)将编译好的带包的.class放到WEB-INF/classes下以外,还要配置web应用的 web.xml注册Servlet
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>cn.itheima.FirstServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<url-pattern>/FirstServlet</url-pattern>
</servlet-mapping>
3.利用MyEclipse开发Servlet
二、Servlet的详述
1.生命周期:一件事物什么时候生,什么时候死,在生存期间必然会做的事情,所有这些放在一起就是该事物的声明周期。
2.Servlet的生命周期:通常情况下,servlet第一次被访问的时候在内存中创建对象,在创建后立即调用init()方法进行初始化。对于每一次请求都掉用service(req,resp)方法处理请求,此时会用Request对象封装请求信息,并用Response对象(最初是空的)代表响应消息,传入到service方法里供使用。当service方法处理完成后,返回服务器服务器根据Response中的信息组织称响应消息返回给浏览器。响应结束后servlet并不销毁,一直驻留在内存中等待下一次请求。直到服务器关闭或web应用被移除出虚拟主机,servlet对象销毁并在销毁前调用destroy()方法做一些善后的事情。
3.Servlet接口的继承结构
Servlet接口:定义了一个servlet应该具有的方法,所有的Servlet都应该直接或间接实现此接口
|
|----GenericServlet:对Servlet接口的默认实现,通用Servlet,这是一个抽象类,其中的大部分方法都做了默认实现,只有service方法是一个抽象方法需要继承者自己实现
|
|----HttpServlet:对HTTP协议进行了优化的Servlet,继承自GenericServlet类,并且实现了其中的service抽象方法,默认的实现中判断了请求的请求方式,并根据请求方式的不同分别调用不同的doXXX()方法。通常我们直接继承HttpServlet即可
4.web.xml注册Servlet的注意事项
4.1利用<servlet><servlet-mapping>标签注册一个Servlet
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>cn.itheima.FirstServlet</servlet-class> 注意:此处要的是一个Servlet的完整类名,不是包含.java或.class扩展的文件路径
</servlet>
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<url-pattern>/FirstServlet</url-pattern>
</servlet-mapping>
4.2一个<servlet>可以对应多个<servlet-mapping>
4.3可以用*匹配符配置<serlvet-mapping>,但是要注意,必须是*.do或者/开头的以/*结束的路径。
~由于匹配符的引入有可能一个虚拟路径会对应多个servlet-mapping,此时哪个最像找哪个servlet,并且*.do级别最低。
4.4可以为<servlet>配置<load-on-startup>子标签,指定servlet随着服务器的启动而加载,其中配置的数值指定启动的顺序
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
4.5缺省servlet:如果一个servlet的对外访问路径被设置为/,则该servlet就是一个缺省servlet,其他servlet不处理的请求都由它来处理
~在conf/web.xml中配置了缺省servlet,对静态资源的访问和错误页面的输出就是由这个缺省servlet来处理的。如果我们自己写一个缺省servlet把爸爸web.xml中的缺省servlet覆盖的话,会导致静态web资源无法访问。所以不推荐配置。
4.6servlet的线程安全问题
4.6.1由于通常情况下,一个servlet在内存只有一个实例处理请求,当多个请求发送过来的时候就会有多个线程操作该servlet对象,此时可能导致线程安全问题。
(1)serlvet的成员变量可能存在线程安全问题
*实验:定义一个成员变量 int i = 0;在doXXX()方法中进行i++操作并输出i值到客户端,此时由于延迟可能导致线程安全问题
(2)serlvet操作资源文件时,多个线程操作同一文件引发线程安全问题
*实验:请求带着一个参数过来,servlet将请求参数写入到一个文件,再读取该文件,将读取到的值打印到客户端上,有可能有线程安全问题
4.6.2解决方法
(1)利用同步代码块解决问题。缺陷是,同一时间同步代码块只能处理一个 请求,效率很低下,所以同步代码块中尽量只包含核心的导致线程安全问题的代码。
(2)为该servlet实现SingleThreadModel接口,此为一个标记接口,被标记的servlet将会在内存中保存一个servlet池,如果一个线程来了而池中没有servlet对象处理,则创建一个新的。如果池中有空闲的servlet则直接使用。这并不能真的解决线程安全问题。此接口已经被废弃。
(3)两种解决方案都不够完美,所以尽量不要在servlet中出现成员变量。
三、ServletConfig
1.代表servlet配置的对象,可以在web.xml中<servlet>中配置
<servlet>
<servlet-name>Demo5Servlet</servlet-name>
<servlet-class>cn.itheima.Demo5Servlet</servlet-class>
<init-param>
<param-name>data1</param-name>
<param-value>value1</param-value>
</init-param>
</servlet>
然后在servlet中利用this.getServletConfig()获取ServletConfig对象,该对象提供了getInitParameter()和getInitParameterNames()方法,可以遍历出配置中的配置项。
不想在servlet中写死的内容可以配置到此处。
四、ServletContext
1.代表当前web应用的对象。
2.作为域对象使用,在不同servlet之间传递数据,作用范围是整个web应用
生命周期:当web应用被加载进容器时创建代表整个web应用的ServletContext对象。当服务器关闭或web应用被移除出容器时,ServletContext对象跟着销毁。
~域:一个域就理解为一个框,这里面可以放置数据,一个域既然称作域,他就有一个可以被看见的范围,这个范围内都可以对这个域中的数据进行操作,那这样的对象就叫做域对象。
3.在web.xml可以配置整个web应用的初始化参数,利用ServletContext去获得
<context-param>
<param-name>param1</param-name>
<param-value>pvalue1</param-value>
</context-param>
this.getServletContext().getInitParameter("param1")
this.getServletContext().getInitParameterNames()
4.在不同servlet之间进行转发
this.getServletContext().getRequestDispatcher("/servlet/Demo10Servlet").forward(request, response);
方法执行结束,service就会返回到服务器,再有服务器去调用目标servlet,其中request会重新创建,并将之前的request的数据拷贝进去。
5.读取资源文件
5.1由于相对路径默认相对的是java虚拟机启动的目录,所以我们直接写相对路径将会是相对于tomcat/bin目录,所以是拿不到资源的。如果写成绝对路径,当项目发布到其他环境时,绝对路径就错了。
5.2为了解决这个问题ServletContext提供了this.getServletContext().getRealPath("/1.properties"),给进一个资源的虚拟路径,将会返回该资源在当前环境下的真实路径。this.getServletContext().getResourceAsStream("/1.properties"),给一个资源的虚拟路径返回到该资源真实路径的流。
5.3当在非servlet下获取资源文件时,就没有ServletContext对象用了,此时只能用类加载器
classLoader.getResourceAsStream("../../1.properties"),此方法利用类加载器直接将资源加载到内存中,有更新延迟的问题,以及如果文件太大,占用内存过大。
classLoader.getResource("../1.properties").getPath(),直接返回资源的真实路径,没有更新延迟的问题。
-----------其他------------
day03过渡到day04的代码。
课堂:
一、response
ServletResponse -- 通用的response提供了一个响应应该具有最基本的属性和方法
|
|-HttpServletResponse -- 在ServletResponse的基础上针对于HTTP协议增加了很多强化的属性和方法
1.输出数据
response.setContentTye("text/html;charset=utf-8");
response.getOUtputStream().write("".getBytes("utf-8"));
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("");
笔记:
一、Response
1.Resonse的继承结构:
ServletResponse--HttpServletResponse
2.Response代表响应,于是响应消息中的 状态码、响应头、实体内容都可以由它进行操作,由此引伸出如下实验:
3.利用Response输出数据到客户端
response.getOutputStream().write("中文".getBytes())输出数据,这是一个字节流,是什么字节输出什么字节,而浏览器默认用平台字节码打开服务器发送的数据,如果服务器端使用了非平台码去输出字符的字节数据就需要明确的指定浏览器编码时所用的码表,以防止乱码问题。response.addHeader("Content-type","text/html;charset=gb2312")
response.getWriter().write(“中文”);输出数据,这是一个字符流,response会将此字符进行转码操作后输出到浏览器,这个过程默认使用ISO8859-1码表,而ISO8859-1中没有中文,于是转码过程中用?代替了中文,导致乱码问题。可以指定response在转码过程中使用的目标码表,防止乱码。response.setCharcterEncoding("gb2312");
其实response还提供了setContentType("text/html;charset=gb2312")方法,此方法会设置content-type响应头,通知浏览器打开的码表,同时设置response的转码用码表,从而一行代码解决乱码。