spring 类型转换器_Spring中的类型转换

spring 类型转换器

以下是一些需要类型转换的简单情况:
情况1。 为了帮助简化bean配置,Spring支持属性值与文本值之间的转换。 每个属性编辑器仅设计用于某些类型的属性。 为了使用它们,我们必须在Spring容器中注册它们。
案例2。 同样,在使用Spring MVC时,控制器会将表单字段值绑定到对象的属性。 假设对象是由另一个对象组成的,则MVC控制器无法自动将值分配给内部自定义类型对象,因为表单中的所有值都作为文本值输入。 Spring容器将把文本值转换为原始类型,而不转换为自定义类型对象。 为此,我们必须在MVC流中初始化自定义编辑器。

本文将讨论实现自定义类型对象的转换器的各种方法。 为了详细说明这些,让我们考虑以下用例。 在该示例中,我想模拟游戏场地预订系统。 所以这是我的领域对象:

public class Reservation {public String playGround;public Date dateToReserve;public int hour;public Player captain;public SportType sportType;public Reservation(String playGround, Date date, int hour, Player captain, SportType sportType) {this.playGround = playGround;this.dateToReserve = date;this.hour = hour;this.captain = captain;this.sportType = sportType;}/*** Getters and Setters*/
}public class Player {private String name;private String phone;/*** Getters and Setters*/}public class SportType {public static final SportType TENNIS = new SportType(1, "Tennis");public static final SportType SOCCER = new SportType(2, "Soccer");private int id;private String name;public SportType(int id, String name) {this.id = id;this.name = name;}public static Iterable<SportType> list(){return Arrays.asList(TENNIS, SOCCER);}public static SportType getSport(int id){for(SportType sportType : list()){if(sportType.getId() == id){return sportType;}}return null;}/*** Getters and Setters*/
}

这是案例1的示例:假设我们要定义一个预留bean,这是我们的方法:

<bean id="dummyReservation" class="com.pramati.model.Reservation"><property name="playGround" value="Soccer Court #1"/><property name="dateToReserve" value="11-11-2011"/><property name="hour" value="15"/><property name="captain"><bean class="com.pramati.model.Player"><property name="name" value="Prasanth"/><property name="phone" value="92131233124"/></bean></property><property name="sportType"><property name="id" value="1"/><property name="name" value="TENNIS"/></property>
</bean>

这个bean的定义很冗长。 如果定义看起来像这样,它本来可以表现得更好:

<bean id="dummyReservation" class="com.pramati.model.Reservation"><property name="playGround" value="Soccer Court #1"/><property name="dateToReserve" value="11-11-2011"/><property name="hour" value="15"/><property name="captain" value="Prasanth,92131233124"/><property name="sportType" value="1,TENNIS"/>
</bean>

为此,我们应该告诉Spring在定义bean的过程中使用自定义转换器。

这是案例2的示例:假设我的应用程序中有一个JSP,它允许用户在一天的特定时间预订游乐场。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!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=ISO-8859-1">
<title>Reservation Form</title>
<style type="text/css">
.error {color: #ff0000;font-weight: bold;
}
</style>
</head>
<body><form:form method="post" modelAttribute="reservation"><table><tr><th>Court Name</th><td><form:input path="courtName" /></td></tr><tr><th>Reservation Date</th><td><form:input path="date" /></td></tr><tr><th>Hour</th><td><form:input path="hour" /></td></tr><tr><th>Player Name</th><td><form:input path="player.name" /></td></tr><tr><th>Player Contact Number</th><td><form:input path="player.phone" /></td></tr><tr><th>Sport Type</th><td><form:select path="sportType" items="${sportTypes}"itemLabel="name" itemValue="id" /></td></tr><tr><td colspan="3"><input type="submit" name="Submit" /></td></tr></table></form:form>
</body>
</html>

这是对应的MVC控制器:

@Controller
@RequestMapping
@SessionAttributes("reservation")
public class ReservationFormController {@Autowiredprivate ReservationService reservationService;@ModelAttribute("sportTypes")public Iterable<SportType> getSportTypes(){return SportType.list();}@RequestMapping(value="/reservationForm/{captainName}", method=RequestMethod.GET)public String initForm(Model model, @PathVariable String captainName){Reservation reservation = new Reservation();reservation.setPlayer(new Player(captainName, null));reservation.setSportType(SportType.TENNIS);model.addAttribute("reservation", reservation);return "reservationForm";}@RequestMapping(value="/reservationForm/{captainName}",method=RequestMethod.POST)public String reserve(@Valid Reservation reservation, BindingResult bindingResult, SessionStatus sessionStatus){validator.validate(reservation, bindingResult);if(bindingResult.hasErrors()){return "/reservationForm";} else{reservationService.make(reservation);sessionStatus.setComplete();return "redirect:../reservationSuccess";}}
}

现在您可以看到,在JSP中,我们将表单字段绑定到Reservation对象(modelAttribute =“ reservation”)。 该对象由传递给视图的控制器(在initForm()方法中)保留在模型中。 现在,当我们提交表单时,Spring会引发一条验证消息,指出无法将字段值转换为类型Player和SportType。 为此,我们必须定义自定义转换器并将其注入Spring MVC流中。

现在的问题是如何定义自定义转换器? Spring提供了两种支持这些自定义转换器的方式:

  • 解决方案1:使用PropertyEditors
  • 解决方案2:使用转换器

使用PropertyEditor:

PropertyEditorSupport,实现PropertyEditor接口,是用于帮助构建PropertyEditor的支持类。

public class SportTypeEditorSupport extends PropertyEditorSupport {/*** Sets the property value by parsing a given String.  May raise* java.lang.IllegalArgumentException if either the String is* badly formatted or if this kind of property can't be expressed* as text.** @param text  The string to be parsed.*/@Overridepublic void setAsText(String text) throws IllegalArgumentException {try{SportType sportType = SportType.getSport(Integer.parseInt(text));setValue(sportType);// setValue stores the custom type Object into a instance variable in PropertyEditorSupport.}catch(NumberFormatException nfe){throw new RuntimeException(nfe.getMessage());}}/*** Gets the property value as a string suitable for presentation* to a human to edit.** @return The property value as a string suitable for presentation*       to a human to edit.* <p>   Returns "null" is the value can't be expressed as a string.* <p>   If a non-null value is returned, then the PropertyEditor should*	     be prepared to parse that string back in setAsText().*/@Overridepublic String getAsText() {SportType sportType = (SportType)getValue();return Integer.toString(sportType.getId());}
}

现在,在PropertyEditorRegistry中注册自定义编辑器。 PropertyEditorRegistrar在PropertyEditorRegistry中注册自定义编辑器。 这是您的操作方式:

import java.text.SimpleDateFormat;
import java.util.Date;import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;import com.pramati.model.SportType;public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {@Overridepublic void registerCustomEditors(PropertyEditorRegistry registry) {registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("dd-MM-yyyy"), true));registry.registerCustomEditor(SportType.class, new SportTypeEditorSupport());}
}

CustomEditorConfigurer被实现为Bean工厂后处理器,您可以在实例化任何Bean之前注册自定义属性编辑器。 为此,我们将PropertyEditorRegistry与CustomEditorConfigurer关联。

<bean id="customPropertyEditorRegistrar" class="com.pramati.spring.mvc.CustomPropertyEditorRegistrar"/><bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"><property name="propertyEditorRegistrars"><list><ref bean="customPropertyEditorRegistrar"/></list></property>
</bean>

现在,当Spring容器看到​​此信息时:

<property name="captain" value="Prasanth,92131233124"/>

Spring自动将指定的值转换为Player对象。 但是,此配置对于Spring MVC流还不够。 控制器仍然会抱怨类型不兼容,因为它期望一个Player对象在获取String的地方。 为了将表单字段值解释为自定义类型对象,我们必须进行很少的MVC配置更改。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.request.WebRequest;public class CustomWebBindingInitializer implements WebBindingInitializer {@Autowiredprivate CustomPropertyEditorRegistrar customPropertyEditorRegistrar;@Overridepublic void initBinder(WebDataBinder binder, WebRequest request) {customPropertyEditorRegistrar.registerCustomEditors(binder);}
}

现在,手动删除并定义必要的bean,因为我们需要将WebBindingInitializer注入RequestMappingHandlerAdapter

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="webBindingInitializer"><bean class="com.pramati.spring.mvc.CustomWebBindingInitializer"/></property>
</bean>

现在,控制器会自动将String转换为必要的自定义类型对象。 请注意,我们必须进行单独的配置更改,以简化Spring MVC中的bean配置和表单字段的类型转换。 同样值得指出的是,在扩展PropertyEditorSupport时,我们将自定义类型对象存储在实例变量中,因此使用PropertyEditors并不是线程安全的。 为了克服这些问题,Spring 3.0引入了转换器和格式化程序的概念。

使用转换器:

转换器组件用于将一种类型转换为另一种类型,并通过强制将所有此类与转换相​​关的代码放在一个位置来提供更清晰的分隔。 Spring已经支持常用类型的内置转换器,并且该框架可扩展性足以编写自定义转换器。 Spring Formatters进入图片以根据呈现数据的显示来格式化数据。 在考虑编写适合特定业务需求的自定义转换器之前,总是有必要先查看详尽的预制转换器列表。 有关查看预建转换器的列表,请参见org.springframework.core.convert.support软件包。

回到我们的用例,让我们实现String到SportType转换器:

import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import com.pramati.model.SportType;public class StringToSportTypeConverter implements Converter<String, SportType> {@Overridepublic SportType convert(String sportIdStr) {int sportId = -1;try{sportId = Integer.parseInt(sportIdStr);} catch (NumberFormatException e) {throw new ConversionFailedException(TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(SportType.class), sportIdStr, null);}SportType sportType = SportType.getSport(sportId);return sportType;}}

现在,在ConversionService中注册它,并将其与SpringMVC流链接:

<mvc:annotation-driven conversion-service="conversionService"/><bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean" ><property name="converters"><set><bean class="com.pramati.type.converters.StringToSportTypeConverter"/><bean class="com.pramati.type.converters.StringToDateConverter"/><bean class="com.pramati.type.converters.StringToPlayerConverter"/></set></property>
</bean>

如果您使用的是自定义bean声明而不是‹mvc:annotation-driven /›,则可以使用以下方法:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.request.WebRequest;public class CustomWebBindingInitializer implements WebBindingInitializer {@Autowiredprivate ConversionService conversionService;@Overridepublic void initBinder(WebDataBinder binder, WebRequest request) {binder.setConversionService(conversionService);}}

现在将WebBindingInitializer注入RequestMappingHandlerAdapter。

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="webBindingInitializer"><bean class="com.pramati.spring.mvc.CustomWebBindingInitializer"/></property>
</bean>

单独注册ConversionService将有助于简化bean配置(案例1)。 为了使案例2正常工作,我们必须在Spring MVC流中注册ConversionService。 请注意,这种类型转换方式也是线程安全的。

同样,除了使Converters / PropertEditor对应用程序中的所有控制器都可用之外,我们还可以基于每个控制器启用它们。 这是您的操作方式。 删除上面指定的通用配置,并在控制器类中引入@InitBinder,如下所示:

@Controller
@RequestMapping
@SessionAttributes("reservation")
public class ReservationFormController {private ReservationService reservationService;private ReservationValidator validator;@Autowiredpublic ReservationFormController(ReservationService reservationService, ReservationValidator validator){this.reservationService = reservationService;this.validator = validator;}@Autowiredprivate ConversionService conversionService;@InitBinderprotected void initBinder(ServletRequestDataBinder binder) {binder.setConversionService(conversionService);}/*@InitBinderprotected void initBinder(ServletRequestDataBinder binder) {binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("dd-MM-yyyy"), true));binder.registerCustomEditor(SportType.class, new SportTypeEditorSupport(reservationService));}*//*@Autowiredprivate PropertyEditorRegistrar propertyEditorRegistrar;@InitBinderprotected void initBinder(ServletRequestDataBinder binder) {propertyEditorRegistrar.registerCustomEditors(binder);}*/@ModelAttribute("sportTypes")public Iterable<SportType> getSportTypes(){return SportType.list();}@RequestMapping(value="/reservationForm/{userName}", method=RequestMethod.GET)public String initForm(Model model, @PathVariable String userName){Reservation reservation = new Reservation();reservation.setPlayer(new Player(userName, null));reservation.setSportType(SportType.TENNIS);model.addAttribute("reservation", reservation);return "reservationForm";}@RequestMapping(value="/reservationForm/{userName}",method=RequestMethod.POST)public String reserve(@Valid Reservation reservation, BindingResult bindingResult, SessionStatus sessionStatus){validator.validate(reservation, bindingResult);if(bindingResult.hasErrors()){return "/reservationForm";} else{reservationService.make(reservation);sessionStatus.setComplete();return "redirect:../reservationSuccess";}}@RequestMapping("/reservationSuccess")public void success(){}
}

因此,如果您看到上面的代码,您会注意到在使用PropertyEditor而不是转换器的地方,注释的代码。 因此,在两种实现方式中都可以使用基于控制器启用类型转换器的功能。

参考: prasanthnath博客上的JCG合作伙伴 Prasanth Gullapalli 在Spring中进行了类型转换 。

翻译自: https://www.javacodegeeks.com/2013/11/type-conversion-in-spring-2.html

spring 类型转换器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346727.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java+语音识别+谷歌_JAVA使用谷歌语音识别API

我正在尝试使用谷歌语音识别API.这是我写的代码&#xff1a;有用.我从服务器得到答案&#xff1a;{"status":5,"id":"8803471b14a2310dfcf917754e8bd4a7-1","hypotheses":[]}现在的问题是“状态&#xff1a;5”.事实上,这里的状态代码…

java中对象字节数_JAVA中求解对象所占字节大小

该类为cache4j缓存框架中的工具类方法&#xff0c;该方法实现了两个接口接口1&#xff1a;计算对象在内存中所占字节数接口2&#xff1a;复制对象&#xff0c;实现深度克隆效果&#xff0c;实现原理为先序列化对象&#xff0c;然后在反序列化对象&#xff1b;返回一个新的对象&…

excel查重复_毕业季 | 如何降低论文的查重率

毕业季吾日三省吾身实验做完了吗&#xff1f;论文写完了吗&#xff1f;查重能通过吗&#xff1f;学术圈的前辈告诉我们&#xff0c;只有站在巨人的肩膀上才能看得更远。在撰写一篇论文时&#xff0c;为保证质量和可靠性&#xff0c;难免需要引用前人的成果&#xff0c;这也反映…

Sun过去的世界中的JDK 11和代理

使用JDK 11后&#xff0c;就sun.misc.Unsafe的第一种方法。 其中&#xff0c; defineClass方法已删除。 代码生成框架通常使用此方法在现有的类加载器中定义新的类。 尽管此方法易于使用&#xff0c;但它的存在也使JVM本质上不安全&#xff0c;正如其定义类的名称所暗示的那样。…

java中 private final_Java笔记:final与private关键字

记录一个有趣的现象&#xff0c;private修饰的方法子类是访问不了的&#xff0c;且类中所有private修饰的方法都隐式的指定为final(可以对private方法添加final修饰词&#xff0c;但是这并不能给该方法增加任何额外的意义)&#xff0c;final修饰的方法是不可以被重写的。但是如…

Java,JavaFX的流畅设计风格进度栏

按照承诺&#xff0c;刚刚发布的Java JavaFX主题JMetro 4.6版为进度栏带来了新样式。 进度栏有两种可能的状态&#xff1a;确定和不确定&#xff0c;新的JMetro版本具有这两种状态。 在本文中&#xff0c;我还将详细介绍一些我在JMetro中遵守的API设计原则。 JMetro API设计原…

安卓最新系统_成纺移动校园(移动办公系统)V3.2.1 安卓最新版

成纺移动校园(移动办公系统)是额一个非常实用的办公工具。您可以使用该软件及时浏览最新的校园信息&#xff0c;同时涵盖许多功能&#xff0c;例如时间表查询&#xff0c;会议安排&#xff0c;校园地图&#xff0c;校车等。有需要的用户欢迎来绿色先锋网下载。 成纺移动校园简介…

java时间日期格式器_JAVA基础类库(二)-----日期、时间类和格式器

Date类public classDateTest{public static voidmain(String[] args){Date d1 newDate();//获取当前时间之后100ms的时间Date d2 new Date(System.currentTimeMillis() 10000);System.out.println(d1);System.out.println(d2);//比较d1,d2是否相等,相等返回0&#xff0c;大于…

pyqt 获取 UI 中组件_你想知道的React组件设计模式这里都有(上)

本文梳理了容器与展示组件、高阶组件、render props这三类React组件设计模式往期回顾&#xff1a;HBaseCon Asia 2019 Track 3 概要回顾随着 React 的发展&#xff0c;各种组件设计模式层出不穷。React 官方文档也有不少相关文章&#xff0c;但是组织稍显凌乱&#xff0c;本文就…

jvm上的随机数与熵_向您的JVM添加一些熵

jvm上的随机数与熵能否生成真正的随机数取决于系统中的熵。 有人声称&#xff0c;这可以通过掷骰子来保证。 其他人认为&#xff0c;用此主体替换OpenJDK的java.math.Random.nextInt&#xff08;&#xff09;方法将有所帮助&#xff1a; public int nextInt() {return 14; }资…

typora导出word指定样式_(二)最简洁的Markdowd编辑器:Typora

&#xff08;提醒&#xff1a;前面都是介绍和语法&#xff0c;想下载了就能用的直接看最后总结&#xff09;大家好&#xff0c;半瓶醋同学又来误人子弟了。现在办公文档或者邮件的处理&#xff0c;一般都是用微软的office word或者邮件自带的编辑器。但是用word或者邮件自带编辑…

cc java开发环境搭建_Windows系统下java开发环境搭建

总的来说&#xff0c;开发环境是程序员工作的基础&#xff0c;没了他&#xff0c;IT工作就没得开展了。话不多说&#xff0c;今天提供的教程是Windows系统下Java开发环境的搭建&#xff0c;具体如下1.下载并安装JDK(JAVA Development Kit)JDK是整个java开发的核心&#xff0c;它…

使用数据库中的Java流制作数据透视表

来自数据库行和表的原始数据不能为人类读者提供太多了解。 相反&#xff0c;如果我们对数据执行某种聚合&#xff0c;则人类更有可能看到数据模式 在展示给我们之前。 数据透视表是聚合的一种特定形式&#xff0c;我们可以在其中应用排序&#xff0c;求平均值或求和之类的操作…

java map的keyset_Java Map keySet()用法及代码示例

此方法用于返回此映射中包含的键的Set视图。该集合由Map支持&#xff0c;因此对Map的更改会反映在集合中&#xff0c;反之亦然。用法:Set keySet()参数&#xff1a;此方法没有参数。返回值&#xff1a;此方法返回一个包含指定映射键的集合。下面的程序显示int keySet()方法的实…

asynchttpclient 超时_dnf这才是混子的毕业套装,却发现超时空漩涡不买账!

dnf这才是混子的毕业套装&#xff0c;却发现超时空漩涡不买账&#xff01;按道理来说&#xff0c;光兵和帕拉丁穿这套装备去混团是最好的&#xff0c;结果现在超时空漩涡不要&#xff01;虽然说兵法套是95最好的魂之涛&#xff0c;但是这个混子套属性真心弱爆&#xff0c;不如正…

统计多维数组php_PHP多维数组中统计元素个数

Array([0] > Array([0] > Array([0] > Array([id] > 12[name] > 1)[1] > Array([id] > 28[name] > 2).....)[1] > Array([0] > Array([id] > 121[name] > 2)[1] > Array([id] > 281[name] > 4)...))....)我想统计name对应的值出现…

mongodb web_MongoDB和Web应用程序

mongodb web当今时代是数据以非常大的速度增长的时代。 数据存储不是问题&#xff0c;是的&#xff0c;但是它的结构化和存储方式可能会增加或减少所需数据块的查找时间。 不断增长的非结构化数据的用例 脸书&#xff1a; 活跃用户达7.5亿&#xff0c;互联网用户中有三分之一…

win7亮度怎么调_揭秘极米NEW Z8X投影仪怎么样?千万不要上当?!!!!【揭秘反馈

反馈测评极米NEW Z8X投影仪怎么样?求真实点评注意事项极米NEW Z8X投影仪怎么样?靠谱真实回答 外形外观&#xff1a;简约时尚大气&#xff0c;手感不错&#xff01;\n投影亮度&#xff1a;1080P、4K&#xff0c;都能做到&#xff01;\n投影色彩&#xff1a;非常好&#xff0c;…

php的完整代码块,简单测试了一下php中的代码块、内部类等知识

简单测试了一下php中的代码块、内部类等知识<?php class a{public $b;public function print_result(){//普通代码块&#xff0c;但已经不是java中的代码块{$c变量;echo 普通代码块&#xff1f;;}echo $c;}//错误的语法&#xff0c;Parse error: syntax error, unexpected …

Paw 百度ai_直面落地!百度EasyDL产业智能创新大赛成果覆盖能源、交通、水利民生重业...

物体检测模型实现高压线路隐患检测、图像分类实现短视频快速剪辑和量产、文本情感分类辅助潜在心理疾病患者自发检测、图片识别车辆轮轴数监管车辆载重……每一个创想都能简单快速实现&#xff0c;没有AI开发基础的小伙伴们也能做到&#xff01;这一切都缘于百度零门槛AI开发平…