前言 我們最初的javaSE部分學習後,基本算是入門了,也熟悉了Java的語法和一些常用API,然後再深入到資料庫操作、WEB程式開發,漸漸會接觸到JDBC、Servlet/Jsp之類的知識,期間可能會接觸一兩個關係型資料庫,例如MySQL/Oracle等等。像前面的MyBatis部分,主要是針對J ...
前言
我們最初的javaSE部分學習後,基本算是入門了,也熟悉了Java的語法和一些常用API,然後再深入到資料庫操作、WEB程式開發,漸漸會接觸到JDBC、Servlet/Jsp之類的知識,期間可能會接觸一兩個關係型資料庫,例如MySQL/Oracle等等。像前面的MyBatis部分,主要是針對JDBC的進一步封裝,使得更適用於實際項目開發過程,但是JDBC、MyBatis或者Hibernate都是針對持久層資料庫操作,例如查詢、更新記錄等等,我們開發程式最終的展現對象是用戶,而用戶操作程式往往用的是什麼?各種各樣的瀏覽器,而不是通過我們後臺的這些測試代碼,用戶看不懂代碼,也不需要懂。用戶只需要點擊、需要輸入,比如點擊一個鏈接,跳轉到一個新頁面,頁面中的部分數據都是從資料庫中查詢獲取的;又或者是輸入一段文本,點擊提交按鈕,更新的是資料庫中的記錄。我們要理清的是,這些頁面的操作指令是怎樣傳遞到後臺伺服器,然後訪問到資料庫的;還有資料庫的數據是怎麼從後臺又傳回前端,怎樣顯示到頁面上的?
如果有學習過Servlet/Jsp相關內容,應該會對上面的問題多少有些理解。首先回顧下什麼是Servlet,Servlet是運行在我們伺服器上的Java程式,作用於中間層,即客戶端請求和伺服器之間,我們發送請求,控制資料庫、業務邏輯、做出響應,返回前端頁面數據等等都可以通過其實現。Servlet的生命周期:1.初始化調用init()方法,2.處理客戶端請求調用service()方法,3.結束程式調用destroy方法,4.最後垃圾回收。JSP本質上也是Servlet,項目啟動,Web容器將JSP的代碼編譯成JVM能夠識別的java類即Servlet。Jsp重點偏向於頁面的展示,應用html、CSS、JavaScript等前端技術在這裡都不成問題,而Servlet更傾向於後臺的業務邏輯、控制轉發等等。
SpringMVC是在Servlet基礎上進一步封裝開發的一套WEB層框架,所以如果能深入理清Servlet的相關內容,那麼很容易就可以上手SpringMVC,下麵我們先簡單回顧一下之前Servlet的實現過程。
Servlet篇
新建一個普通web工程或者maven web工程,通過繼承HttpServlet,創建我們自定義的Servlet,如下所示
package com.mmm.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyServletA extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //請求轉發,相當於一次請求 req.getRequestDispatcher("/a.jsp").forward(req, resp); //響應重定向,相當於二次請求,前一次請求設置的屬性值在頁面中將無法獲取到 //resp.sendRedirect("./a.jsp"); //這裡往往還要通過持久層對象訪問資料庫,獲取或者更新數據 //獲取到的數據通過設置屬性,然後在前端Jsp頁面可以通過el表達式之類的方法拿到然後渲染樣式展示出來 } }
這裡的/a.jsp,代表Jsp頁面路徑,為web文件根目錄下例如webapp下,所以我們在webapp下簡單創建a.jsp如下
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>a.jsp</title> </head> <body> 這是a.jsp </body> </html>
然後在web文件夾下WEB-INF文件夾下web.xml中<web-app></web-app>節點內添加如下內容
<servlet> <servlet-name>MyServletA</servlet-name> <servlet-class>com.mmm.servlet.MyServletA</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServletA</servlet-name> <url-pattern>/a.do</url-pattern> </servlet-mapping>
這裡的<servlet-name>的值在<servlet>和<servlet-mapping>中要保持一致,<servlet-class>即為我們前面自定義的Servlet全名(含包名),<url-pattern>用於匹配我們在地址欄輸入的url地址。例如這裡通過localhost:8080/servlet-web/a.do就可以匹配到該Servlet,從而運行到該Servlet中的相關方法,這裡會請求轉發到a.jsp,如下圖所示。
上面為一個最基本的從前端http請求到後臺伺服器,運行Servlet後,返回前端視圖的過程。但是實際情況下,前端的請求不會是這樣簡單拿回一個靜態無數據的頁面,也不會只有一個,舉個例子,如果上面a.do對應一個增加一條商品數據的操作,即在我們自定義的MyServlet中doPost()方法里執行添加操作,那麼如果還有刪改查操作,按照這裡的路子,我們需要再定義MyServletB、MyServletC、MyServletD,然後web.xml添加3段對應的Servlet節點定義,再繼續拓展,我們不止對商品進行增刪改查,還有員工、銷售記錄等等進行操作,這樣下去,我們得定義和配置多少個Servlet,有的人想到辦法,例如商品的操作路徑匹配都是a.do,然後加個參數判斷,及路徑後加上?action=add或者?action=del等等,這樣同一類對象的操作我們將其統一匹配到同一個Servlet,在Servlet的方法內部再去根據具體的action操作類型去判斷到底要執行哪種操作(運行哪段業務邏輯)。
SpirngMVC更是將這種思想進化到了極致,我們在web,xml只定義有且只有一個Servlet,這個Servlet能匹配到所有的正常請求,然後可以根據路徑精確解析到具體的執行某個類的某個方法,這裡的類即控制層Controller,例如一個商品的相關操作,我們定義一個商品Controller類,類中定義各種操作方法,需要訪問資料庫的話,往往是通過Service層對象去調用持久層的代碼實現資料庫操作。下麵就實例一段單獨通過SpringMVC來實現中間控制層效果的小案例。
SpringMVC篇
為了方便管理jar包,這裡我們可以新建一個maven web項目,pom依賴可參考前面的環境搭建篇,這裡同Servlet對比,我們僅需要一個Java類也就是上面提到的controller,然後是一個指定路徑下的jsp文件,最後稍微修改一下web.xml,這三步即可簡單過一遍SpringMVC的基本運行過程。下麵分別詳細寫出這三步的內容。
DemoController.java
package com.mmm.web; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("demo") public class DemoController { @RequestMapping(value="/toPage") public String toPage() { return "page"; } }
從上往下,首先@Controller註解屬於Spring系列組件bean註解之一,對應web表現層的組件,類似的還有代表業務邏輯層的@Service,代表資料庫訪問層的@Repositoty,通用組件@Component等等,實際項目中,層與層之間類對象還會相互調用,基於Spring容器的IOC及依賴註入,我們又還會接觸到@Autowired,@Autowired等等註解。在這裡我們可以簡單理解為通過@Controller註解,Spring會識別並實例化這個bean,這個類對象的創建和管理將交由Spring容器去控制。
然後@RequestMapping("demo"),看英文單詞意思應該不難理解,Request請求,Mapping映射,請求映射,通過我們客戶端例如瀏覽器那邊過來的http請求,前面我們用過的Servlet會通過配置url匹配到訪問路徑從而匹配到相應的Servlet中,而在這裡類似,SpringMVC會根據我們的訪問路徑匹配到相應的Contoller中的相應方法,是的,這裡還會進一步精確匹配到方法。下麵@RequestMapping(value="/toPage")即方法名的映射,例如這裡把類和方法的映射名組合起來即為demo/toPage,在本例中,我們通過localhost:8080/spring-mvc/demo/toPage,即可匹配到這個DemoController的toPage方法中執行。
可以看到方法的返回值是String字元串類型,這裡可以理解為用於獲取視圖頁面路徑。下麵結合Spring MVC配置文件講解。
application-mvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 自動掃描開啟 --> <context:component-scan base-package="com.mmm.web" /> <mvc:annotation-driven/> <!-- Spring MVC視圖解析配置--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean> </beans>
這裡的<context:component-scan base-package="com.mmm.web" />即用於Spring掃描識別bean註解,例如剛剛講到的@Controller,而<mvc:annotation-driven/>則用於掃描SpringMVC相關特定註解,例如這裡@RequestMapping等等。
下麵的視圖解析配置即結合剛剛上面講到的視圖頁面路徑,prefix和suffix分別為首碼和尾碼的意思,結合前面的controller中方法,即頁面請求轉發路徑的統一前尾碼,前面controller中方法的返回值為"page",那麼組合前尾碼,即為/WEB-INF/views/page.jsp,而這個路徑對應哪裡,如下圖所示。
所以我們要在這裡創建一個jsp文件,views文件夾也是。
最後在web.xml中加入如下內容
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/application-mvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
我們會發現這裡也是配置的Servlet,即org.springframework.web.servlet.DispatcherServlet,只不過只配置了這單獨一個,映射路徑匹配通用請求,同時init-param設置初始參數即我們SpringMVC配置文件路徑。這樣一來,我們請求都會被SpringMVC系列組件接受、解析路徑、分配到相應的Controller的相應方法。
上面步驟結束後,我們發佈項目並啟動Tomcat伺服器,在瀏覽器地址欄輸入http://localhost/spring-mvc/demo/toPage,看到如下頁面,即為成功
小結
通過上面基礎的實例,我們能一步步理解從Servlet到web框架SpringMVC的使用,實際開發中同樣遵循這些基本規則,只不過事更多的業務邏輯、視圖文件等等,比如這裡講到頁面跳轉中的請求轉發,那麼是否類似Servlet還有響應重定向,還有,Controller中方法我們不一定是跳轉到頁面,也可以直接傳遞JSON數據返回前端,以及我們前面學習到的MyBatis封裝持久層,那麼我們在這裡怎麼與持久層連接起來去訪問資料庫查詢或者更新數據,還有到底什麼是業務邏輯,等等這些都是我們需要考慮的問題,後面準備分別以具體實例展開說明,歡迎一起探討。