從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>