Oldingi bo'limda aytilganidek, core.convert – umumiy maqsadli turli konvertatsiya tizimi. Bu ConversionService nomli yagona API interfeysni, shuningdek, Converter nomli aniq turdagi SPI interfeysni turli turlar o'rtasida o'zgartirish logikasini amalga oshirish uchun taqdim etadi. Spring konteyneri bu tizimdan bean xususiyatlarini qiymatiga bog'lash uchun foydalanadi. Shuningdek, Spring Expression Language (SpEL) va DataBinder ham bu tizimdan maydon qiymatlarini bog'lash uchun foydalanadi. Masalan, agar SpEL Short ni Long ga o'zgartirish zarur bo'lsa, expression.setValue(Object bean, Object value) urinishini yakunlash uchun, core.convert tizimi bu konversiyani amalga oshiradi.
Endi esa, odatiy mijoz muhitidagi, masalan veb-ilova yoki dastur dasturidagi turli konversiya talablarini ko'rib chiqamiz. Bunday muhitiarda, String uchun konversiyalar odatda mijoz qismidan ma'lumotni qaytarish jarayonini ta'minlash uchun amalga oshiriladi, shuningdek, String'ga qaytarish uchun yig'ish jarayonini ta'minlash uchun amalga oshiriladi. Bundan tashqari, String qiymatlarini mahalliylashtirish ko'pincha talab qilinadi. core.convert Converter umumiy SPI interfeysi bunday formatlash talablarini to'g'ridan-to'g'ri qondirmaydi. Ularni to'g'ridan-to'g'ri qondirish uchun Spring 3'da PropertyEditor dasturlar uchun oson va ishonchli muqobilni ta'minlovchi qulay SPI interfeysi Formatter aniqlangan.
Umuman olganda, agar siz turli konversiya logikasini amalga oshirish kerak bo'lsa, masalan, java.util.Date davrida Long o'zgartirishni amalga oshirish kerak bo'lsa Converter SPI interfeysidan foydalanishingiz mumkin. Agar siz mijoz muhitida (masalan, veb-ilovada) ishlayotgan bo'lsangiz va lokalizatsiyalangan maydon qiymatlarini sintaksisli tahlil qilish va chiqarish kerak bo'lsa Formatter SPI interfeysidan foydalanishingiz mumkin. ConversionService har ikki SPI interfeysi uchun yagona turli konversiya API interfeysini taqdim etadi.
SPI interfeysi Formatter
Formatter maydonlar formatlash logikasini amalga oshirish uchun oddiy va qat'iy tipli SPI interfeysdir. Quyidagi listda Formatter interfeysining aniqlanishi ko'rsatilgan:
package org.springframework.format;
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
Formatter Printer va Parser qurilish bloklari interfeyslaridan kengaytiriladi. Quyidagi listda ushbu ikki interfeyslar aniqlanishi ko'rsatilgan:
public interface Printer<T> {
String print(T fieldValue, Locale locale);
}
import java.text.ParseException;
public interface Parser<T> {
T parse(String clientValue, Locale locale) throws ParseException;
}
O'zingizning Formatter yarating va T ni siz formatlashingiz kerak bo'lgan obyekt turi sifatida parametrizatsiya qiling – masalan, java.util.Date. Mijoz lokalidagi T nusxasini chiqarish uchun print() amaliyotini, mijoz lokalidan qaytariladigan formatlangan ko'rinishdan T ning sintaksis talqinini amalga oshirish uchun parse() amaliyotini amalga oshiring. Sizning Formatter noto'g'ri sintaksisiy tahlil qilishga urinish uchun ParseException yoki IllegalArgumentException istisnolarini chiqarishi kerak. Sizning Formatter implementatsiyangizning oqim xavfsizligiga e'tibor bering.
format sub-paketlari qulaylik uchun bir necha Formatter implementatsiyalarga ega. Number paketi NumberStyleFormatter, CurrencyStyleFormatter va PercentStyleFormatter'ni java.text.NumberFormat'dan foydalangan holda raqam obyektlarini formatlash uchun o'z ichiga oladi. datetime paketi java.util.Date obyektlarini java.text.DateFormat yordamida formatlash uchun DateFormatter'ni o'z ichiga oladi.
Quyidagi DateFormatter Formatter implementatsiyasi misolidir:
package org.springframework.format.datetime;
public final class DateFormatter implements Formatter<Date> {
private String pattern;
public DateFormatter(String pattern) {
this.pattern = pattern;
}
public String print(Date date, Locale locale) {
if (date == null) {
return "";
}
return getDateFormat(locale).format(date);
}
public Date parse(String formatted, Locale locale) throws ParseException {
if (formatted.length() == 0) {
return null;
}
return getDateFormat(locale).parse(formatted);
}
protected DateFormat getDateFormat(Locale locale) {
DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale);
dateFormat.setLenient(false);
return dateFormat;
}
}
class DateFormatter(private val pattern: String) : Formatter<Date> {
override fun print(date: Date, locale: Locale)
= getDateFormat(locale).format(date)
@Throws(ParseException::class)
override fun parse(formatted: String, locale: Locale)
= getDateFormat(locale).parse(formatted)
protected fun getDateFormat(locale: Locale): DateFormat {
val dateFormat = SimpleDateFormat(this.pattern, locale)
dateFormat.isLenient = false
return dateFormat
}
}
Spring jamoasi Formatter ishlab chiqishda hamjamiyat ishtirokini xush ko'radi. O'z takliflaringizni kiritish uchun "GitHub Issues" sahifasiga qarang.
Annotatsiyalar orqali boshqariladigan formatlash
Maydon formatlashni maydon turi yoki annotatsiya yordamida sozlash mumkin. Annotatsiyani Formatter ga bog'lash uchun AnnotationFormatterFactory ni amalga oshiring. Quyidagi listda AnnotationFormatterFactory interfeysining aniqlanishi ko'rsatilgan:
package org.springframework.format;
public interface AnnotationFormatterFactory<A extends Annotation> {
Set<Class<?>> getFieldTypes();
Printer<?> getPrinter(A annotation, Class<?> fieldType);
Parser<?> getParser(A annotation, Class<?> fieldType);
}
Quyidagi holatlarga amalga oshirish uchun:
-
A ni sizning formatlash logikangizni bog'lashni istagan maydonning
annotationTypesifatida parametrizatsiya qiling – masalan,org.springframework.format.annotation.DateTimeFormat. -
getFieldTypes()imkoniyatlarida foydalanilishi mumkin bo'lgan maydon turlarini qaytarishi kerak. -
getPrinter()annotatsiyalan yeplangan maydon qiymatini chiqarish uchunPrinterni qaytarishi kerak. -
getParser()annotatsiyalan yeplangan maydon qiymati uchunclientValuesintaksis talqinini amalga oshirish uchunParserni qaytarishi kerak.
Quyidagi AnnotationFormatterFactory implementatsiya misolda @NumberFormat annotatsiyasini formatlash logikasiga bog'laydi, shunda raqamlaning uslubi yoki andozasini ko'rsatish mumkin:
public final class NumberFormatAnnotationFormatterFactory
implements AnnotationFormatterFactory<NumberFormat> {
public Set<Class<?>> getFieldTypes() {
return new HashSet<Class<?>>(asList(new Class<?>[] {
Short.class, Integer.class, Long.class, Float.class,
Double.class, BigDecimal.class, BigInteger.class }));
}
public Printer<Number> getPrinter(NumberFormat annotation, Class<?> fieldType) {
return configureFormatterFrom(annotation, fieldType);
}
public Parser<Number> getParser(NumberFormat annotation, Class<?> fieldType) {
return configureFormatterFrom(annotation, fieldType);
}
private Formatter<Number> configureFormatterFrom(NumberFormat annotation, Class<?> fieldType) {
if (!annotation.pattern().isEmpty()) {
return new NumberStyleFormatter(annotation.pattern());
} else {
Style style = annotation.style();
if (style == Style.PERCENT) {
return new PercentStyleFormatter();
} else if (style == Style.CURRENCY) {
return new CurrencyStyleFormatter();
} else {
return new NumberStyleFormatter();
}
}
}
}
class NumberFormatAnnotationFormatterFactory : AnnotationFormatterFactory<NumberFormat> {
override fun getFieldTypes(): Set<Class<*>> {
return setOf(Short::class.java, Int::class.java, Long::class.java, Float::class.java, Double::class.java, BigDecimal::class.java, BigInteger::class.java)
}
override fun getPrinter(annotation: NumberFormat, fieldType: Class<*>): Printer<Number> {
return configureFormatterFrom(annotation, fieldType)
}
override fun getParser(annotation: NumberFormat, fieldType: Class<*>): Parser<Number> {
return configureFormatterFrom(annotation, fieldType)
}
private fun configureFormatterFrom(annotation: NumberFormat, fieldType: Class<*>): Formatter<Number> {
return if (annotation.pattern.isNotEmpty()) {
NumberStyleFormatter(annotation.pattern)
} else {
val style = annotation.style
when {
style === NumberFormat.Style.PERCENT -> PercentStyleFormatter()
style === NumberFormat.Style.CURRENCY -> CurrencyStyleFormatter()
else -> NumberStyleFormatter()
}
}
}
}
Formatlashni chaqirish uchun, maydonlarni @NumberFormat orqali annotatsiyalashingiz mumkin, quyidagi misolda ko'rsatilgani kabi:
public class MyModel {
@NumberFormat(style=Style.CURRENCY)
private BigDecimal decimal;
}
class MyModel(
@field:NumberFormat(style = Style.CURRENCY) private val decimal: BigDecimal
)
Annotatsiya formatining API interfeysi
org.springframework.format.annotation paketida mavjud transport annotatsiya formati API mavjud. Number maydonlarini, masalan, Double va Long formatlash uchun @NumberFormat dan foydalanishingiz mumkin, shuningdek, java.util.Date, java.util.Calendar, Long (vaziyat vaqti belgilarini millisekundlar uchun) va JSR-310 o'z ichiga olgan java.time formatlash uchun @DateTimeFormat dan foydalanishingiz mumkin.
Quyidagi misolda java.util.Date ISO standartiga muvofiq (YYYY-MM-DD) formatlash uchun @DateTimeFormat dan foydalaniladi:
public class MyModel {
@DateTimeFormat(iso=ISO.DATE)
private Date date;
}
class MyModel(
@DateTimeFormat(iso=ISO.DATE) private val date: Date
)
SPI interfeysi FormatterRegistry
FormatterRegistry – formatlashni va konvertorlarni ro'yxatga olish uchun SPI interfeys. FormattingConversionService ko'p muhitlar uchun mos FormatterRegistry ni amalga oshiradi. Siz buni dasturiy yoki deklarativ tarzda Spring bean sifatida moslashingiz mumkin, masalan, FormattingConversionServiceFactoryBean yordamida. Chunki, bu amalga oshirish ConversionService ni ham amalga oshiradi, siz buni DataBinder va Spring Expression Language (SpEL) dan foydalanish uchun to'g'ridan-to'g'ri moslashingiz mumkin.
Quyidagi listda FormatterRegistry SPI interfeysining aniqlanishi ko'rsatilgan:
package org.springframework.format;
public interface FormatterRegistry extends ConverterRegistry {
void addPrinter(Printer<?> printer);
void addParser(Parser<?> parser);
void addFormatter(Formatter<?> formatter);
void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);
void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);
void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);
}
Ilk listda ko'rsatilganidek, maydon turi yoki annotatsiya bo'yicha formatlashchilarni ro'yxatga olish mumkin.
FormatterRegistry markaziy ravishda formatlash qoidalarini sozlashga imkon beradi, har bir nazoratchi uchun bunday konfiguratsiyani takrorlashdan ko'ra. Misol uchun, barcha vaqt turlarining ma'lum bir tarzda formatlanishini yoki ma'lum bir annotatsiyaga ega maydonlarning ma'lum bir tarzda formatlanishini majburiy qilish mumkin. FormatterRegistry orqali siz bir marta bu qoidalarni belgilab, ular har safar formatlash kerak bo'lganda qo'llaniladi.
SPI interfeysi FormatterRegistrar
FormatterRegistrar – bu FormatterRegistry orqali formatlashchilarni va konvertorlarni ro'yxatga olish uchun SPI interfeys. Quyidagi listda ushbu interfeysning aniqlanishi ko'rsatilgan:
package org.springframework.format;
public interface FormatterRegistrar {
void registerFormatters(FormatterRegistry registry);
}
FormatterRegistrar bog'langan bir nechta konvertor va formatlashchilarni ma'lum bir formatlash turkumi uchun, masalan, sana formatlash uchun ro'yxatga olishda foydali. Bu deklarativ ro'yxatga olish etarli bo'lmasa ham foydalidir – masalan, agar formatlashni o'z <T> dan farqli maydon turi bo'yicha indekslash kerak bo'lsa yoki Printer/Parser juftligini ro'yxatga olish kerak bo'lsa. Quyidagi bo'limda konvertorlar va formatlashchilarni ro'yxatga olish haqida qo'shimcha ma'lumot taqdim etiladi.
Spring MVC da formatlashni sozlash
Global sana va vaqt formatini sozlash
Odatiy holda @DateTimeFormat bilan annotatsiyalanmagan vaqt maydonlari DateFormat.SHORT uslubi yordamida qatorlardan konvertatsiya qilinadi. Agar istasangiz, o'zingizning global formatni yaratishingiz mumkin.
Buning uchun Spring odatiy formatlashchilarni ro'yxatga olmasligiga ishonch hosil qiling. Buning o'rniga, formatlashchilarni qo'lda ro'yxatga olishingiz mumkin:
-
org.springframework.format.datetime.standard.DateTimeFormatterRegistrar -
org.springframework.format.datetime.DateFormatterRegistrar
Misol uchun, quyidagi Java konfiguratsiyasi yyyyMMdd uslubida global formatni ro'yxatga oladi:
@Configuration
public class AppConfig {
@Bean
public FormattingConversionService conversionService() {
// DefaultFormattingConversionService dan foydalanamiz, lekin odatiy qiymatlarni ro'yxatga olmaymiz
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);
// @NumberFormat hanuz qo'llab-quvvatlanishiga ishonch hosil qilaylik
conversionService.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
// JSR-310 standarti bo'yicha maxsus global formatda sana konvertatsiyasini ro'yxatga olamiz
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"));
registrar.registerFormatters(conversionService);
// Maxsus global formatda sana konvertatsiyasini ro'yxatga olamiz
DateFormatterRegistrar registrar = new DateFormatterRegistrar();
registrar.setFormatter(new DateFormatter("yyyyMMdd"));
registrar.registerFormatters(conversionService);
return conversionService;
}
}
@Configuration
class AppConfig {
@Bean
fun conversionService(): FormattingConversionService {
// DefaultFormattingConversionService dan foydalanamiz, lekin odatiy qiymatlarni ro'yxatga olmaymiz
return DefaultFormattingConversionService(false).apply {
// @NumberFormat hanuz qo'llab-quvvatlanishiga ishonch hosil qilaylik
addFormatterForFieldAnnotation(NumberFormatAnnotationFormatterFactory())
// JSR-310 standarti bo'yicha maxsus global formatda sana konvertatsiyasini ro'yxatga olamiz
val registrar = DateTimeFormatterRegistrar()
registrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"))
registrar.registerFormatters(this)
// Maxsus global formatda sana konvertatsiyasini ro'yxatga olamiz
val registrar = DateFormatterRegistrar()
registrar.setFormatter(DateFormatter("yyyyMMdd"))
registrar.registerFormatters(this)
}
}
}
Agar siz XML asosidagi konfiguratsiyaga ustuvorlik beradigan bo'lsangiz, FormattingConversionServiceFactoryBean dan foydalanishingiz mumkin. Quyidagi misolda buni qanday amalga oshirish ko'rsatilgan:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="registerDefaultFormatters" value="false" />
<property name="formatters">
<set>
<bean class="org.springframework.format.number.NumberFormatAnnotationFormatterFactory" />
</set>
</property>
<property name="formatterRegistrars">
<set>
<bean class="org.springframework.format.datetime.standard.DateTimeFormatterRegistrar">
<property name="dateFormatter">
<bean class="org.springframework.format.datetime.standard.DateTimeFormatterFactoryBean">
<property name="pattern" value="yyyyMMdd"/>
</bean>
</property>
</bean>
</set>
</property>
</bean>
</beans>
Veb-ilovalarda vaqt va sana formatlarini o'rnatishda qo'shimcha jihatlarni hisobga olish kerakligini unutmang.
GO TO FULL VERSION