SpringMVC(三)Restful風格及實例、參數的轉換


個人博客網:https://wushaopei.github.io/    (你想要這里多有)

一、Restful風格

1、Restful風格的介紹

Restful 一種軟件架構風格、設計風格,而不是標准,只是提供了一組設計原則和約束條件。它主要用於客戶端和服務器交互類的軟件。基於這個風格設計的軟件可以更簡潔,更有層次,更易於實現緩存等機制。

 

REST(英文:Representational State Transfer,簡稱REST)描述了一個架構樣式的網絡系統,比如 web 應用程序。在目前主流的三種Web服務交互方案中,REST相比於SOAP(Simple Object Access protocol,簡單對象訪問協議)以及XML-RPC更加簡單明了,無論是對URL的處理還是對Payload的編碼,REST都傾向於用更加簡單輕量的方法設計和實現。值得注意的是REST並沒有一個明確的標准,而更像是一種設計的風格。

原則條件

REST 指的是一組架構約束條件和原則。滿足這些約束條件和原則的應用程序或設計就是 RESTful。

Web 應用程序最重要的 REST 原則是,客戶端和服務器之間的交互在請求之間是無狀態的。從客戶端到服務器的每個請求都必須包含理解請求所必需的信息。如果服務器在請求之間的任何時間點重啟,客戶端不會得到通知。此外,無狀態請求可以由任何可用服務器回答,這十分適合雲計算之類的環境。客戶端可以緩存數據以改進性能。

在服務器端,應用程序狀態和功能可以分為各種資源。資源是一個有趣的概念實體,它向客戶端公開。資源的例子有:應用程序對象、數據庫記錄、算法等等。每個資源都使用 URI (Universal Resource Identifier) 得到一個唯一的地址。所有資源都共享統一的接口,以便在客戶端和服務器之間傳輸狀態。使用的是標准的 HTTP 協議,比如 GET、PUT、POST 和 DELETEHypermedia 是應用程序狀態的引擎,資源表示通過超鏈接互聯。

 

干貨(簡單明了):

Restful是一種設計風格。對於我們Web開發人員來說。就是使用一個url地址表示一個唯一的資源。然后把原來的請求參數加入到請求資源地址中。然后原來請求的增,刪,改,查操作。改為使用HTTP協議中請求方式GET、POST、PUT、DELETE表示。

  1. 把請求參數加入到請求的資源地址中
  2. 原來的增,刪,改,查。使用HTTP請求方式,POST、DELETE、PUT、GET分別一一對應。

二、如何學習restful風格,這里需要明確兩點:

1、就是把傳統的請求參數加入到請求地址是什么樣子?

傳統的方式是:

比如:http://ip:port/工程名/資源名?請求參數

舉例:http://127.0.0.1:8080/springmvc/book?action=delete&id=1

restful風格是:

比如:http://ip:port/工程名/資源名/請求參數/請求參數

舉例:http://127.0.0.1:8080/springmvc/book/1

請求的動作刪除由請求方式delete決定

2、restful風格中請求方式GET、POST、PUT、DELETE分別表示查、增、改、刪。


GET請求		對應    查詢
http://ip:port/工程名/book/1		HTTP請求GET		表示要查詢id為1的圖書
http://ip:port/工程名/book		HTTP請求GET		表示查詢全部的圖書

POST請求	對應	添加
http://ip:port/工程名/book		HTTP請求POST		表示要添加一個圖書

PUT請求		對應	修改
http://ip:port/工程名/book/1		HTTP請求PUT		表示要修改id為1的圖書信息

DELETE請求	對應	刪除
http://ip:port/工程名/book/1		HTTP請求DELETE		表示要刪除id為1的圖書信息

3、SpringMVC中如何發送GET請求、POST請求、PUT請求、DELETE請求

 我們知道發起GET請求和POST請求,只需要在表單的form標簽中,設置method=”get” 就是GET請求。

設置form標簽的method=”post”。就會發起POST請求。而PUT請求和DELETE請求。要如何發起呢。

  1. 要有post請求的form標簽
  2. 在form表單中,添加一個額外的隱藏域_method=”PUT”或_method=”DELETE”
  3. 在web.xml中配置一個Filter過濾器org.springframework.web.filter.HiddenHttpMethodFilter(注意,這個Filter一定要在處理亂碼的Filter后面
        <!-- 負責把隱藏域中的put,改為請求的put請求 --> <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>

三、Restful風格的Controller如何實現

1、Controller實現代碼

@Controller public class RestfulController { @RequestMapping(value="/book/1",method=RequestMethod.GET) public String queryBookById() { System.out.println("根據id查詢一本圖書"); return "/restful.jsp"; } @RequestMapping(value="/book",method=RequestMethod.GET) public String queryBooks() { System.out.println("查詢全部圖書"); return "/restful.jsp"; } @RequestMapping(value="/book",method=RequestMethod.POST) public String addBook() { System.out.println("post請求 添加圖書"); return "/restful.jsp"; } @RequestMapping(value="/book/1",method=RequestMethod.PUT) public String updateBook() { System.out.println("修改圖書"); return "/restful.jsp"; } @RequestMapping(value="/book/1",method=RequestMethod.DELETE) public String deleteBook() { System.out.println("刪除圖書"); return "/restful.jsp"; } }

2、restful風格的jsp頁面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <a href="${ pageContext.request.contextPath }/book/1">查詢一本圖書</a> <a href="${ pageContext.request.contextPath }/book">查詢全部圖書</a> <form action="${ pageContext.request.contextPath }/book" method="post"> <input type="submit" value="post添加圖書"/> </form> <form action="${ pageContext.request.contextPath }/book/1" method="post"> <!-- 表示這是put請求 --> <input type="hidden" name="_method" value="PUT"/> <input type="submit" value="put修改圖書"/> </form> <form action="${ pageContext.request.contextPath }/book/1" method="post"> <!-- 表示這是DELETE請求 --> <input type="hidden" name="_method" value="DELETE"/> <input type="submit" value="DELETE 刪除圖書"/> </form> </body> </html>

四、Restful風格在高版本Tomcat中無法轉發到jsp頁面

在Tomcat8之后的一些高版本,使用restful風格訪問然后轉發到jsp頁面。就會有如下的錯誤提示:

解決有兩個方法:

1、在需要跳轉去的頁面中設置當前是錯誤頁面isErrorPage="true"

2、在put或delete方法中,使用重定向返回

五、@PathVariable 路徑參數獲取

前面我們已經知道如何編寫和配置restful風格的請求和控制器。

那么 現在的問題是。如何接收restful風格請求的參數。比如前面的id值。

第一種情況,一個path參數:

        /** * @PathVariable 注解表示取路徑參數的值。<br/> * value="/book/{id}" 這里我們把id寫成了{id}這是路徑參數<br/> * @PathVariable(name="id") 這里的name屬性表示把路徑參數id的值注入到請求方法的id參數中 */ @RequestMapping(value="/book/{id}",method=RequestMethod.GET) public String queryBookById(@PathVariable(name="id") Integer id) { System.out.println("根據id查詢一本圖書。 id ====>>>> " + id); return "/restful.jsp"; }

第二種情況,多個path參數

        /** * @PathVariable 注解表示取路徑參數的值。<br/> * value="/book/{id}" 這里我們把id寫成了{id}這是路徑參數<br/> * @PathVariable(name="id") 這里的name屬性表示把路徑參數id的值注入到請求方法的id參數中<br/> * name的屬性,表示取路徑中哪個參數。默認情況下。參數名是name的值<br/> */ @RequestMapping(value = "/book/{id}/{abc}", method = RequestMethod.GET) public String queryBookById(@PathVariable(name = "id") Integer id, @PathVariable(name = "abc") String abc) { System.out.println("根據id查詢一本圖書。 id ====>>>> " + id); System.out.println("abc ===>>>> " + abc); return "/restful.jsp"; }

六、Restful風格實現的CRUD圖書

把前面的傳統請求方式的圖書的CRUD換成剛剛講的Restful風格的圖書模塊的CRUD。只需要修改頁面端的請求方式和地址,以及服務器端Controller的接收。

1、Restful風格的crud工程的搭建

2、列表功能實現

Controller中的代碼:

        /** * 查詢全部圖書 * * @return */ @RequestMapping(value = "/book", method = RequestMethod.GET) public ModelAndView list() { // 2 轉發到book/bookList.jsp頁面 ModelAndView modelAndView = new ModelAndView("bookList"); // 1 查詢全部的圖書,保存到request域中 modelAndView.addObject("bookList", bookService.queryBooks()); return modelAndView; }

請求方式:

<href="${ pageContext.request.contextPath }/book">圖書管理</a>

3、刪除功能實現

Controller中的代碼:

        @RequestMapping(value = "/book/{id}",method=RequestMethod.DELETE) public ModelAndView delete(@PathVariable(name="id") Integer id) { // 調用BookService刪除圖書 bookService.deleteBookById(id); // 重定向 到圖書列表管理頁面 return new ModelAndView("redirect:/book"); }

到web.xml中去配置 支持restful風格的Filter過濾器

        <!-- 配置支持restful的Filter過濾器 --> <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>

bookList.jsp中,需要修改提交的方式:

	    <td> <!-- 表示啥也不干 --> <a class="deleteA" itemId="${ book.id }" href="javascript:void(0);">刪除</a>、 <a href="${ pageContext.request.contextPath }/book/getBook?id=${book.id}">修改</a> <form id="item_${ book.id }" action="${ pageContext.request.contextPath }/book/${book.id}" method="post"> <input type="hidden" name="_method" value="DELETE" /> </form> </td>
        <script type="text/javascript"> $(function(){ // 給刪除綁定單擊事件 $("a.deleteA").click(function(){ // 提示用戶確認操作 if ( confirm("你確定要刪除【" + $(this).parent().parent().find("td:first").text() + "】嗎?")){ // 點擊刪除,提交form表單 // submit(function(){})是給表單的提交事件添加功能 // submit() 讓表單提交 $("#item_" + $(this).attr("itemId")).submit(); } }); }); </script> 

4、添加功能實現

        @RequestMapping(value = "/book", method = RequestMethod.POST) public ModelAndView add(Book book) { // 1 調用bookService保存 bookService.addBook(book); // 2 重定向回圖書列表管理頁面 return new ModelAndView("redirect:/book"); }

bookEdit.jsp頁面請求方式需要調整:

5、更新功能實現

更新圖書分為兩個步驟:

  1. 查詢需要更新的圖書,填充到更新頁面
  2. 提交請求,發送數據給服務器更新保存修改。

5.1、查詢需要更新的圖書,填充到更新頁面

        @RequestMapping(value = "/book/{id}", method = RequestMethod.GET) public ModelAndView getBook(@PathVariable(name = "id") Integer id) { ModelAndView modelAndView = new ModelAndView(); // 模型 是需要修改的圖書===調用BookService.queryBookById modelAndView.addObject("book", bookService.queryBookById(id)); // 設置跳轉的頁面 modelAndView.setViewName("bookEdit"); return modelAndView; }

5.2、提交請求,發送數據給服務器更新保存修改。

        @RequestMapping(value = "/book/{id}",method=RequestMethod.PUT) public ModelAndView update(@PathVariable Integer id, Book book) { // 保存修改 bookService.updateBook(book); // 跳到圖書列表管理頁面 return new ModelAndView("redirect:/book"); }

bookEdit.jsp頁面的修改

<center> <h3>添加圖書</h3> <c:if test="${ not empty requestScope.book }"> <form action="${ pageContext.request.contextPath }/book/${requestScope.book.id}" method="post"> </c:if> <c:if test="${ empty requestScope.book }"> <form action="${ pageContext.request.contextPath }/book" method="post"> </c:if> <c:if test="${ not empty requestScope.book }"> <input type="hidden" name="_method" value="PUT"/> </c:if> <input type="hidden" name="id" value="${ requestScope.book.id }"/> <table> <tr> <td>書名</td> <td><input name="name" type="text" value="${ requestScope.book.name }"/></td> </tr> <tr> <td>作者</td> <td><input name="author" type="text" value="${ requestScope.book.author }" /></td> </tr> <tr> <td>價格</td> <td><input name="price" type="text" value="${ requestScope.book.price }" /></td> </tr> <tr> <td>銷量</td> <td><input name="sales" type="text" value="${ requestScope.book.sales }" /></td> </tr> <tr> <td>庫存</td> <td><input name="stock" type="text" value="${ requestScope.book.stock }"/></td> </tr> <tr> <td align="center" colspan="2"> <input type="submit" /> </td> </tr> </table> </form> </center>

6、字符集的Filter一定要在Restful的Filter前面

        <filter> <filter-name>CharacterEncodingFilter</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>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置支持restful的Filter過濾器 --> <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>

七、SpringMVC標簽庫

1、搭建SpringMVC開發環境

2、創建對象模型Person對象

public class Person { private Integer id; private String name; private Date birthDate; private String email; private BigDecimal salary;

PersonController控制器代碼:

@Controller public class PersonController { @RequestMapping(value="/toAddPerson") public String toAddPerson(Map<String, Object> map) { System.out.println("經過Controller控制器"); map.put("person", new Person());// return "/person/addPerson.jsp"; } @RequestMapping("/addPerson") public String addPerson(Person person) { System.out.println("添加用戶:" + person); return "/index.jsp"; } }

addPerson.jsp頁面

        <body> 添加用戶 <!-- action 提交的地址 method 請求的方式 modelAttribute SpringMVC的標簽庫,需要跟隱含模型中一個對象相對應 modelAttribute="person"一定要和隱含模型中的key相對應 也就是Person用戶模塊,隱含模型中的key是person,表單的modelAttribute屬性值也是person 如果是圖書模塊,隱含模型中的key是book,表單的modelAttribute屬性值也是book --> <form:form action="${ pageContext.request.contextPath }/addPerson" modelAttribute="person" method="post"> <!-- 每個input 的path屬性值要跟模型的屬性名相對應 --> id <form:input path="id"/><br/> name <form:input path="name"/><br/> birthDate <form:input path="birthDate"/><br/> email <form:input path="email"/><br/> salary <form:input path="salary"/><br/> <input type="submit" /> </form:form> </body>

八、自定義參數轉換器

1、WebDataBinder類介紹

SpringMVC中有WebDataBinder類。這個類專門用來負責將請求參數類型轉換。以及請求參數數據驗證,錯誤信息綁定等功能。

WebDataBinder會調用各種類型轉換器,得到屬性相對應類型的值。然后再注入到屬性中(調用setXxxx方法)

WebDataBinder類中有三個組件分別處理三種不同的功能。

        conversionService 負責處理參數類型轉換。把請求的參數轉換成為Controller中的方法參數值。

convertersConversionService組件中需要各種類型轉換器,在conversionService組件中需要依賴於各種轉換器類去實現轉換工作。

         validators 負責驗證傳入的參數值是否合法。

         bindingResult 負責接收驗證后的錯誤信息。

下圖展示了WebDataBinder、ConversionService、Converter的關系。

如果我們要自定義請求參數的類型轉換器。需要實現

org.springframework.core.convert.converter.Converter<S,T>接口。

然后注入到ConversionService組件中。最后再將ConversionService注入到WebDataBinder中。

創建ConversionService組件,需要配置

org.springframework.format.support.FormattingConversionServiceFactoryBean對象。

2、自定義String到java.util.Date類型轉換器

public class MyStringToDate implements Converter<String, Date> { private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); /** * convert方法負責轉換<br/> * source客戶端發送過來的值<br/> * Date轉換之后的結果 */ @Override public Date convert(String source) { if (source == null) { return null; } source = source.trim(); try { // 調用轉換器 return sdf.parse(source); } catch (ParseException e) { e.printStackTrace(); throw new IllegalArgumentException("Invalid java.util.Date value '" + source + "'"); } } }

到ApplicationContext.xml中去配置,並使用

	<!-- 配置一個類型轉換器組件 --> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <!-- 把你自定義的類型轉換器注入到ConversionService組件中 --> <property name="converters"> <set> <bean class="com.webcode.converter.MyStringToDate"/> </set> </property> </bean> <!-- springMVC的標配 --> <mvc:default-servlet-handler/> <!-- SpringMVC中的高級功能 conversion-service="conversionService" 將你自己配置的類型轉換器,注入到SpringMVC的系統中 --> <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven> 

3、@DateTimeFormat注解類型轉換器

我們也可以像上面。在類的Date類型的屬性上標上注解。就可以自動將String類型轉換成為Date數據

pattern屬性表示 日期的格式。最完成的格式是:yyyy-MM-dd hh:mm:ss

    yyyy    表示年份必須是4位
    MM	    表示月份必須是2位
    dd	    表示日期必須是2位

    hh	    表示小時,必須是2位
    mm	    表示分鍾,必須是2位
    ss	    表示秒鍾,必須是2位

九、較驗器----參數的有效性驗證Validate----Hibernate

在JavaEE6.0中,定義了很多的驗證規范。這些規范統稱為:JSR303驗證規范。

而這些規范的實現。我們使用現在業內比較認可的Hibernate-Validate驗證

 

@AssertTrue

用於boolean字段,該字段只能為true  

@AssertFalse

該字段的值只能為false

@CreditCardNumber

對信用卡號進行一個大致的驗證

@DecimalMax

只能小於或等於該值

@DecimalMin

只能大於或等於該值

@Digits(integer=,fraction=)

檢查是否是一種數字的整數、分數,小數位數的數字

@Email

檢查是否是一個有效的email地址

@Future

檢查該字段的日期是否是屬於將來的日期

@Length(min=,max=)

檢查所屬的字段的長度是否在min和max之間,只能用於字符串

@Max

該字段的值只能小於或等於該值

@Min

該字段的值只能大於或等於該值

@NotNull

不能為null

@NotBlank

不能為空,檢查時會將空格忽略

@NotEmpty

不能為空,這里的空是指空字符串

@Null

檢查該字段為空

@Past

檢查該字段的日期是在過去

@Pattern(regex=,flag=)

被注釋的元素必須符合指定的正則表達式

@Range(min=,max=,message=)

被注釋的元素必須在合適的范圍內

@Size(min=, max=)

檢查該字段的size是否在min和max之間,可以是字符串、數組、集合、Map等

@URL(protocol=,host,port)

檢查是否是一個有效的URL,如果提供了protocol,host等,則該URL還需滿足提供的條件

使用Hiberante的驗證器較驗數據分以下步驟:

  1. 入Hibernate驗證的jar包

        hibernate-validator-5.0.0.CR2.jar

        hibernate-validator-annotation-processor-5.0.0.CR2.jar

        classmate-0.8.0.jar

        jboss-logging-3.1.1.GA.jar

        validation-api-1.1.0.CR1.jar

    2. 在實體bean對象的屬性上使用校驗的注解

    3. 在Controller的方法參數上,給需要驗證的bean對象。添加驗證注解@Valid,以及在驗證對象后跟一個BindingResult 對象用於接收驗證的錯誤信息

        /** * @Valid當前方法的person參數我要做數據較驗<br/> * BindingResult用來接收前面一個對象的錯誤信息 */ @RequestMapping("/addPerson") public String addPerson(@Valid Person person, BindingResult personBindingResult) { if (personBindingResult.hasErrors()) { personBindingResult.getAllErrors().forEach(System.out::println); return "/person/addPerson.jsp"; } System.out.println("添加用戶:" + person); return "/index.jsp"; }

     4. 在SpringMVC的form表單字段后,使用<form:errors path="字段名" />輸出對應字段的錯誤信息

	<form:form action="${ pageContext.request.contextPath }/addPerson" modelAttribute="person" method="post"> <!-- 每個input 的path屬性值要跟模型的屬性名相對應 --> id:<form:input path="id"/><form:errors path="id" /><br/> name:<form:input path="name"/><form:errors path="name" /><br/> birthDate:<form:input path="birthDate"/><form:errors path="birthDate" /><br/> email:<form:input path="email"/><form:errors path="email" /><br/> salary:<form:input path="salary"/><form:errors path="salary" /><br/> <input type="submit" /> </form:form>

十、自定義錯誤信息的回顯

1、錯誤消息規則:

這是校驗錯誤的key規則:

格式1:	        Pattern.bean.property
說明:		校驗格式.隱含模型包.屬性名
示例:		Email.person.email		person對象的email屬性驗證Email格式失敗

格式2:	        Pattern.property
說明:		校驗格式.屬性名
示例:		Email.email			任何對象的email屬性驗證Email格式失敗

格式3:	        Pattern.javaType
說明:		校驗格式.字段數據類型
示例:		Email.java.lang.String		任何String類型的屬性驗證Email格式失敗

key4:		Pattern
說明:		校驗格式
示例:		Email				校驗Email格式失敗

參數轉換失敗的key規則:

格式1:		typeMismatch.bean.property
說明:		類型不匹配.隱含模型包.屬性名
示例:		typeMismatch.person.birthDate	person對象的birthDate屬性轉換失敗

格式2:		typeMismatch.property
說明:		類型不匹配.屬性名
示例:		typeMismach.birthDate		任何對象的birthDate屬性轉換失敗

格式3:	        typeMismatch.javaType
說明:		類型不匹配.字段數據類型
示例:		typeMismach.java.util.Date	Java.util.Date類型轉換失敗

格式4:	        typeMismatch
說明:		類型不匹配
示例:		typeMismach			字段類型轉換失敗

2、在源碼目錄下配置錯誤信息的屬性配置文件

Past=\u8FD9\u4E2A\u65F6\u95F4\u4E0D\u5BF9
typeMismatch.java.util.Date=\u975E\u6CD5\u8F93\u5165
Length=\u957F\u5EA6\u5FC5\u987B\u662F 5 \u5230 12 \u4F4D
Email=\u4E0D\u597D\u597D\u5E72\u6D3B\u660E\u5929\u6CA1\u996D\u5403
Min=\u4E0D\u80FD\u5C0F\u4E8E 3000
typeMismatch.salary=\u5DE5\u8D44\u8F93\u5165\u4E0D\u5BF9

3、在application.xml中配置屬性信息

        <!-- 
		org.springframework.context.support.ResourceBundleMessageSource可以做加載properties屬性配置文件使用,
		還可以做國際化
	 -->
	<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
		<!-- 
			basename配置文件名,但不帶后綴
		 -->
		<property name="basename" value="errors"/>
	</bean>

使用占位符{數字}

對於SpringMvc模型來說,傳值是框架做的工作。我們只需要寫好數字即可。

第一個參數Spring傳入的是驗證的屬性名


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM