Spring MVC,即 Spring Model-View-Controller,是一個實現了通用開發模式(模型-視圖-控制器)的Web框架,它經過一個DispatcherServlet處理HTTP請求、完成資源映射、遞交請求給控制器完成業務邏輯,相應數據則經過Model傳遞給視圖解析器解析爲相應的頁面或數據流返回給客戶端。
這裏,咱們能夠經過Spring官方給出的圖示大體瞭解其內部的工做機制: 前端
DispatcherServlet做爲前端控制器(Front Controller)過濾全部客戶端發來的請求,檢查請求路徑並根據配置好的映射規則,將請求提交給指定的控制器(Controller),完成業務邏輯處理(好比,數據庫訪問),生成數據模型(model),傳遞給指定視圖解析器(Spring內部已爲咱們定義好的一系列模板,拿來用便可)解析爲相應的視圖數據,最後返回客戶端響應。 web
其實,比如咱們最初學習Java Web開發同樣,首先要在web.xml文件中配置DispatcherServlet: spring
01 |
<!-- Spring Dispatcher Servlet--> |
03 |
<servlet-name>SpringDispatcher</servlet-name> |
04 |
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> |
06 |
<param-name>contextConfigLocation</param-name> |
07 |
<param-value>classpath:config/springDispatcher.xml</param-value> |
09 |
<load-on-startup>1</load-on-startup> |
12 |
<servlet-name>SpringDispatcher</servlet-name> |
13 |
<url-pattern>/</url-pattern> |
這裏配置了名爲SpringDispatcher的Servlet,處理全部客戶端的請求,contextConfigLocation參數指明瞭同時要加載的Spring MVC配置信息。 數據庫
既然SpringDispatcher會過濾全部的請求,那若是請求的是靜態資源的話,咱們這樣作就有點得不償失了。不過不用擔憂,Spring MVC爲咱們提供了處理靜態資源的解決辦法: json
在springDispatcher.xml文件中,引入spring mvc標記,並添加<mvc:resource>標籤便可: spring-mvc
01 |
<?xml version="1.0" encoding="UTF-8"?> |
02 |
<beans xmlns="http://www.springframework.org/schema/beans" |
03 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
04 |
xmlns:mvc="http://www.springframework.org/schema/mvc" |
06 |
http://www.springframework.org/schema/mvc |
07 |
http://www.springframework.org/schema/mvc/spring-mvc.xsd |
08 |
http://www.springframework.org/schema/beans |
09 |
http://www.springframework.org/schema/beans/spring-beans.xsd> |
10 |
<!-- Handle requests for static resources --> |
11 |
<mvc:resources mapping="/resources/**" location="/resources/"/> |
如上所配置,<mvc:resources>會將全部直接返回以/resources/開始的靜態資源請求,而不會經過SpringDispatcher進行處理。 mvc
DispatcherServlet配置好後,接下來就須要建立咱們的控制器類了,Spring MVC裏咱們能夠經過組件掃描來註冊咱們所寫的控制器,自動織入所需的bean: app
1 |
http://www.springframework.org/schema/context |
2 |
http://www.springframework.org/schema/context/spring-context.xsd> |
4 |
<!-- Enable annotation-driven features --> |
5 |
<mvc:annotation-driven/> |
7 |
<!-- Enable component-scan features --> |
8 |
<context:component-scan base-package="com.alan"/> |
控制器類以下:
02 |
@RequestMapping("/user") |
03 |
public class UserController { |
05 |
private final UserService userService; |
08 |
public UserController(UserService userService) { |
09 |
this.userService = userService; |
12 |
@RequestMapping("/queryAll") |
13 |
public String queryAll(@RequestParam("type") int type, Model model) { |
15 |
List<User> users = userService.findAll(); |
16 |
model.addAttribute("users", users); |
經過註解技術,咱們能夠很方便的將咱們的業務類註冊給控制器,在初始化時由Spring容器幫咱們完成依賴注入。其中@RequestMapping註解則告訴Spring全部以「/user」開始的請求將由UserController來處理,而"/user/queryAll"則交由queryAll方法處理。@RequestParam則會接收URL請求參數,這裏爲type,而且自動轉化爲對應的參數類型。Model即爲數據模型,由Spring提供,咱們能夠將處理後的結果數據綁定到Model上,返回Model給指定視圖解析器。queryAll方法最後的return "UserList"意思是告訴視圖解析器返回哪個頁面。這裏咱們須要再增長視圖解析器的配置到springDsipatcher.xml中:
1 |
<!-- Configure view resolver --> |
2 |
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> |
3 |
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> |
4 |
<property name="prefix" value="/WEB-INF/views/"/> |
5 |
<property name="suffix" value=".jsp"/> |
以上XML配置代表,咱們使用JstlView視圖(支持JSTL),而且返回「/WEB-INF/views/」下面全部以「.jsp」爲後綴的文件。本例中,即爲「
/WEB-INF/views/UserList.jsp
」。
是否是很easy呢?不過,可能有的同窗要問了,若是我不想返回頁面,而是直接返回字符串或者IO流怎麼辦。好吧,Spring框架固然也想到了。咱們能夠在方法上增長@ResponseBody標記以代表直接返回響應內容,而不是轉交視圖解析器處理,就像下面這樣:
框架
01 |
@RequestMapping("/queryAll2") |
03 |
public String queryAll2(@RequestParam("type") int type) { |
04 |
JSONObject jsonObj = new JSONObject(); |
06 |
List<User> users = userService.findAll(); |
07 |
jsonObj.put("users", users); |
09 |
return jsonObj.toString(); |
咱們便可很輕鬆的返回字符串數據,好比返回JSON字符串。 jsp
InternalResourceViewResolver一般使用轉發的方式返回頁面數據。若是咱們須要重定向到某個頁面,則能夠在方法返回的時候增長「redirect:」標記便可:
1 |
return "redirect:/UserList"; |
固然,若是須要轉發至某個Controller的方法也很方便:
1 |
return "forward:/user/queryAll2?type=2" |
此外,常常使用Struts的同窗也比較喜歡錶單數據綁定到Model的功能以減輕本身獲取全部請求參數的繁瑣工做,Spring亦有提供實現。便可經過@ModelAttribute標記獲取表單參數(這須要Spring MVC所提供的form tag庫的支持):
2 |
public class HelloWorldController { |
4 |
@RequestMapping(value = "/helloWorld", method=RequestMethod.POST) |
5 |
public String helloWorld(@ModelAttribute User user) { |
好像還少了點什麼對不對?是的,我若是要在Controller裏得到ServletContext對象呢?別擔憂,只要咱們implements ServletContext便可,這樣咱們就能夠在Controller裏獲取Servlet上下文,於是什麼request、response都不在話下了,這裏給出一個上傳JPG圖片的例子:
02 |
@RequestMapping("/upload") |
03 |
public class FileUploadController implements ServletContextAware { |
05 |
private ServletContext servletContext; |
07 |
public void setServletContext(ServletContext servletContext) { |
08 |
this.servletContext = servletContext; |
11 |
@RequestMapping("/jpg") |
12 |
public String uploadJPG(@RequestParam("image") MultipartFile image, Model model) { |
14 |
if(!image.isEmpty()) { |
15 |
validateImage(image, "image/jpeg"); |
17 |
model.addAttribute("img", "resources/upload" + File.separator + image.getName()); |
19 |
} catch (UploadImageException e) { |
20 |
model.addAttribute("msg", e.getMessage()); |
26 |
private void saveImage(MultipartFile image) throws UploadImageException { |
27 |
String name = image.getName(); |
29 |
File file = new File(servletContext.getRealPath("/resources/upload") + File.separator + name); |
30 |
FileUtils.writeByteArrayToFile(file, image.getBytes()); |
31 |
} catch (IOException e) { |
32 |
throw new UploadImageException("保存圖片出錯!"); |
37 |
private void validateImage(MultipartFile image, String type) throws UploadImageException { |
38 |
if(!image.getContentType().equals(type)) { |
39 |
throw new UploadImageException("只接受JPG格式的文件!"); |
還有,還有,記得咱們常常會用到Session來保存一些共享數據,Spring MVC裏能夠在Controller上加上@SessionAttributes標記來完成這個功能:
02 |
@RequestMapping("/user") |
03 |
@SessionAttributes("user") |
04 |
public class UserController { |
06 |
private final UserService userService; |
09 |
public UserController(UserService userService) { |
10 |
this.userService = userService; |
驚喜遠遠不只如此,Spring MVC還提供了更多,這裏再也不一一列舉,有了以上的這些簡單介紹,想必
你
對Spring MVC的開發模式有了必定的瞭解,不得不說這個框架用起來其實仍是蠻方便、蠻體貼的。