(转载) 在讨论Servlet之前,我们先来看看JSP运行机制:服务器运行JSP时候,底层是将JSP编译成为java类文件来运行的,这种类文件就是Servlet。 那么我们可不可以直接编写Servlet类呢? 1. 当我们在JSP里面写大量Java代码时,可以把Java代码分离到Servlet中。 2. 当我们希望程序运行得快一些时,可以使用Servlet。 下面讨论一下Servlet的生命周期 当客户端发送请求(Request)到Servlet中,Servlet{dy}次运行的时候会调用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 {
//初始化函数,重写,{dy}次访问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("消亡函数");
}
}
<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的输出结果,由此说明初始化函数是{dy}次运行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:就是参数中的response HttpSession session = request.getSession();//得到session ServletContext application = this.getServletContext();//得到application for(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{zh0}不要有大量的逻辑,这样会造成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.浏览器地址栏变成了目标页面的url response.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/javaee http://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>
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。只要在访问的时候要做检查的工作,我们都可以用过滤器来实现。 |