java-web 第四讲 servlet 学习心得

来源:互联网 发布:photoshop最新软件版本 编辑:程序博客网 时间:2024/06/01 09:50

1:servlet 接口:

1.1 servlet 主要方法: init()    --ServletConfig
servlet 实例化后,容器会先调用init 方法,用于初始化该对象,即在处理客户需求前完成一些初始化工作。每一个 servlet实例,init 只能被调用一次,相当于java的static 块。
   servlet 使用 ServletConfig 对象 从web 应用程序的配置信息中获取以 键值对形式提供的初始化参数。
   servlet 使用 ServletConfig 对象获取 ServletContext 对象,使用 ServletContext 可以使 servlet 和servlet 容器进行通信。 

service() --ServeltRequest ServletResponse

容器调用service() 方法来处理客户的请求,注意: 在service 方法前必须确保 init 方法正确完成。
容器会构造一个请求对象 ServletRequest 和 响应对象 ServletResponse 作为参数传递给service ().

destroy(): 当容器检测到servlet 对象从服务中移除的时候会调用该方法。释放资源 给GC

getServletConfig() 返回servletconfig 对象

getServletInfo() 返回一个字符串,包含servlet 信息

1.2 servlet 创建的三种方法一是实现Servlet接口,二是继承抽象类GenericServlet,三是继承HttpServlet类。

1: 实现servlet 接口 必须实现servlet 五个方法
  1. public class TestServlet implements Servlet{  
  2.     public void init(ServletConfig config) throws ServletException{  
  3.         System.out.println("init");  
  4.         }  
  5.     public ServletConfig getServletConfig(){  
  6.         reture null;  
  7.         }  
  8.     public void service(ServletRequest req,ServletResponse res)   
  9.         throws ServletException,IOException{  
  10.             //这里可以实现请求后要做的内容  
  11.             PrintWriter out = response.getWriter();  
  12.       out.println("Hello World!");  
  13.  
  14.             }  
  15.     public String getServletInfo(){  
  16.         return null;  
  17.         }  
  18.     public void destroy(){  
  19.         System.out.println("destory");  
  20.         }  
  21.     }  
2: 继承抽象类 GenericServletGenericServlet类中只有一个抽象方法,即service(ServletRequest req, ServletResponse res)
  1. public TestGenericServlet extends GenericServlet{  
  2.     public abstract void service(ServletRequest req,ServletResponse res)  
  3.                       throws ServletException,IOException{  
  4.      PrintWriter out = response.getWriter();  
  5.      out.println("Hello World!");                       
  6.      }  
3: 继承HttpServlet类编写Servlet应该是最容易的,而且是最常见的,我们一般要编写Servlet直接继承这个类就行了,重写doGet()或者doPost()方法即可
  1. public TestHttpServlet extends HttpServlet{  
  2.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  3.         throws IOException, ServletException {  
  4.   response.setContentType("text/html;charset=gb2312");  
  5.   PrintWriter out = response.getWriter();  
  6.  
  7.   out.println("<html>");  
  8.   out.println("<head>");  
  9.   out.println("<title>HelloWorld</title>");  
  10.   out.println("</head>");  
  11.   out.println("<body bgcolor=\"white\">");  
  12.   out.println("<hr>");  
  13.   out.println("HelloWorld");  
  14.   out.println("</body></html>");  
  15.  }  
  16.  
  17.  public void doPost(HttpServletRequest request, HttpServletResponse response)  
  18.    throws IOException, ServletException {  
  19.   doGet(request, response);  
  20.  }  
  21.  

在servlet 中,主要接口与类方法如下:

1.3: HttpServlet 详解

1:七种请求方法 doGet doPost doHead doPut doDelete doTrace doOptions 参数都是 HttpRequest HttpResponse

2:servlet 执行顺序: 当容器收到一个servlet 请求后, 先调用 公共的 service() 方法 在调用service 时候,首先将参数转换为 HttpRequest 和 HttpResponse
然后调用保护的(protected) service() 方法 将转换后的 HttpRequest 和 HttpResponse 作为参数传递下去
在 protected service 中 ,首先调用 HttpRequest 的 getMethod() 获取 HTTP 请求方法的名字,然后根据类型调用相应的 doXXX() 方法

1.4: HttpServletRequest,HttpServletResponse 详解

HttpServletRequest:String getContextPath()  返回请求URL 中表示上下文的部分 如: /simple/test  返回 /simple
Cookie[] getCookies()  返回本次请求所有的Cookie 对象
String  getHeader()  返回请求报头的值
String getMethod() 返回本次请求使用的HTTP 方法的名字  如 post  get Trace 等
String getPathInfo()  返回额外 url 信息 如 /simple/test  返回 test
String getPathTranslated() 返回真实路径信息  如 
String getQueryString() 返回请求的action 名称 如  返回 logon
HttpSession getSession() 返回和此次请求相关联的session
HttpServletResponse:void addCookie(Cookie cookie) 新增一个cookie 到响应中去,可以设置多个。
addheader(String name,String value) 用给出的name and value 增加一个响应报头到响应中去
sendRedirect(String location)  发送一个临时的重定向到客户端 让客户端访问的url重新定位

1.5: ServletConfig

servlet容器使用ServletConfig 对象在容器初始化的时候向其传递配置信息
四种主要方法:   String getInitParemeter(String name) 返回名字为 name 的初始化参数的值,初始化参数在配置文件 web.xml 中配置
Enumeration getInitParameterNames() 返回servlet 所有初始化参数名字的枚举集合
ServletContext getServletContext() 返回servlet 上下文对象的引用
String getServletName() 返回 当前servlet 的名称

2:servlet 配置

  1:web.xml: web 应用程序的配置和部署都是通过web.xml 来完成的,其包含以下信息:

ServletContext 的初始化参数
Session 的配置
Servlet/Jsp 的定义
Servlet/jsp 的
MIME 类型映射
欢迎文件列表
错误页面
安全
地区和编码映射
JSP 配置 
<?xml version="1.0" encoding="UTF-8"?><web-app version="3.0" 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_3_0.xsd">  <display-name></display-name>  <welcome-file-list>    <welcome-file>index.jsp</welcome-file>  </welcome-file-list>  <servlet>  <!-- Servlet名字,可以随便取,有多个Servlet时不允许重名 -->  <servlet-name>SimpleServlet</servlet-name>  <!-- 指定实现这个Servlet的类 完整的包名+类名 -->  <servlet-class>com.tide.servlet.SimpleServlet</servlet-class>  </servlet>  <servlet-mapping>  <!-- –必须和<servlet>里的<servlet-name>内容一样 -->  <servlet-name>SimpleServlet</servlet-name>  <!-- 指定访问这个Servlet的URL。这里给出的是对于整个Web应用的相对URL路径  这里是浏览器访问时的地址 http://localhost:8080/Myservlet/hello  即可访问-->   <url-pattern>/hello</url-pattern>  </servlet-mapping></web-app>
对于servlet 上的页面 有两种访问方式: 一种是在web.xml 中的 url-pattern 中直接访问地址   另一种是访问jsp 对象

3:servlet 例子

3.1 简单表单模拟

web.xml 部署为
<?xml version="1.0" encoding="UTF-8"?><web-app version="3.0" 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_3_0.xsd">  <display-name></display-name>  <welcome-file-list>    <welcome-file>index.jsp</welcome-file>  </welcome-file-list>    <servlet>  <servlet-name>loginjsp</servlet-name>  <servlet-class>com.tide.servlet.Login</servlet-class>  </servlet>   <servlet-mapping>  <servlet-name>loginjsp</servlet-name>  <url-pattern>/login</url-pattern>  </servlet-mapping></web-app>
login.jsp 测试登陆
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"contentType="text/html; charset=UTF-8"%><% request.setCharacterEncoding("UTF-8"); %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>    <title>用户注册</title>  </head>    <body>    <center>    <h2>用户注册</h2>    <hr>    <form action="login" method="post">    用户姓名:<input type="text" name="username" style="width:138px" />    <br>    用户密码:<input type="password" name="password" style="width:138px" />    <br>    <br>    <input type="submit" value="确定"/>    <input type="reset" value="取消"/>    </form>    </center>  </body></html>
package com.tide.servlet;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Login extends HttpServlet {public void doGet(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException {String name = req.getParameter("username");System.out.println("获取的名称为-- " + name);PrintWriter pw;pw = res.getWriter();/*pw.print("<html><head><title>");pw.print("Welcome");pw.print("<title><head>");pw.print("<body>");pw.print("hello " + name);pw.print("</body></html>");*/pw.print("hello "+name);pw.close();}public void doPost(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException{  String username = req.getParameter("username");        String password = req.getParameter("password");        res.setContentType("text/html");        PrintWriter out = res.getWriter();        out.println("<html><head><title>Login Result</title></head>");        out.println("<body> username: " + username + "<br>");        out.println("password: " + password + "</body></html>");        out.flush();}}
--------------------------------------------------------------------------------------------------
采用post 模式 可以避免密码的泄露

get与post方法之间的差别:

  1.浏览器地址栏呈现的结果不同(表象);
  2.真正的原因在于向服务器端发送请求时的形式是不同的。  3.get的请求格式:  GET /test/LoginServlet?username=hello&password=world HTTP/1.1  4.post的请求格式:  POST /test/LoginServlet HTTP/1.1   Connection: Keep-Alive  username=hello&password=world  5.通过浏览器进行文件上传时,一定要使用post方式而绝不能使用get方式。  6.通过浏览器地址栏输入网址的方式来访问服务器端资源,全部使用的是get方法请求的。
------------------------------------------------------------------------------------------------------

3.2 消息包头输出到客户端

servlet 实现:  报文头部 客户端的运行环境等信息 全部通过 HttpServletRequest 来获取
public class OutputInfo extends HttpServlet {public void doGet(HttpServletRequest req,HttpServletResponse res) throws ServletException,IOException{res.setContentType("text/html;charset=gb2312");PrintWriter pw = res.getWriter();Enumeration headName = (Enumeration) req.getHeaderNames();pw.println("<html><head>");pw.println("<title> Info Page </title>");pw.println("</head>");pw.println("<body><center>");pw.println("<table border=1 align=center>");pw.println("<caption>Servlet 接收到的Http 消息 包头的信息</caption>");pw.println("<tr bgcolor=#999999>");pw.println("<th>消息包头的名字</th>");pw.println("<th>消息包头的值</th>");pw.println("</tr>");while(headName.hasMoreElements()){String name = (String) headName.nextElement();String value = req.getHeader(name);pw.println("<tr>");pw.println("<td>"+name+"</td>");pw.println("<td>"+value+"</td>");pw.println("</tr>");}pw.println("</table><p>");pw.println("<table border=1 align=center>");pw.println("<caption> 其他访问信息 </caption>");pw.println("</tr>");pw.println("<tr>");pw.println("<td>客户端的IP地址</td>");pw.println("<td>"+req.getRemoteAddr()+"</td>");pw.println("</tr>");pw.println("<tr>");pw.println("<td>客户端的端口号</td>");pw.println("<td>"+req.getRemotePort()+"</td>");pw.println("</tr>");pw.println("<tr>");pw.println("<td>服务器端的IP地址</td>");pw.println("<td>"+req.getLocalAddr()+"</td>");pw.println("</tr>");pw.println("<tr>");pw.println("<td>服务器端的端口号</td>");pw.println("<td>"+req.getLocalPort()+"</td>");pw.println("</tr>");pw.println("</table>");pw.println("</center></body></html>");pw.close();}}
将 servlet 添加到 web.xml 中 然后在客户端测试结果为 :
Servlet 接收到的Http 消息 包头的信息消息包头的名字消息包头的值hostlocalhost:8080connectionkeep-alivecache-controlmax-age=0accepttext/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8user-agentMozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36accept-encodinggzip,deflate,sdchaccept-languagezh-CN,zh;q=0.8其他访问信息客户端的IP地址127.0.0.1客户端的端口号60255服务器端的IP地址127.0.0.1服务器端的端口号8080

4:Servlet 生命周期

Servlet 运行期间,其生命周期由容器来统一管理,生命周期通过 Servlet 的 init()  destroy()  service()  三种方法来表示
 主要包含了四个阶段:
1:加载和实例化
在容器启动 或者响应第一个客户请求时,创建servlet  实例。
2:初始化
servlet 实例化后,容器必须调用 servlet 的 init() 方法来初始化这个servlet 对象,目的为了servlet 在处理客户请求前完成一系列的初始化工作,
对于每一个servlet  init() 只调用一次, 此时可以使用 ServletConfig 来从web.xml 中获取初始化的参数信息。
3:请求处理
servlet 容器调用servlet 的 service() 方法对请求进行处理,在此之前 init() 方法必须调用成功。 
Servlet 通过 ServletRequest 来获取客户端的信息和请求,对请求处理后 调用 ServletResponse 来设置响应信息。出现错误的话:该实例永久不可用-404  暂时不可用-503
4:服务终止
容器检测到实例从服务中移除后,调用 destroy()

5:Servlet 上下文

运行在java 虚拟机中的每一个web程序都有一个与之相关的 Servlet 上下文, java servlet API 提供了一个 ServletContext 接口来表示上下文。
一个 ServletContext 对象表示了一个web 程序的上下文, servlet 容器在初始化实例期间,向其传递 ServletConfig 对象, 通过其  getServletContext() 获取上下文。
上下文例子: 统计页面访问量   *************注意这里的上下文必须放在安全锁里 
public class CountDemo extends HttpServlet {public void doGet(HttpServletRequest req,HttpServletResponse res) throws ServletException,IOException{ServletContext context = getServletContext();//Enumeration<String> count = context.getAttributeNames();Integer count = null;synchronized(context){count = (Integer)context.getAttribute("counter");if(null == count){count = new Integer(1);}else{count = new Integer(count.intValue()+1);}context.setAttribute("counter", count);}res.setContentType("text/html;charset=gb2312");PrintWriter pw = res.getWriter();pw.println("<html><head>");pw.println("<title>页面访问统计</title>");pw.println("</head><body>");pw.println("该页面已经被访问了  :"+"<b>"+count+"</b>"+" 次");pw.println("</body></html>");pw.close();}}

6:Servlet 请求转发

好处:  <1> 提供了统一的访问方式   <2> 控制器(controller)可以将不同的请求发送给不同的servlet 来进行处理 本身不处理请求,缩短了响应时间

6.1 RequestDispacher: servlet 控制器

RequestDispacher 对象由 Servlet 来创建,用于封装一个由路径所标示的服务器资源。  主要有以下两种方法:
forward(ServletRequest req,ServletResponse res) :  该方法用于将 请求从一个servlet 传递给服务器上的 另外的 servlet  jsp 页面,或者 HTML 文件
 注意: 这个方法必须在响应被提交给客户端之前使用,之后的话会爆出 IllegastateException 错误  在 forward() 调用后原先在响应缓存中的未被提交的内容将自动清除。
include(ServletRequest req,ServletResponse res)  该方法用于响应中包含其他的资源信息(servlet  jsp  html)等内容。
这两个方法的区别是:include 将请求转发给其他对象后,被调用的servlet 做出的响应将并入原来的响应对象中,原来的servlet 对象还可以继续输出响应数据。
   forward  将请求转发给其他对象后,将由被调用的servlet 对象做出响应,原来的servlet 执行将终止。
    6.2  RequestDispache 对象的获取
三种方法:
<1> ServletRequest.getRequestDispacher(String path)   --资源路径名
<2> ServletContext.getNamedDispacher(String name)      --  jsp  或  servlet 名称
<3> SerletContext.getRequestDispacher(String path)-- 这里路径必须以 /  开头  相对于当前上下文根的路径  如 /MyServlet
  6.3  请求转发的实例
package com.tide.servlet;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang3.StringUtils;public class Login extends HttpServlet {public void doPost(HttpServletRequest req,HttpServletResponse res)throws ServletException,IOException{res.setContentType("text/html;charset=GB2312");ServletContext context = getServletContext();String name = req.getParameter("user");String pass = req.getParameter("passwd");System.out.println("获取到的用户名为 :"+name+"  --密码为 :"+pass);if(StringUtils.isBlank(name) || StringUtils.isBlank(pass)){System.out.println("用户名或密码为空");RequestDispatcher dis = context.getRequestDispatcher("/register.jsp");dis.forward(req, res);}else{RequestDispatcher dis = context.getRequestDispatcher("/loginsuccess.jsp");dis.forward(req, res);}}}
底层分析:
请求转发(RequestDispatcher)的过程:
         客户首先发送一个请求到服务器端,服务器端发现匹配的servlet,并指定它去执行,当这个servlet执行完之后,它要调用getRequestDispacther()方法,把请求转发给指定的test.jsp,整个流程都是在服务器端完成的,而且是在同一个请求里面完成的,因此servlet和jsp共享的是同一个request,在servlet里面放的所有东西,在jsp中都能取出来,因此,jsp能把结果getAttribute()出来,getAttribute()出来后执行完把结果返回给客户端。整个过程是一个请求,一个响应。
重定向(sendRedirect)的工作原理:
             客户发送一个请求到服务器,服务器匹配servlet,这都和请求转发一样,servlet处理完之后调用了sendRedirect()这个方法,这个方法是response的方法,所以,当这个servlet处理完之后,看到response.senRedirect()方法,立即向客户端返回这个响应,响应行告诉客户端你必须要再发送一个请求,去访问test.jsp,紧接着客户端受到这个请求后,立刻发出一个新的请求,去请求test.jsp,这里两个请求互不干扰,相互独立,在前面request里面setAttribute()的任何东西,在后面的request里面都获得不了。可见,在sendRedirect()里面是两个请求,两个响应。

0 0