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

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

}

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现这样的功能可以通过使用枚举、泛型和多态综合运用。具实现步骤如下: 1. 定义一个枚举类型,其中每个枚举值都对应一个接口类型和实现类类型。 ``` public enum RequestTypeEnum { TYPE_1(Request1.class, Service1.class), TYPE_2(Request2.class, Service2.class); private Class<? extends Request> requestClass; private Class<? extends Service> serviceClass; RequestTypeEnum(Class<? extends Request> requestClass, Class<? extends Service> serviceClass) { this.requestClass = requestClass; this.serviceClass = serviceClass; } public Class<? extends Request> getRequestClass() { return requestClass; } public Class<? extends Service> getServiceClass() { return serviceClass; } } ``` 2. 定义一个泛型方法,根据获取对应的枚举值,并根据枚举值获取对应的接口类型和实现类类型。 ``` public <T extends Request, R extends Service> R getService(T request) { RequestTypeEnum requestTypeEnum = getRequestTypeEnum(request); Class<T> requestClass = (Class<T>) requestTypeEnum.getRequestClass(); Class<R> serviceClass = (Class<R>) requestTypeEnum.getServiceClass(); T typedRequest = objectMapper.convertValue(request, requestClass); return applicationContext.getBean(serviceClass).execute(typedRequest); } private <T extends Request> RequestTypeEnum getRequestTypeEnum(T request) { // 根据获取对应的枚举值 // ... return requestTypeEnum; } ``` 3. 定义一个统一的入口方法,根据不同不同实体类接收,并调用泛型方法获取对应的实现类并执行。 ``` @RequestMapping("/execute") public Object execute(@RequestParam("type") String type, @RequestBody Object request) { RequestTypeEnum requestTypeEnum = RequestTypeEnum.valueOf(type.toUpperCase()); Class<? extends Request> requestClass = requestTypeEnum.getRequestClass(); Request typedRequest = objectMapper.convertValue(request, requestClass); return getService(typedRequest); } ``` 通过以上步骤,我们就可以实现一个统一的请求入口,根据不同不同实体类接收,根据不同类型获取对应的实现类并执行。同时,通过使用枚举、泛型和多态综合运用,我们可以让代码更加简洁、易读和易维护。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值