Servlet详细教程(一)

一、Servlet概述

      1) java web目录结构

        

        2)Tomcat 目录结构


          3)Servlet 接口

                Servlet 是一种实现了 javax.servlet.Servlet 接口的类。

                Servlet 接口规定了特定的方法来处理特定的请求,开发者只需要实现 Servlet的相关方法,用户访问

                              Web 程序的时候,Tomcat会调用这些方法完成业务处理

二、编写及部署Servlet


       【具体开发方式见:4、开发 Servlet 的方式 ,

         下面的具体代码可在阅读完后面的内容后再回头来看】

       1)简介

             直接实现 Servlet 接口来编写 Servlet 很不方便,需要实现的方法太多。

             在 JDK中 javax.servlet.*,javax.servlet.http.*包下提供了对 Servlet 的支持。

             如 javax.servlet.http.HttpServlet 类已经实现了 Servlet 接口的所有方法。

             编写 Servlet时直接继承 HttpServlet,并覆盖需要的方法即可,一般只覆盖 doGet()与 doPost()方法

        2)实现Servlet

              在 MyEclipse中新建 Web Project,取名servlet,新建 Servlet,取名 FirstServlet。

              FirstServlet.java 文件:

package 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 FirstServlet extends HttpServlet {
	
	private static final long serialVersionUID = 2386052823761867369L;
	
	/**
	 * 以 GET 方式访问页面时执行该函数。
	 * 执行 doGet 前会先执行 getLastModified, 如果浏览器发现 getLastModified 返回的数值
	 * 与上次访问时返回的数值相同,则认为该文档没有更新,浏览器采用缓存而不执行 doGet。
	 * 如果 getLastModified 返回 -1,则认为是时刻更新的,总是执行该函数。
	 */ 
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// 调用 HttpServlet 自带的日志函数输出信息到控制台
		this.log("执行 doGet 方法... ");

		// 处理 doGet
		this.execute(request, response);
	}

	/**
	 * 以 POST 方式访问页面时执行该函数。
	 */ 
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		this.log("执行 doPost 方法... ");
		
		// 处理 doPost
		this.execute(request, response);
	}
	
	/**
	 * 返回该 Servlet 生成的文档的更新时间。对 Get 方式访问有效。
	 * 返回的时间为相对于 1970年1月1日08:00:00 的毫秒数。
	 * 如果为 -1 则认为是实时更新。默认为 -1。
	 */
	@Override
	public long getLastModified(HttpServletRequest request) {
		
		this.log("执行 getLastModified 方法... ");
		
		return 0;
	}

	private void execute(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException{

		response.setCharacterEncoding("UTF-8");//设置 request,response 编码方式
		request.setCharacterEncoding("UTF-8");
		
		// 访问该 Servlet 的 URI
		String requestURI = request.getRequestURI();
		// 访问该 Servlet 的方式,是 GET 还是 POST
		String method = request.getMethod();
		// 客户端提交的参数 param 值
		String param = request.getParameter("param");
		
		response.setContentType("text/html"); //设计文档类型
		PrintWriter out = response.getWriter(); //获取 out 对象
                //输出到客户端浏览器
                out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
		out.println("<HTML>");
		out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
		out.println("  <BODY>");
		out.println("	以 " + method + " 方式访问该页面。取到的 param 参数为:" + param + "<br/>");
		
		out.println("	<form action='" + requestURI + "' method='get'><input type='text' name='param' value=''><input type='submit' value='以 GET 方式访问 RequestServlet'></form>");
		out.println("	<form action='" + requestURI + "' method='post'><input type='text' name='param' value=''><input type='submit' value='以 POST 方式访问 RequestServlet'></form>");
		
		// 由客户端浏览器读取该文档的更新时间
		out.println("	<script>document.write('本页面最后更新时间:' + document.lastModified + '<br />'); </script>");
		out.println("	<script>document.write('本页面URL:' + location + '<br/>' ); </script>");
		
		out.println("  </BODY>");
		out.println("</HTML>");
		out.flush();
		out.close();
		
	}

}


         3)配置 <servlet>、<servlet-mapping>

               一个完整的 Servlet 包括 Servlet 类、<servlet> 配置、<servlet-mapping> 配置,缺一不可,

                   利用 MyEclipse 向到新建 Servlet,MyEclipse 会自动完成 <servlet>、<servlet-mapping> 等配置

               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">
  <servlet>
   
    <!--下面两行可以省略 -->
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>

    <servlet-name>FirstServlet</servlet-name> <!-- Servlet的注册名,必须配置的属性,可自己定义,默认使用该Servletde的名字 [3]-->
    <servlet-class>servlet.FirstServlet</servlet-class> <!-- Servlet类的全路径(包名+类名),必须配置的属性 [4]-->
  </servlet>

  <servlet-mapping> <!-- 对一个已经注册的 Servlet的映射 -->
    <servlet-name>FirstServlet</servlet-name> <!-- Servlet的注册名 [2]-->
    <url-pattern>/servlet/FirstServlet</url-pattern> <!--指明访问该 Servlet的访问路径 [1]-->
  </servlet-mapping>

</web-app>

<!-- 服务器调用流程:http://localhost:8080/ABC --[1]--[2]--[3]--[4]  -->


        4)部署 Web 程序

              a)手工部署:  在 Tomcat 目录 的 webapps下面新建文件夹,命名为 firstWeb,然后找到刚才 MyEclipse 的工作目录,将该目录下的

servlet工程下的 WebRoot 下的所有内容复制到 刚才在 Tomcat目录下建好的 webapps\firstWeb 下,启动 Tomcat,浏览器输入:

http://localhost:8080/firstWeb/servlet/FirstServlet,即可访问上面新建的 Servlet了



        b)MyEclipse 自动部署

          

              MyEclipse菜单中选择 Window |Preferences ,找到 Tomcat6.x,进行配置如下:

            配置完毕后,下面进行部署 servlet:

     部署后效果如下:

     (在需要时,可以点击 Redeploy  来 reload 应用,

     也可以登录Tomcat 管理 应用 http://localhost:8080/,在相应的应用后点击 reload)

     下面 在 MyEclipse 下 启动 Tomcat


   此时,部署完成,在浏览器输入地址即可访问 建立的 Servlet了(也可以在 MyEclipse内集成的浏览器打开)


          5)测试

               分别以 GET 和 POST 方式访问,查看不同之处

              (下面是手动部署的地址,MyEclipse部署的地址应该是:http://localhost:8080/servlet/servlet/FirstServlet):

  

        6)get 提交 和 post 的提交的区别

             (1)post提交数据是隐式的,get是通过在url里面传递的(可以看一下你浏览器的地址栏),用来传递一些不需要保密的数据。post比get安全

             (2)从速度看 get > post

             (3)用get时,传输数据的大小有限制 (注意不是参数的个数有限制),一般不要大于2K;而post理论上无限制,实际开发中,建议不要大于64K。

             (4)还有用GET的时候在SERVLET中要用DOGET方法,用POST就要用DOPOST方法。这是JSP在处理GET和POST的时候在JAVA 角度看的不同。

             (5)还有一点需要注意哦,通过get方式来获取参数用的方法和通过post方式有些区别:

                     post:request.getParameter("");

                     get: request.QueryString("");


        7)容易出错的地方

            注意默认情况下,建立 Servlet 文件时,Servlet 的 URL 前会自动添加一个 /servlet 目录(跟工程名无关),(所以 web.xml 下的路径也是:

            /sevlet/FirstServlet,这样的话,在运行时,浏览器输入的路径应该是:localhost:8080/工程名/url ,即http://localhost:8080/servlet/servlet/FirstServlet

            而不是:http://localhost:8080/servlet/FirstServlet(注意,凑巧这里的工程名也是servlet),否则会报404错误 :

                                                                                           The requested resource (Servlet action is not available) is not available.

            若想使用后者,可以在建立servlet文件时将 URL前面的默认的 /servlet 删除即可。




           7)实例:response 生成图片验证码

           服务器对客户端浏览器做出的响应被封装成一个 HttpServletResponse 对象。

           要对浏览器进行操作,只需要操作 HttpServletResponse 对象就可以了。通过HttpServletResponse.getWriter()

获得一个 PrintWrite() 对象,该对象为 OutputStream 的子类。然后使用该对象输出信息就可以了。

          通过 HttpServletResponse 获取的 PrintWrite 对象只能写字符型的数据,如果需要在客户端写二进制数据,

可以使用HttpServletResponse.getOutputStream()。方法 getWrite() 可以看做是方法getOutputStream() 的一个封装。

           IdentityServlet,java文件:

package servlet;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class IdentityServlet extends HttpServlet {

	private static final long serialVersionUID = -479885884254942306L;
        //随机字符字典,不包含 O、0、1、I 等难辨认的字符
	public static final char[] CHARS = { '2', '3', '4', '5', '6', '7', '8',
			'9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
			'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };

	public static Random random = new Random();  //随机数

	public static String getRandomString() {   //获取6位随机数
		StringBuffer buffer = new StringBuffer(); //字符串缓存
		for (int i = 0; i < 6; i++) {                   //循环6次
			buffer.append(CHARS[random.nextInt(CHARS.length)]); //每次取一个随机字符
		}
		return buffer.toString();
	}

	public static Color getRandomColor() {      //获取随机的颜色
		return new Color(random.nextInt(255), random.nextInt(255), random
				.nextInt(255));
	}

	public static Color getReverseColor(Color c) { //返回某颜色的反色
		return new Color(255 - c.getRed(), 255 - c.getGreen(), 255 - c
				.getBlue());
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException { //GET方法

		response.setContentType("image/jpeg"); //设置输出类型

		String randomString = getRandomString(); //随机字符串
		request.getSession(true).setAttribute("randomString", randomString); //放到 session 中

		int width = 100;  //图片宽度
		int height = 30;  //图片高度

		Color color = getRandomColor(); //随机颜色,用于背景色
		Color reverse = getReverseColor(color); //反色,用于前景色

		BufferedImage bi = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_RGB); //创建一个彩色图片
		Graphics2D g = bi.createGraphics(); //获取绘图对象
		g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 16));//设置字体
		g.setColor(color);           //设置颜色
		g.fillRect(0, 0, width, height); //绘制背景
		g.setColor(reverse);//设置颜色
		g.drawString(randomString, 18, 20); //绘制随机字符
		for (int i = 0, n = random.nextInt(100); i < n; i++) { //画最多100个噪音点
			g.drawRect(random.nextInt(width), random.nextInt(height), 1, 1); //随机噪音点
		}

		
		ServletOutputStream out = response.getOutputStream(); // 转成JPEG格式	
                JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); //编码器
		encoder.encode(bi);   //对图片进行编码
		out.flush();  //输出到客户端
	}

	public static void main(String[] args) {
		System.out.println(getRandomString());
	}
}

    上面程序中,

在Eclipse中处理图片,需要引入两个包:
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

若有报错

Access restriction:The type JPEGCodec is not accessible due to restriction on required library 

Access restriction: The type JPEGImageEncoder is not accessible due to restriction on required library

解决方法:Project -> Properties,先remove掉JRE System Library,然后再Add Library重新加入。


           运行结果:

      为了方便演示,在 WebRoot 下建立一个 identity.html 文件引用这个图片验证码:

<!DOCTYPE html>
<html>
  <head>
    <title>identity.html</title>
	
    <meta name="keywords" content="keyword1,keyword2,keyword3">
    <meta name="description" content="this is my page">
    <meta name="content-type" content="text/html; charset=GB2312">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    <script>
	function reloadImage() {
		document.getElementById('btn').disabled = true;
		document.getElementById('identity').src='servlet/IdentityServlet?ts=' + new Date().getTime();
	}
	</script>

		<img src="servlet/IdentityServlet" id="identity" onload="btn.disabled = false; " />
		<input type=button value=" 换个图片 " onclick="reloadImage()" id="btn">
  </body>
</html>

    运行如下:



三、Servlet生命周期

      

              1.      当serlvet 第一次被调用的时候,会触发init函数,该函数会servlet实例装载到内存.init函数只会被调用一次

              2.      然后去调用servlet  的 service函数

              3.      当第二次后访问该servlet 就直接调用 service 函数.

              4.      当 web应用 reload 或者关闭 tomcat 或者关机 都会去调用destroy函数,该函数就会去销毁serlvet

           Servlet的生命周期

                         当客户端第一次向web服务器发出一个servlet请求时,web服务器将会创建一个该servlet的实例,

并且调用servlet的init()方法;如果当服务器已经存在了一个servlet实例,那么,将直接使用此实例;然后再调用service()方法,

service()方法将根据客户端的请求方式来决定调用对应的doXXX()方法;当 web应用reload 或者关闭tomcat 或者关机

web服务器将调用destroy()方法,将该servlet从服务器内存中删除。

           生命全过程:

              1.加载

              2.实例化

              3.初始化

              4.处理请求

              5.退出服务

简述servlet的生命周期(工作流程)?

标准版本:

①WEB服务器首先会检查是否已经装载并创建了该servlet实例对象。如果是直接进行第④步,否则执行第②步。

②装载并创建该Servlet的一个实例对象。

③调用Servlet实例对象的init()方法。

④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用service()方法并将请求和响应作为参数传递进去。

⑤WEB应用被停止或重启之前,Servlet引擎将卸载Servlet,在卸载之前调用Servlet的destroy()方法


四、开发 Servlet 的方式

      开发 Servlet 有三种方法:(1)实现 Servlet 接口

                                                 (2)通过继承 GenericServlet

                                                 (3)通过继承 HttpServlet

        1)实现 Servlet 接口的方式

             新建  Web Object,命名为 ooo ,新建 Servlet,命名为,MyServlet,url 路径为  /MyServlet

             MyServlet.java 代码

package ooo;

import java.io.IOException;  
import java.io.PrintWriter;  
  
import javax.servlet.Servlet;  
import javax.servlet.ServletConfig;  
import javax.servlet.ServletException;  
import javax.servlet.ServletRequest;  
import javax.servlet.ServletResponse;  

public class MyServlet implements Servlet
{
    //该函数用于初始化servlet,就是把该servlet装载到内存中
    //该函数只会被调用一次
    public void init(ServletConfig config)
          throws ServletException{
        System.out.println("init it"); 
        
    }

    //得到ServletConfig对象
    public ServletConfig getServletConfig(){
        return null;
    }
    
    //该函数是服务函数,我们的业务逻辑代码就是写在这里
    //该函数每次都会被调用
    public void service(ServletRequest req,
                    ServletResponse res)
             throws ServletException,
                    java.io.IOException{
        System.out.println("service it"); 
        PrintWriter printWriter=res.getWriter();  
        printWriter.println("<h1>"+"hello,world"+"</h1>");      
    }
    //该函数时得到servlet配置信息
    public java.lang.String getServletInfo(){
        return null;
    }
    //销毁该servlet,从内存中清除,该函数被调用一次
    public void destroy(){
        System.out.println("destroy it"); 
    }
} 

部署完成后,在浏览器中输入:http://localhost:8080/ooo/MyServlet


 刷新一下,最后用 Tomcat Manager 停止 ooo 应用,对应的 Tomcat 服务器的显示如下:




  

        2)使用 GenericServlet 开发 servlet(了解即可)

              通过 GenericServlet 去开发 servlet,只需要重写 service 方法,相对来讲简单一些。

              在 ooo 工程中,建立 Servlet 命名为:MyGenericServlet

              MyGenericServlet.java 代码

package ooo;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class MyGenericServlet extends GenericServlet
{
	public  void service(ServletRequest req,
                             ServletResponse res)
                      throws ServletException,
                             java.io.IOException{
		res.getWriter().println("hello,world,i am geneirc servlet");
	}
}


          部署,浏览器运行:



         3)使用继承 HttpServlet 的方法开发 Servlet

               这个是目前最常用的方式。

               在 ooo 工程中,建立 Servlet 命名为:MyHttpServlet

              MyHttpServlet.java 代码如下:

package ooo;

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 MyHttpServlet extends HttpServlet
{
	//在HttpServlet 中,设计者对post 提交和 get提交分别处理
	//回忆 <form action="提交给?" method="post|get"/>,默认是get
	//其实 doGet()/ doPost() 最终也去调用 service 方法

	protected void doGet(HttpServletRequest req,
                     HttpServletResponse resp)
              throws ServletException,
                     java.io.IOException{
		resp.getWriter().println("i am httpServet doGet()");
		
	}
	protected void doPost(HttpServletRequest req,
                      HttpServletResponse resp)
               throws ServletException,
                      java.io.IOException{ 
		resp.getWriter().println("i am httpServet doPost() post name="+req.getParameter("username"));
	}
}

          运行结果:



五、Servlet的细节问题

      (1)一个已经注册的Servlet可以被多次映射即:

 <servlet>
   
    <!--下面两行可以省略 -->
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>

    <servlet-name>MyServlet</servlet-name> <!-- Servlet的注册名,必须配置的属性,可自己定义,默认使用该Servletde的名字 -->
    <servlet-class>ooo.MyServlet</servlet-class> <!-- Servlet类的全路径(包名+类名),必须配置的属性 -->
  </servlet>

<servlet-mapping> <!--映射1-->
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/MyServlet1</url-pattern>
  </servlet-mapping>
  <servlet-mapping> <!--映射2-->
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/MyServlet2</url-pattern>
  </servlet-mapping> 


测试:使用http://localhost:8080/ooo/MyServlet1 与 http://localhost:8080/ooo/MyServlet2  效果一样



     (2)当映射一个 servlet 时候,可以多层,可以随意后缀(因此:后缀名是可能是假象),如:再添加一个映射


   <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/My/abc.html</url-pattern> </servlet-mapping>

        

   使用  http://localhost:8080/ooo/My/abc.html 测试,效果一样



    

      (3)使用通配符在 servlet 映射到 URL 中

 

              有两种格式:

                第一种格式:   *.扩展名  比如 *.do  *.ss

                第二种格式:    以 / 开头 同时以 /* 结尾    比如     /*      /news/*

                通配符练习题:

                        Servlet1映射到 /abc/*

                        Servlet2映射到 /*

                        Servlet3映射到 /abc

                        Servlet4映射到 *.do

            问题(面试题):

            当请求URL为“/abc/a.html”:  “/abc/*”和“/*”都匹配,哪个servlet响应Servlet引擎将调用Servlet1。

            当请求URL为“/abc”时:“/abc/*”和“/abc”都匹配,哪个servlet响应Servlet引擎将调用Servlet3。

            当请求URL为“/abc/a.do”时:“/abc/*”和“*.do”都匹配,哪个servlet响应 Servlet引擎将调用Servlet1

            当请求URL为“/a.do”时:“/*”和“*.do”都匹配,哪个servlet响应Servlet引擎将调用Servlet2。

            当请求URL为“/xxx/yyy/a.do”时:“/*”和“*.do”都匹配,哪个servlet响应?Servlet引擎将调用Servlet2。

         

             在匹配的时候,要参考的标准:

             1、看谁的匹配度高,谁就被选择

             2 、 *.do 的优先级最低

     (4)Servlet 单例问题

              当 Servlet 被第一次访问后,就被加载到内存,以后该实例对各个请求服务。即在使用中是单例。

              因为 Servlet 是单例,因此会出现线程安全问题,比如,售票系统,如果不加同步机制,则会出现问题。

              解决原则:1)如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制

                                      synchronized(对象) { //同步代码  }

                                2) 如果一个变量不需要共享,则直接在 doGet() 或者 doPost()定义.这样不会存在线程安全问题


       (5)servlet 中的 <load-on-stratup> 配置

                需求: 当我们的网站启动的时候,可能会要求初始化一些数据,(比如创建临时表), 在比如:

                我们的网站有一些要求定时完成的任务[ 定时写日志,定时备份数据.. 定时发送邮件..]

                 解决方法: 可以通过<load-on-startup> 配合 线程知识搞定.

              

               

                 先说明<load-on-startup>: 通过配置<load-on-startup> 我们可以指定某个Servlet 自动创建.

                 下面模拟一个定时发送电子邮件的功能:

                  实现思路:

                  sendEmailTable(表)

                  id                  content                 sendtime

                  1                   “hello”                  2011-11-1120:11

                  2                   “hello2”                2012-11-1110:00


                 看看如何线程去完成任务:新建 SendMailTread.java 类


package ooo;

public class SendEmailThread extends Thread{
	@Override
	public void run() {
		int i=0;
		try {
			while(true){
				//每休眠一分钟(这里为了方便演示,写的是10秒),就去扫表sendmail, 看看那份信件应当被发出
				Thread.sleep(10*1000);
				System.out.println("发出 第"+(++i)+"邮件");//javamail
			}
		} catch (Exception e) {
			e.printStackTrace();
			// TODO: handle exception
		}
	}
}

                新建 Servlet 命名:MyInitServlet


package ooo; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; public class MyInitServlet extends HttpServlet { public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } /** * Initialization of the servlet. <br> * * @throws ServletException if an error occurs */ public void init() throws ServletException { // Put your code here System.out.println("MyInitServlet1 的init被调用.."); //完成一些初始化任务 System.out.println("创建数据库,表,读取参数"); //创建一个线程 SendEmailThread sendEmailThread=new SendEmailThread(); sendEmailThread.start(); } }


                配置 web.xml

               1)删除下面的映射


  <servlet-mapping>
    <servlet-name>MyInitServlet</servlet-name>
    <url-pattern>/MyInitServlet</url-pattern>
  </servlet-mapping>


              2)在 servlet 中添加<load-on-startup>:


<servlet> <servlet-name>MyInitServlet</servlet-name> <servlet-class>ooo.MyInitServlet</servlet-class> <!-- 1表示该servlet被 init的顺序 --> <load-on-startup>1</load-on-startup> </servlet>


             配置之后,就无法直接从浏览器访问,通过后台运行:每隔10秒模拟发送一次邮件:



六、ServletConfig 对象

      该对象只要用于 读取 servlet 的配置信息

      实例:新建 Servlet 命名:ServletConfigTest

     web.xml 中添加 以下配置信息:


  <servlet>

    <servlet-name>ServletConfigTest</servlet-name>
    <servlet-class>ooo.ServletConfigTest</servlet-class>
    
    <init-param> <!-- 这里可以给servlet配置信息,这里配置的信息,只能被该servlet 读取 -->
    <param-name>enconding</param-name>
    <param-value>gb2312</param-value>
    </init-param>
    
    <!--  可以配置很多信息 -->
    <init-param> 
    <param-name>version</param-name>
    <param-value>1.0</param-value>
    </init-param>
    <init-param> 
    <param-name>author</param-name>
    <param-value>wtfmonking</param-value>
    </init-param>
    
  </servlet>
  
  <!-- 如果这里配置参数,可被所有servlet读取 -->
 <!--  
 <context-param>
 <param-name></param-name>
 <param-value></param-value>
 </context-param>
-->

     ServletConfigTest.java 代码


package ooo; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletConfigTest extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); //这里可以通过读取 ServletConfig 里的数据 进行设置 Enconding response.setCharacterEncoding(this.getServletConfig().getInitParameter("enconding")); PrintWriter out = response.getWriter(); out.println("Enconding :"+this.getServletConfig().getInitParameter("enconding")+"......"); //如果要把所有的参数都读取,则使用 如下方法 : Enumeration<String> names=this.getServletConfig().getInitParameterNames(); while(names.hasMoreElements()) { String name=names.nextElement(); out.println(name+" is :"); out.println(this.getServletConfig().getInitParameter(name)+"......"); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }


      浏览器输出结果:


七、http 协议 (后续再讲)


八、HttpServletResponse的再说明 

   

       getWriter() 与 getOutputStream()  的区别

             1)getWriter() 用于向客户机回送字符数据

             2)getOutputStream() 返回的对象,可以回送字符数据,也可以回送字节数据(二进制数据)

                        

OutputStream os=response.getOutputStream();os.write("hello,world".getBytes());


             如何选择:

             如果我们是回送字符数据,则使用  PrintWriter对象 ,效率高

             如果我们是回送字节数据(binarydate) ,则只能使用 OutputStream

             注意:

             这两个流不能同时使用,如下,则会报错



OutputStream os=response.getOutputStream();
os.write("hello,world".getBytes());
PrintWriter out=response.getWriter();
out.println("abc");


   

        原因分析:


           

           从图中可以看出,web 服务器会自动关闭流(当然,最好是在程序中主动关闭流)


九、参数的传递方式sendRedirect()和session()


        需求:当用户登录成功后,把该用户名字显示在登录成功页面;

        解决思路:

                    a、使用java基础 static

                    b、使用sendRedirect()

                    c、使用session 传递

       1、使用sendRedirect()来传递字符参数


             基本格式: response.sendRedirect(“servlet的地址?参数名=参数值&参数名=参数值...”);

             参照值是String , 参数名应当使用 字母组合

             接收数据:String 参数=request.getParameter(“参数名”);

             实例:


response.sendRedirect("/UsersManager/MainFrame?uname="+username+"&pwd="+password);

//另一个 servlet中:

String username=request.getParameter("uname");
String upwd=request.getParameter("pwd");
out.println(username+" pwd="+upwd);


        2、使用session()来传递字符参数和对象

             1)传递字符串


request.getSession().setAttribute("loginuser",username); //放入session

//另一个 Servlet中:

String username2=(String) request.getSession().getAttribute("loginuser");//取出session


             2)传递对象

               建立一个 User 对象,包含用户名和密码

            User user= new User();

            user.setName("wtf");

            user.setPassWord("123");

request.getSession().setAttribute("userobj",user); //放入session   

//另一个 Servlet中:

User user=(User)request.getSession().getAttribute("userObj");//取出session



十、中文乱码处理

      (1)表单 form

                a)post 方式提交

                      在服务器端设置成浏览器端的编码方式。

                      解决方法:  request.setCharacterEncoding("utf-8"); //gbk gb2312

                b)get 方式提交

                      解决方法:

String username=new String(request.getParameter("username").getBytes("iso-8859-1"),"utf-8");// 把iso-8859-1 转换成 utf-8

                     或直接写一个工具类

package com.wtf;
public class MyTools {
	public static String getNewString(String str) {
		String newString="";
		try {
			newString=new String(str.getBytes("iso-8859-1"),"utf-8");
		} catch (Exception e) {
			e.printStackTrace();
			// 把iso-8859-1 转换成 utf-8
		} 
		return newString;
	}
}



(2) 超链接

                    <a href=”http://www.baidu.com?name=汉字”>测试</a>

                    解决:该方法和get处理方法一样.因为超链接是使用 get 提交

          (3)sendRedirect() 发生乱码

                    response.sendRedirect(“servlet地址?username=汉字”);

                    解决:该方法和get处理方法一样.


           说明: 我们应当尽量使用post 方式提交;

   

           (4)返回浏览器显示乱码

           在服务端是中文,在response的时候,也要考虑浏览器显示是否正确,一般我们通过

           response.setContentType(“text/html;charset=utf-8”); 解决

          (5)下载提示框中文乱码

                     当我们下载文件的时候,可能提示框是中文乱码

                     解决方法:Stringtemp=java.net.URLEncoder.encode("传奇.mp3","utf-8");

                  

                    response.setHeader("Content-Disposition","attachment;filename="+temp);



十一、HttpServletRequest对象的详解

        

            该对象表示浏览器的请求(http请求), 当web 服务器得到该请求后,会把请求信息封装成一个HttpServletRequest 对象

           (1) getRequestURL方法返回客户端发出请求时的完整URL。

           (2) getRequestURI方法返回请求行中的资源名部分。

           (3) getQueryString 方法返回请求行中的参数部分(参数名+值)。

                     准确的说就是接收以 get 方式提交的 参数=参数值

                     该函数可以获取请求部分的数据比如:

                                http://localhost/web名?username=abc&pwd=123

                                request.getQueryString();就会得到 username=abc&pwd=123

                     (可以使用split将参数按&分隔)

          (4)getRemoteAddr方法返回发出请求的客户机的IP地址

          (5)getRemoteHost方法返回发出请求的客户机的完整主机名

          (5)getRemotePort方法返回客户机所使用的网络端口号,客户机的端口号是随机选择的,web服务器的端口号是一定的

          (6)getLocalPort方法返回web服务器所使用的网络端口号

          (7)getLocalAddr方法返回WEB服务器的IP地址。

          (8)getLocalName方法返回WEB服务器的主机名

          (9)url 和 uri 的区别

                     Url=http://localhost:8088/ooo/MyServlet  完整的请求

                     Uri=/ooo/GetinfoServlet      web应用的名称+资源的名称


十二、表单实例:如何获取用户提交的内容(通过表单提交的内容)


           表单 Servlet:FormServlet.java  


package ooo;

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 FormServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		out.println("<form action='/ooo/ClServlet' method='post'><br/>");
		out.println("<input type='hidden' value='这里是隐藏的内容' name='hidden1'/>");
		out.println("用户名:<input type='text' name='username'/><br/>");
		out.println("密 码:<input type='password' name='pwd'/><br/>");
		out.println("性 别:<input type='radio' name='sex' value='男'/>男 <input type='radio' name='sex' value='女'/>女<br/>");
		out.println("你的爱好:<input type='checkbox' name='hobby' value='音乐'>音乐 <input type='checkbox' name='hobby' value='体育'>体育 <input type='checkbox' name='hobby' value=\"旅游\">旅游<br/>");
		out.println("所在城市:<select name='city'><option value='bj'>北京</option><option value='cq'>重庆</option></select><br/>");
		out.println("你的介绍:<textarea cols='20' rows='10' name='intro' >请输入介绍..</textarea><br/>");
		out.println("提交照片:<input type='file' name='photo'><br/>");
		//什么时候使用hidden传输数据 1.不希望用户看到该数据 2. 不希望影响节目,同时使用该数据
		
		out.println("<input type='submit' value='提交信息'/>");
		out.println("</form>");

	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		this.doGet(request, response);
	}

}


处理表单的 Servlet:ClServlet.java


package ooo;

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 ClServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		String u=request.getParameter("username");
		String p=request.getParameter("pwd");
		String sex=request.getParameter("sex");
		//如果接受复选框的内容,则使用getparameterValues
		String [] hobbies=request.getParameterValues("hobby");
		String city=request.getParameter("city");
		String intro=request.getParameter("intro");
		String hidden1=request.getParameter("hidden1");
		out.println("用户名="+u+"<br/>");
		out.println("密 码="+p+"<br/>");
		out.println("性  别="+sex+"<br/>");
		if(hobbies!=null){
			for(int i=0;i<hobbies.length;i++){
				out.println("爱好:"+hobbies[i]);
			}
		}else{
			out.println("你没有爱好");
		}
		out.println("<br/>所在城市:"+city);
		out.println("<br/>个人介绍:"+intro);
		out.println("<br/>隐藏控件数据:"+hidden1);
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doGet(request, response);
	}
}  

   


           效果:




猜你喜欢

转载自blog.csdn.net/u012561696/article/details/22154207
今日推荐