韩顺平2011细说Servlet笔记1

 

韩顺平2011细说Servlet笔记1

  1278人阅读  评论(0)  收藏  举报
servlet tomcat 浏览器 web服务 string web

u       背景知识介绍

J2EE的13种技术

 

java->servlet->jsp [技术总是有一个演变过程]

zip粘贴到word设置

u       回顾一下我们现有的技术

 

java 基础(面向对象,集合,界面,线程,文件,网络)

jdbc (java 的数据库编程)

oracle / mysql / sqlserver

html css javascript (web  开发)  ->网页设计

xml

 

serlvet+jsp ->java web开发[使用java技术做 web开发]

 

u       java ee 体系的介绍

u       servlet项目演示

u       web 开发介绍

①    静态页面 (html)

②    动态页面

1.      用户可以输入数据,和页面交互(注册,购物,发帖子,付款...)

2.      不同时间打开页面,内容是变化.

3.      目前比较流行的左动态页面的技术 ( servlet/jsp , php , asp.net , asp, cgi )

 

u       动态网页技术的比较(了解)

 

u       bs 和 cs的比较

(1)BS:browser server 浏览器服务器

(2)cs client server 客户服务

u       为什么需要的web服务器/web究竟是干什么的?

 

模拟一个web服务器 MyWebServer.java

 

import java.io.*;

import java.net.*;

public class MyWebServer

{

       publicstatic void main(String []args) throws Exception{

             

              ServerSocketss=new ServerSocket(80);

      

                     Sockets=ss.accept();

                     //提示一句话

                     System.out.println("在 9999 上等待连接...");

                     OutputStreamos=s.getOutputStream();

                     BufferedReaderbr=new BufferedReader(new FileReader("d:\\hello.html"));

                     Stringbuf="";

                     while((buf=br.readLine())!=null){

                            os.write(buf.getBytes());

                     }

             

              //关闭流

              br.close();

              os.close();

              s.close();

             

 

       }

}

u       通过tomcat来讲解BS结构

u       安装tomcat服务器

(1)   解压即可

 

(2)   配置

①在环境变量中添加

JAVA_HOME= 指向你的jdk的主目录(并不是bin文件目录

②    在不配置JAVAHOME的前提下启动tomcat

startup.bat的第25行中添加set JAVA_HOME=JKD路劲 

 

 

(3)   启动tomcat服务器

到 tomcat 主目录下 bin/startup.bat

 

(4)   验证是否安装成功

http://localhost:8080(8080是默认端口如果该端口已经被占用需要修改端口)

 

u       tomcat安装后问题解决

(1)tomcat无法正常启动的原因分析

1.      JAVA_HOME 配置错误,或者没有配置

2.      如果你的机器已经占有了8080 端口,则无法启动,

解决方法

(1) 你可以8080 先关闭

netstat –an

netstat –anb 来查看谁占用该8080

(2) 主动改变tomcat的端口.

到conf/server.xml 文件中修改

port="8088"(去修给config->server.xml的端口号)protocol="org.apache.coyote.http11.Http11NioProtocol"redirectPort="8443"/>

(3) 能够正常启动,但是会导航到另外一个页面.

去修改工具->管理加载项,把默认的导航给禁用即可.

(4) 在访问 tomcat时候,一定保证 tomcat 服务器是启动

 

 

u      tomcat的目录结构文件

bin: 启动和关闭tomcat的bat文件

conf: 配置文件

-->server.xml : 该文件用于配置和 server 相关的信息, 比如 tomcat启动端口后,配置Host,  配置Context 即web应用

-->web.xml : 该文件配置与 web应用(web应用就相当于是一个 web站点)

-->tomcat-users.xml: 该文件用户配置tomcat 的用户密码 和 权限

lib 目录: 该目录放置运行tomcat 运行需要的jar包

logs 目录:存放日志, 当我们需要去查看日志的时候,很有用!,当我们启动tomcat错误时候,可以查询信息.

webapps 目录: 该目录下,放置我们的web应用(web 站点), 比如:

建立 web1 目录  下面放置我们的html 文件 jsp 文件..图片... 则 web1就被当做一个web应用管理起来(☞ 特别说明tomcat 6.0以后支持 tomcat 5 版本 还有别的设置)

 work: 工作目录: 该目录用于存放jsp被访问后 生成的对应的 server文件 和.class文件

u       如何去访问一个 web 应用的某个文件

 

 

 

u      首页面设置及目录规范结构

现在我们要求:hello.html文件设置成 web应用的首页,则需要把web应用的目录格式做的更加规范:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


①在web文件夹下配置WEB-INF文件夹

②在 web.xml 文件中添加配置的代码:

 

  

    hello1.html

  

       ③通过http://localhost:8088/web1来访问hello1.html

web-inf目录下的 classes目录将来是存放  class文件

lib 目录将来时存放 jar文件

web.xml 配置当前这个web应用的信息.

 

u       tomcat如何去管理虚拟目录

需求: 当我们把 web 应用放到 webapps目录,tomcat会自动管理,如果我们希望tomcat可以管理其它目录下的web应用?->虚拟目录配置

 

我在d 盘有一个web应用.

u       虚拟目录配置步骤:

①    找到server.xml文件

②    编辑host节点 添加Context path

在server.xml中添加:<Contextpath="/myweb2"docBase="d:\web2"/>

myweb2:是访问时输入的web名,实际取出的是web2中的资源

"d:\web2"绝对路径下web2中存放资源如:hello2.html

实际访问时输入的地址:http://localhost:8088/myweb2/hello2.html

绝对路径:从根分区找某个文件

相对路径:从该文件位置去找另一个文件

③ 需要重启tomcat,才能生效.(因为是采用的dom技术讲信息加载到内存中)

 

u      context  的几个属性的说明

path:

docbase:

reloadable  ;如果设为ture ,表示 tomcat 会自动更新 web应用,这个开销大,建议在开发过程中,可以设为true, 但是一旦真的发布了,则应当设为false;

upackWAR: 如果设为 ture ,则自动解压,否则不自动解压.

                     ①:打war包 cd:d/web2 然后jar –cvf web2.war *

                     ②:

                     浏览打好的war包 Deploy发布后会在webapps中自动生存改文件

u      配置域名

我们看和一个如何配置自己的主机名:

我们在实际访问网站的过程中,不可能使用http://localhost:8080/web应用/资源名  的方式去访问网站,实际上使用类似

       http://www.sina.com.cn 或者

       http://news.sina.com.cn 的方式去访问网站,这个又是怎么实现的呢?

 

看看ie浏览器访问一个web站点的流程.

 

 

实现的步骤如下:

(1)C:\WINDOWS\system32\drivers\etc 下的host文件添加127.0.0.1 www.sina.com.cn

(2) 在tomcat的server.xml文件添加主机名

              

(3) 在d:\web3 加入了一个 /WEB-INF/web.xml 把 hello2.html设为首页面

如果连端口都不希望带,则可以吧tomcat的启动端口设为80即可.

(4) 重启生效

u       tomcat体系的再说明

图:

如何配置默认主机:

在tomcat/conf/server.xml文件

defaultHost="主机名">

 

 

 

 

u       为什么需要servlet技术?

比如需求:我们希望用户可以贴,用户还可以回复 ....这样一些和用户可以交互的功能,用普通的java技术就完成不了,  sun 就开发了 servlet技术供程序员使用.

u       servlet的介绍

①    servlet 其实就是java程序(java类)

②    该 java 程序(java 类)要遵循servlet开发规范

③    serlvet是运行在服务端

④    serlvet 功能强大,几乎可以完成网站的所有功能

⑤    是学习jsp基础

 

u       tomcat 和 servlet 在网络中的位置

u       servlet的生命周期是怎样的/servlet究竟是怎样工作的

UML 时序图帮助大家理解

参看execel

 

 

面试题: 请简述servlet的生命周期(工作流程)

答:

标准版本:

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

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

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

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

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

 

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

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

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

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

5.      Servlet的生命周期

当客户端第一次向web服务器发出一个servlet请求时,web服务器将会创建一个该servlet的实例,并且调用servlet的init()方法;如果当服务器已经存在了一个servlet实例,那么,将直接使用此实例;然后再调用service()方法,service()方法将根据客户端的请求方式来决定调用对应的doXXX()方法;当 web应用reload 或者 关闭tomcat 或者关机,web服务器将调用destroy()方法,将该servlet从服务器内存中删除。

生命全过程:

1.加载

2.实例化

 3.初始化

 4.处理请求

 5.退出服务

 

u       开发servlet有三种方法

(1)   实现 Servlet接口

(2)   通过继承 GenericServlet

(3)   通过继承 HttpServlet

u       ①实现servlet接口的方式

需求如下: 请使用实现接口的方式,来开发一个Servlet ,要求该Servlet 可以显示Hello,world,同时显示当前时间.

步骤

1.      在webapps下建立一个web应用 hspWeb1

2.      在hspWeb1 下建立 WEB-INF->web.xml[web.xml可以从ROOT/WEB-INF/web.xml拷贝]

3.      在WEB-INF 下建立 classes目录(我们的Servlet 就要在该目录开发.),建立  lib文件夹

4.      开发MyServlet.java

 

 

package com.hsp;

 

import javax.servlet.*;

import javax.servlet.http.*; 为了能将servlet-api.jar包引入,需要配置环境变量

变量值; E:\tomcat\apache-tomcat-6.0.20\lib\servlet-api.jar 记得带上文件名

 

import java.io.*;

 

class MyFirstServlet implements Servlet

{

       //该函数用于初始化servlet,就是把该servlet装载到内存中

       //该函数只会被调用一次

       publicvoid init(ServletConfig config)

         throws ServletException{

       }

 

       //得到ServletConfig对象

       publicServletConfig getServletConfig(){

              returnnull;

       }

      

       //该函数是服务函数,我们的业务逻辑代码就是写在这里

       //该函数每次都会被调用

       publicvoid service(ServletRequest req,

                    ServletResponse res)

            throws ServletException,

                    java.io.IOException{

       }

       //该函数时得到servlet配置信息

       publicjava.lang.String getServletInfo(){

              returnnull;

       }

       //销毁该servlet,从内存中清除,该函数被调用一次

       publicvoid destroy(){

       }

}

 

5.      根据Servlet规范,我们还需要部署Servlet

 

 

  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"

  version="2.5">

 

       

        

              

      <servlet-name>MyFirstServlet

        

      <servlet-class>com.hsp.MyFirstServlet注意:后面不要带.java

    

             

        <servlet-mapping>

              

        <servlet-name>MyFirstServlet

              

        <url-pattern>/ABC

   

 

服务器调用流程:http://localhost:8088/ABC--->--->--->--->

6.      在浏览器中测试

在浏览器中输入

http://localhost:8088/hspweb1/ABC

 

7.      分析一下自己写可能出现的错误

(1)   MyFirstServlet名字不一样 (启动tomcat错误)

(2)   com.hsp.MyFirstServlet  写成MyFirstServlet.java,会报告500

(3)   资源名自己写错

 

http://localhost:8088/hspweb1/错误的资源url-pattern

404 错误

 

 

补充: 如果使用javac 去编译一个java文件,则需要带命令参数

javac –d . java文件

补充: 如何不重启tomcat,就指定去 reload 一个web应用,方法:

进入到 tomcat 的 manager:

点击reload即可.

 

课堂练习

自己使用 实现Servlet接口的方法,开发一个Servlet,该servlet 可以输出自己的名字

在显示当前日期.

 

 

 

u       ②使用GenericServlet开发servlet

了解即可:

       案例 :

package com.hsp;

 

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,iam geneirc servlet");

       }

}

将该Servlet部署到web.xml文件中:

        

              

     MyGenericServlet

        

     com.hsp.MyGenericServlet

    

              

        

              

       MyGenericServlet

              

        /MyGenericServlet

 

 

u       ③使用继承 HttpServlet 的方法来开发Serlvet

(1)    在软件公司 90%都是通过该方法开发.

(2)    举例说明; 还是显示 hello,world 当前日期

 

代码:

 

packagecom.hsp;

 

importjavax.servlet.*;

importjavax.servlet.http.*;

importjava.io.*;

 

public class MyHttpServlet extends HttpServlet

{

       //HttpServlet 中,设计者对post 提交和 get提交分别处理

       //回忆 提交给?"method="post|get"/>,默认是get

 

       protectedvoid doGet(HttpServletRequest req,

                     HttpServletResponse resp)

              throws ServletException,

                     java.io.IOException{

              resp.getWriter().println("iam httpServet doGet()");

             

       }

       protectedvoid doPost(HttpServletRequest req,

                      HttpServletResponse resp)

               throws ServletException,

                      java.io.IOException{

              resp.getWriter().println("iam httpServet doPost() postname="+req.getParameter("username"));

       }

}

 

还有一个login.html

u:

 

u        小结 get 提交 和 post的提交的区别

①     从安全看 get

②     从提交内容看 get

③     从速度看 get>post

④     Get可以保留uri中的参数,利于收藏

 

u      使用ide来开发servlet

使用ide (eclipse[java se]+myeclipse[插件 可以支持jsp/servlet/struts/hibernate/spring..])开发servlet

需求:使用 ide 开发一个servlet ,该servlet显示 hello,world, 和当前日期

u      开发步骤:

(1)   建立web工程

(2)   在Src 目录下创建了一个包 com.hsp.servlet

(3)   开发一个Servlet

 

MySerlvet 的代码:

publicvoid doGet(HttpServletRequest request,HttpServletResponse response)

           throws ServletException, IOException {

 

       response.setContentType("text/html");

       PrintWriter out = response.getWriter();

       out.println("hello"+newjava.util.Date().toString() );

    }

 

    publicvoid doPost(HttpServletRequest request,HttpServletResponse response)

           throwsServletException, IOException {

 

       this.doGet(request,response);

    }

 

(4)   配置tomcat

点击add 选择要发布到那个服务器即可:

 

(5)   启动tomcat

1.       使用我们的老方法

2.       从eclipse 启动 tomcat

(6)   在使用eclipse 开发servlet 可能会出现一个很麻烦事情,版本不一致错误.

java.lang.UnsupportedClassVersionError: Bad version number in .class file (unableto load class com.hsp.servlet.MyServlet1)

原因是因为 tomcat 使用jdk  servlet 使用的 jdk不一样,

解决方法就是统一即可.

 

请大家使用eclipse 并配置继承 HttpServlet 开发一个servlet, 显示hello, 和当前日期.

 

 

u       Servlet的细节问题

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

  <servlet>

    <description>This is thedescription of my J2EE componentdescription>

    <display-name>This is thedisplay name of my J2EE componentdisplay-name>

   

    <servlet-name>MyServlet1servlet-name>

    

    <servlet-class>com.hsp.servlet.MyServlet1servlet-class>

  servlet>

  <servlet-mapping>

  

    <servlet-name>MyServlet1servlet-name>

  

    <url-pattern>/MyServlet1url-pattern>

  servlet-mapping>

 

  <servlet-mapping>

  <servlet-name>MyServlet1servlet-name>

  <url-pattern>/hspurl-pattern>

  servlet-mapping>

②    当映射一个servlet时候,可以多层 比如

/servlet/index.html ok

从这里还可以看出,后缀名是 html 不一定就是 html,可能是假象.

 

③    使用通配符在servlet映射到URL中

有两种格式:

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

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

通配符练习题:

l      Servlet1映射到 /abc/*

l      Servlet2映射到 /*

l      Servlet3映射到 /abc

l      Servlet4映射到 *.do

问题(面试题):

l      当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应

       Servlet引擎将调用Servlet1。

l      当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应

       Servlet引擎将调用Servlet3。

l      当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应

       Servlet引擎将调用Servlet1

l      当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应

       Servlet引擎将调用Servlet2。

l      当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应

       Servlet引擎将调用Servlet2。

 

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

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

(2)    *.do 的优先级最低

 

④    Servlet单例问题

 

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

因为 Servlet是单例,因此会出现线程安全问题: 比如:

售票系统. 如果不加同步机制,则会出现问题:

 

这里我给大家一个原则:

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

synchronized(对象){

       //同步代码

}

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

 

⑤    servlet中的 配置

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

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

解决方法: 可以通过 配合 线程知识搞定.

 

先说明: 通过配置 我们可以指定某个Servlet 自动创建.

 

我们来模拟一个定时发送电子邮件的功能:

实现思路:

 

sendEmailTable

id                   content                 sendtime

1                   “hello”                   2011-11-11 20:11

2                   “hello2”                 2012-11-1110:00

 

 

看看如何线程去完成任务:

这里的代码请参考项目:

SendMailThread.java

package com.hsp.model;

publicclass SendEmailThread extends Thread{

    @Override

    publicvoid run() {

       int i=0;

       try {

           while(true){

              //每休眠一分钟,就去扫表sendmail, 看看那份信件应当被发出

              Thread.sleep(10*1000);

              System.out.println("发出"+(++i)+"邮件");//javamail

           }

       catch (Exceptione) {

           e.printStackTrace();

           // TODO: handle exception

       }

    }

}

MyInitServlet1.java

publicvoid init() throwsServletException {

       // Put yourcode here

       System.out.println("MyInitServlet1 init被调用..");

       //完成一些初始化任务

       System.out.println("创建数据库,表,读取参数");

       //创建一个线程

       SendEmailThread sendEmailThread=new SendEmailThread();

       sendEmailThread.start();

    }

说明:

<load-on-startup>1load-on-startup>

 

 

u      ServletConfig对象

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

 

 

案例:

<servlet>

    <servlet-name>ServletConfigTestservlet-name>

    <servlet-class>com.hsp.servlet.ServletConfigTestservlet-class>

    

    <init-param>

    <param-name>encodingparam-name>

    <param-value>utf-8param-value>

    init-param>

  servlet>

如何使用

Stringencoding=this.getServletConfig().getInitParameter("encoding");

补充说明:这种配置参数的方式,只能被某个Servlet独立使用.如希望让所有的Servlet都去读取某个参数,这样配置:

 

 

 

u     如果要把所有的参数都读取,则使用 如下方法 :

Enumerationnames=this.getServletConfig().getInitParameterNames();

      

       while(names.hasMoreElements()){

           String name=names.nextElement();

           System.out.println(name);

           System.out.println(this.getServletConfig().getInitParameter(name));

       }

 

补充,如何去修改Servlet的配置模板.

 

u      编写项目

1.    先完成用户登录

2.    添加在主界面,添加一个超链接,可以返回登录界面重写登录

 

 

u      http协议的再介绍

①       http协议是建立在tcp/ip协议基础上

②       http协议全称 超文本传输协议

③       http协议1.0 , 1.1版本 ,目前通用的是1.1版本

http1.0 称为短连接

http1.1 称为长连接.

所谓长,和短指的是  持续时间的 长连接 1.1 30s ,短连接是发送完数据就断掉.

 

 

u      http的请求部分:

基本结构:

GET /test/hello.html HTTP/1.1 [请求行]

Accept: */*  [消息名]  消息名:内容

Referer: http://localhost:8080/test/abc.html 

Accept-Language: zh-cn

User-Agent: Mozilla/4.0

Accept-Encoding: gzip, deflate 

Host: http://www.sohu.com:80

Connection: Keep-Alive     [消息头格式 (消息名内容 )

特别说明: 并不是每一次请求的消息头都一样.]

空行

发送的内容 [格式 : 内容名字=内容体]

u       请求方式

请求行中的GET称之为请求方式,请求方式有:POST,GET,HEAD,OPTIONS,DELETE,TRACE,PUT

常用的有:POST,GET

u      get和post

参看ppt,和以前的笔记

 

GET News/abc.jsp

u      http请求消息头

1)       Accept: text/html,image/*  [告诉服务器,我可以接受文本,网页,图片]

2.      Accept-Charset: ISO-8859-1 [接受字符编码 iso-8859-1]

3.      Accept-Encoding: gzip,compress [可以接受 gzip,compress压缩后数据.]

4.      Accept-Language: en-us,zh-cn [浏览器支持中,英文]

5.      Host: www.sohu.com:80 [我要找主机是www.sohu.com:80]

6.      If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT [ 告诉服务器,我的缓冲中有这个资源文件,该文件的时间是。。。]

7.      Referer: http://www.sohu.com/index.jsp [告诉服务器,我来自哪里,该消息头,常用于防止盗链]

8.      User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)[告诉服务器,浏览器内核]

9.      Cookie [cookie??]

10.  Connection:close/Keep-Alive   [保持连接,发完数据后,我不关闭连接]

11.   Date: Tue, 11 Jul 2000 18:23:51 GMT [浏览器发送该http请求的时间]

 

关于Referer的实际案例:

//获取用户浏览器Referer

       String referer=request.getHeader("Referer");

       if(referer==null||!referer.startsWith("http://localhost:8088/servletPro")){

           response.sendRedirect("/servletPro/Error");

           return;

       }

红色的部分可以根据实际情况来修改.

 

u      http的响应

基本结构:

状态行:

格式:HTTP版本号 状态码 原因叙述

举例:HTTP/1.1200 OK

状态码                      含义

100-199         表示成功接收请求,要求客户端继续提交下一次请求才能完成整个处理过程

200-299         表示成功接收请求并完成整个处理过程,常用200

300-399             为完成请求,客户需要进行一步细化请求。例如:请求的资源已经移动一个新的地址,常用302,307

400-499         客户端的请求有错误404

500-599         服务器端出现错误,常用500  

u      http响应的状态行举例说明

200 就是整个请求和响应过程没有发生错误,这个最常见.

302: 表示当你请求一个资源的时候,服务器返回302 表示,让浏览器转向到另外一个资源,比如: response.sendRedirect(“/web应用/资源名”)

 

案例:

   response.setStatus(302);

    response.setHeader("Location""/servletPro/Servlet2");

    // 上面两句话等价  response.sendRedirect("/servletPro/Servlet2");

 

404: 找不到资源

500: 服务器端错误

 

 

u      http响应消息头详解

n        Location: http://www.baidu.org/index.jsp  【让浏览器重新定位到url

n        Server:apache tomcat 【告诉浏览器我是tomcat

n        Content-Encoding: gzip 【告诉浏览器我使用 gzip

n        Content-Length: 80  【告诉浏览器会送的数据大小80节】

n        Content-Language: zh-cn 【支持中文】

n        Content-Type: text/html;charset=GB2312 [内容格式text/html; 编码gab2312]

n        Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT 【告诉浏览器,该资源上次更新时间】

n        Refresh: 1;url=http://www.baidu.com 【过多久去,刷新到 http://www.baidu.com

n        Content-Disposition: attachment; filename=aaa.zip 【告诉浏览器,有文件下载】

n        Transfer-Encoding: chunked  [传输的编码]

n        Set-Cookie:SS=Q0=5Lb_nQ; path=/search[后面详讲]

n        Expires: -1[告诉浏览器如何缓存页面IE]

n        Cache-Control: no-cache  [告诉浏览器如何缓存页面火狐]

n        Pragma: no-cache   [告诉浏览器如何缓存页面]

n        Connection: close/Keep-Alive  [保持连接 1.1是Keep-Alive]

n        Date: Tue, 11 Jul 2000 18:23:51 GMT

 

①定时刷新Refresh使用

 response.setHeader("Refresh","5;url=/servletPro/Servlet2");

 

②文件下载Content-Disposition

publicvoid doGet(HttpServletRequest request, HttpServletResponseresponse)

           throwsServletException, IOException {

 

       response.setContentType("text/html");

       //PrintWriterout = response.getWriter();

      

       //演示下载文件

       response.setHeader("Content-Disposition""attachment; filename=winter.jpg");

      

       //打开文件.说明一下web 站点下载文件的原理

       //1.获取到要下载文件的全路径

       String path=this.getServletContext().getRealPath("/images/Winter.jpg");

       //System.out.println("path="+path);

       //2创建文件输入流

       FileInputStream fis=new FileInputStream(path);

       //做一个缓冲字节数组

       byte buff[]=newbyte[1024];

       int len=0;//表示实际每次读取了多个个字节

       OutputStreamos=response.getOutputStream();

       while((len=fis.read(buff))>0){

          

           os.write(buff, 0, len);

       }

       //缺点没有进度条./图标/

      

       //关闭

       os.close();

       fis.close();

    }

 

③缓存讲解

提出问题:浏览器默认情况下,会缓存我们的页面,这样出现一个问题:如果我们的用户习惯把光标停留在地址栏,然后回车来取页面,就会默认调用cache中取数据。

(1)      有些网站要求及时性很高,因此要求我们不缓存页面

代码:

//指定该页面不缓存 Ie

       response.setDateHeader("Expires", -1);【针对IE浏览器设置不缓存】

       //为了保证兼容性.

       response.setHeader("Cache-Control""no-cache");【针对火狐浏览器等】

       response.setHeader("Pragma""no-cache");【其他浏览器】

(2)         有些网站要求网页缓存一定时间,比如缓存一个小时

response.setDateHeader("Expires", System.currentTimeMillis()+3600*1000*24);后面一个参数表示设置的缓存保持时间,-1表示永远缓存

 

 

练习:

 

加入防止盗链下载.

 

u       HttpServletResponse的再说明

getWriter()

getOutputStream();

 

区别

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

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

OutputStream os=response.getOutputStream();

os.write("hello,world".getBytes());

 

如何选择:

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

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

☞ 这两个流不能同时使用.

比如:

OutputStreamos=response.getOutputStream();

       os.write("hello,world".getBytes());

       PrintWriter out=response.getWriter();

       out.println("abc");

就会报错:

java.lang.IllegalStateException: getOutputStream() has already been called for this response
 

不能同时使用printWriter和outputstream的原因

Web服务器会自动检查并关闭流

从该图,我们也可以看出. 为什么我们没有主动关闭流,程序也没有问题的原因.

当然:你主动关闭流,更好.

 

 

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

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

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

解决思路:

1.      使用java基础 static

2.      使用sendRedirect()

代码:

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

3.      使用session 传递[后面讲]

这里,我们先预热.

 

说明:

基本格式:

response.sendRedirect(“servlet的地址?参数名=参数值&参数名=参数值...”);

 

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

 

在接受数据的Servlet中:

 

String 参数=request.getParameter(“参数名”);

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

A.传递字符串

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

取出session   在JSP中通过session取出request.getSession.getAttribute("loginUser");

B.传递对象

User user= new User();

user.setName(“xiaoli”);

user.setPassWord(“123”);

 

放入session   request.getSession.setAttribute("userObj",userObj);

取出session   User user=(User)request.getSession.getAttribute(“userObj”);

 

上机练习:

1. 实际运用到项目: 在wel页面中显示登录用户的姓名,就可以使用该方法.让我们动手一起来做做吧!

2. 请写一篇关于HTTP协议的笔记,要求:

•        描述清楚HTTP请求头、响应头的格式

•        请求头和响应头中各个头字段的含义

l       如果浏览器传递给WEB服务器的参数内容超过1K,应该使用那种方式发送请求消息?

l       请描述200、302、304、404和500等响应状态码所表示的意义。

l       请列举三种禁止浏览器缓存的头字段,并写出相应的

 

u       中文乱码处理

发生中文乱码有三种情况

 

①    表单form

(1)   post

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

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

(2)   get

写一个工具类:

package com.hsp.utils;

publicclass MyTools {

    publicstatic String getNewString(String str) {

       String newString="";

       try {

           newString=newString(str.getBytes("iso-8859-1"),"utf-8");

       catch (Exceptione) {

           e.printStackTrace();

           // iso-8859-1 转换成 utf-8

       }

       return newString;

    }

}

②    超链接

测试

该方法和get处理方法一样.

③    sendRedirect() 发生乱码

response.sendRedirect(“servlet地址?username=顺平”);

 

版本低导致的乱码

特别说明,如果你的浏览器是 ie6 或以下版本,则我们的 ② 和 ③中情况会出现乱码(当中文是奇数的时候)

解决方法是 :

Stringinfo=java.net.URLEncoder.encode("你好吗.jpg", "utf-8");

测试

response.sendRedirect(“servlet地址?username=”+info);

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

返回浏览器显示乱码

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

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

 

下载提示框中文乱码

补充一个知识点: 当我们下载文件的时候,可能提示框是中文乱码

String temp=java.net.URLEncoder.encode("传奇.mp3","utf-8");

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

 

u       HttpServletRequest对象的详解

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

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

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

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

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

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

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

 

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

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

getRemotePort方法返回客户机所使用的网络端口号

客户机的端口号是随机选择的,web服务器的端口号是一定的

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

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

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

u       url 和 uri 的区别

比如:

       Url=http://localhost:8088/servletPort3/GetinfoServlet完整的请求

       Uri=/servletPort3/GetinfoServletweb应用的名称+资源的名称

练习题:

请在服务器这端,给浏览器回送该浏览器发送的具体请求内容是什么?

韩顺平

http://localhost:8088/web名/GetInfoServlet?abc=123&uu=90&iio=中国

大龙

http://localhost:8088/web名/GetInfoServlet?kkk=你好[email protected]

 

你的请求是

kkk=你好

[email protected]

u      如何获取用户提交的内容(通过表单提交的内容)

 

代码:

界面:

packagecom.hsp;

 

importjava.io.IOException;

importjava.io.PrintWriter;

 

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

 

publicclass MyInfoForm 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("
");

              out.println("");

              out.println("用户名:
");

              out.println("密 码:
");

              out.println("性 别:
");

              out.println("你的爱好:音乐 体育 旅游
");

              out.println("所在城市:
");

              out.println("你的介绍:
");

              out.println("提交照片:
");

              //什么时候使用hidden传输数据 1.不希望用户看到该数据 2. 不希望影响节目,同时使用该数据

             

              out.println("");

              out.println("");

 

       }

 

       public void doPost(HttpServletRequestrequest, HttpServletResponse response)

                     throws ServletException,IOException {

 

              this.doGet(request, response);

       }

 

}

 

接受信息的Servlet:

package com.hsp;

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;

publicclass RegisterCl extends HttpServlet{

    publicvoid doGet(HttpServletRequest request,HttpServletResponse response)

           throwsServletException, 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+"
"
);

       out.println("密 码="+p+"
"
);

       out.println("  ="+sex+"
"
);

       if(hobbies!=null){

           for(int i=0;ilength;i++){

              out.println("爱好:"+hobbies[i]);

           }

       }else{

           out.println("你没有爱好");

       }

       out.println("
所在城市:"+city);

       out.println("
个人介绍:"+intro);

       out.println("
隐藏控件数据:"+hidden1);

    }

    publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)

           throws ServletException,IOException {

       this.doGet(request,response);

    }

}

 

 

练习题:请大家自己写一个表单,提交数据(个人名字:电子邮件: 性别:你喜欢的城市 select(可以选多个):  你的特长 (checkbox) 你的个人签名, 用hidden传输重要数据)

 

 

u       请求转发requeset.getRequestDispatcher(资源地址).forward(request,response);

资源地址:不需要项目名。因为它只是在WEB服务器内部转发。

Request.getRequestDispatcher(资源地址).forward(request,response);

我们现在使用请求转发的方法来实现上次我们使用 response.sendRedirect() 实现效果

使用 request提供的转发方法.

Request中的Attribute在一次请求有效。一次请求:没有返回到浏览器,就为一次请求。

u       请求转发的的(uml)图

这里我们画图说明(uml)

 

1.      使用 forward 不能转发到web应用 url

2.      因为 forward 是发生在web服务器,所以 Servlet1  Servlet 2使用的是用一个request response.

l       使用sendRedirect() 方法不能通过request.setAttribute() 把 属性传递给下一个Servlet

 

u       比较sendRedirect()和request.getRequestDispatcher().forward(request,response)

请问 sendRedirect() 和 forward 的区别是什么

答:

(1)      叫法sendRedirect() 重定向,转发  forward() 叫转向

(2)      实际发生的位置不一样

sendRedirect发生 浏览器

forward 发生 web服务器

(3)      用法不一样

request.getRequestDispatcher(“/资源URI”).forward(request,response)

response.sendRedirect(“/web应用/资源URI”);

(4)      能够去URL范围不一样

sendRedirect可以去 外边URL

forward 只能去当前的WEB应用的资源

 

 

 

 

☞ 什么是一次 http请求:

只要没有停止,也没有回到浏览器重定向,就算一次

比如;

 

☞ 如果转发多次,我们的浏览器地址栏,保留的是第一次 转向的那个ServletUrl

 

小练习:

使用uml 软件,画出  forward 和sendRedirect() 的流程.

 

 

u       用户管理系统的继续开发

u       用户管理系统的框架图       用户管理框架图.xls

 

①    增加到数据库去验证用户功能

(1)    在oracle 数据库中创建一张表

users

createtable users

(idnumber primary key,

usernamevarchar2(32) not null,

emailvarchar2(64) not null,

gradenumber default 1,

passwdvarchar2(32) not null) 

初始化一些数据

insertinto users values(1,’aaaaa1’,’[email protected]’,1,’123’);

insertinto users values(2,’aaaaa2’,’[email protected]’,1,’123’);

 

insertinto users values(3,’aaaaa3’,’[email protected]’,1,’123’);

 

insertinto users values(4,’aaaaa4’,’[email protected]’,1,’123’);

 

insertinto users values(5,’aaaaa5’,’[email protected]’,5,’123’);

(2)    在LoginClServlet 中添加到数据库验证用户的功能.

ok:

//到数据库中取验证

       Connection ct=null;

       ResultSet rs=null;

       PreparedStatement ps=null;

       try {

          

           //1加载驱动

           Class.forName("oracle.jdbc.driver.OracleDriver");

           //2.得到连接

           ct=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:ORCLHSP","scott","tiger");

           //3.创建PreparedSatement

           ps=ct.prepareStatement("select * from users where id=? andpasswd=?");

           //赋值

           ps.setObject(1, id);

           ps.setObject(2, password);

          

           //4.执行操作

           rs=ps.executeQuery();

           //5.根据结果左处理

           if(rs.next()){

              //说明该用户合法

              request.getRequestDispatcher("/MainFrame").forward(request, response);

           }else{

              request.getRequestDispatcher("/LoginServlet").forward(request, response);

           }

          

       catch (Exceptione) {

           e.printStackTrace();

           // TODO: handle exception

       }finally{

           //关闭资源

           if(rs!=null){

              try {

                  rs.close();

              catch(SQLException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

              }

              rs=null;

           }

           if(ps!=null){

              try {

                  ps.close();

              catch(SQLException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

              }

              ps=null;

           }

           if(ct!=null){

              try {

                  ct.close();

               }catch (SQLException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

              }

              ct=null;

           }

          

       }

②    如果输入的用户id 密码不正确,则给出提示.

 

 

 

课后练习; 参看给出的用户管理开发文档,完成 1, 2, 3 页面功能[分页和安全性暂时不考虑.]

 

③    用户管理系统的界面添加图片

 

 

④    用户管理系统添加分页功能

 

思路:

定义四个分页变量

pageNow  表示第几页,该变量是由用户来决定,因此变化

pageSize     每页显示几条记录,由程序指定,也可以由用户定制

pageCount 表示共有多少页, 该变量是计算出来->思考 怎样确定

rowCount  共有多少条记录,该变量是查询数据库得到

 

如何确定pageCount

(1)

if(rowCount% pageSize==0){

       pageCount=rowCount/pageSize;

}else{

       pageCount=rowCount/pageSize+1;

}

试试: 比如 users表 9 条记录 pageSize=3  =>pageCount=3

       比如 users表 10 条记录 pageSize=3  =>pageCount=4

(2)

上面的算法等价于

pageCount=rowCount% pageSize==0 ?rowCount/pageSize: rowCount/pageSize+1;

 

该运算称为三目运算

(3)

更简单的算法是:

pageCount=(rowCount-1)/pageSize+1;

试试: 比如 users表 9 条记录 pageSize=3  =>pageCount=3

       比如 users表 11 条记录 pageSize=3  =>pageCount=4

 

 

 

 

回忆: oracle 分页的select

 

 

 

特别说明:如果某个web应用你不需要,请把该web应用从 webapps目录下移走,否则tomcat启动的速度会越来越慢.

 

上机练习题:

1.      完成自己项目的分页

2.      再做一个  上一页 1 2 3 4 5 6  下一页   当前页/总页数 

              跳转到 [ ] 页   【如何在servlet中使用js技术】

3.      思考题:

如何控制我们的超链接只显示10页,    << 1 2 3 4 5 6 7 8 9 10   >>

>> 显示后面的10页 << 显示前10页

如何控制直接输入跳转页的时候,pageNow的值过大的问题?

 

你可能感兴趣的:(韩顺平2011细说Servlet笔记1)