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);}
}

现在,根据需要将WebBindingInitializer注入RequestMappingHandlerAdapter中,手动删除并定义必要的bean。

<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

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

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

相关文章

响应式方案调研及前端开发管理思考

网易首页响应式风格实现技术调研网易首页实现页面&#xff08;字体&#xff09;响应式风格的方式是在不同尺寸的视口中使用不同的容器类&#xff0c;如图 1所示。当视口大于等于1420px时&#xff0c;使用大尺寸容器类 &#xff08;index2017_1200_wrap&#xff0c;width: 1200p…

响应式html编辑器布局,基于Bootstrap响应式所见即所得的jQuery编辑器插件

LineControl Editor是一款基于Bootstrap的响应式、所见即所得的富文本编辑器jQuery插件。该富文本编辑器可以使用textarea元素或任何一个容器元素来生成&#xff0c;它拥有常见富文本编辑器的所有功能&#xff0c;使用快捷方便。插件依赖该富文本编辑器插件依赖于jQuery2.1.0和…

linux nexus启动_Linux一键部署Nexus 3私服仓库自动化部署脚本

此脚本是Linux一键部署Nexus 3私服仓库自动化脚本&#xff0c;有需要朋友可以参考&#xff0c;脚本内容如下&#xff1a;环境准备&#xff1a;操作系统&#xff1a;CentOS Linux release 7.8.2003软件版本&#xff1a;Docker&#xff1a;docker-ce-19.03.12[rootlocalhost ~]# …

zabbix 模板 创建逻辑 + 主动模式-被动模式

模板通常包含了item、trigger、graph(图形)、application以及low-level discovery rule&#xff1b;模板可以直接链接至某个主机&#xff1b; 模板包含一系列的item&#xff0c;trigger等&#xff0c;可以快速地把多个item应用到host或者group。 参考&#xff1a;https://www.c…

JavaFX中的塔防(3)

在最后一部分中&#xff0c;您了解了如何创建Sprite&#xff0c;为其设置动画并赋予其Behavior。 但是动画效果不是很好&#xff0c;因为作为Insectoid&#xff0c;您应该始终看起来在飞行中。 记住&#xff1a;安全第一&#xff01; 我们可以通过创建自定义的TileSetAnimation…

day21 pickle json shelve configpaser 模块

1. 序列化:我们在网络传输的时候,需要我们对对象进行处理,把对象处理成方便存储和传输的格式,这个过程就叫序列化 序列化的方法不一定一样,三十目的都是为了方便储存和传输. 在python中有三种序列化方案: 1. pickle 可以将我们python中任意数据类型转化为bytes写入文件中…

flex.css快速入门,极速布局

什么是flex.css? css3 flex 布局相信很多人已经听说过甚至已经在开发中使用过它&#xff0c;但是我想我们都会有一个共同的经历&#xff0c;面对它的各种版本&#xff0c;各种坑&#xff0c;傻傻的分不清楚&#xff0c;flex.css就是对flex布局的一种封装&#xff0c;通过简洁…

计算机英语阅读路线,高考英语阅读理解真题解析·计算机运用

说明:引用此文请注明出处,并务请保留后面的有效链接地址,谢谢&#xff01;高考英语阅读理解真题解析计算机运用Computer people talk a lot about the need for other people to become“computer-literate.”But not all experts(专家) agree that this is a good idea.One pi…

优化Angularjs的$watch方法

Angularjs的$watch相信大家都知道&#xff0c;而且也经常使用&#xff0c;甚至&#xff0c;你还在为它的某些行为感到恼火。比如&#xff0c;一进入页面&#xff0c;它就会调用一次&#xff0c;我明明希望它在我初始化之后&#xff0c;值再次变动才调用。这种行为给我们带来许多…

JavaFX中的塔防(2)

在上一部分中&#xff0c;我们创建了一个简单的编辑器&#xff0c;让我们放置炮塔。 现在&#xff0c;我们将在敌人起源的地方添加一个生成点&#xff0c;并为其定义攻击目标。 首先&#xff0c;我将通过对象层向地图添加更多信息。 这是标准的TMX&#xff0c;因此我们可以在Ti…

微软edge浏览器不显示图片问题

用HBuider写的Web项目&#xff0c;项目名如果包含中文&#xff0c;edge下无法显示图片转载于:https://www.cnblogs.com/phoenixBlog/p/9964820.html

计算机辅助设计基础学什么,东大计算机辅助设计基础X20秋学期《计算机辅助设计基础》在线平时作业3资料...

计算机辅助设计基础X20秋学期《计算机辅助设计基础》在线平时作业36 e0 Y; q) j3 q3 c1.[单选题] 根据集成水平的不同&#xff0c;基于PDM的应用集成可分为3个层次&#xff0c;下面哪一个不在其中&#xff1f; 8 R- M/ w3 C& P" [ n. 答案资料下载请参考帮助中心说明…

在Python工作环境中安装包命令后加上国内源速度*15

example: pip install -r requests.txt -r https://pypi.tuna.tsinghua.edu.cn/simple/ --trusted-host pypi.tuna.tsinghua.edu.cn 转载于:https://www.cnblogs.com/xiangribai/p/9243426.html

12面魔方公式图解法_三阶魔方入门

一、魔方的构造这里只讲常见的普通三阶魔方。三阶魔方一共有26个色块&#xff0c;分三个层&#xff0c;从上到下分别为顶层、中间层、底层。26个色块按位置分为中心块、角色块、棱色块。中心块6个&#xff0c;角色块8个&#xff0c;棱色块12个。中心块为每一个面最中央的色块。…

Mongo 查询(可视化工具)

distinct MongoDB 的 distinct 命令是获取特定字段中不同值列表的最简单工具。 该命令适用于普通字段、数组字段以及数组内嵌文档&#xff08;集合对象&#xff09;。 db.getCollection(customer).distinct("customer_type")// chances字段的值是个集合&#xff0c;获…

使用JAX-RS的HTTP缓存

在上一个博客中&#xff0c;我们讨论了不同类型的缓存及其用例。 在本文中&#xff0c;我们将探讨如何利用HTTP响应标头和JAX-RS提供的支持来利用缓存。 过期标题 在HTTP 1.0中&#xff0c;一个名为Expires的简单响应头将告诉浏览器它可以缓存对象或页面多长时间。 在将来的某…

前端模块化,AMD与CMD的区别

原创 2016年08月03日 17:15:51标签&#xff1a;javascript /模块化 /前端21234最近在研究cmd和amd&#xff0c;在网上看到一篇不错的文章&#xff0c;整理下看看。 在JavaScript发展初期就是为了实现简单的页面交互逻辑&#xff0c;寥寥数语即可&#xff1b;如今CPU、浏览器性能…

上财的计算机专业408,【2020考研】上财408分经验分享

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼数学&#xff0c;三月份到四月中旬把本科教材看了一遍。事实上还是有用的。比如&#xff0c;今年的二阶差分。看似超纲&#xff0c;其实不超纲。大纲要求认识二阶差分的形式&#xff0c;会解一阶差分方程。那道题恰好是用二阶差分表…

Linux ls命令详解

ls常见命令参数 ls: -F 给不同的文件添加不同表示,添加帽子 d/ l* s -a: 显示隐藏文件 以.开头的文件 -p: 只给目录添加/ -t: 按照修改时间排序 time --time-stylelong-iso: ls -l --time-stylelong-iso 显示友好长格式时间 -r: 倒着排序 reverse -S: 按照文件…

caffe 人脸关键点检测_人脸检测关键点新增至81个,比Dlib更精准、更贴边

人脸关键点检测是人脸识别和分析领域中的关键一步&#xff0c;它是诸如自动人脸识别、表情分析、三维人脸重建及三维动画等其它人脸相关问题的前提和突破口。虽然人脸的结构是确定的&#xff0c;由眉毛、眼睛、鼻子和嘴等部位组成&#xff0c;近似是一个刚体&#xff0c;但由于…