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;
    }
相關文章
相關標籤/搜索