2

在Spring Boot中整合Katharsis,来快速开发JSON API的Web应用

 1 year ago
source link: https://www.pkslow.com/archives/springboot-katharsis
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

我们进行Web API开发的时候,经常会使用Json格式的消息体,而Json格式非常灵活,不同的人会有不同的设计风格和实现,而JSON API提供了一套标准。但它并不提供直接实现。

Katharsis是JSON API的Java实现,使用它可以快速开发出Json based的Web接口,还能快速的整合到Spring中。今天我们就来试试如何在Spring Boot中使用Katharsis。

springboot-katharsis.katharsis-logo.png

2 整合过程

2.1 添加依赖

我们在Spring Boot中添加依赖如下,包括常规的starter、jpa和h2,而整合Katharsis只需要katharsis-spring即可。

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
  </dependency>
  <dependency>
    <groupId>io.katharsis</groupId>
    <artifactId>katharsis-spring</artifactId>
    <version>3.0.2</version>
  </dependency>
</dependencies>

2.2 Entity类

我们定义两个Entity,一个是学生,一个是教室,而教室对象会包含多个学生。

@JsonApiResource(type = "students")
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    @JsonApiId
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
}
@JsonApiResource(type = "classrooms")
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Classroom {
    @JsonApiId
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "classrooms_students", joinColumns = @JoinColumn(name = "classroom_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "student_id", referencedColumnName = "id"))
    @JsonApiRelation(serialize= SerializeType.EAGER)
    private Set<Student> students;
}

注解JsonApiResource这个会指定资源名称,这个会影响api的URL,注解JsonApiId则指定资源的id。

2.3 资源操作类

Katharsis使用ResourceRepository来对资源进行增删改查操作,这个跟数据库的增删改查类似,但属于更高一层。抽象到资源RESTful的资源层面,然后再调用数据库的Repository来操作,这里统一实现ResourceRepositoryV2接口。

@Component
public class StudentResourceRepository implements ResourceRepositoryV2<Student, Long> {

    private final StudentRepository studentRepository;

    public StudentResourceRepository(StudentRepository studentRepository) {
        this.studentRepository = studentRepository;
    }

    @Override
    public Student findOne(Long id, QuerySpec querySpec) {
        Optional<Student> student = studentRepository.findById(id);
        return student.orElse(null);
    }

    @Override
    public ResourceList<Student> findAll(QuerySpec querySpec) {
        return querySpec.apply(studentRepository.findAll());
    }

    @Override
    public ResourceList<Student> findAll(Iterable<Long> ids, QuerySpec querySpec) {
        return querySpec.apply(studentRepository.findAllById(ids));
    }

    @Override
    public <S extends Student> S save(S entity) {
        return studentRepository.save(entity);
    }

    @Override
    public void delete(Long id) {
        studentRepository.deleteById(id);
    }

    @Override
    public Class<Student> getResourceClass() {
        return Student.class;
    }

    @Override
    public <S extends Student> S create(S entity) {
        return save(entity);
    }

}

而数据库方面我们使用JPA实现即可:

public interface StudentRepository extends JpaRepository<Student, Long> {
}

上面的代码是针对Student资源类型的,对Classroom类似,就不把代码列出来了。

2.4 配置

为了使用Katharsis,我们需要在配置中引入KatharsisConfigV3,我们直接在Spring Boot启动类中引入即可:

@SpringBootApplication
@Import(KatharsisConfigV3.class)
public class KatharsisExample {
    public static void main(String[] args) {
        SpringApplication.run(KatharsisExample.class, args);
    }
}

Spring Boot的配置文件如下:

server.port=8080
server.servlet.context-path=/

katharsis.domainName=https://www.pkslow.com
katharsis.pathPrefix=/api/katharsis

spring.datasource.url = jdbc:h2:mem:springKatharsis;DB_CLOSE_DELAY=-1
spring.datasource.username = sa
spring.datasource.password =

spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = create-drop
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.globally_quoted_identifiers=true

katharsis.pathPrefix是URL前缀,而katharsis.domainName会影响Self Link等返回。

2.5 初始化数据

为了方便测试,初始化一些数据进行查询:

@Component
public class InitData {

    private final ClassroomRepository classroomRepository;

    private final StudentRepository studentRepository;

    public InitData(ClassroomRepository classroomRepository, StudentRepository studentRepository) {
        this.classroomRepository = classroomRepository;
        this.studentRepository = studentRepository;
    }

    @PostConstruct
    private void setupData() {
        Set<Student> students = new HashSet<>();
        Student student = Student.builder().name("Larry Deng").build();
        students.add(student);
        studentRepository.save(student);
        student = Student.builder().name("Eason").build();
        students.add(student);
        studentRepository.save(student);
        student = Student.builder().name("JJ Lin").build();
        students.add(student);
        studentRepository.save(student);

        Classroom classroom = Classroom.builder().name("Classroom No.1").students(students)
                .build();
        classroomRepository.save(classroom);
    }
}

至此则整合完毕了。

整合完后启动,就可以用curl或Postman开始测试了:

查询一个student:

$ curl http://localhost:8080/api/katharsis/students/1 | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   139    0   139    0     0   9828      0 --:--:-- --:--:-- --:--:-- 23166
{
  "data": {
    "id": "1",
    "type": "students",
    "attributes": {
      "name": "Larry Deng"
    },
    "links": {
      "self": "https://www.pkslow.com/api/katharsis/students/1"
    }
  }
}

查询多个student:

$ curl http://localhost:8080/api/katharsis/students | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   429    0   429    0     0   3633      0 --:--:-- --:--:-- --:--:--  3830
{
  "data": [
    {
      "id": "1",
      "type": "students",
      "attributes": {
        "name": "Larry Deng"
      },
      "links": {
        "self": "https://www.pkslow.com/api/katharsis/students/1"
      }
    },
    {
      "id": "2",
      "type": "students",
      "attributes": {
        "name": "Eason"
      },
      "links": {
        "self": "https://www.pkslow.com/api/katharsis/students/2"
      }
    },
    {
      "id": "3",
      "type": "students",
      "attributes": {
        "name": "JJ Lin"
      },
      "links": {
        "self": "https://www.pkslow.com/api/katharsis/students/3"
      }
    }
  ],
  "meta": {
    "totalResourceCount": null
  }
}

查询一个教室:

$ curl http://localhost:8080/api/katharsis/classrooms/4 | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   834    0   834    0     0  62462      0 --:--:-- --:--:-- --:--:--  116k
{
  "data": {
    "id": "4",
    "type": "classrooms",
    "attributes": {
      "name": "Classroom No.1"
    },
    "relationships": {
      "students": {
        "data": [
          {
            "id": "3",
            "type": "students"
          },
          {
            "id": "2",
            "type": "students"
          },
          {
            "id": "1",
            "type": "students"
          }
        ],
        "links": {
          "self": "https://www.pkslow.com/api/katharsis/classrooms/4/relationships/students",
          "related": "https://www.pkslow.com/api/katharsis/classrooms/4/students"
        }
      }
    },
    "links": {
      "self": "https://www.pkslow.com/api/katharsis/classrooms/4"
    }
  },
  "included": [
    {
      "id": "1",
      "type": "students",
      "attributes": {
        "name": "Larry Deng"
      },
      "links": {
        "self": "https://www.pkslow.com/api/katharsis/students/1"
      }
    },
    {
      "id": "2",
      "type": "students",
      "attributes": {
        "name": "Eason"
      },
      "links": {
        "self": "https://www.pkslow.com/api/katharsis/students/2"
      }
    },
    {
      "id": "3",
      "type": "students",
      "attributes": {
        "name": "JJ Lin"
      },
      "links": {
        "self": "https://www.pkslow.com/api/katharsis/students/3"
      }
    }
  ]
}

新增一个学生:

$ curl --header "Content-Type: application/json"   --request POST   --data '{
    "data": {
        "type": "students",
        "attributes": {
            "name": "Justin"
        }
    }
}'   http://localhost:8080/api/katharsis/students | jq .

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   249    0   135  100   114  11202   9459 --:--:-- --:--:-- --:--:-- 41500
{
  "data": {
    "id": "6",
    "type": "students",
    "attributes": {
      "name": "Justin"
    },
    "links": {
      "self": "https://www.pkslow.com/api/katharsis/students/6"
    }
  }
}
$ curl --header "Content-Type: application/json"   --request PATCH   --data '{
    "data": {
        "id":"6",
        "type": "students",
        "attributes": {
            "name": "Justin Wu"
        }
    }
}'   http://localhost:8080/api/katharsis/students/6 | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   273    0   138  100   135   4425   4329 --:--:-- --:--:-- --:--:-- 10920
{
  "data": {
    "id": "6",
    "type": "students",
    "attributes": {
      "name": "Justin Wu"
    },
    "links": {
      "self": "https://www.pkslow.com/api/katharsis/students/6"
    }
  }
}
$ curl --header "Content-Type: application/json"   --request DELETE   --data '{
    "data": {
        "id":"6",
        "type": "students",
        "attributes": {
            "name": "Justin Wu"
        }
    }
}'   http://localhost:8080/api/katharsis/students/6 | jq .

至此,我们已经覆盖了增删改查操作了。而我们在代码中并没有去写我们之前常写的Controller,却可以访问对应接口。因为Katharsis默认已经帮我们实现了,可以查看类:io.katharsis.core.internal.dispatcher.ControllerRegistry

springboot-katharsis.base-controller.png

代码请看GitHub: https://github.com/LarryDpk/pkslow-samples


References:

JSON API Implementations

JSON API - Spring Boot Katharsis Example

JSON API in a Spring Application


Code for all: GitHub

欢迎关注微信公众号<南瓜慢说>,将持续为你更新...

file

Recommendations:
Cloud Native
Terraform
Container: Docker/Kubernetes
Spring Boot / Spring Cloud
Https
如何制定切实可行的计划并好好执行


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK