一、SpringMVC 基礎
1、三層架構
表現層:
- 也就是我們常說的web層。
- 它負責接收客戶端請求,向客戶端響應結果,通常客戶端使用http協議請求web 層,web 需要接收 http 請求,完成 http 響應。
- 表現層包括展示層和控制層:控制層負責接收請求,展示層負責結果的展示。表現層依賴業務層,接收到客戶端請求一般會調用業務層進行業務處理,並將處理結果響應給客戶端。
- 表現層的設計一般都使用 MVC 模型。(MVC 是表現層的設計模型,和其他層沒有關係)
業務層:
- 也就是我們常說的 service 層。
- 它負責業務邏輯處理,和我們開發項目的需求息息相關。web 層依賴業務層,但是業務層不依賴 web 層。
- 業務層在業務處理時可能會依賴持久層,如果要對數據持久化需要保證事務一致性。(也就是我們說的,事務應該放到業務層來控制)
持久層:
- 也就是我們是常說的 dao 層。
- 負責數據持久化,包括數據層即數據庫和數據訪問層,數據庫是對數據進行持久化的載體,數據訪問層是業務層和持久層交互的接口,業務層需要通過數據訪問層將數據持久化到數據庫中。通俗的講,持久層就是和數據庫交互,對數據庫表進行曾刪改查的。
2、MVC 模型
MVC 模型是一種用於設計創建 Web 應用程序表現層的模式。
Model(模型):
- 通常指的就是我們的數據模型。作用一般情況下用於封裝數據。
View(視圖):
- 通常指的就是我們的 jsp 或者 html。作用一般就是展示數據的。
- 通常視圖是依據模型數據創建的。
Controller(控制器):
- 是應用程序中處理用戶交互的部分。作用一般就是處理程序邏輯的。
Controller(控制器)相對於前兩個不是很好理解,這裏舉個例子:
我們要保存一個用戶的信息,該用戶信息中包含了姓名,性別,年齡等等。這時候表單輸入要求年齡必須是 1~100 之間的整數。姓名和性別不能爲空。並且把數據填充到模型之中。此時除了 js 的校驗之外,服務器端也應該有數據準確性的校驗,那麼校驗就是控制器的該做的。 當校驗失敗後,由控制器負責把錯誤頁面展示給使用者。如果校驗成功,也是控制器負責把數據填充到模型,並且調用業務層實現完整的業務需求。
3、SpringMVC 概述
- SpringMVC 是一種基於 Java 的實現 MVC 設計模型的請求驅動類型的輕量級 Web 框架。
- Spring是框架,MVC 是一種設計模式。
- Spring 框架提供了構建 Web 應用程序的全功能 MVC 模塊。
- 使用 Spring 可插入的 MVC 架構,從而在使用 Spring 進行 WEB 開發時,可以選擇使用 Spring 的 Spring MVC 框架或集成其他 MVC 開發框架。
4、SpringMVC 在三層架構的位置
5、SpringMVC 的優勢
- 清晰的角色劃分:
前端控制器(DispatcherServlet
)
請求到處理器映射(HandlerMapping
)
處理器適配器(HandlerAdapter
)
視圖解析器(ViewResolver
)
處理器或頁面控制器(Controller
)
驗證器(Validator
)
命令對象(Command
請求參數綁定到的對象就叫命令對象)
表單對象(Form Object
提供給表單展示和提交到的對象就叫表單對象)。 - 分工明確,而且擴展點相當靈活,可以很容易擴展,雖然幾乎不需要。
- 由於命令對象就是一個 POJO,無需繼承框架特定 API,可以使用命令對象直接作爲業務對象。
- 和 Spring 其他框架無縫集成,是其它 Web 框架所不具備的。
- 可適配,通過 HandlerAdapter 可以支持任意的類作爲處理器。
- 可定製性,HandlerMapping、ViewResolver 等能夠非常簡單的定製。
- 功能強大的數據驗證、格式化、綁定機制。
- 利用 Spring 提供的 Mock 對象能夠非常簡單的進行 Web 層單元測試。
- 本地化、主題的解析的支持,使我們更容易進行國際化和主題的切換。
- 強大的 JSP 標籤庫,使 JSP 編寫更容易。
二、示例代碼
第一步:配置核心控制器,一個 Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置SpringMVC核心控制器-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置初始化參數,用於讀取SpringMVC的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/SpringMVC.xml</param-value><!--文件位置在resource中-->
</init-param>
<!--配置 servlet 的對象的創建時間點:應用加載時創建,取值只能是非 0 的正整數,表示啓動順序-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--映射路徑-->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name><!--取值與上面的值對應-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
第二步:創建 spring mvc 的配置文件,SpringMVC.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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--配置 Spring 容器要要掃描的包-->
<context:component-scan base-package="cn.lemon"/>
<!--配置處理器映射器,作用是根據路徑查找處理器-->
<!--<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>-->
<!--處理器適配器,作用是執行具體的處理器-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
<!--
一般情況下,處理器映射器、處理器適配器可以省略,也可以用 <mvc:annotation-driven> 來代替
mvc:annotation-driven:作用就是代替處理器映射器和處理器適配器
-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--配置視圖解析器-->
<bean id="resolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--
通過前綴和後綴來解析這個視圖
prefix:前綴
suffix:後綴
-->
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
第三步:編寫控制器並使用註解配置
package cn.lemon;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* HelloController 相當於一個 servlet,
* 相比於 servlet,HelloController 可以放入 Spring 容器中,可以使用依賴注入與控制反轉
* servlet 不可以放入 Spring 容器中,因爲 servlet 是tomcat 產生的
*/
@Controller
public class HelloController {
@RequestMapping("/hello")
public String sayHello() {
System.out.println("hello SpringMVC...........");
return "success";//轉發到 WEB-INF/pages/(前綴)success(名字).jsp(後綴)(這個文件路徑是在 SpringMVC.xml 視圖解析器中加上前綴和後綴生成的)
}
}
第四步:新建展示頁面 index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主頁</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/hello">點擊跳轉</a>
</body>
</html>
第五步:在WEB-INF/pages 中新建跳轉頁面 success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>成功</title>
</head>
<body>
<h3>成功!!!!</h3>
</body>
</html>
三、SpringMVC 執行原理
1、案例的執行過程
1、服務器啓動,應用被加載。讀取到 web.xml 中的配置創建 spring 容器並且初始化容器中的對象。從上面的案例中可以看到的是:HelloController
和InternalResourceViewResolver
,但是遠不止這些。
2、瀏覽器發送請求,被 DispatherServlet
捕獲,該 Servlet
並不處理請求,而是把請求轉發出去。轉發的路徑是根據請求 URL,匹配@RequestMapping
中的內容。
3、匹配到了後,執行對應方法。該方法有一個返回值。
4、根據方法的返回值,藉助 InternalResourceViewResolver
找到對應的結果視圖。
5、渲染結果視圖,響應瀏覽器。
2、SpringMVC 的請求響應流程
3、上面案例中的組件分析
1、DispatcherServlet:前端控制器
- 用戶請求到達前端控制器,它就相當於 mvc 模式中的 c,dispatcherServlet
是整個流程控制的中心,由它調用其它組件處理用戶的請求,dispatcherServlet 的存在降低了組件之間的耦合性。
2、HandlerMapping:處理器映射器
- HandlerMapping 負責根據用戶請求找到 Handler 即處理器,SpringMVC
提供了不同的映射器實現不同的映射方式,例如:配置文件方式,實現接口方式,註解方式等。
3、Handler:處理器
- 它就是我們開發中要編寫的具體業務控制器。由 DispatcherServlet 把用戶請求轉發到 Handler。由Handler對具體的用戶請求進行處理。
4、HandlAdapter:處理器適配器
- 通過 HandlerAdapter 對處理器進行執行,這是適配器模式的應用,通過擴展適配器可以對更多類型的處理器進行執行。
5、View Resolver:視圖解析器
- View Resolver 負責將處理結果生成 View 視圖,View Resolver
首先根據邏輯視圖名解析成物理視圖名即具體的頁面地址,再生成 View 視圖對象,最後對 View 進行渲染將處理結果通過頁面展示給用戶。
6、View:視圖
- SpringMVC 框架提供了很多的 View 視圖類型的支持,包括:jstlView、freemarkerView、pdfView等。我們最常用的視圖就是 jsp。一般情況下需要通過頁面標籤或頁面模版技術將模型數據通過頁面展示給用戶,需要由程序員根據業務需求開發具體的頁面。
7、<mvc:annotation-driven>
說明
- 在 SpringMVC 的各個組件中,處理器映射器、處理器適配器、視圖解析器稱爲 SpringMVC 的三大組件。
- 使 用
<mvc:annotation-driven>
自動加載RequestMappingHandlerMapping
(處理映射器) 和RequestMappingHandlerAdapter
( 處 理 適 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用<mvc:annotation-driven>
替代註解處理器和適配器的配置
8、SpringMVC 框架基於組件方式執行流程
4、RequestMapping 註解
示例:
jsp代碼
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主頁</title>
</head>
<body>
<h3>案例</h3>
<a href="${pageContext.request.contextPath}/hello">點擊跳轉</a><hr/>
<h3>添加</h3>
<a href="${pageContext.request.contextPath}/account/add">點擊跳轉</a><hr/>
<h3>Get請求,刪除</h3>
<a href="${pageContext.request.contextPath}/account/delete">點擊跳轉</a><hr/><%--會報錯,報 405--%>
<h3>Post請求,刪除</h3>
<form method="post" action="${pageContext.request.contextPath}/account/delete"><%--會執行成功--%>
<input type="submit" value="提交">
</form><hr/>
<h3>Get請求,修改</h3>
<a href="${pageContext.request.contextPath}/account/update">點擊跳轉</a><hr/><%--會報 404--%>
<h3>Get請求,修改</h3>
<a href="${pageContext.request.contextPath}/account/update?aid=2">點擊跳轉</a><hr/><%--會報 404--%>
<h3>Get請求,修改</h3>
<a href="${pageContext.request.contextPath}/account/update?id=1">點擊跳轉</a><hr/><%--會執行成功--%>
</body>
</html>
java代碼
package cn.lemon;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
//請求 URL 的第一級訪問目錄。此處不寫的話,就相當於應用的根目錄。寫的話需要以/開頭。
@RequestMapping("/account")
public class AccountController {
@RequestMapping("/add")
public String add() {
System.out.println("添加賬戶。。。。。。。。。。。");
return "success";
}
@RequestMapping(value = "/delete", method = RequestMethod.POST)
public String delete() {
System.out.println("刪除賬戶。。。。。。。。");
return "success";
}
/*
* 屬性:
value:用於指定請求的 URL。它和 path 屬性的作用是一樣的。
method:用於指定請求的方式。
params:用於指定限制請求參數的條件。它支持簡單的表達式。要求請求參數的 key 和 value 必須和配置的一模一樣。
* */
@RequestMapping(value = "/update", method = {RequestMethod.POST, RequestMethod.GET}, params = {"id"})
public String update() {
System.out.println("修改賬戶。。。。。。。。");
return "success";
}
}
四、請求參數的綁定
1、綁定的機制
我們都知道,表單中請求參數都是基於 key=value 的。SpringMVC 綁定請求參數的過程是通過把表單提交請求參數,作爲控制器中方法參數進行綁定的。
2、支持的數據類型
- 基本類型參數:包括基本類型和 String 類型
- POJO 類型參數:包括實體類,以及關聯的實體類
- 數組和集合類型參數:包括 List 結構和 Map 結構的集合(包括數組)
3、使用要求
- 如果是基本類型或者 String 類型:要求我們的參數名稱必須和控制器中方法的形參名稱保持一致。(嚴格區分大小寫)
- 如果是 POJO 類型,或者它的關聯對象:要求表單中參數名稱和 POJO 類的屬性名稱保持一致。並且控制器方法的參數類型是 POJO 類型。
- 如果是集合類型,有兩種方式:
-
- 第一種:
要求集合類型的請求參數必須在 POJO 中。在表單中請求參數名稱要和 POJO 中集合屬性名稱相同。
給 List 集合中的元素賦值,使用下標。
給 Map 集合中的元素賦值,使用鍵值對。
- 第一種:
-
- 第二種:
接收的請求參數是 json 格式數據。需要藉助一個註解實現。
- 第二種:
4、示例代碼——基本類型作爲參數
jsp 代碼
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主頁</title>
</head>
<body>
<h2>基本類型參數綁定</h2>
<a href="${pageContext.request.contextPath}/account/add?accountId=1&accountName=lemon">點擊跳轉</a><hr/>
</body>
</html>
java控制器代碼
package cn.lemon;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/account")
public class AccountController {
@RequestMapping("/add")
public String add(Integer accountId, String accountName){
System.out.println("添加賬戶,添加賬戶的 id 爲:" + accountId + ",添加賬戶的姓名爲:" + accountName);
return "success";
}
}
5、示例代碼——POJO 類型作爲參數
定義實體類 Account.java、User.java
package cn.lemon.domain;
import java.io.Serializable;
public class Account implements Serializable {
private String username;
private String password;
private Double money;
private User user;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", money=" + money +
", User=" + user +
'}';
}
}
package cn.lemon.domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private String uname;
private Integer age;
private Date birthday;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"uname='" + uname + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
}
}
jsp頁面代碼
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主頁</title>
</head>
<body>
<h2>POJO 實體類</h2>
<form action="${pageContext.request.contextPath}/account/add" method="post">
姓名:<input type="text" name="username"/><br>
密碼:<input type="text" name="password"/><br>
金額:<input type="text" name="money"/><br>
用戶姓名:<input type="text" name="user.uname"/><br>
用戶年齡:<input type="text" name="user.age"/><br>
<input type="submit" value="提交"/>
</form>
</body>
</html>
java控制器代碼
package cn.lemon.controller;
import cn.lemon.domain.Account;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/account")
public class AccountController {
@RequestMapping(value = "/add",method = RequestMethod.POST)
public String add(Account account){
System.out.println("添加成功" + account);
return "success";
}
}
6、示例代碼——數組和集合類型作爲參數
在User.java 實體類中添加集合,並生成get 、set 方法
private List<Account> accountList = new ArrayList<>();
private Map<String, Account> accountMap = new HashMap<>();
jsp頁面代碼
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主頁</title>
</head>
<body>
<h2>封裝參數到集合(list,map)</h2>
<form action="${pageContext.request.contextPath}/user/add" method="post">
用戶姓名:<input type="text" name="uname" /><br/>
用戶年齡:<input type="text" name="age" /><br/>
賬號1名字:<input type="text" name="accountList[0].username" /><br/>
賬號1金額:<input type="text" name="accountList[0].money" /><br/>
賬號2名字:<input type="text" name="accountList[1].username" /><br/>
賬號2金額:<input type="text" name="accountList[1].money" /><br/>
賬號3名字:<input type="text" name="accountList[2].username" /><br/>
賬號3金額:<input type="text" name="accountList[2].money" /><br/>
<hr>
map1名字:<input type="text" name="accountMap['one'].username" /><br/>
map1金額:<input type="text" name="accountMap['one'].money" /><br/>
map2名字:<input type="text" name="accountMap['two'].username" /><br/>
map2金額:<input type="text" name="accountMap['two'].money" /><br/>
<input type="submit" value="提交" />
</form>
</body>
</html>
java控制器代碼
package cn.lemon.controller;
import cn.lemon.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/add")
public String add(User user) {
System.out.println("添加用戶..." + user);
return "success";
}
}
7、請求參數亂碼問題
1、post 請求方式:
在 web.xml 中配置一個 SpringMVC 編碼過濾器
<!--配置 SpringMVC 編碼過濾器-->
<filter>
<filter-name>filter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--設置過濾器中的屬性值-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!--啓動過濾器,默認情況下是啓動的,可以省略-->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!--過濾所有請求-->
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2、get 請求方式:
tomacat 對 GET 和 POST 請求處理方式是不同的,GET 請求的編碼問題,要改 tomcat 的 server.xml 配置文件(Tomcat 8 已經解決)
8、自定義類型轉換器
第一步:定義一個類 StringToDateConverter.java,實現 Converter 接口
package cn.lemon.utils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringToDateConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
try {
if (StringUtils.isEmpty(s)) {
throw new NullPointerException("請輸入日期");
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(s);
} catch (Exception e) {
throw new RuntimeException("輸入的日期錯誤");
}
}
}
第二步:在 spring 配置文件中(SpringMVC.xml)配置類型轉換器
spring 配置類型轉換器的機制是,將自定義的轉換器註冊到類型轉換服務中去。
<!--配置類型轉換器工廠-->
<bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!--給工廠注入一個新的類型轉換器-->
<property name="converters">
<array>
<!--配置自定義類型轉換器-->
<bean class="cn.lemon.utils.StringToDateConverter"/>
</array>
</property>
</bean>
第三步:在 annotation-driven 標籤中引用配置的類型轉換服務
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>
8、SpringMVC 使用 Servlet API
jsp代碼
<a href="${pageContext.request.contextPath}/servletapi">點擊跳轉</a>
java控制器代碼
@RequestMapping("/servletapi")
public String servletApi(HttpServletRequest request, HttpServletResponse response, HttpSession session, PrintWriter printWriter) throws Exception {
System.out.println(request);
System.out.println(response);
System.out.println(session);
//response.getWriter().print("hello servlet ......");
printWriter.print("hello servlet .......");
return null;
}
五、常用的註解
1、RequestParam
作用: 把請求中指定名稱的參數給控制器中的形參賦值。
屬性:
value:請求參數中的名稱。
required:請求參數中是否必須提供此參數。默認值:true。表示必須提供,如果不提供將報錯。
jsp代碼
<h2>RequestParam 註解</h2>
<a href="${pageContext.request.contextPath}/user/requestparam?name=lemon&location=beijing&age=18">點擊訪問</a>
java 代碼
package cn.lemon.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/requestparam")
//第一個@RequestParam(name = "name") 是可以省略的
// 第二個是不可以省略的,
// 第三個 @RequestParam 中 required = true,意思是必須要傳入的參數,默認 required = false
//第四個 @RequestParam ,是設置默認值
public String requestParam(
@RequestParam(name = "name") String name,
@RequestParam(name = "location") String address,
@RequestParam(required = true) Integer age,
@RequestParam(defaultValue = "lemon") String usernmae){
System.out.println("RequestParam , name = " + name + ",address = " + address + ",age =" + age + ",username = " + usernmae);
return "success";
}
}
2、RequestBody
作用: 用於獲取請求體內容。直接使用得到是 key=value&key=value...
結構的數據。get 請求方式不適用。
屬性:
required:是否必須有請求體。默認值是:true。當取值爲 true 時,get 請求方式會報錯。如果取值爲 false,get 請求得到是 null。
jsp 頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主頁</title>
</head>
<script src="${pageContext.request.contextPath}/js/jquery-2.1.0.min.js" charset="utf-8"></script>
<body>
<h2>RequestBody 註解</h2>
<form action="${pageContext.request.contextPath}/user/requestbody" method="post">
姓名:<input type="text" name="username"><br>
密碼:<input type="password" name="password"><br>
年齡:<input type="text" name="age"><br>
<input type="submit" value="保存">
</form>
<h2>RequestBody2 註解</h2>
<input type="button" value="提交ajax" id="btn">
<script>
$(function () {
$("#btn").click(function () {
var json = {'username':'lemon','password':'1223','age':'18'};//定義一個json對象
var string_json = JSON.stringify(json);//把json 對象轉換成一個字符串
/*使用 Ajax 發送 HTTP 請求*/
$.ajax({
method:"POST",
url:"${pageContext.request.contextPath}/user/requestbody2",
contentType:"application/json;charset=UTF-8",
data:string_json,
success:function (result) {
alert(result);
}
})
})
})
</script>
</body>
</html>
java頁面
package cn.lemon.controller;
import cn.lemon.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/requestbody")
//@RequestBody 可以把請求體轉換爲字符串
public String requestBody(@RequestBody String body) {
System.out.println("body = " + body);
return "success";
}
@RequestMapping("/requestbody2")
//@RequestBody 可以把請求體轉換爲user 對象
//不過,@RequestBody 需要藉助 Jackson 框架(Maven引入 jackson 如上圖),把json字符串序列化成實體對象
public String requestBody2(@RequestBody User user) {
System.out.println(user);
return null;
}
}
在SpringMVC.xml中配置靜態資源不過濾
<!--
在 springmvc 的配置文件中可以配置,靜態資源不過濾 (因爲上面過濾掉了所有請求):
location 表示路徑,mapping 表示文件,**表示該目錄下的文件以及子目錄的文件
-->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/scripts/" mapping="/javascript/**"/>
3、PathVariable
作用: 用於綁定 url 中的佔位符。例如:請求 url 中 /delete/{id}
,這個{id}
就是 url 佔位符。url 支持佔位符是 spring3.0 之後加入的。是 springmvc 支持 rest 風格 URL 的一個重要標誌。
屬性:
value:用於指定 url 中佔位符名稱。
required:是否必須提供佔位符。
jsp 代碼
<a href="${pageContext.request.contextPath}/user/pathvariable/100">PathVariable</a>
java 代碼
@RequestMapping("/pathvariable/{id}")
public String pathVariable(@PathVariable("id") Integer id) {
System.out.println("添加成功,id = " + id);
return "success";
}
4、REST 風格 URL
REST(英文:Representational State Transfer,簡稱 REST)描述了一個架構樣式的
restful 的示例:
/account
HTTP POST: 新增 account/account/1
HTTP GET : 得到 id = 1 的 account/account/1
HTTP DELETE: 刪除 id = 1 的 account/account/1
HTTP PUT: 更新 id = 1 的 account
基於 HiddentHttpMethodFilter 的示例
作用:
- 由於瀏覽器 form 表單只支持 GET 與 POST 請求,而 DELETE、PUT 等 method 並不支持,Spring3.0添加了一個過濾器,可以將瀏覽器請求改爲指定的請求方式,發送給我們的控制器方法,使得支持 GET、POST、PUT 與 DELETE 請求。
使用方法:
- 第一步:在 web.xml 中配置該過濾器。
- 第二步:請求方式必須使用 post 請求。
- 第三步:按照要求提供_method 請求參數,該參數的取值就是我們需要的請求方式。
web.xml 中的過濾器
<!--使瀏覽器支持 rest 風的 URL-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<!--映射路徑-->
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
jsp代碼
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主頁</title>
</head>
<body>
<h2>rest 風格的 URL</h2>
<form action="${pageContext.request.contextPath}/rest/add" method="post">
<input type="submit" value="新增">
</form>
<form action="${pageContext.request.contextPath}/rest/delete/100" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="刪除">
</form>
<form action="${pageContext.request.contextPath}/rest/update/100" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="更新">
</form>
<a href="${pageContext.request.contextPath}/rest/find/100">查詢</a>
</body>
</html>
java 代碼
package cn.lemon.controller;
import cn.lemon.domain.Account;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/rest")
public class RestController {
/*
/account HTTP POST: 添加 account
/account/1 HTTP GET : 查詢 id = 1 的 account
/account/1 HTTP DELETE: 刪除 id = 1 的 account
/account/1 HTTP PUT: 更新 id = 1 的 account
*/
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String add(Account account) {
System.out.println("添加用戶,用戶爲:" + account);
return "success";
}
@RequestMapping(value = "/find/{id}", method = RequestMethod.GET)
public String find(@PathVariable("id") Integer id) {
System.out.println("查詢用戶,用戶的id 爲:" + id);
return "success";
}
@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
public String delete(@PathVariable("id") Integer id) {
System.out.println("刪除用戶,id 爲:" + id);
return "redirect:/index.jsp";//提醒:這裏需要重定向,不能轉發
}
@RequestMapping(value = "/update/{id}", method = RequestMethod.PUT)
public String update(@PathVariable("id") Integer id) {
System.out.println("更新用戶,更新的id 爲:" + id);
return "redirect:/index.jsp";//提醒:這裏需要重定向,不能轉發
}
}
5、RequestHeader
作用: 用於獲取請求消息頭。
屬性:
value:提供消息頭名稱
required:是否必須有此消息頭
jsp 代碼
<h2>RequestHeader 獲取請求頭</h2>
<a href="${pageContext.request.contextPath}/other/header">獲取請求頭</a>
java 代碼
package cn.lemon.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/other")
public class OtherController {
@RequestMapping("/header")
public String requestHeader(@RequestHeader(value = "Accept-Language",required = false) String requestHeader){
System.out.println("獲取請求頭消息,消息爲:" + requestHeader);
return "success";
}
}
6、CookieValue
作用: 用於把指定 cookie 名稱的值傳入控制器方法參數。
屬性:
value:指定 cookie 的名稱。
required:是否必須有此 cookie。
jsp 代碼
<h2>CookieValue 傳Cookie的值</h2>
<a href="${pageContext.request.contextPath}/other/cookie">Cookie</a>
java 代碼
@RequestMapping("/cookie")
public String cookieValue(@CookieValue(value = "JSESSIONID",required = false) String cookieValue) {
System.out.println("獲取 Cookie 的值," + cookieValue);
return "success";
}
7、ModelAttribute
作用: 該註解是 SpringMVC4.3 版本以後新加入的。它可以用於修飾方法和參數。出現在方法上,表示當前方法會在控制器的方法執行之前,先執行。它可以修飾沒有返回值的方法,也可以修飾有具體返回值的方法。出現在參數上,獲取指定的數據給參數賦值。
屬性:
value:用於獲取數據的 key。key 可以是 POJO 的屬性名稱,也可以是 map 結構的 key。
應用場景:
當表單提交數據不是完整的實體類數據時,保證沒有提交數據的字段使用數據庫對象原來的數據。
例如:
我們在編輯一個用戶時,用戶有一個創建信息字段,該字段的值是不允許被修改的。在提交表單數據是肯定沒有此字段的內容,一旦更新會把該字段內容置爲 null,此時就可以使用此註解解決問題。
jsp 代碼
<h2>ModelAttribute 在控制器方法之前執行</h2>
<a href="${pageContext.request.contextPath}/other/model">ModelAttribute</a>
java 代碼
@ModelAttribute
public void showModel(User user) {
System.out.println("這是被 @ModelAttribute 修飾的方法,方法名爲 showModel" + user);
}
@RequestMapping("/model")
public String modelAttribute(User user) {
System.out.println("執行了控制器的方法");//會執行被 @ModelAttribute 修飾的方法
return "success";
}
8、SessionAttribute
作用: 用於多次執行控制器方法間的參數共享。
屬性:
value:用於指定存入的屬性名稱
type:用於指定存入的數據類型。