在Spring Boot中整合Katharsis,来快速开发JSON API的Web应用
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.
我们进行Web API开发的时候,经常会使用Json格式的消息体,而Json格式非常灵活,不同的人会有不同的设计风格和实现,而JSON API提供了一套标准。但它并不提供直接实现。
Katharsis是JSON API的Java实现,使用它可以快速开发出Json based的Web接口,还能快速的整合到Spring中。今天我们就来试试如何在Spring Boot中使用Katharsis。
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
代码请看GitHub: https://github.com/LarryDpk/pkslow-samples
References:
JSON API - Spring Boot Katharsis Example
JSON API in a Spring Application
Code for all: GitHub
欢迎关注微信公众号<南瓜慢说>,将持续为你更新...
Recommendations:
Cloud Native
Terraform
Container: Docker/Kubernetes
Spring Boot / Spring Cloud
Https
如何制定切实可行的计划并好好执行
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK