1. 程式人生 > >從IO 到框架(4)-Servlet + JDBC (Idea Maven)

從IO 到框架(4)-Servlet + JDBC (Idea Maven)

動態Web 應用的基礎程式碼。

關於IDE:最開始入門用Eclipse,但一用Idea 就立刻棄了Eclipse。Idea 相比來說更加智慧,除了佔記憶體多點以外,用Idea 體驗超好,遠超Eclipse。

關於Maven:學Maven 之前做專案都需要導Jar 包,比較麻煩而且可能有包版本衝突。有Maven 之後就爽多了!回不去了!它不僅用幾行程式碼配置代替了導包的步驟,還會自動地匯入很可能會用到的關聯包,可節省不少時間。

1)上篇博文寫的是靜態頁面,以下兩圖展示的是動態頁面相關技術和基本流程。



2)Web Server - Tomcat: 是由 Apache 組織開發的一個 Servlet/JSP 容器(也就是負責解析和執行JSP),由純 Java 開發完成的,若系統的負荷壓力不是太大的話也可以兼作 Web 伺服器(輕量級)。

Servlet 的Java 的、用來實現動態頁面的 規範,由應用伺服器(如Tomcat) 中的容器(Container) 來控制。

Tomcat 只支援J2EE 中的JSP以及Servlet規範,有的伺服器支援更多規範,如WebLogic 和WebSphere 都支援J2EE 13種規範(EJB )。

當訪問Tomcat 伺服器的某個靜態資源時,實際上在訪問Tomcat 配置的預設Servlet,url-pattern 為"/";

Tomcat 訪問順序:先找servlet, 沒有的話執行預設servlet 找靜態資源,還沒有的話返回404 等錯誤頁面

(預告:Struts2 框架就是一個大大的Servlet,會<load-on-startup>,提前初始化,1的優先順序最高。)

訪問tomcat出現java.lang.IllegalStateException No output folder錯誤解決方法
問題:tomcat分為安裝版和解壓縮版,解壓縮版如果解壓到安裝盤,在瀏覽器中訪問http://localhost:8080,可能會出現500錯誤,錯誤提示如下: 
localhost:8080 java.lang.IllegalStateException: No output folder 
原因如下:tomcat目錄沒有被讀寫的許可權,導致檔案不能被編譯到指定的工作目錄中。 
解決辦法: 

找到tomcat目錄,右鍵“屬性--->安全--->編輯”,找到Users,將“完全控制

”選項“允許”打鉤,應用。

配置Tomcat (第5步專案建立後):選單Run - Edit configurations - 左側欄Defaults - Tomcat Server - Local, 設定Application Server 和Open browser,Apply,如下圖;然後不用關此對話方塊,點左上角加號,新增Tomcat Server - Local - 設定Deployment,OK。




3)Servlet (Server Applet) 是Java Servlet的簡稱,稱為小服務程式或服務聯結器,用Java編寫的伺服器端程式,主要功能在於互動式地瀏覽和修改資料,生成動態Web內容。狹義的Servlet是指Java語言實現的一個介面,廣義的Servlet是指任何實現了這個Servlet介面的類。Servlet運行於支援Java的應用伺服器中。從原理上講,Servlet可以響應任何型別的請求,但絕大多數情況下Servlet只用來擴充套件基於HTTP協議的Web伺服器。

4)開始用Idea 建立Maven 專案:File - New - Project... - Maven - Create from archetype (勾選上) - webapp - Next。如下圖(第3步還有一個webapp 可選::org.apache.maven.archetypes:maven-archetype-webapp,這個模板更簡單,需要新建java 和resources 資料夾;2.3版的web.xml 裡很乾淨但2.4版之前是不支援EL表示式的,要換高版本或在jsp 頁面加上"<%@page isELIgnored="false" %>";pom自帶了junit dependency 依賴):


5)填寫GroupId 和 ArtifactId,一路Next(其間可修改專案名稱等),直到Finish,需等待Idea Run "Import change",完成後佈局如下圖(沒有java 資料夾的話,新建一個,然後在其上右鍵 - Mark Directory As - Sources Root);

點選"Enable Auto-Import",這樣每次修改Maven 的配置檔案pom.xml,如新增依賴等,就會自動執行匯入。

自動生成的web.xml 是2.4 版本,而且裡面有些至少暫時用不到的servlet, listen 等配置,需要刪掉。此模板應該可以修改的,尚未深究。



6)在pom.xml <plugins> 節點內新增以下外掛程式碼,新建的選項就會出現Servlet、Filter、Listener 這三個。如果沒有的話刪除這段程式碼再貼上即可。新增servlet, mysql-connector, jstl 等依賴。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.7</source>
    <target>1.7</target>
  </configuration>
</plugin>


<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.1.0</version>
</dependency>

另外Idea 不自動編譯釋出java 資料夾內的資原始檔,在pom 配置中的build 標籤內新增以下程式碼填上此坑

<resources>
  <resource>
    <directory>src/main/java</directory>
    <includes>
      <include>**/*.xml</include>
    </includes>
  </resource>
</resources>

7)建立前端頁面;新建Servlet 實現類,Idea 會自動在web.xml 生成servlet 節點,但servlet-mapping(對映) 需要手動寫上。

此Servlet 類繼承了HttpServlet,重寫父類的doGet() 和doPost() 方法(或Service() 方法),即可處理來自頁面的Get 或Post 請求。注意它是沒有主函式的,由Tomcat 內的容器呼叫才可執行。

<servlet>
    <servlet-name>UserServlet</servlet-name>
    <servlet-class>cn.rock.framework.controller.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>UserServlet</servlet-name>
    <url-pattern>/UserServlet</url-pattern>
</servlet-mapping>

8)Servlet 的執行過程

  • Form 表單的action, a 標籤的href 等可直接指向servlet 對映地址(即URL;也可指向靜態頁面資源),可用問號傳引數,Form 表單input 標籤內的name - value 引數一起打包提交;
  • Tomcat Connector監聽到瀏覽器發來的請求,解析出請求指向某個Servlet,然後把該請求交給它所在的Service的Container (Engine),Container 就會建立兩個物件:1) HttpServletResponse 2) HttpServletRequest (儲存頁面提交過來的URL和引數);
  • Container 根據request 傳來的URL 找到正確匹配的servlet,為此request 建立或指定一個servlet 執行緒,並將request 和response 物件作為引數傳給此servlet 執行緒;
  • Container 呼叫此servlet 的servcie() 方法,service() 方法根據請求型別呼叫 doGet() 或 doPost() 方法;
  • doGet() 或doPost() 可通過request.getParameter("name") 獲取傳來的引數,根據引數可分發請求、處理引數,與資料庫互動,若有需要傳給頁面的資訊,可用request.setAttribute("name", "value") 存到request. 
  • request 轉發(多數情況下)或重定向到jsp 頁面,jsp頁面可用jstl 和EL 表示式展示動態資料。
  • jsp 頁面被存在response 物件,servlet 執行緒結束,Container 將response 物件轉換為一個Http Response,傳送給瀏覽器,並刪除request 和response 物件。

9)建立資料庫連線:



10)接第8條第5點,servlet 與資料庫互動的具體過程:

  • doGet() 或doPost() 方法呼叫Service介面(其實現類為ServiceImpl),ServiceImpl 呼叫Dao介面(其實現類為DaoImpl);
  • JDBC(Java DataBase Connectivity):Java 操作資料庫的技術,是一套介面標準,很好實現了面向介面程式設計,多型應用;
    面向介面是面向物件的衍生。類似:電腦的USB 介面。
    程式設計最重要的是可讀性、可維護性、擴充套件性好,而不是功能。
    底層思想基本都是封裝、繼承、多型。
  • DaoImpl 直接與資料庫互動:
                String username = "root";
		String password = "root";
		String url = "jdbc:mysql://localhost:3306/mydb";//協議 ip 埠 資料庫
		String driver = "com.mysql.jdbc.Driver";//驅動
		
		//1、載入資料庫驅動 - 程式只要載入一次
		Class.forName(driver);
		
		//2、獲取資料庫的連線
		Connection conn = DriverManager.getConnection(url, username, password);
		
		//3、執行sql語句
		//準備一條sql語句
		String sql = "insert into student value(null, '小明', 20, 0, '1998-07-14', '計算機系', '北京市朝陽區')";
		//通過connection獲得Statement物件
		Statement statment = conn.createStatement();
		//statement物件傳輸sql語句
		//如果是增刪改  executeUpdate 返回值表示本次sql語句影響的行數
		//如果是查 executeQuery
		int result = statment.executeUpdate(sql);
		
		System.out.println("sql語句執行的結果:" + result);
		
		//4、關閉連線
		statment.close();
		conn.close();

11)至此,最基本的專案流程都過了一遍,之後就是在此基礎上不斷迭代升級。

12)升級1:提取資料庫配置檔案,在方法內處理異常、關閉資源,預處理sql 以避免sql 注入問題,提取資料庫連線工具類

        配置檔案(.properties .xml)作用:不需要編譯,可由維護人員直接在專案執行時修改;只修改配置檔案的內容就能全部修改為想要的資料。最主要的是不用修改程式碼,所以工作中配置檔案往往比java程式碼還要多。

升級2:在ServiceImpl 層引入事務(即多條sql 作為一個邏輯單元,要麼一起執行,要麼都不執行),以滿足現實需求。

升級3:使用 c3p0資料庫連線池,更高效使用資料庫連線。還有dbcp與druid 可選。

升級4:使用過濾器Filter,可過濾頁面、統一編碼等。(監聽器Listener 目前作用不大)

升級5:JavaScript 的Ajax 區域性重新整理技術,通過Ajax Engine 獲取xml 資料, 現在多用json;使用JQuery 比原生JS 要高效得多。

<script type="text/javascript" src="js/jquery-1.8.3.js"></script>
    <script>
        $(function () {
            $("input").blur(function () {
                var value = $(this).val();
                if ($.trim(value) == "") {
                    alert("Username can't be void");
                    return;
                }

                /*$.get("RegisterServlet", {"username": value}, function (data) {
                    if (data == 0) {
                        $("input").next().html("Yes");
                    } else {
                        $("input").next().html("No");
                    }
                });*/

                $.ajax({
                    url: "RegisterServlet",
                    data: {username: value},
                    success: function (data) {
                        if (data == 0) {
                            $("input").next().html("Yes");
                        } else {
                            $("input").next().html("No");
                        }
                    }
                })
            });

            //ajax to submit form
            $("button").click(function () {
                $.ajax({
                    type: "post",
                    url: $("form").attr("action"),
                    data: $("form").serialize(),
                    success: function () {

                    }
                });
            });
        });
        
    </script>