Servlet與JSP以及MVC設計模式

一、設計模式是什麼?

Servlet(Server + Applet):java服務器端小程序
用java編寫的服務器端程序,接收用戶的請求並作出響應.

閱讀JavaEE_6_API幫助文檔.chm 中servlet的含義

上面的文檔包含了JavaEE的全部技術

也可以查看servlet的獨立文檔(只包含servlet技術的api)

查api源文檔:
This interface defines methods to initialize a servlet, to service requests, and to remove a servlet from the server. These are known as life-cycle methods and are called in the following sequence:

The servlet is constructed, then initialized with the init method.
Any calls from clients to the service method are handled.
The servlet is taken out of service, then destroyed with the destroy method, then garbage collected and finalized.

二、如何寫Servlet?

1)新建web工程
1.起一個web工程名
2.選J2EE1.4版本(高版本的多了個EJB,目前不需要,所以不選高版本)

Web工程的目錄結構

ShanshiWeb(Web工程名)
    --src(java源文件)
    --WebRoot(web應用程序)
        --頁面文件(html、jsp...)
        --WEB-INF
            --lib(jar包放到這,比如ojdbc6.jar)
            --classes(java字節碼文件)
            --web.xml(web部署描述符文件 用來配置web應用程序的信息)

2)如何編寫第一個servlet?

需求:服務器向客戶端輸出 Hello,Servlet!!!

總共分三步

1.導包

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;


2.繼承HttpServlet 抽象類 重寫doGet() 和doPost();


public class HelloServlet extends HttpServlet{

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

        PrintWriter out = response.getWriter();

        out.println("Hello,Servlet!!!");

        out.flush();
        out.close();
    }

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

        this.doGet(request, response);
    }
}


3.在web.xml配置Servlet


servlet配置如下
  <servlet>
   <servlet-name>HelloWorldServlet</servlet-name>
   <servlet-class>com.servlet.HelloWorldServlet</servlet-class>
  </servlet>

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

3)如何運行第一個Servlet?
運行普通的java程序,需要JRE就可以了,運行jsp/servlet程序,需要web服務器.
常用的Web服務器

1.tomcat (apache 開源 免費) 準確的說叫JSP/Servlet容器

2.jboss(開源 紅帽)

3.WebSphere(IBM 支持J2EE的13個規範)

4.WebLogic(BEA 被oracle收購了 用的最多 支持J2EE規範 的13個技術規範)

5.GlassFish(sun公司 被oracle收購了)

6.resin…

7.jetty

我們使用tomcat

前提:配置web服務器

1.去官方網站下載 http://tomcat.apache.org/

有安裝版的,有綠色版的,建議下載綠色版!!!

2.直接把tomcat解壓縮到一個目錄下就ok了

注意不要放到帶中文或帶空格的路徑下,比如Program Files

如果想在MyEclipse下使用Tomcat,需要在MyEclipse配置一下

Windows-Preferences–MyEclipse–Servers
–tomcat—tomcat6.x 選中tomcat服務器根目錄後 點擊Enable
然後apply and ok就可以了

1.部署

Web應用程序 放到web服務器上(tomcat)

(1)手工部署

把WebRoot文件夾拷貝到了 tomcat 下webapps裏,並且把WebRoot更名爲和Web Project名一樣的名字

(2)使用MyEclipse工具部署

底層做了什麼?

把WebRoot文件夾拷貝到了 tomcat 下webapps裏,並且把WebRoot更名爲和Web Project名一樣的名字,相當於手工部署,只不過更加方便.

2.啓動tomcat

必須配置JAVA_HOME

因爲tomcat是java寫的程序,依賴JRE, 不配置JAVA_HOME, tomcat啓動時一閃而過

(1)使用MyEclipse工具

(2)在控制檯下使用s tartup.bat命令

如果在控制檯下敲命令啓動還需要配置其他兩個環境變量

PATH 加入D:\apache-tomcat-8.0.23\bin;以前的內容

CATALINA_HOME=D:\apache-tomcat-8.0.23

告訴startup.bat這個啓動程序tomcat在哪裏?

使用兩個tomcat演示

建議不配置CATALINA_HOME和PATH,這樣點哪個tomcat的startup.bat就是啓動哪個

shutdown.bat 關閉tomcat

3.訪問

在瀏覽器中輸入

http://localhost:8080/HuangHuaiMiddle/HelloServlet

http://tomcat服務器的ip地址:端口號/Web應用程序名/頁面名或Servlet名

另:默認訪問歡迎頁面 在web.xml 裏面配置

<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>

補充:Servlet3(使用註解配置Servlet)
注意: 如果想使用Servlet3必須注意如下兩步
1.創建工程的時候 選JavaEE6規範
2.Tomcat要使用7.0+(含7.0)

@WebServlet(name=”HelloServlet”,urlPatterns={“/aaa”,”/bbb”})
public class HelloServlet extends HttpServlet {
}


@WebServlet(“/abc”)
public class HelloServlet extends HttpServlet {
}

使用管理員權限訪問tomcat

tomcat6:

tomcat-users.xml
在</tomcat-users>前面加入下面兩句話保存後,重啓tomcat即可

<role rolename="manager"/>
<user username="tomcat" password="tomcat" roles="manager"/>

tomcat7\8:

tomcat-users.xml
在</tomcat-users>前面加入下面兩句話保存後,重啓tomcat即可

<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="manager-gui"/>

三、編寫第一個Servlet(手工)

編譯HelloServlet.java時找不到依賴的類,因爲javac默認把j2se 的jar包添加到classpath下,
其他的jar包,需要手工添加,所以必須把servlet-api.jar添加到classpath下

CLASSPATH=.;C:\Program Files\Java\jdk1.8.0_31\lib;D:\apache-tomcat-6.0.44\lib\servlet-api.jar

四、如何調錯?

經常出現的錯誤之404—-頁面沒找到

頁面沒找到或請求的Servlet不存在

經常出現的錯誤之500—-服務器內部錯誤

自己寫的Servlet代碼錯誤,具體錯誤看報錯描述,看自己寫的代碼的第一行。

五、tomcat的兩種服務器模式

1.running模式(運行模式)

2.debug模式(調試模式)

debug模式 會幫你重新部署和加載

區別1:
Running模式不能進行斷點調試,debug模式 可以進行斷點調試
區別2:
Running模式類和配置文件變了以後 只會從新部署、不會從新加載類和配置文件
Debug模式 類和配置文件變了以後 會從新部署、從新加載

小技巧1

如果想查看是否重新部署了,去webapps/web應用/WEB-INF/classes 用反編譯工具看一下
但是重新部署 只是 硬盤上修改了 我們真正訪問的 是 內存中的對象

小技巧2:
如果沒有幫你從新加載 可以在web.xml 打兩個空格 工具會幫你從新加載 相當於重啓了服務器 不要隨便重啓服務器

因爲實際工作中 一重啓服務器 可能要1分鐘多鍾

看到這個界面證明服務器已經從新加載了類文件,這樣再訪問就是更改後的類了
補充:配置servlet url-pattern時一定不能配置成/和*.jsp

/

/ 爲缺省的servlet,即當請求的servlet都沒有匹配上時,使用缺省的servlet處理

參見tomcat\conf\web.xml

default
org.apache.catalina.servlets.DefaultServlet


default
/

如果用戶自己在項目下的web.xm中也配置一個 url-pattern爲/的servlet,這樣會把tomcat默認提供的缺省的servlet給覆蓋掉,這樣當訪問的資源(jsp或servlet)不存在時,就不會給你提供404的錯誤提示了.
*.jsp同理

相對路徑問題

六、亂碼問題

1.服務器給客戶端寫的時候亂碼

爲什麼有亂碼

編碼和解碼方式不一致

編碼: 把看的懂得明文轉換成看不懂的密文.

解碼: 把看不懂的密文轉換成看的懂的明文.

解決方法:
response.setContentType(“text/html;charset=utf-8”);

作用:一.設置服務器響應類型 服務器向客戶端產生一個文本或html文件

二.charset=utf-8的作用
1.設置服務器響應的編碼方式(即生成的html頁面的編碼方式)
2.提示瀏覽器使用該編碼方式 解碼

2.客戶端給服務器傳數據時

解決方法:
1.method=”post”時,在servlet中加入request.setCharacterEncoding(“utf-8”);//提示tomcat使用utf-8解碼發過來的數據
2.tomcat6及之前,上述解決方法只對post方式有效,tomcat6之後,method=”get”的方式就不用修改了,服務器默認get也用post的方式處理。
tomcat6,如果method=”get”時,需要修改tomcat\conf\server.xml 的71行,加入URIEncoding=”utf-8”即可。
7.0以上不用修改。

六、爲什麼有Servlet?

1.Servlet的最初目的
以前最初servlet 是用來動態產生html頁面(時間、用戶名) 但是這樣很麻煩

演示代碼

    PrintWriter out = response.getWriter();

    out.println("<html>");
    out.println("<head>");
    out.println("<title>測試</title>");
    out.println("</head>");

    out.println("<body>");
    out.println("當前時間:" + new Date());
    out.println("</body>");
    out.println("</html>");

    out.flush();
    out.close();

這樣寫非常繁瑣,不太好!

所以爲了簡化Servlet輸出,有了JSP(Java Server Pages)

演示代碼 test.jsp

<body>
    <%=new Date() %>
</body>

1.Servlet的現在用途
當做控制器

相當於項目經理

職責: 起控制和調配大局的作用

1.填充數據(接收客戶端請求)
2.調用業務邏輯 (添加商品種類)
3.轉發視圖(jsp)

開發過程中的兩種模型

model1= jsp + javabean (已被淘汰)
model2 = jsp + javabean + servlet
model2模型更符合MVC設計模式,符合OCP原則,符合高內聚,低耦合的設計。

MVC設計模式

蓋一個樓

架構模式(考慮整體 一棟樓的整體輪廓 架子 如何搭起來 考慮宏觀)

設計模式(考慮局部)

1.戶型如何設計(兩室一廳、三室一廳) 2.暖氣管道怎麼佈置 3.牆體保溫層如何設計

一.M Model 模型
javabean

(1)業務模型 Service+Dao
(2)數據模型 VO

二.V View 視圖

JSP 向客戶端顯示信息

三.C Controller 控制器 Servlet

1.填充數據
2.調用業務邏輯
3.轉發視圖jsp

model2=jsp(V)+javabean(M)+servlet(C)

三層架構

三層架構
持久層:DAO+VO(實體類) 功能把數據持久化(保存)到數據庫
業務層:Service
表現層:Controller + JSP

“強大”的Servlet

初學者容易犯的錯 直接把業務邏輯代碼 寫到 控制器中
如果把業務邏輯直接寫到控制器中,相當於項目經理直接幹底層的活,這種寫法叫 “強大”的servlet

七、Servelt生命週期(面試常考)和創建Servlet的時機

創建servlet時機有兩個

1.第一次訪問Servlet的時候創建(演示servlet生命週期)

1.類加載

2.實例化一個servlet 創建Servlet對象

以前調用方法是程序員在main方法中主動調用的

public static void main(String[] args){
HelloServlet hs = new HelloServlet();
hs.doPost();
}

現在爲什麼沒有創建對象和調用方法 該方法也能執行呢?

是因爲現在的創建對象和調用方法 都是tomcat容器(jsp/servlet容器)幫你完成的

3.init方法

做一些初始化工作..比如從web.xml文件中讀取配置信息

4.service方法 //用來處理客戶端請求 判斷請求類型get 調用doGet,post 調用doPost 在該方法中完成

tomcat會爲每一個客戶端創建一個單獨的線程 在該線程中調用service()方法爲客戶端服務

if(客戶端請求是post){
this.doPost(request,response);
}else if(get請求){
this.doGet(request,response);
}

5.destroy方法 (銷燬方法)

程序員能主動調用destroy方法來銷燬servlet對象嗎?

不能,這些方法都是tomcat容器調用的

destroy方法 什麼時候會被調用

(1)web服務器關閉時
(2) web應用程序關閉時(或被移除時)

(3)如果一個Servlet長時間沒有訪問 調用destory方法

具體執行策略:會先把對象 保存到文件中(使用對象序列化技術) 等再訪問該servlet對象時使用返序列化技術恢復Servlet
這樣Servlet的狀態就不會被丟失了(比如servlet中的實例變量 就不會被清零了)

6.類卸載

演示代碼:

package com.servlet;

import java.io.IOException;
import java.io.PrintWriter;

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

//演示servlet生命週期
public class LifeCycleServlet extends HttpServlet {

static {
    System.out.println("1.LifeCycleServlet類加載");
}

public LifeCycleServlet() {
    super();
    System.out.println("2.創建了Servlet對象");
}

@Override
public void init(ServletConfig config) throws ServletException {
    System.out.println("3.(1)帶參數的init方法執行");
    super.init(config);
    /*String encoding = config.getInitParameter("encoding");
    System.out.println(encoding);*/
}

public void init() throws ServletException {
    System.out.println("3.(2)不帶參數的 init方法被調用");
}



protected void service(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {

    System.out.println("4.service方法被調用");
}

@Override
protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {

    System.out.println("in doGet");
    PrintWriter out = response.getWriter();

    out.println("hello,servlet!");
    out.flush();
    out.close();
}

@Override
protected void doPost(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {

    System.out.println("in doPost");
    this.doGet(request, response);
}

public void destroy() {
    super.destroy();
    System.out.println("Servlet對象被銷燬");

    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {

        e.printStackTrace();
    }
}

}

重點:只有一個Servlet對象

對於同一個Servlet類的請求 只有一個Servlet對象

相當於每來一個新的請求 容器會爲這個新的請求啓動一個線程 並且在該線程內調用
service()方法

執行過程:

第一次訪問時 先類加載、創建對象、調用init方法初始化、service方法

第二次再訪問 前面的都不執行了,直接執行service方法

二. web服務器啓動時創建

如果想讓servlet啓動時就被創建

<servlet-name>LifeCycleServlet</servlet-name>
<servlet-class>com.servlet.LifeCycleServlet</servlet-class>

 <!-- 如果想讓servlet對象 在服務器啓動時就被創建 可以在這配置 -->
<load-on-startup>1</load-on-startup>

十一.如何在servlet裏獲取web.xml裏的初始化參數

在web.xml配置 需求變了 可以不修改代碼 符合OCP

1.首先在web.xml配置

<servlet-name>LifeCycleServlet</servlet-name>
<servlet-class>com.servlet.LifeCycleServlet</servlet-class>

 <init-param>
    <param-name>encoding</param-name>
    <param-value>utf-8</param-value>
 </init-param>

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

2.然後在servlet的init(ServletConfig config)方法中讀取web.xml中的初始化參數

public void init(ServletConfig config) throws ServletException {
super.init(config);

    String encoding = config.getInitParameter("encoding");
    System.out.println(encoding);
}

八、servlet相關類和接口

1.Servlet接口

2.GenericServlet抽象類 實現了Servlet

3.HttpServlet抽象類 繼承了GenericServlet

九、Servlet多線程安全問題

由於對於同一個Servlet類的請求(比如HelloServlet),只會創建一個Servlet對象。Tomcat
是對於一個客戶端的請求,起一個單獨的線程處理,在該線程內調用service方法,所以Servlet
有多線程安全問題.

代碼演示:

public class UnSafeServlet extends HttpServlet {

private int sum = 0;//共享資源

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

    PrintWriter out = response.getWriter();

    sum++;

    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {

        e.printStackTrace();
    }

    out.println(sum);//第一個客戶端期望看到1 實際看到的是2

}

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

    this.doGet(request, response);
}

}

如何解決

1.實現SingleThreadModel

public class UnSafeServlet extends HttpServlet implements SingleThreadModel {

這時候對於一個新的客戶端請求,tomcat會爲其創建一個新的Servlet對象爲它服務,所以不會出現多線程安全問題。

不推薦 100W個用戶同時訪問 創建了100W個對象 內存溢出

2.同步代碼塊

不推薦 太慢 一個Servlet執行完 才能執行另外一個

3.不要在Servlet中寫實例變量

附:MyEclipse2014 如何修改Servlet模板
默認創建的Servlet帶註釋,每次創建都需要刪除比較麻煩,如何修改Servlet模板

1.找到MyEclipse安裝路徑下的plugins文件夾
C:\Users\Administrator.USER-20150213PV\AppData\Local\MyEclipse Professional 2014\
Plugins

2.搜索

com.genuitec.eclipse.wizards

3.使用winrar打開後 ,模板文件在templates文件夾下

4.Servlet.java就是Servlet的模板文件,解壓出來一份,然後修改完模板後,

直接把修改後的文件拖拽到rar裏替換以前的Servlet.java文件

5.重啓MyEclipse即可

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章