spring boot 基于jackson 多态数据类型处理简化rest api 开发

开发好可扩展的rest api 是一门技术,同时开发灵活扩展的rest api 也是比较费事的,很多时候
我们为了业务开发了特别多的rest api,造成系统的维护以及使用都很复杂,graphql 是一种不错的
解决方法(同时业界也有类似通用查询处理),以下是一个简单的基于jackson 多态数据处理简单
开发的一个玩法,可以参考

核心说明

实际上是基于约定的,包含了实体处理(基于jackson多态处理),以及服务层处理(很多时候我们是需要包含依赖的ioc)

项目准备

  • 项目结构
    就是一个标准的spring boot maven 项目
 
├── pom.xml
└── src
    ├── main
    ├── java
    └── com
    └── dalong
    └── jacksonapp
    ├── ContextUtil.java
    ├── ExceptionHandlers.java
    ├── FirstMyService.java
    ├── FirstUser.java
    ├── JacksonappApplication.java
    ├── MyApi.java
    ├── MyService.java
    ├── MyUser.java
    ├── SecondMyService.java
    └── SecondUser.java
    └── resources
    ├── application.properties
    ├── static
    └── templates
  • pom.xml
    基于starter生成的,主要就是一个web 项目
  • jackson 实体定义说明
 
// 基于JsonTypeInfo 定义类型
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
public interface  MyUser<T> {
    String token(); // 实体demo 方法
    T instance(); // 返回实体类型
    Class serviceType(); // 方便实体需要的服务类型定义(比如不同实体会有不同的service,dao层。。。。)
}

子类
FirstUser

 
@Data
public class FirstUser implements MyUser<FirstUser>{
    private String name;
    private int age;
    @Override
    public String token() {
        return String.format("FirstUser-%d-%s",this.age,this.name);
    }
 
    @Override
    public FirstUser instance() {
        return this;
    }
 
    @Override
    public Class serviceType() {
        return FirstMyService.class;  // 使用FirstMyService服务处理bean
    }
}

SecondUser

@Data
public class SecondUser implements MyUser<SecondUser>{
    private String name;
    private int age;
 
    @Override
    public String token() {
        return String.format("SecondUser-%d-%s",this.age,this.name);
    }
 
    @Override
    public SecondUser instance() {
        return this;
    }
 
    @Override
    public Class serviceType() {
        return SecondMyService.class; // 使用SecondMyService 服务处理bean
    }
}

实体的服务处理契约(处理具体实体的service)

public interface MyService<T extends  MyUser> {
     default String demo(T t){
      return   t.token();
    }
}
 
 

FirstUser 的服务处理实现

@Service
public class FirstMyService  implements  MyService<FirstUser> {
}

SecondUser 的service

@Service
public class SecondMyService  implements  MyService<SecondUser> {
}

服务工具类ContextUtil,方便基于bean 类型获取特定实体的服务处理bean

public class ContextUtil {
    public static  <T extends  MyService> T getBean(Class<T> cls) {
       return JacksonappApplication.applicationContext.getBean(cls);
    }
}

通用服务api 处理入口

@RestController
public class MyApi {
    @RequestMapping(value = {"/demoapp"})
    public  Object demo(@RequestBody MyUser myUser){
      // 通过实体可以找到servie,然后基于service 的方法处理对于实体的业务逻辑
       return ContextUtil.getBean(myUser.serviceType()).demo(myUser);
    }
}

spring boot 入口
通过CommandLineRunner 进行数据类型的注册,没有直接使用JsonSubTypes 注解是因为直接基于直接的话,代码就固化了
使用CommandLineRunner的好处是可以灵活的扩展服务(比如多模块,插件化处理。。。)

 
@SpringBootApplication
public class JacksonappApplication {
 
    public static ApplicationContext applicationContext;
    @Bean
    public CommandLineRunner commandLineRunner(ObjectMapper objectMapper){
        return args -> {
            objectMapper.registerSubtypes(new NamedType(FirstUser.class, "first"));
            objectMapper.registerSubtypes(new NamedType(SecondUser.class, "second"));
        };
    }
    public static void main(String[] args) {
        applicationContext= SpringApplication.run(JacksonappApplication.class, args);
    }
 
}

使用效果

  • 访问first 类型的
curl --location --request POST 'http://localhost:8080/demoapp' \
--header 'Content-Type: application/json' \
--data-raw '{
    "type":"first",
    "age":333,
    "name":"dalong"
    }'

效果

 

 

  • 访问second 类型
curl --location --request POST 'http://localhost:8080/demoapp' \
--header 'Content-Type: application/json' \
--data-raw '{
    "type":"second",
    "age":333,
    "name":"dalong"
    }'

 

 

说明

以上是一个简单的实践玩法,我们基于此可以实现一个入口灵活的rest api 处理,比如适合post 类型的处理(比如graphql 就是完全基于post 进行数据处理的,包装了查询以及修改数据),完整代码可以参考github 代码

参考资料

https://www.cnblogs.com/rongfengliang/p/15999843.html
https://github.com/rongfengliang/spring-boot-jackson

posted on 2022-03-13 20:53  荣锋亮  阅读(375)  评论(0编辑  收藏  举报

导航