自定义注释驱动格式化Spring MVC

我正在将一个java EE应用程序迁移到spring boot,我遇到了转换问题。 现在无论好坏我将我的货币存储为Long(其德国欧元)。 我写了一个自定义的jsf转换器,它做了类似的事情:

长 – >字符串

22 – > 00,22

3310 – > 33,10

字符串 – >长

3 – > 3

22,11 – > 2211

现在,Spring MVC是摆脱JSF的一个原因。 我想使用303 Beanvalidation,使用Spring MVC(@Valid @ModelAttribute,BindingResult适用于@Pattern,例如)

现在我不能使用@NumberFormat(style = Style.Currency),这可以做我想要的,如果我没有存储我的货币那么久。

我写了一个自定义格式化程序并将其注册到FormatterRegistry

public class LongCurrencyFormatter implements Formatter{ @Getter private static final long serialVersionUID = 1L; @Override public String print(Long arg0, Locale arg1) { //logic removed for shorter post } @Override public Long parse(String arg0, Locale arg1) throws ParseException { //logic removed for shorter post } } 

到目前为止,everthing工作,但现在每一个长期都被转换。 我认为是对的。 所以在经过一些研究之后,我研究了6.6.2注释驱动格式http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html

我在文档中创建了一个AnnotationFormatterFactory

 public class LongCurrencyFormatAnnotationFormatterFactory implements AnnotationFormatterFactory { @Override public Set<Class> getFieldTypes() { Set<Class> setTypes = new HashSet<Class>(); setTypes.add(Long.class); return setTypes; } @Override public Parser getParser(LongCurrency annotation, Class fieldType) { return new LongCurrencyFormatter(); } @Override public Printer getPrinter(LongCurrency annotation, Class fieldType) { return new LongCurrencyFormatter(); } } 

我的注释:

 public @interface LongCurrency { } 

我的豆子:

 public class Costunit { //other attributes @LongCurrency private long value; } 

遗憾的是它无法正常工作:无法将类型为java.lang.String的属性值转换为属性值所需的long类型; 嵌套exception是java.lang.NumberFormatException:对于输入字符串:“22,00”

对不起,很长的post,知道我做错了什么? 或者更好的解决方案将格式化程序绑定到一个控制器? Databasemirgration应该是最少的选择。

谢谢!

EDIT1:完整的格式化程序代码(工作但当然可能更好)

 import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.ParseException; import java.util.Locale; import java.util.regex.Pattern; import lombok.Getter; import org.springframework.format.Formatter; public class LongCurrencyFormatter implements Formatter{ @Getter private static final long serialVersionUID = 1L; @Override public String print(Long arg0, Locale arg1) { String returnValue = arg0.toString(); boolean minusChar = returnValue.startsWith("-"); returnValue = returnValue.replace("-", ""); if (returnValue.length() > 2) { String tempStr = returnValue.substring(0, returnValue.length()-2); Long val = Long.parseLong(tempStr); DecimalFormat df = new DecimalFormat(); df.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.GERMAN)); String output = df.format(val) + "," + returnValue.substring(returnValue.length()-2); returnValue = output; } else { if(returnValue.length() == 1) { returnValue = "0,0"+returnValue; } else { returnValue = "0,"+returnValue; } } if(minusChar) { returnValue = "-" + returnValue; } return returnValue; } @Override public Long parse(String arg0, Locale arg1) throws ParseException { Long returnLong = null; // 1Test :only one - in front, only digits and "." and one "," , and // only 2 digits behind "," // if "," only 2 not 1 digit behind if (!isValidateLongCurrency(arg0)) { returnLong = 0L; } else { String valueFiltered = arg0.replace(".", ""); // 2: add 2 00 if no ",": if (!valueFiltered.contains(",")) { valueFiltered += "00"; } else { //E,C or E,CC String[] splittedValue = valueFiltered.split(","); if(splittedValue[splittedValue.length-1].length() == 1) { valueFiltered = valueFiltered + 0; } valueFiltered = valueFiltered.replace(",", ""); } try { returnLong = new Long(valueFiltered); } catch (NumberFormatException numEx) { } } return returnLong; } private boolean isValidateLongCurrency(String value) { boolean returnValue = true; String valueFiltered = value.replace(".", ""); //Euro String regEx = "^-?[1-9][0-9]*(,[0-9][0-9]?)?$|^-?[0-9](,[0-9][0-9]?)?$|^$"; returnValue = Pattern.matches( regEx, valueFiltered ) ; return returnValue; } } 

编辑2,现在它的作品

做出的改变:

 import java.lang.annotation.*; @Target(value={ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER}) @Retention(value=RetentionPolicy.RUNTIME) public @interface LongCurrency { } @Override public void addFormatters(FormatterRegistry registry) { super.addFormatters(registry); registry.addFormatterForFieldAnnotation(new LongCurrencyFormatAnnotationFormatterFactory()); } 

感谢M. Deinum

对于初学者来说,你的注释不再存在了。 您需要确保它在运行时保留,默认情况下会删除注释。 为此,在注释上添加@Retention元注释。 您可能还想添加@Target注释以指定可以设置的类型。

 @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface LongCurrency {} 

接下来确保您已正确注册LongCurrencyFormatAnnotationFormatterFactory 。 如果您没有注册它将不会被使用。

 @Override public void addFormatters(FormatterRegistry registry) { registry.addFormatterForFieldAnnotation(new LongCurrencyFormatAnnotationFormatterFactory()); } 

这两个更改都应该使您的格式化程序被调用/使用。