原創聲明:本文為作者原創,未經允許不得轉載,經授權轉載需注明作者和出處
本帖子介紹ssm框架之一的springmvc,網上的資料常常把它和struts進行對比,為了掌握一個框架,了解它的原理,知曉與它對等框架之間的區別和聯系很有必要,這里提供一個分析springmvc和struts很好的一篇博客:http://blog.csdn.net/gstormspire/article/details/8239182
對于springmvc(也稱之為Spring Web MVC),其整體工作流程我畫了一個草圖,如下
springmvc有兩種配置方式,一種是基于springmvc.xml文件進行配置,一種是基于注解的配置,當然后者更廣泛的被應用,本篇將介紹的是xml版配置,之后介紹注解版的配置。之所以不直接學習實用的注解配置,正是因為“學習”二字,這是一個過程,我習慣于從繁化簡(當學習到最后我能吐槽一句原來這樣更簡單就說明我成功了)
圖中的前端控制器即為 DispatcherServlet ,在web.xml中配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>MVC</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- 注冊控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.mn</url-pattern>
</servlet-mapping>
</web-app>
welcome-file-list
是默認進入頁面,即直接輸入 “localhost:8080/項目名/” 就會加載的頁面,默認名為index,在/WebContent
目錄下
導入springmvc所需的jar包:http://pan.baidu.com/s/1kV39hC7
目前還未使用maven,所以直接下載jar包放入/WebContent/WEB-INF/lib
目錄下即可
init-param
為選填,如果不寫,則DispatcherServlet默認會去查找/WEB-INF/<servlet-name>-servlet.xml
文件,(例:我上訴的配置將會自動去查到springmvc-servlet.xml
)
如果配置了init-param
,則會根據param-value
去對應的目錄下查找配置文件,并且可以自定義xml文件名稱。
其中param-name
是固定名稱,大小寫敏感classpath:
表示根目錄(與src同級)
如上訴配置,DispatcherServlet會去src/config下尋找springmvc.xml文件
(自定義的方式可以更好的統一管理配置文件,建議使用)
url-pattern
配置攔截器,即判斷什么請求可以去訪問action類。上訴配置是接受以.mn
為后綴的請求,也可以寫成/*
,但是這樣會接受所有的請求,包括html、jsp后綴,對于頁面的請求我們是不需要到后臺的,所以不建議該寫法,攔截器可配置多個,重復寫servlet-mapping
即可
Action類的形式有很多
可以是實現接口的類,可以是繼承類,甚至可以是普通類
以實現Controller為例(這不是最好的方法)
package action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloWorldAction implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest req,HttpServletResponse resp) throws Exception {
ModelAndView modelAndView=new ModelAndView();
modelAndView.addObject("msg","第一個springmvc項目!");
modelAndView.setViewName("/jsp/helloWorld.jsp");
return modelAndView;
}
}
addObject用于傳值,setViewName指定返回的模型(注意,現在寫的是真實路徑)
<body>
${requestScope.msg}
</body>
這是JSP的EL表達式,不需要過多理解,只要知道是獲取Action傳遞的值
<?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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- 注冊Action處理類 -->
<bean name="/hw.mn" class="action.HelloWorldAction"></bean>
</beans>
這是最簡單的配置,頭信息固定不變,需要我們寫的只有Action處理類,class表示處理類的全路徑,name表示請求路徑。
運行結果:
運行成功
在springmvc.xml中可以配置的有:
1.注冊Action處理類(控制器)
2.映射器
3.適配器
4.視圖解析器
有這么多,但是我們上面只寫了一行處理類,由此可見,Action處理類是必寫項,而其它的都是可選
完整版如下:
<bean name="/hw.mn" class="action.HelloWorldAction"></bean>
<!-- 映射器 BeanNameUrlHandlerMapping(其中之一)表示將上一行bean標簽中的name屬性當作url請求-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
</bean>
<!-- 適配器 SimpleControllerHandlerAdapter表示用于尋找HelloWorldAction類-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter">
</bean>
<!-- 視圖解析器 InternalResourceViewResolver表示通過ModelAndView封裝的視圖名找到頁面-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
</bean>
通過三種常見場景,理解一下它們
頁面之間的跳轉
不推薦配置攔截器的時候使用/*
,是因為當直接跳轉頁面請的時候,請求是不需要經過后臺的,如果寫成/*
會導致普通的跳轉頁面也要經過后臺。這里就有一個問題需要注意的,當你要跳轉的頁面不在WEB-INF下的時候,可以直接在url上寫上真實路徑就能跳轉。
例如:<a href="${pageContext.request.contextPath }/jsp/xxx.jsp">跳轉到jsp文件夾下的頁面</a>
前面部分是EL表達式獲取當前路徑,等價http://localhost:8080/springMVC
但是!如果你要請求的頁面在WEB-INF下的話,出于安全考慮,這個設定就是不能通過url直接訪問WEB-INF目錄下的頁面,不過,通過配置控制器
<bean name="/xxx.mn" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<property name="viewName" value="success"/>
</bean>
可以把.mn
請求通過 ParameterizableViewController
類轉換成普通的頁面之間跳轉,包括對WEB-INF目錄下頁面的訪問
之前的例子可以理解為一對一,一個請求就需要寫一個Action處理類的bean,如果多個請求訪問的是同一個Action類,則是如下寫法:
<bean name="/hw1.mn" class="action.HelloWorldAction"></bean>
<bean name="/hw2.mn" class="action.HelloWorldAction"></bean>
<bean name="/hw2.mn" class="action.HelloWorldAction"></bean>
<!--映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
優化后的代碼:
<bean id="hwId" class="action.HelloWorldAction"></bean>
<!-- 映射器 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- key表示請求路徑 -->
<prop key="/hw1.mn">hwId</prop>
<prop key="/hw2.mn">hwId</prop>
<prop key="/hw3.mn">hwId</prop>
</props>
</property>
</bean>
此時注冊Action處理類不是用name,而是用id,通過SimpleUrlHandlerMapping實現多個請求訪問同一個Action
剛開始在Action類中setViewName方法寫的是文件的真實路徑,那如何使用邏輯路徑定位到真實的頁面路徑呢
視圖解析器就是做這一行的:
springmvc.xml新增配置:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
HelloWorld.java:
public ModelAndView handleRequest(HttpServletRequest req,HttpServletResponse resp) throws Exception {
ModelAndView modelAndView=new ModelAndView();
modelAndView.addObject("msg","第一個springmvc項目!");
modelAndView.setViewName("helloWorld");
return modelAndView;
}
此時會自動把helloWorld補全成/jsp/helloWorld.jsp
小技巧:
eclipse打開文件所在目錄插件,使用Marketplace下載安裝非常慢,這里提供出離線插件
http://pan.baidu.com/s/1geEqzXx