SpringMVC學習系列(7) 之 格式化顯示
在系列(6)中我們介紹瞭如何驗證提交的資料的正確性,當資料驗證通過後就會被我們儲存起來。儲存的資料會用於以後的展示,這才是儲存的價值。那麼在展示的時候如何按照要求顯示?(比如:小數保留一定的位數,日期按指定的格式等)。這就是本篇要說的內容—>格式化顯示。
從Spring3.X開始,Spring提供了Converter SPI型別轉換和Formatter SPI欄位解析/格式化服務,其中Converter SPI實現物件與物件之間的相互轉換,Formatter SPI實現String與物件之間的轉換,Formatter SPI是對Converter SPI的封裝並添加了對國際化的支援,其內部轉換還是由Converter SPI完成。
下面是一個簡單的請求與模型物件的轉換流程:
Spring提供了FormattingConversionService和DefaultFormattingConversionService來完成物件的解析和格式化。Spring內建的幾種Formatter SPI如下:
名稱 | 功能 |
NumberFormatter | 實現Number與String之間的解析與格式化 |
CurrencyFormatter | 實現Number與String之間的解析與格式化(帶貨幣符號) |
PercentFormatter | 實現Number與String之間的解析與格式化(帶百分數符號) |
DateFormatter | 實現Date與String之間的解析與格式化 |
NumberFormatAnnotationFormatterFactory | @NumberFormat註解,實現Number與String之間的解析與格式化,可以通過指定style來指示要轉換的格式(Style.Number/Style.Currency/Style.Percent),當然也可以指定pattern(如pattern=“#.##”(保留2位小數) ),這樣pattern指定的格式會覆蓋掉Style指定的格式 |
JodaDateTimeFormatAnnotationFormatterFactory | @DateTimeFormat註解,實現日期型別與String之間的解析與格式化這裡的日期型別包括Date、Calendar、Long以及Joda的日期型別。必須在專案中新增Joda-Time包 |
下面就開始演示:
首先把Joda-Time包新增到之前的專案中,這裡用的是joda-time-2.3.jar,在views資料夾下新增一個formattest.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>
money:<br/>${contentModel.money}<br/> date:<br/>${contentModel.date}<br/>
</body> </html>
1.首先我們直接用Formatter來做演示,在com.demo.web.models包中新增FormatModel.java內容如下:
package com.demo.web.models; public class FormatModel{ private String money; private String date; public String getMoney(){ return money; } public String getDate(){ return date; } public void setMoney(String money){ this.money=money; } public void setDate(String date){ this.date=date; } }
在com.demo.web.controllers包中新增FormatController.java內容如下:
package com.demo.web.controllers; import java.math.RoundingMode; import java.util.Date; import java.util.Locale; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.format.datetime.DateFormatter; import org.springframework.format.number.CurrencyFormatter; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.demo.web.models.FormatModel; @Controller @RequestMapping(value = "/format") public class FormatController { @RequestMapping(value="/test", method = {RequestMethod.GET}) public String test(Model model) throws NoSuchFieldException, SecurityException{ if(!model.containsAttribute("contentModel")){ FormatModel formatModel=new FormatModel(); CurrencyFormatter currencyFormatter = new CurrencyFormatter(); currencyFormatter.setFractionDigits(2);//保留2位小數 currencyFormatter.setRoundingMode(RoundingMode.HALF_UP);//向(距離)最近的一邊舍入,如果兩邊(的距離)是相等的則向上舍入(四捨五入) DateFormatter dateFormatter=new DateFormatter(); dateFormatter.setPattern("yyyy-MM-dd HH:mm:ss"); Locale locale=LocaleContextHolder.getLocale(); formatModel.setMoney(currencyFormatter.print(12345.678, locale)); formatModel.setDate(dateFormatter.print(new Date(), locale)); model.addAttribute("contentModel", formatModel); } return "formattest"; } }
執行測試:
更改瀏覽器首選語言:
重新整理頁面:
2.這次用DefaultFormattingConversionService來做演示,把FormatController.java改為如下內容:
package com.demo.web.controllers; import java.math.RoundingMode; import java.util.Date; import org.springframework.format.datetime.DateFormatter; import org.springframework.format.number.CurrencyFormatter; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.demo.web.models.FormatModel; @Controller @RequestMapping(value = "/format") public class FormatController { @RequestMapping(value="/test", method = {RequestMethod.GET}) public String test(Model model) throws NoSuchFieldException, SecurityException{ if(!model.containsAttribute("contentModel")){ FormatModel formatModel=new FormatModel(); CurrencyFormatter currencyFormatter = new CurrencyFormatter(); currencyFormatter.setFractionDigits(2);//保留2位小數 currencyFormatter.setRoundingMode(RoundingMode.HALF_UP);//向(距離)最近的一邊舍入,如果兩邊(的距離)是相等的則向上舍入(四捨五入) DateFormatter dateFormatter=new DateFormatter(); dateFormatter.setPattern("yyyy-MM-dd HH:mm:ss"); DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(); conversionService.addFormatter(currencyFormatter); conversionService.addFormatter(dateFormatter); formatModel.setMoney(conversionService.convert(12345.678, String.class)); formatModel.setDate(conversionService.convert(new Date(), String.class)); model.addAttribute("contentModel", formatModel); } return "formattest"; } }
這次沒有了Locale locale=LocaleContextHolder.getLocale();再次執行測試並更改語言後重新整理,可以看到與第一種方法截圖同樣的效果,說明DefaultFormattingConversionService會自動根據瀏覽器請求的資訊返回相應的格式。
3.估計有人會覺得,啊…我只是想要格式化顯示而已,還要這麼麻煩,寫程式碼一個欄位一個欄位的轉換???別急,上面只是對內建的格式化轉換器做一下演示,實際專案中肯定不會這麼用的,下面就介紹一下基於註解的格式化。首先把FormatModel.java改為如下內容:
package com.demo.web.models; import java.util.Date; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.NumberFormat; import org.springframework.format.annotation.NumberFormat.Style; public class FormatModel{ @NumberFormat(style=Style.CURRENCY)
private double money; @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date date; public double getMoney(){ return money; } public Date getDate(){ return date; } public void setMoney(double money){ this.money=money; } public void setDate(Date date){ this.date=date; } }
注意:這裡的money和date不再是String型別,而是它們自己本來的型別。
把FormatController.java改為如下內容:
package com.demo.web.controllers; import java.util.Date; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.demo.web.models.FormatModel; @Controller @RequestMapping(value = "/format") public class FormatController { @RequestMapping(value="/test", method = {RequestMethod.GET}) public String test(Model model) throws NoSuchFieldException, SecurityException{ if(!model.containsAttribute("contentModel")){ FormatModel formatModel=new FormatModel(); formatModel.setMoney(12345.678); formatModel.setDate(new Date()); model.addAttribute("contentModel", formatModel); } return "formattest"; } }
注意:這裡程式碼裡面只有賦值已經沒有格式化的內容了。
更改檢視formattest.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"> <%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> money:<br/> <spring:eval expression="contentModel.money"></spring:eval><br/> date:<br/> <spring:eval expression="contentModel.date"></spring:eval><br/> </body> </html>
注意:這裡需要新增引用<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>,並用spring:eval來繫結要顯示的值。
執行測試更改瀏覽器語言然後重新整理頁面依然可以看到以第一種方法截圖相同的效果,證明註解有效。
格式化顯示的內容到此結束。
注: 之前沒注意前11篇的示例程式碼,不知道為什麼當時打包上傳上去的是沒有.project專案檔案的,導致下載後不能直接匯入eclipse執行,虛擬機器又 被我刪掉了,這些示例程式碼也沒有備份,但是程式碼檔案還在的,所以可以新建一個Dynamic Web Project把對應的配置檔案和controller還有view匯入就可以了,給大家造成的不便說聲抱歉。