什麼是SpringMVC?
SpringMVC是Spring家族的一員,Spring是將現在開發中流行的元件進行組合而成的一個框架!它用在基於MVC的表現層開發,類似於struts2框架
為什麼要使用SpringMVC?
我們在之前已經學過了Struts2這麼一個基於MVC的框架....那麼我們已經學會了Struts2,為啥要要學習SpringMVC呢???
下面我們來看一下Struts2不足之處:
- 有漏洞【詳細可以去搜尋】
- 執行速度較慢【比SpringMVC要慢】
- 配置的內容較多【需要使用Struts.xml檔案】
- 比較重量級
基於這麼一些原因,並且業內現在SpringMVC已經逐漸把Struts2給替代了...因此我們學習SpringMVC一方面能夠讓我們跟上業界的潮流框架,一方面SpringMVC確實是非常好用!
可以這麼說,Struts2能做的東西,SpringMVC也能夠做....
回顧Struts2開發
在Struts2中,我們的開發特點是這樣的:
- Action類繼承著ActionSupport類【如果要使用Struts2提供的額外功能,就要繼承它】
- Action業務方法總是返回一個字串,再由Struts2內部通過我們手寫的Struts.xml配置檔案去跳轉到對應的view
- Action類是多例的,接收Web傳遞過來的引數需要使用例項變數來記住,通常我們都會寫上set和get方法
Struts2的工作流程
- Struts2接收到request請求
- 將請求轉向我們的過濾分批器進行過濾
- 讀取Struts2對應的配置檔案
- 經過預設的攔截器之後建立對應的Action【多例】
- 執行完業務方法就返回給response物件
SpringMVC快速入門
匯入開發包
前6個是Spring的核心功能包【IOC】,第7個是關於web的包,第8個是SpringMVC包
- org.springframework.context-3.0.5.RELEASE.jar
- org.springframework.expression-3.0.5.RELEASE.jar
- org.springframework.core-3.0.5.RELEASE.jar
- org.springframework.beans-3.0.5.RELEASE.jar
- org.springframework.asm-3.0.5.RELEASE.jar
- commons-logging.jar
- org.springframework.web-3.0.5.RELEASE.jar
- org.springframework.web.servlet-3.0.5.RELEASE.jar
編寫Action
Action實現Controller介面
public class HelloAction implements Controller {
@Override
public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
return null;
}
}
複製程式碼
我們只要實現handleRequest方法即可,該方法已經說了request和response物件給我們用了。這是我們非常熟悉的request和response物件。然而該方法返回的是ModelAndView這麼一個物件,這是和Struts2不同的。Struts2返回的是字串,而SpringMVC返回的是ModelAndView
ModelAndView其實他就是將我們的檢視路徑和資料封裝起來而已【我們想要跳轉到哪,把什麼資料存到request域中,設定這個物件的屬性就行了】。
public class HelloAction implements Controller {
@Override
public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView = new ModelAndView();
//跳轉到hello.jsp頁面。
modelAndView.setViewName("/hello.jsp");
return modelAndView;
}
}
複製程式碼
註冊核心控制器
在Struts2中,我們想要使用Struts2的功能,那麼就得在web.xml檔案中配置過濾器。而我們使用SpringMVC的話,我們是在web.xml中配置核心控制器
<!-- 註冊springmvc框架核心控制器 -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--到類目錄下尋找我們的配置檔案-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:hello.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<!--對映的路徑為.action-->
<url-pattern>*.action</url-pattern>
</servlet-mapping>
複製程式碼
建立SpringMVC控制器
我們在hello.xml配置檔案中把SpringMVC的控制器建立出來
<!--
註冊控制器
name屬性的值表示的是請求的路徑【也就是說,當使用者請求到/helloAction時,就交由HelloAction類進行處理】
-->
<bean class="HelloAction" name="/hello.action"></bean>
複製程式碼
訪問
當我們在瀏覽器訪問http://localhost:8080/hello.action
的時候,Spring會讀取到我們的訪問路徑,然後對比一下我們的配置檔案中是否有配置/hello.action
,如果有。那麼就交由對應的Action類來進行處理。Action類的業務方法將其請求輸出到hello.jsp頁面上。
SpringMVC工作流程
- 使用者傳送請求
- 請求交由核心控制器處理
- 核心控制器找到對映器,對映器看看請求路徑是什麼
- 核心控制器再找到介面卡,看看有哪些類實現了Controller介面或者對應的bean物件
- 將帶過來的資料進行轉換,格式化等等操作
- 找到我們的控制器Action,處理完業務之後返回一個ModelAndView物件
- 最後通過檢視解析器來對ModelAndView進行解析
- 跳轉到對應的JSP/html頁面
上面的工作流程中,我們是沒有講過對映器,介面卡,檢視解析器這樣的東西的。但是SpringMVC的環境還是被我們搭建起來了。
下面就由我來一個一個來介紹他們是有什麼用的!
對映器
我們在web.xml中配置規定只要是.action為字尾的請求都是會經過SpringMVC的核心Servlet。
當我們接收到請求的時候,我們發現是hello.action,是會經過我們的核心Servlet的,那麼核心Servlet就會去找有沒有專門的Action類來處理hello.action請求的。
也就是說:對映器就是用於處理“什麼樣的請求提交給Action”處理。【預設可省略的】.....
其實我們在快速入門的例子已經配置了:name屬性就是規定了hello.action到HelloAction控制器中處理!
<!--
註冊控制器
name屬性的值表示的是請求的路徑【也就是說,當使用者請求到/helloAction時,就交由HelloAction類進行處理】
-->
<bean class="HelloAction" name="/hello.action"></bean>
複製程式碼
對映器預設的值是這樣的:
<!-- 註冊對映器(handler包)(框架)【可省略】 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
</bean>
複製程式碼
當然了,上面我們在建立控制器的時候【也就是HelloAction】可以不使用name屬性來指定路徑,可以使用我們的對映器來配置。如以下的程式碼:
<bean class="HelloAction" id="helloAction"></bean>
<!-- 註冊對映器(handler包)(框架) -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.action">helloAction</prop>
</props>
</property>
</bean>
複製程式碼
當我們需要多個請求路徑都交由helloAction控制器來處理的話,我們只要新增prop標籤就行了!
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.action">helloAction</prop>
<prop key="/bye.action">helloAction</prop>
</props>
</property>
</bean>
複製程式碼
介面卡
當我們對映器找到對應的Action來處理請求的時候,核心控制器會讓介面卡去找該類是否實現了Controller介面。【預設可省略的】
也就是說:介面卡就是去找實現了Controller介面的類
<!-- 介面卡【可省略】 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
複製程式碼
檢視解析器
我們把結果封裝到ModelAndView以後,SpringMVC會使用檢視解析器來對ModelAndView進行解析。【預設可省略的】
也有一種情況是不能省略的。我們在快速入門的例子中,將結果封裝到ModelAndView中,用的是絕對真實路徑!如果我們用的是邏輯路徑,那麼就必須對其配置,否則SpringMVC是找不到對應的路徑的。
那什麼是邏輯路徑呢???我們在Struts2中,返回的是"success"這樣的字串,從而跳轉到success.jsp這樣的頁面上。我們就可以把"success"稱作為邏輯路徑。
在Action中返回hello,hello是一個邏輯路徑。需要我們使用檢視解析器把邏輯路基補全
public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView = new ModelAndView();
//跳轉到hello.jsp頁面。
modelAndView.setViewName("hello");
return modelAndView;
}
複製程式碼
如果不使用檢視解析器的話,那麼就會找不到頁面:
因此,我們需要配置檢視解析器
<!--
如果Action中書寫的是檢視邏輯名稱,那麼檢視解析器就必須配置
如果Action中書寫的是檢視真實名稱,那麼檢視解析器就可選配置
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 路徑字首 -->
<property name="prefix" value="/"/>
<!-- 路徑字尾 -->
<property name="suffix" value=".jsp"/>
<!-- 字首+檢視邏輯名+字尾=真實路徑 -->
</bean>
複製程式碼
控制器
ParameterizableViewController
我們在之前使用Struts2的時候,如果僅僅要跳轉到某個WEB-INF/JSP頁面,也要寫業務方法。而業務方法也僅僅是返回一個簡單的字串。
如下的程式碼:
public String home(){
return "home";
}
複製程式碼
<package name="nsfw-home" namespace="/nsfw" extends="struts-default">
<action name="nsfw_*" class="zhongfucheng.nsfw.HomeAction" method="{1}">
<result name="{1}">/WEB-INF/jsp/nsfw/{1}.jsp</result>
</action>
</package>
複製程式碼
在SpringMVC中,如果僅僅是跳轉到某個檢視上,我們可以省略該Action和業務方法。配置的Action只要繼承著ParameterizableViewController這個類就行了!
<!-- 專用於jsp到jsp/html的轉發控制器 -->
<bean name="/ok.action" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<!-- 轉發到真實檢視名 -->
<property name="viewName" value="/WEB-INF/ok.jsp"/>
</bean>
複製程式碼
- 2017年9月26日15:57:45 現在看來, 好像還是在方法上寫更好。我覺得統一管理起來會更加方便
AbstractCommandController
到目前為止,我們都沒有將SpringMVC是怎麼接收web端傳遞過來的引數的。
我們在Struts2中,只要在Action類上寫對應的成員變數,給出對應的set和get方法。那麼Struts2就會幫我們把引數封裝到對應的成員變數中,是非常方便的。
那麼我們在SpringMVC中是怎麼獲取引數的呢????我們是將Action繼承AbstractCommandController這麼一個類的。
public class HelloAction extends AbstractCommandController {
@Override
protected ModelAndView handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, BindException e) throws Exception {
return null;
}
}
複製程式碼
在講解該控制器之前,首先我們要明白SpringMVC控制器一個與Struts2不同的地方:SpringMVC的控制器是單例的,Struts2的控制器是多例的!
也就是說:Struts2收集變數是定義成員變數來進行接收,而SpringMVC作為單例的,是不可能使用成員變數來進行接收的【因為會有多個使用者訪問,就會出現資料不合理性】!
那麼SpringMVC作為單例的,他只能通過方法的引數來進行接收對應的引數!只有方法才能保證不同的使用者對應不同的資料!
實體
實體的屬性要和web頁面上的name提交過來的名稱是一致的。這和Struts2是一樣的!
public class User {
private String id;
private String username;
public User() {
}
public User(String id, String username) {
this.id = id;
this.username = username;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", username='" + username + '\'' +
'}';
}
}
複製程式碼
提交引數的JSP
<form action="${pageContext.request.contextPath}/hello.action" method="post">
<table align="center">
<tr>
<td>使用者名稱:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>編號</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交">
</td>
</tr>
</table>
</form>
複製程式碼
配置Action處理請求
<bean class="HelloAction" id="helloAction"></bean>
<!-- 註冊對映器(handler包)(框架) -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.action">helloAction</prop>
</props>
</property>
</bean>
複製程式碼
Action接收引數
public class HelloAction extends AbstractCommandController {
/*設定無參構造器,裡邊呼叫setCommandClass方法,傳入要封裝的物件*/
public HelloAction() {
this.setCommandClass(User.class);
}
/**
*
* @param httpServletRequest
* @param httpServletResponse
* @param o 這裡的物件就表示已經封裝好的了User物件了。!
* @param e
* @return
* @throws Exception
*/
@Override
protected ModelAndView handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, BindException e) throws Exception {
User user = (User) o;
System.out.println(user);
ModelAndView modelAndView = new ModelAndView();
//跳轉到ok.jsp
modelAndView.setViewName("/WEB-INF/ok.jsp");
//將資料封裝到ModelAndView中
modelAndView.addObject("USER", user);
return modelAndView;
}
}
複製程式碼
效果:
小總結
Struts2和SpringMVC存值的區別:
- SpringMVC的工作流程:
- 使用者傳送HTTP請求,SpringMVC核心控制器接收到請求
- 找到對映器看該請求是否交由對應的Action類進行處理
- 找到介面卡看有無該Action類
- Action類處理完結果封裝到ModelAndView中
- 通過檢視解析器把資料解析,跳轉到對應的JSP頁面
- 控制器介紹了兩種:
- ParameterizableViewController
- 能夠實現跳轉到WEB-INF下資源,並不用寫處理方法
- AbstractCommandController
- 可以實現對引數資料的封裝
- ParameterizableViewController
如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y