簡介
SpringMVC是一種基于Java的實(shí)現(xiàn)MVC設(shè)計模式的請求驅(qū)動類型的輕量級Web框架,使用了MVC架構(gòu)模式的思想,將web層進(jìn)行職責(zé)解耦,基于請求驅(qū)動指的就是使用請求-響應(yīng)模型,框架的目的就是幫助我們簡化開發(fā)。
特性
1.簡單、容易上手;
2.性能優(yōu)異:jsp+servlet>Struts=SpringMVC>Struts2;
3.靈活、易于擴(kuò)展;
4.易于和Spring容器整合;
SpringMVC程序示例
xml配置版
- 創(chuàng)建動態(tài)Web項(xiàng)目
- 導(dǎo)入spring的jar包,導(dǎo)入common-logging的jar包
- 為web項(xiàng)目引入SpringMVC框架,即在web.xml中配置SpringMVC的DispatcherServlet
<!-- 配置DispatcherServlet -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- SpringMVC的配置文件所在的位置和名稱 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<!--框架進(jìn)行轉(zhuǎn)發(fā)規(guī)則的定義文件-->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!-- SpringMVC攔截所有請求,再進(jìn)行轉(zhuǎn)發(fā) -->
<url-pattern>/</url-pattern>
</servlet-mapping>
- 在src目錄下創(chuàng)建SpringMVC的配置文件springmvc.xml,并加入如下代碼
...
<!--配置方式必須寫的兩個,每個請求對應(yīng)一個Controller,不用此種方式-->
<!-- 標(biāo)明所有實(shí)現(xiàn)了org.springframework.web.servlet.mvc.Controller接口的Bean可以作為Spring Web MVC中的控制器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- 表示將請求的URL和Bean名字映射 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 一個具體的映射,表示將hello.action地址映射到了HelloController的方法上 -->
<bean name="/hello.action" class="com.controller.HelloController"/>
...
- 編寫接受請求的控制器
//實(shí)現(xiàn)Controller接口,配置方式需要實(shí)現(xiàn)Controller類,相當(dāng)于servlet繼承HttpServlet
public class HelloController implements Controller{
//重寫Controller接口的handleRequest方法
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {
//新建一個視圖對象
ModelAndView mav = new ModelAndView();
//給視圖對象里添加鍵值對形式的存儲結(jié)構(gòu),相當(dāng)于返回的鍵值對
mav.addObject("message", "hello springmvc");
//指定視圖的jsp文件
mav.setViewName("hello.jsp");
return mav;
}
}
- 編寫hello.jsp文件
<body>
獲取值${message}
</body>
注解版
- 同上
- 同上
- 同上
- 在src目錄下創(chuàng)建SpringMVC的配置文件springmvc.xml,并加入如下代碼
...
<!-- 配置掃描包,告訴SpringMVC被注解的class都在哪個包下 -->
<context:component-scan base-package="com.controller"></context:component-scan>
<!-- 配置視圖解析器,告訴SpringMVC在網(wǎng)站的哪個目錄下能找到j(luò)sp文件 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
...
- 編寫接受請求的控制器
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloWorld {
/**
* 1. 使用RequestMapping注解來映射請求的URL,寫在方法上面,一個請求對應(yīng)一個方法
* 2. 返回值會通過視圖解析器解析為實(shí)際的物理視圖, 會做如下解析
* 通過prefix+returnVal+suffix 這樣的方式得到實(shí)際的物理視圖,然后會轉(zhuǎn)發(fā)操作
* "/WEB-INF/views/success.jsp"
*/
@RequestMapping("/helloworld")
public String hello(){
System.out.println("hello world");
return "success";
}
}
- 同上
SpringMVC映射規(guī)則
二級映射
在類上和方法上同時注解@RequestMapping,相當(dāng)于地址欄里有兩級的地址
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("one")
public class TestController {
@RequestMapping("two")
public String test(){
return "index";
}
}
//如上注解后,映射地址為:http://localhost:8080/xx/one/two
Method類型選擇接受
@RequestMapping注解括號里,有method屬性作為對提價類型的選擇接受
@RequestMapping(value="/getName",method={RequestMethod.GET, RequestMethod.POST})
//如果沒有指定method,則默認(rèn)為所有請求類型都接受
參數(shù)規(guī)則匹配
在響應(yīng)請求的時候,對提交的參數(shù)規(guī)則進(jìn)行驗(yàn)證,如果不符合設(shè)置的規(guī)則,則不接受請求
- param1=value1 - 請求中必須包含該參數(shù)和指定值
- param2 - 請求中必須包含該參數(shù),值任意
- !param3 - 請求中必須不包含該參數(shù)\
@RequestMapping(value="/getName",method=RequestMethod.GET,params={"id=123","name","!age")
//上述規(guī)則定義了,只能響應(yīng)get請求,并且請求的參數(shù)必須包含id=123,必須包含name,不能包含age
//根據(jù)上述規(guī)則此地址合法:http://localhost:8080/xx?id=123&name=abc
參數(shù)綁定的含義
- 所謂的參數(shù)綁定,就是怎么樣獲取到前臺頁面?zhèn)鬟^來的值,通常是跟據(jù)參數(shù)名(key)來獲取值;
- 綁定頁面?zhèn)髦档膋ey值到映射方法的參數(shù)上,如下程序所示
//頁面端提交請求的程序
$.post("../hc.v",
{
name : "shoji",
price : "8888"
},
function(d) {
alert(d);
}
)
//后臺響應(yīng)上面ajax的post請求的代碼
//通過兩段代碼里“name”和“price”的相同,把“shouji”和“8888”傳到hc方法里
//問號傳值的方式同樣適用 ?name=shoji&price=8888
...
@RequestMapping("hc")
public String hc(String name,String price){
return "test";
}
...
- 用標(biāo)準(zhǔn)PO屬性來進(jìn)行綁定
- 頁面端提交請求的js代碼同上
//新建一個標(biāo)準(zhǔn)的PO,同時當(dāng)前類的屬性名應(yīng)該跟前臺代碼里的KEY對應(yīng)上
public class PO{
private String name;//和key值一樣
private Stirng price;//和key值一樣
//省略各自的set get
}
//后臺響應(yīng)上面ajax的post請求的代碼
//通過PO里的“name”和“price”屬性名和前臺js代碼里的key相同,把“shouji”和“8888”傳到hc方法里
//問號傳值的方式同樣適用 ?name=shoji&price=8888
...
@RequestMapping("hc")
public String hc(PO po){
//po.getName() 取出shoujie
//po.getPrice() 取出8888
return "test";
}
...
- 用注解@RequestParam來綁定
- 頁面端提交請求的js代碼同上
//后臺響應(yīng)上面ajax的post請求的代碼
//通過注解里的“name”和“price”參數(shù)名和前臺js代碼里的key相同,把“shouji”和“8888”傳到hc方法里
//問號傳值的方式同樣適用 ?name=shoji&price=8888
...
@RequestMapping("hc")
public String hc(@RequestParam("name") String p1,@RequestParam("price") String p2){
//p1 取出shoujie
//p2 取出8888
return "test";
}
...
- 通過注解@PathVariable
- 本注解把要傳給后臺程序的值,綁定在地址里
- 頁面端提交請求的地址變?yōu)椋篸ianhua/name/shoji/price/8888
//后臺響應(yīng)上面ajax的post請求的代碼
//@RequestMapping注解的映射改變,地址里值的部分用{}括起來
//在方法的參數(shù)上使用注解@PathVariable
//通過PathVariable注解后面的“idvalue”和“pricevalue”和RequestMapping注解里{}部分相同,把“shouji”和“8888”傳到hc方法里
@RequestMapping("dianhua/name/{idvalue}/price/{pricevalue}")
public String hc(@PathVariable String idvalue,@PathVariable String pricevalue){
//idvalue 取出shoujie
//pricevalue 取出8888
return "test";
}
...
映射方法的返回值類型
- 返回ModelAndView
<!-- springmvc配置文件代碼片段 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
@RequestMapping("/szw/jintiancailai")
public ModelAndView ccc(String namee) {
List list = new ArrayList();
list.add("zhiweizhi");
list.add("luchang");
System.out.println("hello name=" + namee);
ModelAndView mav = new ModelAndView();
mav.addObject("myList", list);
mav.addObject("mySize", "2");
mav.setViewName("first");
//first是一個頁面文件的名字
//在springmvc的配置文件指定頁面文件所在的路徑是/WEB-INF/views/
//在springmvc的配置文件指定頁面文件的類型是.jsp
//我們ModelAndView所展示的頁面會做如下解析 prefix+setViewName+suffix
//即 /WEB-INF/views/first.jsp
return mav;
}
ModelAndView是springmvc框架提供一個包裝界面jsp文件的類,常用的方法addObject和setViewName
addObject有兩個參數(shù),類型都是Object類型,第一個參數(shù)是key,第二個參數(shù)是值;主要用途,把java后的里的數(shù)據(jù)帶到前臺jsp頁面上
setViewName有一個參數(shù),類型是String;參數(shù)是jsp文件的名字;用途是告訴ModelAndView所展示的頁面是哪個jsp文件
- 返回值是String
- 返回值里只有一個字符串
public String ddd() {
return "first";
}
//這樣返回同上面程序注釋的過程
- redirect和forward在返回值字符串前,并且redirect和forward和字串之間有一個冒號
public String eee() {
return "redirect:../first.jsp";
}
public String fff() {
return "forward:../first.jsp";
}
//這樣返回,我們轉(zhuǎn)去的地址不在被springmvc管理,需要轉(zhuǎn)去的地址能直接在地址欄訪問
- @ResponseBody注解
- 當(dāng)返回值是String,并且方法上方有此注解時,返回的字符串將不在被解析為springmvc的視圖(即jsp文件),會被直接以字符串展示在瀏覽器里
@RequestMapping("/test")
@ResponseBody
public String hhh() {
return "first";
}
//first將被輸出到瀏覽器里
- 返回時void
- 需要人為在方法的參數(shù)列表里,加入request和response這兩個參數(shù),所有的操作依靠這兩個參數(shù)來完成,非常類似標(biāo)準(zhǔn)的Servlet
public void ggg(HttpServletRequest req,HttpServletResponse rep) {
//標(biāo)準(zhǔn)servlet里怎么寫,這段代碼就怎么寫
}
文件上傳
Tomcat虛擬目錄的配置
在tomcat的server.xml中,找到<host>節(jié)點(diǎn),在開始和結(jié)束標(biāo)簽中寫如下代碼</host>
<!--
docBase - 網(wǎng)站跟目錄的絕對路徑
path - 在瀏覽器訪問這個網(wǎng)站的網(wǎng)址
-->
<Context docBase="/網(wǎng)站文件夾在硬盤的絕對路徑" path="/瀏覽器地址欄的路徑" reloadable="當(dāng)網(wǎng)站文件被改變時是否自動重啟">
如:
<Context docBase="D:\apps\My12306" path="/my12306" reloadable="true">
springMVC文件上傳
- 導(dǎo)入jar包
commons-fileupload-1.2.1.jar commons-io-1.3.2.jar
- 在springmvc配置文件中配置上傳解析器
<!--
id屬性是bean的實(shí)例名,可以指定
class屬性固定不變
property name="maxUploadSize",property name="defaultEncoding",名字固定,值可以指定
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 上傳文件的最大值 -->
<property name="maxUploadSize">
<value>20971520</value>
</property>
<!-- 上傳流的編碼 -->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
- 編寫Controller代碼
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
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.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
/*
采用三種方式來接收上傳文件,分別用三個方法試驗(yàn)
每個方法里,有程序執(zhí)行時間記錄
實(shí)際運(yùn)用時,三者選其一
第一種最慢,第三種最快,一般選用第二種
*/
@Controller
public class FileController {
/*
* 通過流的方式上傳文件
*
* @RequestParam("file") 將name=file控件得到的文件封裝成CommonsMultipartFile 對象
*/
@RequestMapping("fileUpload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file) throws IOException {
// 用來檢測程序運(yùn)行時間
long startTime = System.currentTimeMillis();
try {
// 獲取輸出流
OutputStream os = new FileOutputStream("E:/" + new Date().getTime() + file.getOriginalFilename());
// 獲取輸入流 CommonsMultipartFile 中可以直接得到文件的流
InputStream is = file.getInputStream();
int temp;
// 一個一個字節(jié)的讀取并寫入
while ((temp = is.read()) != (-1)) {
os.write(temp);
}
os.flush();
os.close();
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("方法一的運(yùn)行時間:" + String.valueOf(endTime - startTime) + "ms");
return "/success";
}
/*
* 采用file.Transto 來保存上傳的文件
*/
@RequestMapping("fileUpload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file) throws IOException {
long startTime = System.currentTimeMillis();
String path = "E:/" + new Date().getTime() + file.getOriginalFilename();
File newFile = new File(path);
// 通過CommonsMultipartFile的方法直接寫文件(注意這個時候)
file.transferTo(newFile);
long endTime = System.currentTimeMillis();
System.out.println("方法二的運(yùn)行時間:" + String.valueOf(endTime - startTime) + "ms");
return "/success";
}
/*
* 采用spring提供的上傳文件的方法
*/
@RequestMapping("springUpload")
public String springUpload(HttpServletRequest request) throws IllegalStateException, IOException {
long startTime = System.currentTimeMillis();
// 將當(dāng)前上下文初始化給 CommonsMutipartResolver (多部分解析器)
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
// 檢查form中是否有enctype="multipart/form-data"
if (multipartResolver.isMultipart(request)) {
// 將request變成多部分request
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
// 獲取multiRequest 中所有的文件名
Iterator iter = multiRequest.getFileNames();
while (iter.hasNext()) {
// 一次遍歷所有文件
MultipartFile file = multiRequest.getFile(iter.next().toString());
if (file != null) {
String path = "E:/springUpload" + file.getOriginalFilename();
// 上傳
file.transferTo(new File(path));
}
}
}
long endTime = System.currentTimeMillis();
System.out.println("方法三的運(yùn)行時間:" + String.valueOf(endTime - startTime) + "ms");
return "/success";
}
}
- 編寫jsp頁面代碼
<!-- 三個form分別對應(yīng)controller里三個上傳方法 -->
<form name="Form1" action="fileUpload.v" method="post" enctype="multipart/form-data">
<h1>采用流的方式上傳文件</h1>
<input type="file" name="file">
<input type="submit" value="upload" />
</form>
<form name="Form2" action="fileUpload2.v" method="post" enctype="multipart/form-data">
<h1>采用multipart提供的file.transfer方法上傳文件</h1>
<input type="file" name="file">
<input type="submit" value="upload" />
</form>
<form name="Form3" action="springUpload.v" method="post" enctype="multipart/form-data">
<h1>使用spring mvc提供的類的方法上傳文件</h1>
<input type="file" name="file">
<input type="submit" value="upload" />
</form>
Ajax和Controller的交互
- 導(dǎo)入jar包
jackson-annotations-2.9.2.jar jackson-core-2.9.2.jar jackson-databind-2.9.2.jar
- 在springmvc的配置文件中,加入json轉(zhuǎn)換器
<!-- 加入到beans標(biāo)簽的標(biāo)簽體里 -->
<mvc:annotation-driven/>
傳入key-value鍵值對,輸出json
- 在ajax的提交請求里,傳給后臺的數(shù)據(jù)格式是kv對
//$.ajax $.post $.get 都是jquery的請求,需要引入jquery.js
//$.post和$.get都是$.ajax的簡寫方式
$.ajax({
type : "post",
url : "../tm.v",
contentType:"application/json; charset=utf-8",//請求成功后,后臺返回的數(shù)據(jù)格式,即success : function(r)里“r”的格式
data : "name=shoji&price=8888",//此處就是標(biāo)題中提到的傳入key-value鍵值對
success : function(r) {
//r 直接就是jsonObject
alert(r.name);
}
})
- 在controller的方法返回值里,傳給前臺的數(shù)據(jù)格式是json
@RequestMapping("tm")
@ResponseBody
public BYQ tm(BYQ byq2){
System.out.println(byq2.getName());
System.out.println(byq2.getPrice());
return byq2;
}
傳入json,輸出json
- 在ajax的提交請求里,傳給后臺的數(shù)據(jù)格式是json串
$.ajax({
type : "post",
url : "../tm.v",
contentType:"application/json; charset=utf-8",
data:'{"name":"shouji","price":"8888"}',//此處就是標(biāo)題中提到的傳入的json格式串
success : function(r) {
//r 直接就是jsonObject
//如果返回的r是字符串,在調(diào)用r.price之前需要把字符串轉(zhuǎn)為json對象,var jsonObject = JSON.parse(r);
alert(r.price);
}
})
- 在controller的方法返回值里,傳給前臺的數(shù)據(jù)格式是json,并且在方法的參數(shù)里接收的也是json串
//@ResponseBody注解和方法的返回值被置為BYQ,是為了返回值是json格式
//@RequestBody注解和方法的參數(shù)是BYQ類型,是為了接收前臺提交過了的json格式
@RequestMapping("tm")
@ResponseBody
public BYQ tm(@RequestBody BYQ byq2){
System.out.println(byq2.getName());
System.out.println(byq2.getPrice());
return byq2;
}
restful
- 簡介
體現(xiàn)在瀏覽器地址;每一個地址代表一種后臺的資源(實(shí)例),地址里不能出現(xiàn)動詞,具體的功能操作用提交method的類型來區(qū)分
- 映射模板
傳統(tǒng)方式:http://localhost:8080/ssm/updateuser?id=123
restful: http://localhost:8080/ssm/user/123 通過這個地址看不出是增刪改,具體操作下面來對應(yīng)
- 提交方法類型對應(yīng)(method的值)
get - 查詢
post - 修改
put - 添加
delete - 刪除
springmvc里對restful的支持
通過注解@PathVariable來支持rest風(fēng)格的地址,詳見
springmvc4以上的版本,提供注解@RestController來支持
當(dāng)SpringMVC映射為/時,不需要被映射的地址處理方式
- 映射為/,即在web.xml中引入springmvc時,url-pattern標(biāo)簽的值為/,即網(wǎng)站下所有地址都被mvc攔截
...
<servlet>
<servlet-name>springmvcservlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mymvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvcservlet</servlet-name>
<url-pattern>/</url-pattern><!-- 被標(biāo)識為/ -->
</servlet-mapping>
<!-- 地址被全部攔截后,出現(xiàn)的問題是,.js、.css、圖片文件等等靜態(tài)資源文件都被攔截了,不能直接訪問 -->
...
- 解決靜態(tài)資源被攔截的方法之一,在SpringMVC的配置文件中加入下面代碼
<!-- 地址里含有js和img的,都不被springmvc攔截 -->
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/img/" mapping="/img/**"/>