http://magicma-007.iteye.com/blog/1536325
Table of Contents
Spring MVC
1. 簡介
Spring MVC是一個(gè)和Spring完美結(jié)合的Web框架。我先前學(xué)過Struts2,再學(xué)Spring MVC,覺得Spring MVC更為簡約、高效和優(yōu)雅,它有不少東西借鑒自Struts2,如依賴注入等。它功能完整,推薦在新項(xiàng)目中替代Struts2,至於Struts,直接 秒殺。
下面的配置均采用Spring 3版本,Spring MVC基於Java Servlet技術(shù)規(guī)範(fàn),主要處理流程圖:
來自瀏覽器的請求URL由DispatcherServlet統(tǒng)一處理(除了css、js、圖片等靜態(tài)文件),它符合Java Servlet規(guī)範(fàn)。在web.xml文件中配置哪些URL由該Servlet處理。
DispatcherServlet根據(jù)配置(通常由註解或xml文件配置)將URL請求發(fā)往相應(yīng)的Controller處理,這個(gè)過程會(huì)帶上服務(wù)器端傳遞過來的參數(shù)並自動(dòng)裝載給Controller。
Controller接收到參數(shù)後,調(diào)用相應(yīng)的方法處理之,方法裡可以調(diào)用業(yè)務(wù)層接口或數(shù)據(jù)層接口等,然後將處理結(jié)果打包到一個(gè)ModelAndView對象中並返回。
DispatcherServlet將ModelAndView對象發(fā)往視圖解析器viewResolver處理。
視圖解析器根據(jù)ModelAndView對象中指定的視圖模板位置和攜帶的數(shù)據(jù)渲染模板文件為html文件,返回渲染後的文件。
DispatcherServlet將html文件(有時(shí)候是純文本或多媒體文件)返回給瀏覽器。
很好的教程:點(diǎn)擊
2. 安裝及配置文件
建議使用eclipse或netbeans編寫程式,只需要導(dǎo)入Spring和Spring Web的所有jar包即可。
按照習(xí)慣,Spring的xml配置文件統(tǒng)一放在classpath根目錄下並遵循applicationContext-*.xml的命名規(guī) 範(fàn);web.xml配置css、js、圖片文件為靜態(tài)文件,靠後綴識別,其它URL由DispatcherServlet處理。web.xml配置文件如 下。
不要使用/js/*作為靜態(tài)文件的url-pattern,這樣可以直接訪問WEB-INF下的文件。
web.xml
<?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">
<!-- 解決亂碼問題 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置靜態(tài)文件 -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpeg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.gif</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.bmp</url-pattern>
</servlet-mapping>
<!-- Spring MVC Servlet配置 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 如果有多個(gè)spring配置文件,用逗號隔開 -->
<param-value>classpath:applicationContext-*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Tomcat, Jetty, JBoss, and GlassFish 默認(rèn)Servlet的名字 – “default”
Google App Engine 默認(rèn)Servlet的名字 – “_ah_default”
Resin 默認(rèn)Servlet的名字 – “resin-file”
WebLogic 默認(rèn)Servlet的名字 – “FileServlet”
WebSphere 默認(rèn)Servlet的名字 – “SimpleFileServlet”
classpath下關(guān)於Spring Web的配置文件:
applicationContext-web.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 【注意】這裡設(shè)置所有Controller所在的包位置,該包中所有使用annotation的類都會(huì)自動(dòng)加載 -->
<context:component-scan base-package="springmvc.web" />
<!--
視圖解析器,由DispatcherServlet控制,根據(jù)Controller返回值選擇對應(yīng)的模板
具體:Controller返回modelAndView或String對象,由對象name前面加上prefix,後面加上subfix形成文件的真實(shí)地址
-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 上傳文件 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
</beans>
3. 編寫Controller之Hello World
3.1 編寫Controller
Controller可以是任意一個(gè)普通類,不需要繼承或?qū)崿F(xiàn)任何東西。Controller類必須放在配置文件applicationContext-web.xml中指定的註解包下,如springmvc.web,應(yīng)根據(jù)實(shí)際情況修改。
HelloWorldController.java
package springmvc.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
// 通過註解使得該類變成Controller類
@Controller
// 根目錄,默認(rèn)是"/",指定後為"/hello"
@RequestMapping("hello")
public class HelloWorldController {
// 該方法對應(yīng)的URL,即訪問"/hello/hello_world"將調(diào)用該方法
@RequestMapping("hello_world")
public ModelAndView handleRequest() {
// modelAndView的名稱將會(huì)結(jié)合viewResolver配置的prefix和suffix合成一個(gè)頁面的路徑
ModelAndView modelAndView = new ModelAndView("hello_world");
// modelAndView對象攜帶的信息
modelAndView.addObject("message", "hello_world MVC!");
return modelAndView;
}
// 一個(gè)類中可以寫很多這樣的方法,名稱自取,使用註解映射到不同的URL
// 如果沒有附帶數(shù)據(jù),也可以直接返回String類型的名稱
}
關(guān)於其它bean依賴注入,比如業(yè)務(wù)層或數(shù)據(jù)層的對象,使用註解可以讓Spring完成自動(dòng)注入:
@Autowired
private CommonDao commonDao;
注意:ModelAndView的類不是org.springframework.web.portlet.ModelAndView
3.2 編寫jsp頁面
當(dāng)請求鏈接”/hello/hello_world”發(fā)送到DispatcherServlet,轉(zhuǎn)發(fā)到 HelloWorldController的handlerRequest方法,該方法返回modelAndView對象,根據(jù)該對象的名稱 hello_world和配置文件中的prefix和suffix組合成物理jsp地址位置:/WEB-INF/jsp/hello_world.jsp
現(xiàn)在創(chuàng)建該jsp頁面:
hello_world.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<p>這是Controller傳過來的數(shù)據(jù)message:${message}</p>
</body>
</html>
modelAndView對象中附帶的message字符串將被渲染到j(luò)sp頁面中。
部署該標(biāo)準(zhǔn)Java Web項(xiàng)目到tomcat服務(wù)器上,本機(jī)訪問http://127.0.0.1:8080/spring_mvc/hello/hello_world就可以看到網(wǎng)頁,其中spring_mvc是我在eclipse中的項(xiàng)目名稱,默認(rèn)是這樣:
這是Controller傳過來的數(shù)據(jù)message:hello_world MVC!
4. 獲得來自瀏覽器的參數(shù)及環(huán)境變量
4.1 GET或POST傳遞的參數(shù)
Spring MVC採用控制反轉(zhuǎn)的思想進(jìn)行依賴注入,假設(shè)HTML頁面需要傳遞參數(shù)name和age,則HTML頁面有個(gè)form:
<form action="/some/url">
Name: <input type="text" name="name"/><br />
Age: <input type="text" name="age"/><br />
</form>
這種提交形式是POST,也可以等同地使用GET方式提交:/some/url?name=pugwoo&age=24
然後Controller中對應(yīng)的方法只需要在參數(shù)上加上對應(yīng)名稱和類型的參數(shù):
@RequestMapping("/some/url")
public ModelAndView handleRequest(String name, Integer age) {
// 此時(shí)name和age已經(jīng)擁有服務(wù)器端傳過來的值
// 類型也會(huì)自動(dòng)轉(zhuǎn)換,比如從String轉(zhuǎn)成Integer
// 接下來,做你想做的事情
}
如果想指定採用GET或POST方式,在@RequestMapping中指定method即可:
@RequestMapping(value = "/url", method = RequestMethod.GET)
或
@RequestMapping(value = "/url", method = RequestMethod.POST)
注:我不喜歡Spring 2.0使用Spring MVC標(biāo)簽來寫HTML頁面的方式。雖然它提供了參數(shù)驗(yàn)證功能,但這個(gè)由自己寫的js來做更好,這樣有利於開發(fā)的解耦。
類Struts2的OGNL傳參形式
當(dāng)頁面的變量很多時(shí),可以採用OGNL方式傳遞變量,加入有類Car,Car有屬性String name和String model並提供對應(yīng)的getter和setter方法,則HTML的<input>名稱可以寫為:”name”和”model”,然後在 Controller的對應(yīng)方法的參數(shù)中只寫Car car,Spring MVC會(huì)將該對象及其值構(gòu)建好。
注意:<input>的name屬性不是填“car.name”,而是“name”。
Date類型的參數(shù)傳遞問題
頁面?zhèn)鬟f過來的數(shù)據(jù)均是String類型,爾後Spring將其轉(zhuǎn)化成對應(yīng)類型。有些類型不是Spring默認(rèn)可以轉(zhuǎn)換的,如Date。只需要在Controller.java代碼中加入一個(gè)binder方法即可:
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
其中日期格式按照實(shí)際需要進(jìn)行設(shè)置,如“yyyy-MM-dd HH:mm:ss”等。
4.2 獲得Cookie的值
在Controller對應(yīng)的方法的參數(shù)使用@CookieValue註解獲得:
@RequestMapping("/some/url")
public ModelAndView handleRequest(@CookieValue("name") String name) {
// 接下來,做你想做的事情
}
4.3 上傳文件
首先是HTML上傳頁面的form表格:
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
<input type="submit" />
</form>
然後編寫Controller,注意一定要加上@RequestParam,原因未明:
UploadController.java
package springmvc.web;
import java.io.IOException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class UploadController {
@RequestMapping("upload")
// 一定要加上@RequestParam
public ModelAndView uploadFile(@RequestParam MultipartFile myfile) throws IOException{
ModelAndView modelAndView = new ModelAndView("result");
// 顯示文件內(nèi)容
StringBuilder sb = new StringBuilder();
// 判斷文件是否已上傳
if (!myfile.isEmpty()) {
sb.append("文件名稱: " + myfile.getOriginalFilename() + "<br/>");
String content = new String(myfile.getBytes());
content = content.replace("\n", "<br/>");
sb.append(content);
} else {
sb.append("沒有選擇文件");
}
modelAndView.addObject("result", sb.toString());
return modelAndView;
}
}
然後新建一個(gè)/WEB-INF/result.jsp文件:
result.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<p>上傳的文件信息:</p>
<p>${result}</p>
</body>
</html>
如果出現(xiàn)java.lang.NoClassDefFoundError: org/apache/commons/io/output/DeferredFileOutputStream異常,加上org.apache.commons.io包即可。
4.4 獲得環(huán)境變量
標(biāo)準(zhǔn)的Servlet規(guī)範(fàn)中,有HttpServletRequest和HttpServletResponse等環(huán)節(jié)變量(關(guān)於這些變量的用途,請參見標(biāo)準(zhǔn)Servlet編程),Spring MVC可以很輕鬆地獲得,只需要像上面獲得參數(shù)一樣在方法參數(shù)中寫即可:
@RequestMapping("/some/url")
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) {
// 你已獲得HttpServletRequest和HttpServletResponse對象,比Struts2實(shí)現(xiàn)***Aware接口還簡單
// 接下來,做你想做的事情
}
5. REST形式的URL
REST形式的URL對搜索引擎友好,看起來也很簡潔漂亮。Spring MVC實(shí)現(xiàn)REST形式URL很簡單,例子:
/**
* 在RequestMapping中,變量用{}括起來
* 然后在處理方法中用@PathVariable獲取,名稱要一致
* @PathVariable 里面也可以加上value="xxx",名稱可以不一致
*/
@RequestMapping("/{name}/page/{p}")
public void handleRequest(Writer writer, @PathVariable String name,
@PathVariable Integer p) throws IOException{
writer.write("you are reading " + name +"'s page " + p);
}
URL中的數(shù)值會(huì)被作為變量傳入到方法中,如name和p,同樣是依賴注入的思想,類型會(huì)自動(dòng)轉(zhuǎn)換,訪問下面的URL查看效果:
http://127.0.0.1:8080/spring_mvc/pugwoo/page/1
http://127.0.0.1:8080/spring_mvc/pugwoo/page/2
http://127.0.0.1:8080/spring_mvc/nick/page/99
6. 其它技巧
輸出純文本
例子,支持中文:
@RequestMapping("test")
public void test(HttpServletResponse resp) throws IOException {
resp.setContentType("text/plain;charset=utf-8");
resp.getWriter().write("Test 測試中文");
}
該方法適合做cgi接口,輸出json等格式的數(shù)據(jù)。
客戶端跳轉(zhuǎn)
設(shè)定Controller對應(yīng)的方法返回名稱“redirect:hello_world”即可跳轉(zhuǎn)到對應(yīng)的頁面,如hello_world。瀏覽器的地址欄會(huì)變化。
服務(wù)器端跳轉(zhuǎn)
設(shè)定Controller對應(yīng)的方法返回名稱“forward:hello_world”即可跳轉(zhuǎn)到對應(yīng)的頁面,如hello_world。
forward並不能將變量通過modelAndView傳遞給新的URL,只能通過將變量放在request或session裏面來完成。而對於redirect,變量只能放在session裏面,不能放在request裏。
jsp頁面標(biāo)籤jstl
導(dǎo)入標(biāo)籤:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
直接獲取某個(gè)變量的值:${message} 或 ${car.name} 等
循環(huán)遍歷容器,假如有類Car,Car有屬性name並且提供getter方法,對象數(shù)組ArrayList<Car> cars,則java語句:
for(Car car : cars) {
System.out.println(car.getName());
}
等同於
<c:forEach items="${cars}" var="car">
${car.name} <br />
</c:forEach>
亂碼問題
上面的web.xml中已經(jīng)解決了POST數(shù)據(jù)的亂碼問題,但是GET方式傳遞數(shù)據(jù)仍有亂碼,這是URL編碼的問題,需要在服務(wù)器容器端設(shè)置,以Tomcat為例,修改conf/server.xml文件對應(yīng)位置新增“URIEncoding”:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="utf-8"/>
修訂日誌
Spring MVC
1. 簡介
Spring MVC是一個(gè)和Spring完美結(jié)合的Web框架。我先前學(xué)過Struts2,再學(xué)Spring MVC,覺得Spring MVC更為簡約、高效和優(yōu)雅,它有不少東西借鑒自Struts2,如依賴注入等。它功能完整,推薦在新項(xiàng)目中替代Struts2,至於Struts,直接 秒殺。
下面的配置均采用Spring 3版本,Spring MVC基於Java Servlet技術(shù)規(guī)範(fàn),主要處理流程圖:
來自瀏覽器的請求URL由DispatcherServlet統(tǒng)一處理(除了css、js、圖片等靜態(tài)文件),它符合Java Servlet規(guī)範(fàn)。在web.xml文件中配置哪些URL由該Servlet處理。
DispatcherServlet根據(jù)配置(通常由註解或xml文件配置)將URL請求發(fā)往相應(yīng)的Controller處理,這個(gè)過程會(huì)帶上服務(wù)器端傳遞過來的參數(shù)並自動(dòng)裝載給Controller。
Controller接收到參數(shù)後,調(diào)用相應(yīng)的方法處理之,方法裡可以調(diào)用業(yè)務(wù)層接口或數(shù)據(jù)層接口等,然後將處理結(jié)果打包到一個(gè)ModelAndView對象中並返回。
DispatcherServlet將ModelAndView對象發(fā)往視圖解析器viewResolver處理。
視圖解析器根據(jù)ModelAndView對象中指定的視圖模板位置和攜帶的數(shù)據(jù)渲染模板文件為html文件,返回渲染後的文件。
DispatcherServlet將html文件(有時(shí)候是純文本或多媒體文件)返回給瀏覽器。
很好的教程:點(diǎn)擊
2. 安裝及配置文件
建議使用eclipse或netbeans編寫程式,只需要導(dǎo)入Spring和Spring Web的所有jar包即可。
按照習(xí)慣,Spring的xml配置文件統(tǒng)一放在classpath根目錄下並遵循applicationContext-*.xml的命名規(guī) 範(fàn);web.xml配置css、js、圖片文件為靜態(tài)文件,靠後綴識別,其它URL由DispatcherServlet處理。web.xml配置文件如 下。
不要使用/js/*作為靜態(tài)文件的url-pattern,這樣可以直接訪問WEB-INF下的文件。
web.xml
<?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">
<!-- 解決亂碼問題 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置靜態(tài)文件 -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpeg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.gif</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.bmp</url-pattern>
</servlet-mapping>
<!-- Spring MVC Servlet配置 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 如果有多個(gè)spring配置文件,用逗號隔開 -->
<param-value>classpath:applicationContext-*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Tomcat, Jetty, JBoss, and GlassFish 默認(rèn)Servlet的名字 – “default”
Google App Engine 默認(rèn)Servlet的名字 – “_ah_default”
Resin 默認(rèn)Servlet的名字 – “resin-file”
WebLogic 默認(rèn)Servlet的名字 – “FileServlet”
WebSphere 默認(rèn)Servlet的名字 – “SimpleFileServlet”
classpath下關(guān)於Spring Web的配置文件:
applicationContext-web.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 【注意】這裡設(shè)置所有Controller所在的包位置,該包中所有使用annotation的類都會(huì)自動(dòng)加載 -->
<context:component-scan base-package="springmvc.web" />
<!--
視圖解析器,由DispatcherServlet控制,根據(jù)Controller返回值選擇對應(yīng)的模板
具體:Controller返回modelAndView或String對象,由對象name前面加上prefix,後面加上subfix形成文件的真實(shí)地址
-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 上傳文件 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
</beans>
3. 編寫Controller之Hello World
3.1 編寫Controller
Controller可以是任意一個(gè)普通類,不需要繼承或?qū)崿F(xiàn)任何東西。Controller類必須放在配置文件applicationContext-web.xml中指定的註解包下,如springmvc.web,應(yīng)根據(jù)實(shí)際情況修改。
HelloWorldController.java
package springmvc.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
// 通過註解使得該類變成Controller類
@Controller
// 根目錄,默認(rèn)是"/",指定後為"/hello"
@RequestMapping("hello")
public class HelloWorldController {
// 該方法對應(yīng)的URL,即訪問"/hello/hello_world"將調(diào)用該方法
@RequestMapping("hello_world")
public ModelAndView handleRequest() {
// modelAndView的名稱將會(huì)結(jié)合viewResolver配置的prefix和suffix合成一個(gè)頁面的路徑
ModelAndView modelAndView = new ModelAndView("hello_world");
// modelAndView對象攜帶的信息
modelAndView.addObject("message", "hello_world MVC!");
return modelAndView;
}
// 一個(gè)類中可以寫很多這樣的方法,名稱自取,使用註解映射到不同的URL
// 如果沒有附帶數(shù)據(jù),也可以直接返回String類型的名稱
}
關(guān)於其它bean依賴注入,比如業(yè)務(wù)層或數(shù)據(jù)層的對象,使用註解可以讓Spring完成自動(dòng)注入:
@Autowired
private CommonDao commonDao;
注意:ModelAndView的類不是org.springframework.web.portlet.ModelAndView
3.2 編寫jsp頁面
當(dāng)請求鏈接”/hello/hello_world”發(fā)送到DispatcherServlet,轉(zhuǎn)發(fā)到 HelloWorldController的handlerRequest方法,該方法返回modelAndView對象,根據(jù)該對象的名稱 hello_world和配置文件中的prefix和suffix組合成物理jsp地址位置:/WEB-INF/jsp/hello_world.jsp
現(xiàn)在創(chuàng)建該jsp頁面:
hello_world.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<p>這是Controller傳過來的數(shù)據(jù)message:${message}</p>
</body>
</html>
modelAndView對象中附帶的message字符串將被渲染到j(luò)sp頁面中。
部署該標(biāo)準(zhǔn)Java Web項(xiàng)目到tomcat服務(wù)器上,本機(jī)訪問http://127.0.0.1:8080/spring_mvc/hello/hello_world就可以看到網(wǎng)頁,其中spring_mvc是我在eclipse中的項(xiàng)目名稱,默認(rèn)是這樣:
這是Controller傳過來的數(shù)據(jù)message:hello_world MVC!
4. 獲得來自瀏覽器的參數(shù)及環(huán)境變量
4.1 GET或POST傳遞的參數(shù)
Spring MVC採用控制反轉(zhuǎn)的思想進(jìn)行依賴注入,假設(shè)HTML頁面需要傳遞參數(shù)name和age,則HTML頁面有個(gè)form:
<form action="/some/url">
Name: <input type="text" name="name"/><br />
Age: <input type="text" name="age"/><br />
</form>
這種提交形式是POST,也可以等同地使用GET方式提交:/some/url?name=pugwoo&age=24
然後Controller中對應(yīng)的方法只需要在參數(shù)上加上對應(yīng)名稱和類型的參數(shù):
@RequestMapping("/some/url")
public ModelAndView handleRequest(String name, Integer age) {
// 此時(shí)name和age已經(jīng)擁有服務(wù)器端傳過來的值
// 類型也會(huì)自動(dòng)轉(zhuǎn)換,比如從String轉(zhuǎn)成Integer
// 接下來,做你想做的事情
}
如果想指定採用GET或POST方式,在@RequestMapping中指定method即可:
@RequestMapping(value = "/url", method = RequestMethod.GET)
或
@RequestMapping(value = "/url", method = RequestMethod.POST)
注:我不喜歡Spring 2.0使用Spring MVC標(biāo)簽來寫HTML頁面的方式。雖然它提供了參數(shù)驗(yàn)證功能,但這個(gè)由自己寫的js來做更好,這樣有利於開發(fā)的解耦。
類Struts2的OGNL傳參形式
當(dāng)頁面的變量很多時(shí),可以採用OGNL方式傳遞變量,加入有類Car,Car有屬性String name和String model並提供對應(yīng)的getter和setter方法,則HTML的<input>名稱可以寫為:”name”和”model”,然後在 Controller的對應(yīng)方法的參數(shù)中只寫Car car,Spring MVC會(huì)將該對象及其值構(gòu)建好。
注意:<input>的name屬性不是填“car.name”,而是“name”。
Date類型的參數(shù)傳遞問題
頁面?zhèn)鬟f過來的數(shù)據(jù)均是String類型,爾後Spring將其轉(zhuǎn)化成對應(yīng)類型。有些類型不是Spring默認(rèn)可以轉(zhuǎn)換的,如Date。只需要在Controller.java代碼中加入一個(gè)binder方法即可:
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
其中日期格式按照實(shí)際需要進(jìn)行設(shè)置,如“yyyy-MM-dd HH:mm:ss”等。
4.2 獲得Cookie的值
在Controller對應(yīng)的方法的參數(shù)使用@CookieValue註解獲得:
@RequestMapping("/some/url")
public ModelAndView handleRequest(@CookieValue("name") String name) {
// 接下來,做你想做的事情
}
4.3 上傳文件
首先是HTML上傳頁面的form表格:
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
<input type="submit" />
</form>
然後編寫Controller,注意一定要加上@RequestParam,原因未明:
UploadController.java
package springmvc.web;
import java.io.IOException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class UploadController {
@RequestMapping("upload")
// 一定要加上@RequestParam
public ModelAndView uploadFile(@RequestParam MultipartFile myfile) throws IOException{
ModelAndView modelAndView = new ModelAndView("result");
// 顯示文件內(nèi)容
StringBuilder sb = new StringBuilder();
// 判斷文件是否已上傳
if (!myfile.isEmpty()) {
sb.append("文件名稱: " + myfile.getOriginalFilename() + "<br/>");
String content = new String(myfile.getBytes());
content = content.replace("\n", "<br/>");
sb.append(content);
} else {
sb.append("沒有選擇文件");
}
modelAndView.addObject("result", sb.toString());
return modelAndView;
}
}
然後新建一個(gè)/WEB-INF/result.jsp文件:
result.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<p>上傳的文件信息:</p>
<p>${result}</p>
</body>
</html>
如果出現(xiàn)java.lang.NoClassDefFoundError: org/apache/commons/io/output/DeferredFileOutputStream異常,加上org.apache.commons.io包即可。
4.4 獲得環(huán)境變量
標(biāo)準(zhǔn)的Servlet規(guī)範(fàn)中,有HttpServletRequest和HttpServletResponse等環(huán)節(jié)變量(關(guān)於這些變量的用途,請參見標(biāo)準(zhǔn)Servlet編程),Spring MVC可以很輕鬆地獲得,只需要像上面獲得參數(shù)一樣在方法參數(shù)中寫即可:
@RequestMapping("/some/url")
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) {
// 你已獲得HttpServletRequest和HttpServletResponse對象,比Struts2實(shí)現(xiàn)***Aware接口還簡單
// 接下來,做你想做的事情
}
5. REST形式的URL
REST形式的URL對搜索引擎友好,看起來也很簡潔漂亮。Spring MVC實(shí)現(xiàn)REST形式URL很簡單,例子:
/**
* 在RequestMapping中,變量用{}括起來
* 然后在處理方法中用@PathVariable獲取,名稱要一致
* @PathVariable 里面也可以加上value="xxx",名稱可以不一致
*/
@RequestMapping("/{name}/page/{p}")
public void handleRequest(Writer writer, @PathVariable String name,
@PathVariable Integer p) throws IOException{
writer.write("you are reading " + name +"'s page " + p);
}
URL中的數(shù)值會(huì)被作為變量傳入到方法中,如name和p,同樣是依賴注入的思想,類型會(huì)自動(dòng)轉(zhuǎn)換,訪問下面的URL查看效果:
http://127.0.0.1:8080/spring_mvc/pugwoo/page/1
http://127.0.0.1:8080/spring_mvc/pugwoo/page/2
http://127.0.0.1:8080/spring_mvc/nick/page/99
6. 其它技巧
輸出純文本
例子,支持中文:
@RequestMapping("test")
public void test(HttpServletResponse resp) throws IOException {
resp.setContentType("text/plain;charset=utf-8");
resp.getWriter().write("Test 測試中文");
}
該方法適合做cgi接口,輸出json等格式的數(shù)據(jù)。
客戶端跳轉(zhuǎn)
設(shè)定Controller對應(yīng)的方法返回名稱“redirect:hello_world”即可跳轉(zhuǎn)到對應(yīng)的頁面,如hello_world。瀏覽器的地址欄會(huì)變化。
服務(wù)器端跳轉(zhuǎn)
設(shè)定Controller對應(yīng)的方法返回名稱“forward:hello_world”即可跳轉(zhuǎn)到對應(yīng)的頁面,如hello_world。
forward並不能將變量通過modelAndView傳遞給新的URL,只能通過將變量放在request或session裏面來完成。而對於redirect,變量只能放在session裏面,不能放在request裏。
jsp頁面標(biāo)籤jstl
導(dǎo)入標(biāo)籤:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
直接獲取某個(gè)變量的值:${message} 或 ${car.name} 等
循環(huán)遍歷容器,假如有類Car,Car有屬性name並且提供getter方法,對象數(shù)組ArrayList<Car> cars,則java語句:
for(Car car : cars) {
System.out.println(car.getName());
}
等同於
<c:forEach items="${cars}" var="car">
${car.name} <br />
</c:forEach>
亂碼問題
上面的web.xml中已經(jīng)解決了POST數(shù)據(jù)的亂碼問題,但是GET方式傳遞數(shù)據(jù)仍有亂碼,這是URL編碼的問題,需要在服務(wù)器容器端設(shè)置,以Tomcat為例,修改conf/server.xml文件對應(yīng)位置新增“URIEncoding”:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="utf-8"/>
修訂日誌