SpringBoot 同一请求入口,根据不同的入参, 调用不同的实体类接收

文章介绍了如何在Java开发中,针对业务类型相同但参数略有不同的接口进行封装。通过使用JsonTypeInfo和JsonSubTypes注解,配合枚举类和泛型,实现了动态判断请求参数并调用相应的业务实现类,避免了使用switch语句,提升了代码的优雅性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 问题

实际开发中遇到的问题:业务类型一样,传参基本一样,有个别参数不同,我们需要将其封装成一个接口,这该怎么实现呢?

2. 简单解决方案

使用switch判断具体需要调用哪一个接口,以及负责处理的业务实现类就可以了。

这样的写法是完全没有问题的,已经满足了实际业务需要,这种入门级的代码,基本不要动什么脑子;

但是,如果想要使用高逼格的代码实现这种功能,能够让我们用更多Java知识应用到实际开发过程中,学以致用,使自己的能力得到升华。

3. 高级解决方案

1. RequestParam

@Data
public class RequestParam<T extends AbstractRequestParam> {

    @JsonProperty("type")
    private String type;

    @JsonProperty("param")
    private ParamTypeEnum type;

    @JsonProperty("version")
    private String version;

    // 作用于类/接口/属性,被用来开启多态类型处理
    @JsonTypeInfo(
            // use:必选,使用哪一种类型识别码
            use = JsonTypeInfo.Id.NAME, // 使用指定名称作为识别码
            // 可选,指定识别码是如何被包含进去的
            include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
            // 可选,指定识别码的属性名称
            property = "param"
    )
    private T params;

}

@JsonProperty注解

反序列化:将json对象的key与实体类的指定属性对照起来,并完成赋值操作;
@JsonProperty,隶属于Jackson,springboot内部集成,请求入参转实体类默认使用的就是Jackson;
由于将请求参数与泛型进行映射,所以,每个属性都需要加上@JsonProperty注解进行对照。

往枚举类注入对象

如果枚举类只有这一点点作用,那我们也不用废这么劲用它接收,干脆用String类来接收岂不方便?

如果这样想,就大错特错了,再来回想一下,如果我们用String类来接收type的值,那我们岂不是又回到了原点:后续还得用switch来判断,进而调用不同的业务实现类。

之所以想用枚举类来接收type,是因为,这个时候,我们已经拿到了type的值,换句话说,我们这个时候就已经知道,它调用的是哪个接口,该用哪个接口实现类来处理!

难点在于:如何往枚举类注入对象?

不同接口的请求使用不同实体类接收;

通过注解@JsonTypeInfo和@JsonSubTypes结合实现

由最开始的时候,我们得知:不同的接口虽然请求参数不同,但都会塞到params这个参数中,所以,我们就能根据参数type来判断当前请求该用哪个请求实体类来接收;

所以,params的类型只能用泛型来接收(只有在运行调用的时候,才能知道它是谁);

这样一来,请求实体类只需继承抽象类AbstractRequestParam,并设置@JsonSubType.Type注解即可。

2. ParamTypeEnum

@AllArgsConstructor
public enum ParamTypeEnum {

    APP("app", "APP"),
    WEB("web", "WEB");

    @JsonValue
    private final String code;
    private final String name;

}

用枚举类来接收请求入参的其中一个参数值:

在这里,是用枚举类ParamTypeEnum 来接收请求参数code的值,这个说法并不对,因为枚举类往往不止有一个属性,而param却只有一个值,按正常逻辑来想,json是完全不能实现发序列化的。

这里就不得不提及注解@JsonValue

被加上注解@JsonValue的属性,将会完成值的映射,也就是code的值最终被赋值到枚举类的param属性上,这样就没有一点问题了。

3. AbstractRequestParam

@JsonSubTypes({
        // 枚举了多态类型(value对应子类)类型的标识符值(name对应参数type的值对应的实体接受类
        @JsonSubTypes.Type(value = AppRequestParam.class, name = "app"),
        @JsonSubTypes.Type(value = WebRequestParam.class, name = "web")
})
public abstract class AbstractRequestParam {
}

4. AppRequestParam

@EqualsAndHashCode(callSuper = true)
@Data
public class AppRequestParam extends AbstractRequestParam {

    private String name;

    private String service;

}

请求实体类只需继承抽象类AbstractRequestParam,并设置@JsonSubType.Type注解即可。

5. WebRequestParam

@EqualsAndHashCode(callSuper = true)
@Data
public class WebRequestParam extends AbstractRequestParam {

    private String name;

    private String ipPath;

}

请求实体类只需继承抽象类AbstractRequestParam,并设置@JsonSubType.Type注解即可。

6. TestController

@RestController
public class TestController {

    @PostMapping("/test")
    public <T extends AbstractRequestParam> String test(@RequestBody RequestParam<T> params) {
        System.out.println("获取到参数信息"+ params);
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.writeValueAsString(params);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值