Appearance
SpringMVC教程 - 12 类型转换
在上一章的消息转换器章节,是将请求体和响应体与Java对象的转换,一般涉及到使用 @RequestBody 、 @ResponseBody 、RequestEntity、ResponseEntity。
而对于 URL 中的参数、表单提交的数据(x-www-form-urlencoded),则是使用类型转换,将请求的字符串转换为 Java 的各种类型,比如 int、long、Date,甚至是自定义对象。
大概的处理流程如下:

简单的说,也就是 SpringMVC 会使用 ConversionService 调用合适的转换器 Formatter 或 Converter 将 String 转换为对应的类型。
当然上面的转换都是 SpringMVC 帮我们完成了,我们只需要了解使用方法就可以了。
12.1 默认的类型转换器
SpringMVC已经内置了许多常用的类型转换器,可以自动处理基本的数据类型转换。例如:
- 字符串转基本类型:
String->int,long,double,boolean等 - 字符串转日期:
String->Date,LocalDate,LocalDateTime等 - 字符串转集合:
String->List,Set,Map等
我们前面请求接口的时候,传递的数据都是字符串的,只是 SpringMVC 帮我们转换为 Controller 参数对应的类型。
下面通过一些例子看一下SpringMVC的默认类型转换功能。
1 基本类型转换
java
package com.foooor.hellospringmvc.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Slf4j
@Controller
public class TypeConversionController {
@GetMapping("/convert/basic")
@ResponseBody
public String basicConversion(
@RequestParam int id,
@RequestParam String name,
@RequestParam double salary,
@RequestParam boolean active) {
log.info("请求参数: id={}, name={}, salary={}, active={}", id, name, salary, active);
return String.format("ID: %d, Name: %s, Salary: %.2f, Active: %s",
id, name, salary, active);
}
}- 当我们访问
http://localhost:8080/convert/basic?id=1001&name=张三&salary=5000.50&active=true时,SpringMVC 会自动将URL参数转换为对应的类型。 - 在上面的转换中,SpringMVC 会使用各种 Converter,例如
StringToIntegerConverter,将字符串转换为整形、浮点型、布尔型。
2 集合类型转换
SpringMVC 可以自动将逗号分隔的字符串转换为集合类型。
java
@GetMapping("/convert/collection")
@ResponseBody
public String collectionConversion(
@RequestParam List<String> names,
@RequestParam Set<Integer> ids) {
return String.format("Names: %s, IDs: %s", names, ids);
}- 当我们访问
http://localhost:8080/convert/collection?names=张三,李四,王五&ids=1001,1002,1003时,SpringMVC会自动将逗号分隔的字符串转换为对应的集合。 - 在上面的转换中,SpringMVC 会使用
CollectionConverter将字符串转换为字符串数组,然后对每个元素调用元素类型的转换器。
3 日期类型转换
SpringMVC 默认也正常将字符串转换为 Date 、LocalDateTime、LocalDateTime 类型。
举个栗子:
java
@GetMapping("/convert/date")
@ResponseBody
public String dateConversion(
@RequestParam Date date,
@RequestParam LocalDate localDate,
@RequestParam LocalDateTime localDateTime) {
log.info("请求参数: date={}, localDate={}, localDateTime={}", date, localDate, localDateTime);
return String.format("Date: %s, LocalDate: %s, LocalDateTime: %s",
date, localDate, localDateTime);
}- 但是这里非常操蛋,请求时候的字符串格式要求很严格,一不对就会报错,上面的接口可以使用
http://localhost:8080/convert/date?date=2025/12/20 10:30:45&localDate=2025-12-20&localDateTime=2025-12-20T10:30:45来访问。date的日期部分写成2025-12-20就很可能报错。
所以我们可以在方法参数上添加 @DateTimeFormat 注解,指定日志字符串的格式:
java
@GetMapping("/convert/date")
@ResponseBody
public String dateConversion(
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate localDate,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime localDateTime) {
log.info("请求参数: date={}, localDate={}, localDateTime={}", date, localDate, localDateTime);
return String.format("Date: %s, LocalDate: %s, LocalDateTime: %s",
date, localDate, localDateTime);
}- 在参数上通过
@DateTimeFormat指定时间参数字符串的格式,按照这个格式传递就可以了,http://localhost:8080/convert/date?date=2025-12-20 10:30:45&localDate=2025-12-20&localDateTime=2025-12-20 10:30:45。 - 需要注意,Date 类型可以同时指定日期和时间,或者其中一部分;LocalDate 只能指定日期,指定时间也不生效;LocalDateTime 需要同时指定日期和时间,并同时传递日期和时间数据,否则会报错。
- 在上面的转换中,SpringMVC 会使用 DateFormatter 将字符串转换为 Date,使用 DateTimeFormatter 将字符串转换为 LocalDate 或 LocalDateTime。
4 路径变量转换
SpringMVC 的 @PathVariable 可以把 URL 路径中的参数直接绑定到方法参数中,并支持类型转换。
java
@GetMapping("/convert/path/{id}/{name}/{salary}/{date}")
@ResponseBody
public String pathVariableConversion(
@PathVariable int id,
@PathVariable String name,
@PathVariable double salary,
@PathVariable @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {
log.info("请求参数: id={}, name={}, salary={}, date={}", id, name, salary, date);
return String.format("ID: %d, Name: %s, Salary: %.2f, Date: %s", id, name, salary, date);
}- 通过
http://localhost:8080/convert/path/1001/张三/5000.50/2025-12-20访问,就可以拿到参数了。 - 具体转换方式和上面转换方式是一样的,使用 Converter 或 Formatter。
5 对象类型转换
SpringMVC 可以将请求参数自动绑定到对象上,它会根据对象的属性名匹配请求参数的name。
举个栗子:
我们首先定义一个类,BookDto.java,如下
java
package com.foooor.hellospringmvc.dto;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@Data
public class BookDto {
private int id;
private String name;
private double salary;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 定义日期时间格式
private LocalDateTime date;
}- 类中定义了不同类型的属性;使用
@DateTimeFormat注解定义日期的格式。
然后定义 Controller 中的方法接收请求的参数:
java
@PostMapping("/convert/object")
@ResponseBody
public String objectConversion(BookDto book) {
log.info("请求参数: {}", book);
return book.toString();
}- 通过 POST 方法,使用 URL
http://localhost:8080/convert/object?id=1001&name=张三&salary=5000.50&active=true&date=2025-12-20 10:30:45就可以请求接口,Controller 中就可以获取到参数了。 - 也可以使用表单的方式提交,但需要注意,表单的请求方法需要使用 POST 方式提交,如果使用 GET 方式,可能导致服务器不解析请求体,导致获取不到参数。
- 在上面的转换方式中,首先创建对象,然后通过 ConversionService 会调用合适的转换器 Formatter 或 Converter 将 String 转换为对应的类型。
- 需要注意,这里不是 JSON 格式的 body!这里没有使用
@RequestBody注解,将 JSON 格式的请求体转换为对象,是消息转换器 MappingJackson2HttpMessageConverter 负责的,对于JSON转对象,使用@DateTimeFormat 是不生效的,需要在属性上添加 @JsonFormat(pattern = "yyyy-MM-dd") 告诉 Jackson 字符串的格式。
12.2 自定义Converter
虽然 SpringMVC 提供了很多默认的类型转换器,但在某些情况下,可能并不能满足我们的要求,我们就需要自定义类型转换逻辑。
但是有一个问题,什么时候使用的是 Formatter,什么时候使用的是 Converter 呢?
如果你的类型转换 和格式无关,只涉及类型 → 类型,那就用 Converter。
典型例子:
- String → Integer
- String → Boolean
- Integer → Long
- String → Double
- String → 自定义对象
- 等等
一句话:Converter 用于普通类型转换,不关心格式。
如果需要“格式模板”来解析字符串,例如时间、金额、数字带格式的情况,就应该用 Formatter。
典型例子:
- "2025-01-01" → LocalDate
- "2025-01-01 10:00:00" → LocalDateTime
- "1,234.56" → BigDecimal
- "¥9.9" → Money
- 日期时间转换(配合 @DateTimeFormat)
一句话:Formatter 用于带格式的 String ↔ 对象转换。
但其实使用 Formatter 能实现的,使用 Converter 也可以实现。
假设现在有一个需求,通过传递参数 ?user=123,ZhangSan,zhangsan@foooor.com ,最终转换为 Controller 方法的 User 类型的参数。
1 实现Converter接口
首先得有 User 类,之前有过:
java
package com.foooor.hellospringmvc.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private String email;
}现在,我们想将格式为id,name,email的字符串转换为User对象。我们可以创建一个自定义的转换器,可以通过实现 Converter<S, T> 接口来创建:
java
package com.foooor.hellospringmvc.converter;
import com.foooor.hellospringmvc.pojo.User;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
@Component
public class StringToUserConverter implements Converter<String, User> {
/**
* 转换字符串到 User 对象
* 假设字符串格式为 "id,name,email"
*/
@Override
public User convert(String source) {
try {
// 假设字符串格式为 "id,name,email"
String[] parts = source.split(",");
if (parts.length == 3) {
Long id = Long.parseLong(parts[0]);
String name = parts[1];
String email = parts[2];
return new User(id, name, email);
}
} catch (Exception e) {
// 处理转换异常
e.printStackTrace();
}
return null;
}
}- 实现
Converter接口,重写convert方法,同时添加@Component交给 Spring 容器来管理。
2 注册类型转换器
在 SpringMVC 配置文件中添加如下配置:
xml
<!-- 启用 Spring MVC 注解支持 -->
<mvc:annotation-driven conversion-service="conversionService">
<!-- 其他配置,略... -->
</mvc:annotation-driven>
<!-- 定义 ConversionService -->
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="stringToUserConverter"/>
</set>
</property>
</bean>- 在
<mvc:annotation-driven>标签上添加conversion-service="conversionService",然后在conversionService中注册自定义的stringToUserConverter。
3 测试
通过使用 URL:http://localhost:8080/convert/user?user=123,ZhangSan,zhangsan@foooor.com 来请求,就可以将参数赋值给 User 对象中的参数了。
java
@GetMapping("/convert/user")
@ResponseBody
public String userConversion(User user) {
log.info("请求参数: {}", user);
return user.toString();
}12.3 类型转换错误处理
当类型转换失败时,SpringMVC会抛出异常,现在我们没有捕获这个异常,所以出现错误的时候,页面会出现如下很丑的页面:

所以我们需要捕获和处理这些异常,返回统一的错误页面或 JSON 数据,这个在后面统一异常处理的章节再讲。
内容未完......