在系列(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來綁定要顯示的值。
運行測試更改瀏覽器語言然后刷新頁面依然可以看到以第一種方法截圖相同的效果,證明注解有效。
格式化顯示的內容到此結束。
代碼下載:http://pan.baidu.com/s/1qWM3Zf2
注: 之前沒注意前11篇的示例代碼,不知道為什么當時打包上傳上去的是沒有.project項目文件的,導致下載后不能直接導入eclipse運行,虛擬機又 被我刪掉了,這些示例代碼也沒有備份,但是代碼文件還在的,所以可以新建一個Dynamic Web Project把對應的配置文件和controller還有view導入就可以了,給大家造成的不便說聲抱歉。