由於工作需要,最近將Net的MVC又重新好好的學習了一遍.學習教材是博客園里的大神的作品《ASP.NET MVC5框架揭秘》。
《ASP.NET MVC5框架揭秘》這本書,說了很多東西,但是總覺得太偏於理論,實際的例子太少。當然,框架揭秘 的確就應該是這個樣子的,畢竟不是什么MVC的速成書籍。
公司以后接的活,其實不僅限於NET平台,JAVA平台也需要考慮的,所以,當前階段Java的知識儲備也是必須的。這篇文章和語言之爭無關,希望不要引起大家的無謂的爭論。學習SpringMVC使用的是ITEYE的大神 開濤的MVC系列教程,版本是Spring MVC2.5/3.0(最新版本是 4.1.2)
環境搭建:
VisualStudio不愧是宇宙第一IDE,NET MVC5的HelloWorld,就是傻瓜式的選選項目類型,然后按下F5就一切搞定了。
MVC5不但把后台的東西幫你准備好了,連前端的框架都替你決定了,bootstrap,Modernize,Jquery。然后你會看到package里面有一大堆東西,
ORM用的,前端用的,JSON,所有的東西都Standby了。如果哪位同學不喜歡bootstrap,想用UIKit,好吧,自己重寫所有的模板吧。
自動生成的所有模板都是基於bootstrap的。然后Shard的TemplateEditor目錄下面就會出現很多類似BooleanExEditor這樣子的東西了。
Spring MVC
Java小白,只會用Elcapse,然后看教程,寫了個HelloWorld。
國內的教程,大都將初學者的水平想得太高了,大段大段的XML配置文件加上簡單的注解,就完事了。
最大的,最主要的目錄結構,半句話都沒有,你讓我這樣的小白,將一大堆xml配置文件放在什么地方好呢。最后只能yahoo.co.jp
找到一篇島國人民的MVC入門文章,搞清楚了目錄結構 http://qiita.com/siguremon/items/84c831391a6204079fd2
島國人民寫出來的入門教程,就是將學習對象當小白處理。然后教材寫得是變態般的詳細。目標是讓歐巴和歐巴桑看了都能夠編程。
[Maven和Nuget]
.NET有Nuget,Java這里有Maven,Maven的一個功能和Nuget一樣,管理依賴項目。
在Maven的幫助下,Spring的MVC所需要的東西,也能夠快速的准備齊全。
下面這個pom.xml里面包含了MySql的JDBC的導入
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.shchuwa</groupId> <artifactId>springmvc</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>springmvc Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <springframework.version>4.1.2.RELEASE</springframework.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency> </dependencies> <build> <finalName>springmvc</finalName> </build> </project>
Spring的包,其實東西也不少JUnit,AOP,Log。。。
接管HTTP控制權
NET的MVC是通過HttpHandler在IIS管道中獲得控制權的,讓Route部件參與IIS管道,如果Route能匹配的話,就讓MVC接手后續的所有事件。
這個過程在NETMVC的大神的書的第一章里說明得很好了。大部分人可能會覺得第一章無所謂,對於開發無關痛癢,但是,往往一些根本性的東西就在第一章里面。
Spring,其實也是差不多的思路,dispatcherServlet這個Servlet(org.springframework.web.servlet.DispatcherServlet)通過配置文件將自己作為Http的處理入口,Tomcat也好,JBoss也好,Apache也好,直接將Http請求轉交給dispatcherServlet處理了。
掌握入口的感覺真心不錯,能處理的處理,不能處理的,交給默認的Servlet處理
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd "> <display-name>spring-todo</display-name> <!-- (1) --> <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:/META-INF/spring/beans-webmvc.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- (2) --> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
關於路由
NET的MVC里面,有一個專門注冊路由的地方,博客園都是MVC的高手,這里就不再啰嗦了。
所有的路由規則都統一放在一起管理,直接了當,一目了然。
Spring的Route規則是通過注解(NET的特性)的方式,寫在Controller中的。
注意:RequestMapping就是Spring的路由
Spring在初始化的時候,會掃描指定位置下面所有的類,如果有@Controller的注解,就將其記錄為Controller
然后會解析@RequestMapping,構建類似於RouteTable這樣的東西。
而NET的話,約定了所有的Controller都放在指定的目錄下面。都繼承於Controller父類/接口。
當然,編碼習慣好的Javer,也會把所有Controller放在同一個目錄/Package的。
package controller; import static org.springframework.web.bind.annotation.RequestMethod.GET; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import model.person; // (1) @Controller public class HelloWorldController { // (2) @RequestMapping(value = "/", method = GET) public String home(ModelMap model) { // (3) person.insert(); model.addAttribute("message", "Spring 3 MVC Hello World"); return "helloworld"; } }
對於Controller的啟動條件,除了GET/POST這樣的檢查之外,Spring的條件貌似更加豐富一些。NET的MVC是否有同樣功能,我不知道。(或許可以使用攔截器)
1.可以要求請求的URL里面有某個參數(或者沒有某個參數),進而可以控制參數的值是否等於某個值。
2.可以對請求類型進行控制。例如,下面是請求一個Json的例子,這里同時對Url和請求類型進行限制
@RequestMapping(value="/header/test3", headers = "Content-Type=application/json"):
數據綁定和驗證
數據綁定這塊,兩者的處理都差不多,如果一個數據類型可以和字符進行相互轉換,那么系統就會自動幫你做綁定。
如果不行的話,自己寫一個類型和字符的轉換類即可。
NET大神用的是 Point(int x,int y)的例子
Sping 大神用的是 PhoneNumber(int AreaCode,int Number)的例子。
一句話,內置的能轉的類型,系統幫你做綁定,不能轉的類型,你告訴我一個字符到類型的雙向變換規則,然后注冊到系統里面去,我也負責給你綁定。
Pattern pattern = Pattern.compile("^(\\d{3,4})-(\\d{7,8})$"); @Override public void setAsText(String text) throws IllegalArgumentException { if(text == null || !StringUtils.hasLength(text)) { setValue(null); //如果沒值,設值為null } Matcher matcher = pattern.matcher(text); if(matcher.matches()) { PhoneNumberModel phoneNumber = new PhoneNumberModel(); phoneNumber.setAreaCode(matcher.group(1)); phoneNumber.setPhoneNumber(matcher.group(2)); setValue(phoneNumber); } else { throw new IllegalArgumentException(String.format("類型轉換失敗,需要格式 [010-12345678],但格式是[%s]", text)); } } @Override public String getAsText() { PhoneNumberModel phoneNumber = ((PhoneNumberModel)getValue()); return phoneNumber == null ? "" : phoneNumber.getAreaCode() + "-" + phoneNumber.getPhoneNumber(); }
內置的驗證約束注解:
MVC.NET使用的應該是自己的東西,
Spring 使用的是Hibernate Validator,能夠檢查的東西都差不多吧。沒有仔細研究。
題外話:NET里面的數據模型叫Model,Spring里面貌似叫做命令對象:Spring大神的原文如下
數據綁定:請求參數綁定到一個command object(命令對象,非GoF里的命令設計模式),這里的命令對象是指綁
定請求參數的任何POJO 對象;
攔截器
Spring 和Net一樣都提供了攔截器來處理AOP
package org.springframework.web.servlet; public interface HandlerInterceptor { boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception; }
前兩個沒有什么好說的,處理前,處理后,最后一個NET中不知道怎么處理的。作用如下:
afterCompletion:整個請求處理完畢回調方法,即在視圖渲染完畢時回調,如性能監控中我們可以在此記錄結束時間 並輸出消耗時間,還可以進行一些資源清理,類似於try-catch-finally中的finally,但僅調用處理器執行鏈中preHandle 返回true的攔截器的afterCompletion。
當然,Spring的攔截器也提供了取消功能,如果取消的話,整個處理就中止了(break)。攔截器的思想都差不多的,大家實現思想也都類似。
由於Spring在學習中,可能有理解錯誤的地方,希望大家指正。公司現在正在招募前端工程師,有興趣的可以發個簡歷。工作地點是上海。
(更多內容以后更新)