servlet总结

u  背景知识介绍javascript

J2EE的13种技术php

 

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

zip粘贴到word设置html

u  回顾一下咱们现有的技术java

 

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

jdbc (java 的数据库编程)程序员

oracle / mysql / sqlserverweb

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:browserserver 浏览器服务器(用HttpWatch Professional抓浏览器包)

(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是默认端口若是该端口已经被占用须要修改端口)

 

tomcat安装后问题解决

(1)tomcat没法正常启动的缘由分析

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

2.      若是你的机器已经占有了8080 端口,则没法启动,

解决方法

(1) 你能够8080 先关闭

netstat –an

netstat –anb 来查看谁占用该8080

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

到conf/server.xml 文件中修改

<ConnectorconnectionTimeout="20000" 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 文件中添加配置的代码:

 

  <welcome-file-list>

    <welcome-file>hello1.html</welcome-file>

  </welcome-file-list>

       ③经过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文件添加主机名

<Host name="www.sina.com" appBase="d:\web3”>

              <Contextpath="/" docBase="d:\web3" />

</Host>

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

若是连端口都不但愿带,则能够吧tomcat的启动端口设为80便可.

(4) 重启生效

u  tomcat体系的再说明

图:

如何配置默认主机:

在tomcat/conf/server.xml文件

<Engine name="Catalina" 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

 

<?xml version="1.0"encoding="ISO-8859-1"?>

<!--

 Licensed to the Apache Software Foundation(ASF) under one or more

 contributor license agreements. See the NOTICE file distributed with

 this work for additional information regarding copyright ownership.

  TheASF licenses this file to You under the Apache License, Version 2.0

 (the "License"); you may not use this file except incompliance with

  theLicense.  You may obtain a copy of theLicense at

 

     http://www.apache.org/licenses/LICENSE-2.0

 

 Unless required by applicable law or agreed to in writing, software

 distributed under the License is distributed on an "AS IS"BASIS,

 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  Seethe License for the specific language governing permissions and

 limitations under the License.

-->

 

<web-appxmlns="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"

  version="2.5">

 

       <!--根据serlvet规范,须要将Servlet部署到web.xml文件,该部署配置能够从examples下拷贝-->

        <servlet>

              <!--servlet-name 给该Servlet取名, 该名字能够本身定义:默认就使用该Servlet的名字-->

      <servlet-name>MyFirstServlet</servlet-name>

         <!--servlet-class要指明该Servlet 放在哪一个包下,形式是//../-->

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

    </servlet>

              <!--Servlet的映射-->

        <servlet-mapping>

              <!--这个Servlet-name要和上面的servlet-name名字同样-->

        <servlet-name>MyFirstServlet</servlet-name>

              <!--url-pattern这里就是未来访问该Servlet的资源名部分-->

        <url-pattern>/ABC</url-pattern>

   </servlet-mapping>

 

</web-app>

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

6.      在浏览器中测试

在浏览器中输入

http://localhost:8088/hspweb1/ABC

 

7.      分析一下本身写可能出现的错误

(1)   <servlet-name>MyFirstServlet</servlet-name>名字不同 (启动tomcat错误)

(2)   <servlet-class>com.hsp.MyFirstServlet</servlet-class>  写成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文件中:

<!--根据serlvet规范,须要将Servlet部署到web.xml文件,该部署配置能够从examples下拷贝-->

        <servlet>

              <!--servlet-name 给该Servlet取名, 该名字能够本身定义:默认就使用该Servlet的名字-->

     <servlet-name>MyGenericServlet</servlet-name>

         <!--servlet-class要指明该Servlet 放在哪一个包下,形式是//../-->

     <servlet-class>com.hsp.MyGenericServlet</servlet-class>

    </servlet>

              <!--Servlet的映射-->

        <servlet-mapping>

              <!--这个Servlet-name要和上面的servlet-name名字同样-->

       <servlet-name>MyGenericServlet</servlet-name>

              <!--url-pattern这里就是未来访问该Servlet的资源名部分,默认命名规范:

              就是该Servlet的名字-->

        <url-pattern>/MyGenericServlet</url-pattern>

</servlet-mapping>

 

 

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提交分别处理

       //回忆 <formaction="提交给?"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

<html>

<body>

<formaction="/hspWeb1/MyHttpServlet" method="post">

u:<inputtype="text" name="username"/>

<inputtype="submit" value="login"/>

</body>

</html>

 

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

①     从安全看 get<post 由于get 会把提交的信息显示到地址栏

②     从提交内容看 get<post get 通常不要大于2k, post理论上无限制,可是在实际              开发中,建议不要大于64k

③     从速度看 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 的代码:

public void doGet(HttpServletRequest request,HttpServletResponse response)

           throws ServletException, IOException {

 

       response.setContentType("text/html");

       PrintWriter out = response.getWriter();

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

    }

 

    public void 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 component</description>

    <display-name>This is thedisplay name of my J2EE component</display-name>

   <!-- servlet的注册名 -->

    <servlet-name>MyServlet1</servlet-name>

    <!--servlet类的全路径(包名+类名) -->

    <servlet-class>com.hsp.servlet.MyServlet1</servlet-class>

  </servlet>

<!-- 对一个已经注册的servlet的映射 -->

  <servlet-mapping>

  <!--servelt的注册名 -->

    <servlet-name>MyServlet1</servlet-name>

  <!--servlet的访问路径 -->

    <url-pattern>/MyServlet1</url-pattern>

  </servlet-mapping>

 

  <servlet-mapping>

  <servlet-name>MyServlet1</servlet-name>

  <url-pattern>/hsp</url-pattern>

  </servlet-mapping>

②    当映射一个servlet时候,能够多层 好比

<url-pattern>/servlet/index.html</url-pattern> 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中的 <load-on-startup> 配置

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

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

解决方法: 能够经过<load-on-startup> 配合 线程知识搞定.

 

先说明<load-on-startup>: 经过配置<load-on-startup> 咱们能够指定某个Servlet 自动建立.

 

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

实现思路:

 

sendEmailTable

id                  content                 sendtime

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

2                   “hello2”                2012-11-11 10:00

 

 

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

这里的代码请参考项目:

SendMailThread.java

package com.hsp.model;

public class SendEmailThread extends Thread{

    @Override

    public void 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

public void init() throwsServletException {

       // Put yourcode here

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

       //完成一些初始化任务

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

       //建立一个线程

       SendEmailThread sendEmailThread=new SendEmailThread();

       sendEmailThread.start();

    }

说明:

<!-- 1表示该servlet init的顺序 -->

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

 

 

u  ServletConfig对象

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

 

 

案例:

<servlet>

    <servlet-name>ServletConfigTest</servlet-name>

    <servlet-class>com.hsp.servlet.ServletConfigTest</servlet-class>

    <!-- 这里能够给servlet配置信息,这里配置的信息,只能被该servlet 读取 -->

    <init-param>

    <param-name>encoding</param-name>

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

    </init-param>

  </servlet>

如何使用

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

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

<!-- 若是这里配置参数,可被全部servlet读取 -->

 <!-- 

 <context-param>

 <param-name></param-name>

 <param-value></param-value>

 </context-param>

-->

 

 

u  若是要把全部的参数都读取,则使用 以下方法 :

Enumeration<String>names=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/*   [告诉服务器,我能够接受文本,网页,图片]

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

2.   Accept-Encoding: gzip,compress [能够接受 gzip,compress压缩后数据.]

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

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

5.   If-Modified-Since: Tue, 11 Jul 200018:23:51 GMT [ 告诉服务器,个人缓冲中有这个资源文件,该文件的时间是。。。(若是有刷新就不更新了)]

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

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

8.   Cookie [cookie??]

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

10.  Date: Tue, 11 Jul 200018: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;

       } 

getHeader("Referer")要走HTTP协议时才有值,也就是说要经过

<a href=”url”>sss</a>才能得到那个值

而经过改变location或

<a href=”javascript:location=’url’”>sss</a>都是得不到值

红色的部分能够根据实际状况来修改.

 

u  http的响应

基本结构:

状态行:

格式:HTTP版本号 状态码 缘由叙述

举例:HTTP/1.1 200 OK

状态码                      含义

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

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

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

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

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

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

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

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

 

案例:

如今是/Servlet1 而后写个跳转到2的 会先一个302 在200

   response.setStatus(302);

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

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

 

404: 找不到资源

500: 服务器端错误

 

 

u  http响应消息头详解

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Date: Tue, 11 Jul 200018:23:51 GMT

 

①  时刷新Refresh使用

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

过了5秒后跳转到URL的页面

 

②文件下载Content-Disposition

public void doGet(HttpServletRequest request,HttpServletResponse response)

           throws ServletException,IOException {

 

       response.setContentType("text/html");

       //PrintWriterout = response.getWriter();

      

       //演示下载文件attachment关键字,附件的意思通常名字不改

//filename=winter.jpg文件路径;

       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[]=new byte[1024];

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

       OutputStreamos=response.getOutputStream();

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

          

           os.write(buff, 0, len);

       }

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

      

       //关闭

       os.close();

       fis.close();

    }

 

② 存讲解

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

//删除缓存 Internet选项 里面

(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

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

好比:

OutputStream os=response.getOutputStream();//write方法只能放字节数组

    os.write("hello,world".getBytes()); //字符串放在字节数组里面的实现

       PrintWriter out=response.getWriter();

       out.println("abc");

就会报错:

java.lang.IllegalStateException: getOutputStream() has already been called for this response
//报500错误,由于OutputStream
 

不能同时使用printWriter和outputstream的缘由

由于OutputStream已经被关闭,因此PrintWriter就不能使用了

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

从该图,咱们也能够看出. 为何咱们没有主动关闭流,程序也没有问题的缘由.

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

 

 

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

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

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

解决思路:

1.      使用java基础 static

2.      使用sendRedirect()

代码:

 

           “/指向的地址           ? uname(随意)="+username+"&pwd="+password

传输多个信息 用&隔开

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    Useruser=(User)request.getSession.getAttribute(“userObj”);

 

上机练习:

1. 实际运用到项目: 在wel页面中显示登陆用户的姓名,就可使用该方法.让咱们动手一块儿来作作吧!

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

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

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

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

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

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

 

中文乱码处理

发生中文乱码有三种状况

 

①    表单form

(1)   post   <form action=”url”  method=”post”/>

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

接收的地方设置一下

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

 

(2)   get    <form action=”url”  method=”get”/>

或写一个工具类:

package com.hsp.utils;

public class MyTools {

    public static 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;

    }

}

工具类的使用:

②    超连接

<a href=”http://www.sohu.com?name=函数后”>测试</a>

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

③    sendRedirect() 发生乱码

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

 

版本低致使的乱码

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

解决方法是 :

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

<a href=”http://www.sohu.com?name=”+ info >测试</a>

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

表单:说明: 咱们应当尽可能使用post 方式提交;

返回浏览器显示乱码

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

response.setContentType(“text/html;charset=utf-8”); ok 黄色的加上,否则提交上去的浏览器不以utf-8编码显示,也会乱码

 

下载提示框中文乱码

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

以前是这样写的

response.setHeader("Content-Disposition","attachment;filename=传奇.mp3);

修改:

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服务器的端口号是必定的(好比 8080

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

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

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

u  url 和 uri 的区别

好比:

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

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

练习题:

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

我在地址栏输入:

http://localhost:8080/servletRequest/UseRequest?abc=123&uu=90&iio=%E4%B8%AD%E5%9B%BD

获得的

abc=123

uu=90

iio=??????

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

大龙

http://localhost:8088/web名/GetInfoServlet?kkk=你好&email=dalong@sohu.com

中文乱码的处理

  //获得请求的参数Map,注意mapvalueString数组类型 

        System.out.println("-----------------");

        StringqueryString=request.getQueryString();

        String quStr[]=queryString.split("&");

        for(String s:quStr){ //s是每次从quStr[]中拿

        String[]name_val=s.split("=");//将等号左右两边分开,咱们要转的是右边的值

        System.out.println(name_val[0]+"="+MyTools.getNewString(name_val[1]));

        out.println(name_val[0]+"="+MyTools.getNewString(name_val[1]));

        //out.println(s+"="+MyTools.getNewString(request.getParameter(s)));

        System.out.println(s);

        }

        System.out.println("---------------");

        Map map = (Map) request.getParameterMap();   //该法最好

        Set<String> keySet = ((java.util.Map<String,String[]>) map).keySet(); 

       for (String key : keySet) { 

        String[] values = (String[]) ((java.util.Map<String,String[]>) map).get(key); 

        for (String value : values) { 

            System.out.println(key+"="+MyTools.getNewString(value)); 

        } 

     }

你的请求是

kkk=你好

email=dalong@sohu.com

获得消息头

//获得请求头的name集合 

        Enumeration<String> em =request.getHeaderNames(); 

        while (em.hasMoreElements()) { 

        String name = (String)em.nextElement(); 

       String value = request.getHeader(name); 

       System.out.println(name+"="+value); 

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(HttpServletRequestrequest, HttpServletResponse response)

                     throws ServletException,IOException {

 

              response.setContentType("text/html;charset=utf-8");

              PrintWriter out =response.getWriter();

              out.println("<formaction='/servletPro3/RegisterCl' method='post'><br/>");

              out.println("<inputtype='hidden' value='abc' 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'><optionvalue='bj'>北京</option><optionvalue='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("<inputtype='submit' value='提交信息'/>");

              out.println("</form>");

 

       }

 

       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;

public class RegisterCl extends HttpServlet{

    public void 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+"<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(HttpServletRequestrequest, 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请求:

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

好比;

 

☞ 若是转发屡次,咱们的浏览器地址栏,保留的是第一次转向的那个Servlet Url

 

小练习:

使用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’,’aaaa1@sohu.com’,1,’123’);

insertinto users values(2,’aaaaa2’,’aaaa2@sohu.com’,1,’123’);

 

insertinto users values(3,’aaaaa3’,’aaaa3@sohu.com’,1,’123’);

 

insertinto users values(4,’aaaaa4’,’aaaa4@sohu.com’,1,’123’);

 

insertinto users values(5,’aaaaa5’,’aaaa5@sohu.com’,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的值过大的问题?

 

       

 

对当前网站结构的问题分析:

1.LoginCL.java文件和ManagerUser.java文件都去操做数据库,他们代码重复,逻辑类似。

2.整个框架没有清晰的文件框架,显得比较凌乱。

3.代码不优雅可读性差,可维护性差。

 

解决方法:

1.业务逻辑代码和界面分离。

2.把经常使用的代码(对数据库的链接和操做)封装到工具类。

 具体方法

①  每一张表对应一个javadomain类(表示数据) 还要对应一个Service类

好比users表对应 users类(domain类) UserService/UserDao(该类会封装对users表的各类操做),实际上体现出数据和操做分离的思想。

 

上机练习:

登录部分改为MVC模式,建议先保存一份再改。

 

完成分页的MVC改写

首先要添加方法

//为何返回ArrayList而不是ResultSet

//1.ArrayList中封装Users更加符合面向对象的编程方式。OOP

//2.ArrayList 和ResultSet 没有关系,能及时关闭数据库资源。

public ArrayList<Users>getPageAll(int pgnow, int pgsize) {

 

}

 

练习:把用户管理系统除了cookie和session 相关功能不作其余都作了。

 

 

 

带你们完成一个完成一个用户管理系统的crud操做。

1.一个请求对应一个控制器。

优势:逻辑清晰。

缺点:未来会形成控制器过多。

 

能够考虑:一类事物的请求咱们作一个控制器,即一个控制器可处理多个请求。为了让一个控制器区分不一样的请求,能够在发请求的同时带请求类型。例如type=add  type=del type=update.....在控制器中接收type值,判断用户但愿干什么。

 

关于跳转到修改用户界面有两种思路:

1.传递用户id号的同时传递用户的其它信息,这样能够减小数据库查询的次数。(缺点:增长网络开销;暴露了用户信息。优势:减小对数据的一次操做。)

2.只传递id号,控制器在数据库查找用户其它信息,从而显示。

 

建立用户:

1.把id建成自增加。

 

什么是会话:

基本概念:指用户开一个浏览器,访问一个网站,只要不关闭浏览器,无论该用户点击多少个超连接,访问多少资源,直到用户关闭浏览器,整个过程称为一个会话。

 

为何须要cookie技术(会话技术)

如何保存用户上次登陆时间

如何显示用户浏览历史:

如何把登陆的用户名和密码保存电脑,下次登陆无需重新输入。

 

 

解决之道cookie技术

 

Cookie的原理图

 

Cookie的小结

① Cookie是在服务器端建立的。

② Cookie是保存在浏览器这一端的。

③ Cookie的生命周期能够经过

        cookie.setMaxAge(2000); 设置。

若是不设置,该cookie的生命周期当浏览器关闭时就消亡。

④ Cookie是能够被多个浏览器共享的

⑤ 怎么理解

咱们能够把cookie想成一张表:

若是cookie重名会有什么问题?

重名会替换原来的值。

⑥ 一个站点能够保存多个cookie

⑦ Cookie存放时是以明文方式存放的,所以安全性比较低。咱们能够经过加密后在保存。

-->补讲一个md5算法:密码都要加密存放,对用户输入的密码要进行MD5加密,再存放到数据库中去。

 

实际案例:

 

Cookie的实际使用:

打开登陆页面时,自动填写用户名密码。

 

Cookie实际应用:

 

Cookie细节:

① 一个浏览器最多放入300个cookie,一个站点最多20个cookie 每一个cookie大小限制在4K之内。

② Cookie生命周期的在说明:

1. Cookie生命周期是会话级别的。

2.经过setMaxAge()能够升值生命周期

setMaxAge(正数) 即多少秒后该cookie失效

setMaxAge(0)  删除该cookie

案例:

        Cookie[] cookies =request.getCookies();

        for(Cookiecookie:cookies){

           if("id".equals(cookie.getName())){               

               cookie.setMaxAge(0);//删除

               response.addCookie(cookie);//回写浏览器,不然不生效

                break;

            }

        }

 

特别说明:若是该web应用中只有一个cookie 则该cookie删除后,浏览器的临时文件夹下就没有了该cookie文件。若是一个web应用中有多个cookie,该cookie被删除文件还在。

setMaxAge(负数),至关于该cookie的生命周期是会话级的。

③ Cookie存放中文怎么处理

存放时:

String val =java.net.URLEncoder.encode("顺平","UTF-8");

Cookie cookie =new Cookie("uname",val);

取出时:

String val =java.net.URLEncoder.decode(cookie.getValue(),"UTF-8");

Out.println("uname="+val);

Session为何有?

如何实如今不一样的页面,能够查看信息(好比说购物车),同时实现不一样的用户看到本身的一份信息。

 

Session小结:

 

① Session是存在服务器的内存中的。

② 一个用户浏览器,独享一个session对象。

③ Session中的属性的默认生命周期是30min,能够经过修改web.xml来修改。

这样修改

一个地方是:tomcat/conf/web.xml

<session-config>

<session-timeout>30</session-timeout>

</session-config>

对全部的web应用生效。

第二个地方是:在单个web应用下的web.xml文件下添加或修改ession-config

<session-config>

<session-timeout>10</session-timeout>

</session-config>

只对本web应用生效

若是两个配置文件冲突,就以单个web应用的配置为准。

第三种方法是:session.setMaxInactiveInterval(600);//以秒为单位

对session生命周期小结:

④ Session中能够存放多个属性。

⑤ Session能够存放对象。

⑥ 若是同一个用户浏览器向Session设置属性时名字相同会替换。Session.setAtrribute("name",val);

 

Session案例:

PrintWriter out = response.getWriter();

HttpSession session =request.getSession();

session.setAttribute("a1","YYY");

session.setAttribute("a2","ttt");

session.removeAttribute("a1");

String val1 = (String)session.getAttribute("a1"):

String val2 =(String)session.getAttribute("a2");

Out.println("val1="+val1+"  val2="+val2);

 

防止用户非法登录到某个页面

用户必须登录后才能操做。

思路:

当用户登录后,将用户信息存放到session,而后再验证页面中的用户信息,若是为空或者不合法可让其重新登录。

 

Session的更深刻理解:为何服务器可以为不一样的浏览器提供不一样的session。

 

www.sourceforge.net开源之祖

 

验证码案例:  原理是使用了java的绘图技术

这里最重要的就是生成验证码的servlet

 

public class CreateCode extends HttpServlet{
   protected void processRequest(HttpServletRequest request,HttpServletResponse response)
           throws ServletException, IOException {
       int width=80;
       int height=20;
       //禁止浏览器缓存图片
       response.setDateHeader("Expires", -1);
       response.setHeader("cache-Control", "no-cache");
       response.setHeader("Pragma","no-cache");
       //通知客户端以图片的方式打开发送过去的数据
       response.setHeader("Content-Type", "image/jpeg");
       //在内存中建立一副图片
       BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR);
       //向图片中写数据
       Graphics g = image.getGraphics();
       //设置背景色
       g.setColor(Color.red);
       g.fillRect(0, 0, width, height);
       
       //设置写入的数据颜色和字体
       g.setColor(Color.black);
       g.setFont(new Font(null,Font.BOLD,20));
       //向图片上写数据
       String str =getNum();
       //把随机数生成的数值保存到session
       request.getSession().setAttribute("checkcode", str);
       g.drawString(str, 2, 18);
       
       //把写好的数据输出给浏览器
       ImageIO.write(image, "jpg", response.getOutputStream());
    }
    //随机生成数字    
   private String getNum(){
       String str = null;
       Random r = new Random();
       //生成7位
       String num = r.nextInt(9999999)+"";
       //若是不够7位,就前面补零
       StringBuffer sb = new StringBuffer();
       for(int i=0;i<7-num.length();i++){
           sb.append("0");
       }
       str =sb.toString()+ num;
       return str;
    }
   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponseresponse)
           throws ServletException, IOException {
       processRequest(request, response);
    }
   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponseresponse)
           throws ServletException, IOException {
       processRequest(request, response);
    }
   @Override
   public String getServletInfo() {
       return "Short description";
   }// </editor-fold>
}


 

使用方法:

< img src=''/验证码servlet的URL />

 

 

在某些状况下咱们使用过滤器。

实现方法:

1.        建立一个过滤器(继承Httpservlet 实现Filter接口)

2.        配置过滤器,默认不生效必须配置

   <filter>

       <filter-name>MyFilter</filter-name>

       <filter-class>org.gust.controller.filter.MyFilter</filter-class>       

   </filter>

   <filter-mapping>

       <filter-name>MyFilter</filter-name>

       <url-pattern>/*</url-pattern>   // /*表示全部网页都过滤

</filter-mapping>

 

3.        在filter中的方法添加逻辑

public class MyFilter extendsHttpServlet implements Filter {

   @Override

   protected void doGet(HttpServletRequest request, HttpServletResponseresponse)

            throws ServletException,IOException {

       processRequest(request, response);

   }   

   @Override

   protected void doPost(HttpServletRequest request, HttpServletResponseresponse)

            throws ServletException,IOException {

       processRequest(request, response);

   }   

   private void processRequest(HttpServletRequest request,HttpServletResponse response) {       

   }

 

   @Override

   public void init(FilterConfig filterConfig) throws ServletException{        

   }

   

   @Override

    public void doFilter(ServletRequestrequest, ServletResponse response, FilterChain chain) throws IOException,ServletException {

        HttpServletRequest hsr =(HttpServletRequest) request;

        //看看请求的资源是什么

        String url = hsr.getRequestURI();

        if(url.startsWith("/UserManager/CreateCode") ||url.startsWith("/UserManager/Login") ||url.startsWith("/UserManager/imgs")) {

            //放行

            chain.doFilter(request, response);

        } else {

            HttpSession session = hsr.getSession();

            Users u = (Users)session.getAttribute("u");

            if (u != null) {

                chain.doFilter(request,response);

            } else {

               request.setAttribute("err", "请登陆");

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

            }

        }

    }

}

 

配置过滤器的顺序能够决定调用顺序。

 

对session销毁时间的讨论

面试题:(关掉IE再打开IE上次购买的商品还在。-->涉及session的销毁时间)

 

分析

咱们的session生命周期是30min,该session不会随着浏览器关闭而销毁。而会到30分钟满后才会被服务器销毁。

咱们使用代码来实现该功能。Session加 cookie才能实现

 

分析实现的思路:

 

如何实现IE禁用cookie后咱们还能继续使用session

一:把session ID回写到cookie

//cookie名字必须为JSESSION 区分大小写

Cookie cookie = newCookie("JSESSION",session.getID());

cookie.setMaxAge(60*30);

response.addCookie(cookie);

二:URL地址重写

 //使用一次session 以便得到sessionID

 request.getSession();

//编码

 String url =response.encodeRedirectURL("/UserManager/BuyBookCL?id=101");

 PrintWriter.println("<a href='"+url+"'>加入购物车</a>");

//在返回时也要加入 URL地址重写

String url =response.encodeRedirectURL("/UserManager/ShowBook");

PrintWriter.println("<ahref='"+url+"'>返回购买页面</a><br/>");

 

简易购物车实例:

思路:

当用户点击购买商品时,咱们就把该商品保存到session中。该session的结构是

Name    value

Books    HashMap

而HashMap 的结构是

Key   value

BookID  Book对象

Book.java

Public Class Booke implements java.io.Serializable{

    private String id;

    private String name;

    private int num;

    private double price;

}

用到下面知识:

1.        Java基础集合 ArrayList HashMap  LinkedHashMap(有序)

2.        Session技术

3.        Servlet

4.        单态

5.        选择不一样的集合  list集合是有序的 map集合默认是无序的。 list和map集合均可以放入空值,list能够放入相同的对象,map能够放入相同的对象可是key不能重复。

 

 

Cookie vs  Session

① 存在的位置

Cookie存在客户端的临时文件夹

Session存在在服务器内存中,一个session域对象为一个用户浏览器服务。

② 安全性

Cookie是以明文方式存放在客户端的,因此说安全性相对较弱.能够MD5加密再存放。

Session是存放服务器内存中的,安全性相对较强。

③ 网络传输量

Cookie会传递信息给服务器

Session属性值不会传递给客户端。

④ 生命周期

Cookie的生命周期是累积时间,即到点就失效。即咱们给cookie设置setAge(30);30秒后及失效。

Session 的声明周期间隔时间,即从最后一次访问后开始计时。即咱们设置Session为20分钟,若是20分钟内没有访问,Session即失效。

如下状况Session也会失效

A.关闭tomcat

B.重启web应用

C.时间到

D..调用session.invalidate();

⑤ 使用原则

由于Session会占用服务器内存,所以不要往session中存放过多过大的对象。

每一个站点最多20个cookie 每一个cookie大小限制在4K之内。

 

1.        为何须要ServletContext

需求1:

需求2:

解决之道ServletContext

快速入门案例:

 

1.ServletContext 是在服务器建立

2.ServletContext被全部客户端共享

3.ServletContext 当web应用启动时自动建立,

4.ServletContext 当web应用关闭 重启动或服务器关闭时都会形成ServletContext销毁

对ServletContext的用法小结:

//获取ServletContext的两种方法

this.getServletContext(); 或者 this.getServletConfig().ServletContext();

//添加属性

servletcontext.setAttribute(String , object);

//取出属性

servletcontext.getAttribute("属性名");

//删除

servletcontext.removeAttribute("属性名");

 

ServletContext的应用

1)       获取web应用的初始化参数

<!-- 若是但愿全部的Servlet均可以访问该配置-->

<context-param>

<param-name>name</param-name>

<param-value>socott</param-value>

</context-param>

如何获取

String val =this.getServletContext().getInitParameter("name");

2)       使用ServletContext实现跳转

目前跳转到页面有几种方法

1 response.sendRedirect("/web应用名/资源URL");

2 resquest.getRequestDispatcher("/资源URL").forward(resuest,response);

   区别 1: getRequestDispatcher跳转发生在服务器而sendRedirect跳转发生在浏览器

2: 若是resquest.setAttribute("name","gust");但愿下个页面可使用其属性则用getRequestDispatcher

3: 若是session.setAttribute("uname","顺平");但愿下个页面可使用其属性则用两种方法均可以,建议使用getRequestDispatcher由于效率高些

4: 若是咱们要跳转到本应用外的URL则使用sendRedirect

3 this.getServletContext().getRequestDispatcher("/资源URL").forward(resuest,response);

跟第二种方法同样...

 

3)       读取文件,和获取文件的路径

//读取文件
InputStream is =this.getServletContext().getResourceAsStream("dbinfo.properties");
//建立properties
Properties pp = new Properties();
pp.load(is);
Out.println("name="+pp.getProperty("username"));
 
//若是文件在src目录下要用类加载器去读
InputStream is=Servlet类名.class.getClassLoader().getResoureAsStream("dbinfo.properties");
 
//获取文件全路径
Stringpath=this.getServletContext().getRealPath("/imgs/a.jpg");
Out.println("path="+path);


 

防刷新 用response.sendRedirect("/web应用名/资源URL");跳转能防刷新

 

网站计数器的思考

分析:

代码:

创建一个recoder.txt文件,用于保存访问量,这样能够保证稳定增加。

实现方法是

创建initservlet 用于初始化servletContext 和 在关闭tomcat时保存访问量

配置文件中加入<load-on-startup>1</load-on-startup>

 

public class InitServlet extendsHttpServlet {
   @Override
   public void destroy(){
       super.destroy();
       Stringpath=this.getServletContext().getRealPath("/record.txt");
       FileWriter fw=null;
       BufferedWriter bw=null;
       try {
            fw = new FileWriter(path);
            bw = new BufferedWriter(fw);
            String nums = (String)this.getServletContext().getAttribute("nums");           
            bw.write(nums);            
       } catch (Exception ex) {
           Logger.getLogger(InitServlet.class.getName()).log(Level.SEVERE, null,ex);
       }finally{
            try {
                if(bw!=null){
                    bw.close();
                }
                if(fw!=null){
                    fw.close();
                }
            } catch (IOException ex) {
               Logger.getLogger(InitServlet.class.getName()).log(Level.SEVERE, null,ex);
            }
       }       
   }
   @Override
   public void init()throws ServletException{
       
       FileReader fr=null;
       BufferedReader br=null;
       try {
            Stringpath=this.getServletContext().getRealPath("/record.txt");
            //打开文件
            fr = new FileReader(path);
            //转为BufferedReader 再读一行
            br = new BufferedReader(fr);
            String nums = br.readLine();
            //把nums放入ServletContext
           this.getServletContext().setAttribute("nums",nums);           
       } catch (Exception ex) {
           Logger.getLogger(InitServlet.class.getName()).log(Level.SEVERE, null,ex);
       }finally{
            try {
                if(br!=null){
                    br.close();
                }
                if(fr!=null){
                    fr.close();
                }
            } catch (IOException ex) {
               Logger.getLogger(InitServlet.class.getName()).log(Level.SEVERE, null,ex);
            }
       }
   }
   protected void processRequest(HttpServletRequest request,HttpServletResponse response)
            throws ServletException,IOException {
       response.setContentType("text/html;charset=UTF-8");
       PrintWriter out = response.getWriter();
       try {
       } finally {           
            out.close();
       }
   }
   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponseresponse)
            throws ServletException,IOException {
       processRequest(request, response);
   }
   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponseresponse)
            throws ServletException,IOException {
       processRequest(request, response);
   }
}


 

当用户登录一次时,咱们取出访问量,并加1

//向servletContext中取出属性并添加

String num=(String)this.getServletContext().getAttribute("nums");

this.getServletContext().setAttribute("nums",(Integer.parseInt(num)+1)+"");

 

在页面显示

String num =(String)this.getServletContext().getAttribute("nums");

Out.println("该页面被访问了"+num+"次");

 

若是咱们的tomcat异常退出怎么办?

使用线程,定时把ServletContext中的值写入recoder.txt 好比10min

 

 

最后说:

针对工具类SQLHelper.java

1.咱们的链接数据库的变量都是static,这样有必定的危险。若是访问量过大,可能形成一些用户的超时。咱们能够这样作,把static变量变成非static

在调用SQLHelper时,建立SQLHelper对象,而后调用其方法。

2.咱们的SQLHelper查询数据时,没有在本类中关闭,不是好习惯。解决方案以下:

   public ArrayListexecuteQuery(String sql, String[] parameters) {
        connection();//链接数据库
        ArrayList list = null;
        try {
            pst =ct.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
            if (parameters !=null) {
                //    System.out.println(sql);
                for (int i =0; i < parameters.length; i++) {
                    //  System.out.println(i+"    "+parameters[i]);
                   pst.setString((i + 1), parameters[i]);
                }
            }
            rs =pst.executeQuery();
            list = newArrayList();
 
            ResultSetMetaDatarmd = rs.getMetaData();
            int column =rmd.getColumnCount();
            while (rs.next()){
                Object obj[] =new Object[column];
                for (int i = 0; i < column; i++) {
                    obj[i] =rs.getObject(i+1);
                }
                list.add(obj);
            }
 
        } catch (Exception ex){
           Logger.getLogger(DBUtil.class.getName()).log(Level.SEVERE, null, ex);
            throw newRuntimeException(ex.getMessage());
        } finally {
            closeConn(); //关闭资源
        }
        return list;
    }
 
    publicArrayList<HashMap> executeQuery2(String sql, String[] parameters) {
        connection();
        ArrayList list = null;
        try {
            pst =ct.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
            if (parameters !=null) {
                //    System.out.println(sql);
                for (int i =0; i < parameters.length; i++) {
                    //  System.out.println(i+"    "+parameters[i]);
                   pst.setString((i + 1), parameters[i]);
                }
            }
            rs =pst.executeQuery();
            list = newArrayList();
            int column =rs.getMetaData().getColumnCount();
            while (rs.next()){
                HashMap obj =new LinkedHashMap();
                for (int i =0; i < column; i++) {
                    String key= rs.getMetaData().getColumnName(i+1);
                    Object val= rs.getObject(i+1);                  
                   obj.put(key, val);
                }
                list.add(obj);
            }
 
        } catch (Exception ex){
            Logger.getLogger(DBUtil.class.getName()).log(Level.SEVERE,null, ex);
            throw newRuntimeException(ex.getMessage());
        } finally {
            closeConn();
        }
        return list;
    }
//executeQuery2使用方法
    publicArrayList<Users> getAll() {
        ArrayList list = newArrayList();
        String sql ="select * from users";
        String[] parameters ={};
        DBUtil db = newDBUtil();
       ArrayList<HashMap> al = db.executeQuery2(sql, parameters);
        for(HashMapmap:al){            
            Users u = newUsers();
           u.setUserid(Integer.parseInt(map.get("userid").toString()));
           u.setUname(map.get("uname").toString());
           u.setEmail(map.get("email").toString());
           u.setPwd(map.get("pwd").toString());
           u.setGrade(Integer.parseInt(map.get("grade").toString()));
            list.add(u);           
        }
        return list;
    }
相关文章
相关标签/搜索