深入探索Servlet

来源:互联网 发布:hadoop2.7 java开发 编辑:程序博客网 时间:2024/06/06 07:38

(转载)  

在讨论Servlet之前,我们先来看看JSP运行机制:服务器运行JSP时候,底层是将JSP编译成为java类文件来运行的,这种类文件就是Servlet。

那么我们可不可以直接编写Servlet类呢?

1. 当我们在JSP里面写大量Java代码时,可以把Java代码分离到Servlet中。

2. 当我们希望程序运行得快一些时,可以使用Servlet。

下面讨论一下Servlet的生命周期

     当客户端发送请求(Request)到Servlet中,Servlet第一次运行的时候会调用init()方法,然后调用service()、doGet()或doPost()方法,如果此时有第二个客户端再来访问这个Servlet,将直接调用service()、doGet()或doPost()方法,这些方法是采用多线程的方法实现以便能够让多个用户同时访问,当服务器关闭的时候,Servlet消亡,会自动调用destroy()方法。

Servlet生命周期实例

编写Servlet1.java的Servlet类,实现测试Servlet的生命周期,代码如下

package wang.servlets;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Servlet1 extends HttpServlet {public Servlet1() {//构造函数System.out.println("构造函数");}public void init() throws ServletException {//初始化函数,重写,第一次访问Servlet时自动调用System.out.println("初始化函数");}//这个函数在以get方式请求这个Servlet时运行//以get方式请求这个Servlet:包括链接、get方式表单提交、直接访问这个servlet等public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("doGet");}//这个函数在以post方式请求这个Servlet时运行//以get方式请求这个Servlet:包括post方式表单提交等public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("doPost");this.doGet(request, response);//将post的内容转接给doGet方法}/*service函数既可以接收get请求,也可以接收post请求protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {super.service(req, resp);}*/public void destroy() {//消亡函数,重写System.out.println("消亡函数");}} 

在web.xml中注册上面的Servlet类,配置代码如下

<servlet><servlet-name>Servlet1</servlet-name><servlet-class>wang.servlets.Servlet1</servlet-class></servlet><servlet-mapping><servlet-name>Servlet1</servlet-name><url-pattern>/servlet/Servlet1</url-pattern> <!-- 定义了Servlet1的访问方式 --></servlet-mapping>

然后启动服务器,在浏览器地址栏中输入:http://localhost:8080/ServletPro/servlet/Servlet1,运行结果如下

构造函数

初始化函数

doGet

从结果可以看出Servlet的执行过程,如果再次刷新页面,相当于另外一个客户端来访问,此时只会得到doGet的输出结果,由此说明初始化函数是第一次运行Servlet的时候才会被调用,然后停止服务器,会得到消亡函数的输出结果,说明调用了消亡函数。

如何在Servlet中访问JSP的内置对象

request:就是参数中的request。

response:就是参数中的response。

session:利用request.getSession()方法。

application:利用getServletContext()方法。

编写Servlet2.java的Servlet类,实现在Servlet中访问JSP的内置对象(九九乘法表的实现),代码如下

package wang.servlets;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;public class Servlet2 extends HttpServlet {public Servlet2() {}public void init() throws ServletException {}public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//怎样在Servlet内访问Jsp内置对象PrintWriter out = response.getWriter();//得到out//得到request:就是参数中的request//得到response:就是参数中的responseHttpSession session = request.getSession();//得到sessionServletContext application = this.getServletContext();//得到applicationfor(int i=1;i<=9;i++) {for(int j=1;j<=i;j++) {out.print(i + "*" + j + "=" + i*j);}out.println();}}public void destroy() {}}

运行结果将得到一个九九乘法表。

Servlet应该负责的怎样的工作?

上面程序存在一个问题,就是显示九九乘法表是在Servlet中实现的,一般情况下Servlet是负责动作或控制逻辑,而对于显示功能就应该使用JSP。但是Servlet最好不要有大量的逻辑,这样会造成Servlet很庞大,并且功能很混杂,这个时候就应该使用JavaBean来实现部分的逻辑。

下面介绍几种Servlet的高级用法

1. 实现页面的跳转。

2. 读取web.xml中的初始化参数。

3. 实现过滤器。

在Servlet内实现页面跳转

编写含有表单的JSP页面,form.jsp,代码如下

<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>My JSP 'form.jsp' starting page</title></head><body><form action="/PrjFu8/servlet/Servlet3">输入一个消息:<input name="message"/><br/><input type="submit" value="提交"/></form></body></html>

编写结果页面result.jsp,代码如下

<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>My JSP 'form.jsp' starting page</title></head><body>这是结果页面</body></html>

编写负责跳转用的Servlet类,Servlet3.java,首先采用重定向的方法

package wang.servlets;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Servlet3 extends HttpServlet {public Servlet3() {}public void init() throws ServletException {}public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//跳转方法1.浏览器地址栏变成了目标页面的urlresponse.sendRedirect("/PrjFu8/result.jsp");}public void destroy() {}}

运行form.jsp页面,点击提交按钮,将跳转到result.jsp页面中,由于上面采用的重定向的方法,所以跳转之后,地址栏上的url地址也发生了变化。

使用重定向方法进行跳转时,存在一个问题,就是在结果页面得不到request中的内容,包括参数和属性。

在Servlet3.java中的doGet方法中添加代码,测试能否得到request的内容

String str = request.getParameter("message");System.out.println(str);在result.jsp中添加如下代码<%String str = request.getParameter("message");out.println(str);%> 运行form.jsp页面,输入消息,点击提交按钮,将跳转到result.jsp页面中,这时在控制台上得到正确的结果,但是在result.jsp中得不到request中的内容,结果页面中request内容丢失。

下面使用forward跳转方法,这种方法不会丢失request中的内容,在doGet方法添加相应代码,doGet方法如下

public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String str = request.getParameter("message");System.out.println(str);//跳转方法1.浏览器地址栏变成了目标页面的url//到了目标页面之后,request内的参数值、属性值丢失了response.sendRedirect("/PrjFu8/result.jsp");//跳转方法2.浏览器地址栏没有变成目标页面的url//相当于在服务器内部将目标页面的输出送给客户端,request参数值、属性值没有丢失ServletContext application = this.getServletContext();RequestDispatcher rd = application.getRequestDispatcher("/result.jsp");rd.forward(request, response);/*** 使用经验:如果在A页面有一些内容要在B页面显示,但是如果内容数量较大,并且是暂态数据* 可以将内容不要放在session内,放在request内,用跳转方法2跳转到B页面显示,节省内存* 跳转方法1相当于重新在客户端输入目标页面地址,重新请求* 方法2相当于服务器内部的跳转* 如果要跳转到服务器以外的url,必须使用方法1,比如跳转到百度*/}

读取web.xml中的参数

在web.xml中可以定义两种形式的参数,全局参数和局部参数

读取全局参数

在web.xml中定义全局参数,代码如下

<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5"xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><!-- 定义全局参数,所有的Servlet都可以读取 --><context-param><param-name>GlobalParam</param-name><param-value>Welcome(Global)</param-value></context-param><servlet><servlet-name>Servlet3</servlet-name><servlet-class>wang.servlets.Servlet3</servlet-class></servlet><servlet-mapping><servlet-name>Servlet3</servlet-name><url-pattern>/servlet/Servlet3</url-pattern></servlet-mapping></web-app> 在Servlet中读取全局参数的代码可以编写在doGet方法,doGet方法代码如下

public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//读取全局参数ServletContext application = this.getServletContext();String value = application.getInitParameter("GlobalParam");System.out.println(value);}

读取局部参数

在web.xml中定义局部参数,代码如下

<servlet><servlet-name>Servlet3</servlet-name><servlet-class>wang.servlets.Servlet3</servlet-class><!-- 定义局部参数,只有这个Servlet才能识别 --><init-param><param-name>LocalParam</param-name><param-value>Welcome(Local)</param-value></init-param></servlet> 

在doGet读取参数的代码如下

public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//读取全局参数ServletContext application = this.getServletContext();String value = application.getInitParameter("GlobalParam");System.out.println(value);//读取局部参数String value2 = this.getInitParameter("LocalParam");System.out.println(value2);}

实现过滤器

过滤器能使每次提交(广义,所有的get,post提交)的时候自动做一些事情。

如何编写过滤器?

1.编写一个类,实现javax.servlet.Filter。

2.编写doFilter:FilterChain.doFilter(request, response)。

3.在web.xml中注册这个过滤器。

<filter>

<filter-name>名称</filter-name>

<filter-class>类</filter-class>

</filter>

<filter-mapping>

       <filter-name>名称</filter-name>

       <url-pattern>/*</url-pattern>

</filter-mapping>

案例:利用过滤器解决中文问题

编写过滤器类,EncodingFilter.java,实现解决中文问题,代码如下

package wang.filter;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;public class EncodingFilter implements Filter {private String encoding;public EncodingFilter() {System.out.println("过滤器构造方法");}public void init(FilterConfig config) throws ServletException {//初始化函数,服务器运行能自动运行一次System.out.println("过滤器初始化函数");config.getInitParameter("xxx"); //得到局部参数encoding = config.getServletContext().getInitParameter("encoding");//得到全局参数}public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {//每次提交都会运行System.out.println("过滤器doFilter函数");request.setCharacterEncoding(encoding);//解决中文问题//过滤器是在提交到达处理之前运行,所以这里要将这个请求向后传递chain.doFilter(request, response);}public void destroy() {//消亡时运行System.out.println("过滤器消亡函数");}} 在web.xml中注册这个过滤器,代码如下

<!-- 注册过滤器 --><filter><filter-name>EncodingFilter</filter-name><filter-class>wang.filter.EncodingFilter</filter-class></filter><!-- 配置过滤器要过滤的对象 --><filter-mapping><filter-name>EncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

过滤器比较重要的作用

1. 做初始化工作,不仅仅是为过滤器本身初始化,而且可以为整个系统工作初始化工作,并且初始化工作只运行一次。

2. 每次做提交的时候(广义上的提交),doFilter()方法都会被调用,这就给我们带来比较好的作用,比如我们登录某个系统,当我们退出该系统时,直接点击浏览器上面的后退按钮,如果不做处理,就会返回到之前登录状态,这显然是不安全的。我们可以通过检查session是不是为空来控制,session为空的话就提示用户重新登录,所以要清空页面的session,这时可以使用过滤器,把要检查session的页面共同用一个过滤器来做过滤,每次访问它们之前都来检查session。只要在访问的时候要做检查的工作,我们都可以用过滤器来实现。

0 0