Servlet 学习总结
刚学习完了Servlet相关的知识,现在做一下整理以备日后方便查找与复习.
一.Servlet的定义
Servlet是一个位于服务器端的独立于平台和协议的Java应用程序,可以生成动态的web页面,也可以像jsp一样直接输出信息.
Servlet类是一个继承了HttpServlet类的Java类,但是有自己的规则.Servlet是位于Web服务器内部的服务器端的Java应用程序,像所有的Java程序一样,Servlet拥有面向对象Java语言的所有优势
Servlet必须在web.xml文件中注册.服务器启动的时候,可以根据这些配置来加载Servlet类.
Servlet是一个位于服务器端的独立于平台和协议的Java应用程序,可以生成动态的web页面,也可以像jsp一样直接输出信息.
Servlet类是一个继承了HttpServlet类的Java类,但是有自己的规则.Servlet是位于Web服务器内部的服务器端的Java应用程序,像所有的Java程序一样,Servlet拥有面向对象Java语言的所有优势
Servlet必须在web.xml文件中注册.服务器启动的时候,可以根据这些配置来加载Servlet类.
二.Servlet的作用:
Servlet主要用来在控制层结合mvc模式做控制转发.
Servlet的应用:
表单是HTML中使用最广泛的传递信息的手段,Servlet使用HttpServlet类中的方法与表单进行交互,HTTPServer把客户请求正确的映射到相应的函数上:
a) doGet 用于处理GET请求,也可以自动的支持HEADER请求
b) doPost 用于处理POST请求
Servlet主要用来在控制层结合mvc模式做控制转发.
Servlet的应用:
表单是HTML中使用最广泛的传递信息的手段,Servlet使用HttpServlet类中的方法与表单进行交互,HTTPServer把客户请求正确的映射到相应的函数上:
a) doGet 用于处理GET请求,也可以自动的支持HEADER请求
b) doPost 用于处理POST请求
三.Servlet的生命周期
Servlet继承了HTTPServlet类,所以要扩展父类中的方法:
1.init()方法:
在 Servlet 的生命期中,仅执行一次init方法.它是在服务器装入 Servlet 时执行的.
例:
/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occure
* 在servlet被第一次访问时,本方法将会被自动调用
* 本方法被称为初始化方法
* 只会被调用一次
*/
public void init() throws ServletException {
// Put your code here
System.out.println("我是init方法");
}
Servlet继承了HTTPServlet类,所以要扩展父类中的方法:
1.init()方法:
在 Servlet 的生命期中,仅执行一次init方法.它是在服务器装入 Servlet 时执行的.
例:
/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occure
* 在servlet被第一次访问时,本方法将会被自动调用
* 本方法被称为初始化方法
* 只会被调用一次
*/
public void init() throws ServletException {
// Put your code here
System.out.println("我是init方法");
}
2.service()方法:
service方法是Servlet的核心.每当一个客户请求一个HttpServlet对象,该对象的service()方法就要被调用,doGet和doPost这两个方法是由service方法调用的
例:
/**
* 具体的业务方法
* 该方法将会被调用多次
* 每次访问servlet时,该方法都会被调用
* service根据request.getMethod得到你的提交方式,然后由它来决定对doGet.doPost的调用
*/
public void service(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{
super.service(request, response);
System.out.println("我是service.....................................");
}
service方法是Servlet的核心.每当一个客户请求一个HttpServlet对象,该对象的service()方法就要被调用,doGet和doPost这两个方法是由service方法调用的
例:
/**
* 具体的业务方法
* 该方法将会被调用多次
* 每次访问servlet时,该方法都会被调用
* service根据request.getMethod得到你的提交方式,然后由它来决定对doGet.doPost的调用
*/
public void service(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{
super.service(request, response);
System.out.println("我是service.....................................");
}
3.destroy()方法
destroy()方法仅执行一次,即在服务器停止且卸装Servlet时执行该方法.
例:
/**
* Destruction of the servlet. <br>
* servlet被注销的时候
* 本方法为销毁方法
* 也只是被服务器自动调用一次
*
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
System.out.println("destroy方法被调用..............");
}
destroy()方法仅执行一次,即在服务器停止且卸装Servlet时执行该方法.
例:
/**
* Destruction of the servlet. <br>
* servlet被注销的时候
* 本方法为销毁方法
* 也只是被服务器自动调用一次
*
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
System.out.println("destroy方法被调用..............");
}
四.Servlet定义的步骤
1.定义一个类,继承HTTPServlet类.
2.重写doGet和doPost方法.
3.实现doGet和doPost的逻辑.
4.在web.xml部署描述文件中定义Servlet的映射方式.
1.定义一个类,继承HTTPServlet类.
2.重写doGet和doPost方法.
3.实现doGet和doPost的逻辑.
4.在web.xml部署描述文件中定义Servlet的映射方式.
五.Servlet在web.xml中的配置
1.配置说明
<servlet>内的<servlet-name>,是一个逻辑名,可以是任何有效的标识名;
1.配置说明
<servlet>内的<servlet-name>,是一个逻辑名,可以是任何有效的标识名;
<init-param>是Servlet初始参数在Servlet的init()方法中通过getInitParameter(“ip”)取得,返回String型数据;
<servlet- mapping>内的<servlet-name>与<servlet>内的<servlet-name>一一对应,把客户端对/HelloServlet的请求对应到<servlet- class>project1.HelloServlet</servlet-class>所指定的位置;
<servlet- mapping>内的<servlet-name>与<servlet>内的<servlet-name>一一对应,把客户端对/HelloServlet的请求对应到<servlet- class>project1.HelloServlet</servlet-class>所指定的位置;
<url-pattern>/HelloServlet</url-pattern>指在IE url中的请求形式.这里的/是相对于当前的web目录的.
例:
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>project1.HelloServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>project1.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/HelloServlet</url-pattern>
</servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/HelloServlet</url-pattern>
</servlet-mapping>
2.欢迎页面的设置:
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
如果第一个页面找不到,会依次向下找
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
如果第一个页面找不到,会依次向下找
3.errorpage的配置:
<error-page>
<error-code>404</error-code>
<location>/notFileFound.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/notFileFound.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.NullPointerException</exception-type>
<location>/null.html</location>
</error-page>
<exception-type>java.lang.NullPointerException</exception-type>
<location>/null.html</location>
</error-page>
4.为Servlet定义初始化参数
使用getInitParameter()方法来提取servlet的初始化参数
定义如下:
<servlet>
<servlet-name>a</servlet-name>
<servlet-class>jsj.lx.demo.MyServlet</servlet-class>
<init-param>
<param-name>type</param-name>
<param-value>text/html;charset=GBK</param-value>
</init-param>
</servlet>
提取方式:
String str = this.getInitParameter("type");
使用getInitParameter()方法来提取servlet的初始化参数
定义如下:
<servlet>
<servlet-name>a</servlet-name>
<servlet-class>jsj.lx.demo.MyServlet</servlet-class>
<init-param>
<param-name>type</param-name>
<param-value>text/html;charset=GBK</param-value>
</init-param>
</servlet>
提取方式:
String str = this.getInitParameter("type");
六.用Servlet控制会话
Servlet定义了一个HTTPsession接口,实现session的功能.在访问者从某个特定的主页到离开为止的那段时间,每个访问者都会单独获得一个session.
使用HTTPServletRequest的getSession方法得到当前存在的session,如果当前没有定义session,则创建一个新的session.
当用完session后,可以使用session.invalidate()方法关闭session.但是这并不是严格要求的.因为,Servlet引擎在一段时间之后会自动关闭session.还可以在web.xml中配置session的过期时间,单位是分钟:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
Servlet定义了一个HTTPsession接口,实现session的功能.在访问者从某个特定的主页到离开为止的那段时间,每个访问者都会单独获得一个session.
使用HTTPServletRequest的getSession方法得到当前存在的session,如果当前没有定义session,则创建一个新的session.
当用完session后,可以使用session.invalidate()方法关闭session.但是这并不是严格要求的.因为,Servlet引擎在一段时间之后会自动关闭session.还可以在web.xml中配置session的过期时间,单位是分钟:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
例:
(1)
HttpSession session = request.getSession();
session.setAttribute("username", "scott");
(1)
HttpSession session = request.getSession();
session.setAttribute("username", "scott");
RequestDispatcher rd = request.getRequestDispatcher("A.jsp");
rd.forward(request, response);
rd.forward(request, response);
(2)
HttpSession ss = request.getSession();
List list=new ArrayList();
list.add("SMITH");
list.add("ALLEN");
ss.setAttribute("userlist", list);
HttpSession ss = request.getSession();
List list=new ArrayList();
list.add("SMITH");
list.add("ALLEN");
ss.setAttribute("userlist", list);
七.Filter过滤器
1.定义:ServletFilter是Servlet2.3规范中新增加的,它是截取用户从客户端提交的请求,在还没有到达需要访问的资源时欲行的一个类.它的操纵来自客户端的请求,在资源还没有发送到客户端前截取响应,并处理这些还没有发送到客户端的响应.
2.ServletFilter的作用:
权限的校验,日志记录,图片的转换,数据的加密等等.
1.定义:ServletFilter是Servlet2.3规范中新增加的,它是截取用户从客户端提交的请求,在还没有到达需要访问的资源时欲行的一个类.它的操纵来自客户端的请求,在资源还没有发送到客户端前截取响应,并处理这些还没有发送到客户端的响应.
2.ServletFilter的作用:
权限的校验,日志记录,图片的转换,数据的加密等等.
3.实现:一个ServletFilter可以分为两部分:Java类自身以及在web.xml文件中xml.
要作为 ServletFilter的Java类必须实现Filter接口.该接口由一对自描述的生命周期方法 init(FilterConfig),destroy()和一个行为方法doFilter(ServletRequest, ServletResponse, FilterChain).
要作为 ServletFilter的Java类必须实现Filter接口.该接口由一对自描述的生命周期方法 init(FilterConfig),destroy()和一个行为方法doFilter(ServletRequest, ServletResponse, FilterChain).
4.实现步骤:
a.实现Filter接口
b.实现doFilter方法
c.传递过滤链,放请求通过
d.在web.xml文件中注册过滤器
a.实现Filter接口
b.实现doFilter方法
c.传递过滤链,放请求通过
d.在web.xml文件中注册过滤器
八.监听器Listener
1.定义:Listioner是Servlet的监听器,它可以监听客户端的请求,服务取得操作等.
通过监听器,可以自动激发一些操作,比如监听在先的用户的数量.当增加一个HTTPsession时,就激发sessionCreated(HTTPsessionEvent sec)方法,这样就可以进行页面访问统计了.
1.定义:Listioner是Servlet的监听器,它可以监听客户端的请求,服务取得操作等.
通过监听器,可以自动激发一些操作,比如监听在先的用户的数量.当增加一个HTTPsession时,就激发sessionCreated(HTTPsessionEvent sec)方法,这样就可以进行页面访问统计了.
2.常用监听接口:
a) ServletContextAttributeListenner监听对ServletContext属性的操作,比如增加,删除,修改属性.
b) ServletContextListener监听ServletContext.
当创建ServletContext时,激发contextInitialized(ServletContextEvent sce)方法.
当销毁ServletContext时,激发contextDestroyed(ServletContextEvent sce)方法.
c) HttpSessionListener监听HttpSession的操作
当创建一个Session时,激发sessionCreated(HttpSessionEvent se)方法;
当销毁一个Session时,激发sessionDestroyed(HttpSessionEvent se)方法.
a) ServletContextAttributeListenner监听对ServletContext属性的操作,比如增加,删除,修改属性.
b) ServletContextListener监听ServletContext.
当创建ServletContext时,激发contextInitialized(ServletContextEvent sce)方法.
当销毁ServletContext时,激发contextDestroyed(ServletContextEvent sce)方法.
c) HttpSessionListener监听HttpSession的操作
当创建一个Session时,激发sessionCreated(HttpSessionEvent se)方法;
当销毁一个Session时,激发sessionDestroyed(HttpSessionEvent se)方法.
d) HttpSessionAttributeListener监听HttpSession中的属性的操作
当在Session增加一个属性时,激发attributeAdded(HttpSessionBindingEvent se) 方法;
当在Session删除一个属性时,激发attributeRemoved(HttpSessionBindingEvent se)方法;
当在Session属性被重新设置时,激发attributeReplaced(HttpSessionBindingEvent se)方法.
当在Session增加一个属性时,激发attributeAdded(HttpSessionBindingEvent se) 方法;
当在Session删除一个属性时,激发attributeRemoved(HttpSessionBindingEvent se)方法;
当在Session属性被重新设置时,激发attributeReplaced(HttpSessionBindingEvent se)方法.
Listener的配置:
<listener>
<listener-class>OnLineCountListener</listener-class>
</listener>
<listener>
<listener-class>OnLineCountListener</listener-class>
</listener>
九.字符的中文转换问题
中文转换可以分多种情况:
1.如果页面中使用jsp:include或jsp:forward关系,中文字符集转换用:
request.setCharacterEncoding("GBK");
中文转换可以分多种情况:
1.如果页面中使用jsp:include或jsp:forward关系,中文字符集转换用:
request.setCharacterEncoding("GBK");
2.在Servlet中显示中文:
由于无法使用jsp页面中的编码指令
<%@ page language="java" import="java.util.*" contentType="text/html;charset=GBK"%>
那么在Servlet中设置输出编码就应该通过:
response.setContentType("text/html;charset=GBK");
由于无法使用jsp页面中的编码指令
<%@ page language="java" import="java.util.*" contentType="text/html;charset=GBK"%>
那么在Servlet中设置输出编码就应该通过:
response.setContentType("text/html;charset=GBK");
3.普通的参数传递
普通的参数也需要考虑到中文的问题.除了页面显示设置contentType="text/html;charset=GBK"之外,我们还需要对中文字符进行字符转换硬编码:
普通的参数也需要考虑到中文的问题.除了页面显示设置contentType="text/html;charset=GBK"之外,我们还需要对中文字符进行字符转换硬编码:
超链接:
String str = request.getParameter("username");
str = new String(str.getBytes("iso8859-1"),"GBK");
String str = request.getParameter("username");
str = new String(str.getBytes("iso8859-1"),"GBK");
form表单:
String str= request.getParameter("username");
str = new String(str.getBytes("iso8859-1"),"GBK");
String str= request.getParameter("username");
str = new String(str.getBytes("iso8859-1"),"GBK");
javascript转向:
String str = request.getParameter("username");
str = new String(str.getBytes("ISO8859-1"),"gbk");
String str = request.getParameter("username");
str = new String(str.getBytes("ISO8859-1"),"gbk");
response方式转向:
String message = "我的中文测试";
response.sendRedirect("L.jsp?message="+URLEncoder.encode(message));
String message = "我的中文测试";
response.sendRedirect("L.jsp?message="+URLEncoder.encode(message));
接收页面:
String message = request.getParameter("message");
message = new String(message.getBytes("ISO8859-1"),"GBK");
String message = request.getParameter("message");
message = new String(message.getBytes("ISO8859-1"),"GBK");
request等作用域不需要进行转换,只要在页面显示设置中设置就可以了
request.setAttribute("username","我的测试名称");
session.setAttribute("passwd","我的密码");
request.setAttribute("username","我的测试名称");
session.setAttribute("passwd","我的密码");
十.Servlet线程
Servlet体系结构是建立在java多线程机制之上的,它的生命周期是由web容器负责的.当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类.当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例.Servlet容器会自动使用线程池等技术来支持系统的运行.
例:
boolean shutdown = true;
/**
* 线程体
*/
public void run(){
int i = 0;
while(true){
i++;
System.out.println(Thread.currentThread().getName()+"="+i);
if(shutdown == false){
break;
}
}
System.out.println("本线程结束!");
}
Servlet体系结构是建立在java多线程机制之上的,它的生命周期是由web容器负责的.当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类.当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例.Servlet容器会自动使用线程池等技术来支持系统的运行.
例:
boolean shutdown = true;
/**
* 线程体
*/
public void run(){
int i = 0;
while(true){
i++;
System.out.println(Thread.currentThread().getName()+"="+i);
if(shutdown == false){
break;
}
}
System.out.println("本线程结束!");
}
java线程共享数据的概念:
多线程使用的数据是共享的,Servlet本身建立在多线程的基础上,所以对于全局变量也存在"共享数据"的问题.
在Servlet中定义一个全局变量,该数据将会被多个线程"共享"
例:
String username;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
username = request.getParameter("username");
try{
Thread.sleep(1000*6);
}catch(InterruptedException e){
e.printStackTrace();
}
out.println(username);
out.close();
}
对于上面这个例子,如果同时提交两个请求:
http://loclhost:8088/servlet/MyServlet?username=zhangsanfeng
http://loclhost:8088/servlet/MyServlet?username=zhangwuji
则两个结果都将显示为zhangwuji.
这是因为第一个在访问时,得到了zhangsanfeng的值,后来username的值被赋为zhangwuji.又因为username是被多个线程所共享的,所以所有里面的username都变成了zhangwuji.为了避免这样的错误,最好避免使用全局变量而使用临时变量.因为方法中的临时变量时在栈上分配空间,而且每个线程都有自己私有的栈空间,所以他们不会影响线程的安全.
多线程使用的数据是共享的,Servlet本身建立在多线程的基础上,所以对于全局变量也存在"共享数据"的问题.
在Servlet中定义一个全局变量,该数据将会被多个线程"共享"
例:
String username;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
username = request.getParameter("username");
try{
Thread.sleep(1000*6);
}catch(InterruptedException e){
e.printStackTrace();
}
out.println(username);
out.close();
}
对于上面这个例子,如果同时提交两个请求:
http://loclhost:8088/servlet/MyServlet?username=zhangsanfeng
http://loclhost:8088/servlet/MyServlet?username=zhangwuji
则两个结果都将显示为zhangwuji.
这是因为第一个在访问时,得到了zhangsanfeng的值,后来username的值被赋为zhangwuji.又因为username是被多个线程所共享的,所以所有里面的username都变成了zhangwuji.为了避免这样的错误,最好避免使用全局变量而使用临时变量.因为方法中的临时变量时在栈上分配空间,而且每个线程都有自己私有的栈空间,所以他们不会影响线程的安全.
十一.自动加载Servlet
Servlet有一个生命周期方法,init,service,destroy.其中init在 Servlet第一次访问的时候访问,它只能被访问一次.而如果你需要在服务器启动的时候让Servlet自动启动,你可以通过load-on- startup来实现.load-on-startup是web.xml文件中Servlet的配置节点.
Servlet有一个生命周期方法,init,service,destroy.其中init在 Servlet第一次访问的时候访问,它只能被访问一次.而如果你需要在服务器启动的时候让Servlet自动启动,你可以通过load-on- startup来实现.load-on-startup是web.xml文件中Servlet的配置节点.
举例:
如果想要在服务器启动时从数据库中查询所有的用户名列表,以便在其他页面中可以直接使用,而不需要从数据库在进行查询,如何实现?
1.ServletContentListener可以再服务器启动时自动执行其方法
2.可以使用一个Servlet,然后定义load-on-startup,让它能够在服务器启动时自动执行其方法.使用<load-on-startup>1</load-on-startup>可以指定服务器加载顺序.
代码如下:
/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occure
* 本方法在servlet被加载时访问
* 这里,我们在服务器启动,自动加载一段数据,起到数据缓存的效果
*/
public void init() throws ServletException {
// Put your code here
List<String> list = new ArrayList<String>();
list.add("WARD");
list.add("JONES");
list.add("JAMES");
this.getServletContext().setAttribute("datalist",list);
}
配置文件设置:
<servlet>
<servlet-name>DataCacheServlet</servlet-name>
<servlet-class>com.sun.demo.DataCacheServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
如果想要在服务器启动时从数据库中查询所有的用户名列表,以便在其他页面中可以直接使用,而不需要从数据库在进行查询,如何实现?
1.ServletContentListener可以再服务器启动时自动执行其方法
2.可以使用一个Servlet,然后定义load-on-startup,让它能够在服务器启动时自动执行其方法.使用<load-on-startup>1</load-on-startup>可以指定服务器加载顺序.
代码如下:
/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occure
* 本方法在servlet被加载时访问
* 这里,我们在服务器启动,自动加载一段数据,起到数据缓存的效果
*/
public void init() throws ServletException {
// Put your code here
List<String> list = new ArrayList<String>();
list.add("WARD");
list.add("JONES");
list.add("JAMES");
this.getServletContext().setAttribute("datalist",list);
}
配置文件设置:
<servlet>
<servlet-name>DataCacheServlet</servlet-name>
<servlet-class>com.sun.demo.DataCacheServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>