diff --git a/docs/graphql/mutation.mdx b/docs/graphql/mutation.mdx index 38de4855a..a91ed2b0c 100644 --- a/docs/graphql/mutation.mdx +++ b/docs/graphql/mutation.mdx @@ -81,7 +81,7 @@ After compilation, the following Input DTO will be generated automatically: ```java title="BookInput.java" -@lombok.Data +@GenertedBy(file = "/src/main/dto/Book.dto") public class BookInput implements Input { ❶ @Nullable @@ -111,6 +111,7 @@ public class BookInput implements Input { ❶ ```kotlin title="BookInput.kt" +@GenertedBy(file = "/src/main/dto/Book.dto") data class BookInput( val id: Long? = null, val name: String = "", diff --git a/docs/mutation/save-command/input-dto/dto-lang.mdx b/docs/mutation/save-command/input-dto/dto-lang.mdx index 0b5ced46d..734f9bab8 100644 --- a/docs/mutation/save-command/input-dto/dto-lang.mdx +++ b/docs/mutation/save-command/input-dto/dto-lang.mdx @@ -88,7 +88,7 @@ package com.yourcompany.yourpoject.model.dto; import com.yourcompany.yourpoject.model.Book; import org.babyfish.jimmer.Input; -@lombok.Data +@GenertedBy(file = "/src/main/dto/Book.dto") public class BookInput implements Input { @Nullable @@ -139,6 +139,7 @@ package com.yourcompany.yourpoject.model.dto import com.yourcompany.yourpoject.model.Book import org.babyfish.jimmer.Input +@GenertedBy(file = "/src/main/dto/Book.dto") data class BookInput( val id: Long? = null, ❶ val name: String = "", diff --git a/docs/mutation/save-command/input-dto/mapstruct.mdx b/docs/mutation/save-command/input-dto/mapstruct.mdx index 25a525dc6..56f805221 100644 --- a/docs/mutation/save-command/input-dto/mapstruct.mdx +++ b/docs/mutation/save-command/input-dto/mapstruct.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 5 title: Using MapStruct --- diff --git a/docs/mutation/save-command/input-dto/null-handling.mdx b/docs/mutation/save-command/input-dto/null-handling.mdx new file mode 100644 index 000000000..b35ef00f9 --- /dev/null +++ b/docs/mutation/save-command/input-dto/null-handling.mdx @@ -0,0 +1,4 @@ +--- +sidebar_position: 4 +title: Handle Null Values +--- \ No newline at end of file diff --git a/docs/query/object-fetcher/dto.mdx b/docs/query/object-fetcher/dto.mdx index 84b16abf6..9d15f9a6f 100644 --- a/docs/query/object-fetcher/dto.mdx +++ b/docs/query/object-fetcher/dto.mdx @@ -81,7 +81,7 @@ package com.yourcompany.yourpoject.model.dto; import com.yourcompany.yourpoject.model.Book; import org.babyfish.jimmer.View; -@lombok.Data +@GenertedBy(file = "/src/main/dto/Book.dto") public class BookDetailView implements View { private long id; @@ -98,7 +98,6 @@ public class BookDetailView implements View { // highlight-next-line private List authors; - @lombok.Data // highlight-next-line public static class TargetOf_store implements View { @@ -112,7 +111,6 @@ public class BookDetailView implements View { ...other members omitted... } - @lombok.Data // highlight-next-line public static class TargetOf_authors implements View { @@ -140,6 +138,7 @@ package com.yourcompany.yourpoject.model.dto import com.yourcompany.yourpoject.model.Book import org.babyfish.jimmer.View +@GenertedBy(file = "/src/main/dto/Book.dto") data class BookDetailView( val id: Long = 0, val name: String = "", diff --git a/docs/spring/repository/dto.mdx b/docs/spring/repository/dto.mdx index 520c5cace..98ca7b201 100644 --- a/docs/spring/repository/dto.mdx +++ b/docs/spring/repository/dto.mdx @@ -77,7 +77,7 @@ package com.yourcompany.yourpoject.model.dto; import com.yourcompany.yourpoject.model.Book; import org.babyfish.jimmer.View; -@lombok.Data +@GenertedBy(file = "/src/main/dto/Book.dto") public class BookDetailView implements Input { private long id; @@ -94,7 +94,6 @@ public class BookDetailView implements Input { // highlight-next-line private List authors; - @lombok.Data // highlight-next-line public static class TargetOf_store implements Input { @@ -108,7 +107,6 @@ public class BookDetailView implements Input { ...Omitted other members... } - @lombok.Data // highlight-next-line public static class TargetOf_authors implements Input { @@ -136,6 +134,7 @@ package com.yourcompany.yourpoject.model.dto import com.yourcompany.yourpoject.model.Book import org.babyfish.jimmer.View +@GenertedBy(file = "/src/main/dto/Book.dto") data class BookDetailView( val id: Long = 0, val name: String = "", diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/graphql/mutation.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/graphql/mutation.mdx index f669948c8..413531f7d 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/graphql/mutation.mdx +++ b/i18n/zh/docusaurus-plugin-content-docs/current/graphql/mutation.mdx @@ -81,7 +81,7 @@ Jimmer提供了两种定义Input DTO的方式 ```java title="BookInput.java" -@lombok.Data +@GenertedBy(file = "/src/main/dto/Book.dto") public class BookInput implements Input { ❶ @Nullable @@ -111,6 +111,7 @@ public class BookInput implements Input { ❶ ```kotlin title="BookInput.kt" +@GenertedBy(file = "/src/main/dto/Book.dto") data class BookInput( val id: Long? = null, val name: String = "", diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/mapping/advanced/view/many-to-many-view.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/mapping/advanced/view/many-to-many-view.mdx index b422ce963..1334239cc 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/mapping/advanced/view/many-to-many-view.mdx +++ b/i18n/zh/docusaurus-plugin-content-docs/current/mapping/advanced/view/many-to-many-view.mdx @@ -633,6 +633,6 @@ alter table learning_link - 构建实体对象时,只能设置原始属性,不能设置视图属性。 - 这和[@IdView](./id-view)不同,对于[@IdView](./id-view)而言,原始属性和试图属性都可以设置 + 这和[@IdView](./id-view)不同,对于[@IdView](./id-view)而言,原始属性和视图属性都可以设置 - 无论原始属性,还是试图属性,预编译器都会生成与之配套的代码,所以二者都可以在[对象抓取器](../../../query/object-fetcher)和强类型SQL DSL中使用 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/dto-lang.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/dto-lang.mdx index 060db7b1a..19bce268e 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/dto-lang.mdx +++ b/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/dto-lang.mdx @@ -87,7 +87,7 @@ package com.yourcompany.yourpoject.model.dto; import com.yourcompany.yourpoject.model.Book; import org.babyfish.jimmer.Input; -@lombok.Data +@GenertedBy(file = "/src/main/dto/Book.dto") public class BookInput implements Input { @Nullable @@ -138,6 +138,7 @@ package com.yourcompany.yourpoject.model.dto import com.yourcompany.yourpoject.model.Book import org.babyfish.jimmer.Input +@GenertedBy(file = "/src/main/dto/Book.dto") data class BookInput( val id: Long? = null, ❶ val name: String = "", diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/mapstruct.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/mapstruct.mdx index 214c646c5..e4500989c 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/mapstruct.mdx +++ b/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/mapstruct.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 5 title: 使用MapStruct --- diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/null-handling.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/null-handling.mdx new file mode 100644 index 000000000..898579577 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/input-dto/null-handling.mdx @@ -0,0 +1,689 @@ +--- +sidebar_position: 4 +title: 处理空值 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Input DTO用于数据录入,对于客户端提交的对象中的可空属性提供了强大行为控制能力,并将这种能力标准化。 + +## 数据录入中null相关的问题 + +### 回顾:直接保存实体对象 + +Jimmer实体最重要一个特征之一,就是严格区分数据未知 *(不指定对象属性)* 和没有数据 *(将对象属性指定为null)*。 + +让我们暂时将Input DTO的概念放到一旁,来回顾一下直接使用Jimmer实体保存数据时二者的差异。 + +- 将可空属性指定为null + + + + + ```java + Book book = BookDraft.$.produce(draft -> { + draft.setId(12L); + draft.setName("TURING"); + // highlight-next-line + draft.setStoreId(null); + }); + sqlClient.update(book); + ``` + + + + + ```kotlin + val book = new(Book::class).by { + id = 12L + name = "TURING" + // highlight-next-line + storeId = null + } + sqlClient.update(book); + ``` + + + + + 生成如下SQL: + + ```sql + update BOOK + set + NAME = ?, /* TURING */ + // highlight-next-line + STORE_ID = ? /* */ + where + ID = ? /* 12 */` + ``` + + 可见,明确地将对象的属性设置为null,利用保存指令执行update操作,数据库中的值会被修改为null。 + +- 根本不指定可空属性 + + + + + ```java + Book book = BookDraft.$.produce(draft -> { + draft.setId(12L); + draft.setName("TURING"); + // highlight-next-line + draft.setStoreId(null); + }); + sqlClient.update(book); + ``` + + + + + ```kotlin + val book = new(Book::class).by { + id = 12L + name = "TURING" + // highlight-next-line + // `storeId` is not specified + } + sqlClient.update(book); + ``` + + + + + 生成如下SQL: + + ```sql + update BOOK + set + NAME = ? /* TURING */ + // highlight-next-line + /* `STORE_ID` is not updated */ + where + ID = ? /* 12 */` + ``` + + 可见,不设置对象的属性,利用保存指令执行update操作,数据库中的值不会被更改。 + +:::info +这个区别非常重要。 + +在本文的后续内容中,我们不再讨论ORM生成了什么样的SQL语句,因为我们只需关注由Input DTO转换而得的实体对象属于哪种即可。 +::: + +### Input DTO面临的问题 + +现在,让我们来定义一个Input DTO: + +```title="src/main/dto/Book.dto" +input BookUpdateInput { + id! + name + // highlight-next-line + id(store) +} +``` + +更多有关DTO语言的细节请参考[相关章节](../../../object/view/dto-language),这里我们重点关注Jimmer预编译器根据这段DTO代码自动生成的Java/Kotlin代码。 + +生成代码如下 + + + + +```java title="BookUpdateInput.java" +@GenertedBy(file = "/src/main/dto/Book.dto") +public class BookUpdateInput implements Input { + + private long id; + + private String name; + + // highlight-next-line + @Nullable + private Long storeId; + + @Override + public Book toEntity() { + ...略... + } + + ...省略其他成员... +} +``` + + + + +```kotlin title="BookUpdateInput.kt" +@GenertedBy(file = "/src/main/dto/Book.dto") +data class BookUpdateInput( + val id: Long, + val name: String, + // highlight-next-line + val storeId: Long? = null +) { + + override fun toEntity(): Book = ...略... + + ...省略其他成员... +} +``` + + + + +在原实体中,`Book.store`关联属性允许为null。此处的DTO语言未对此做出改变,所以,在生成代码中,`storeId`字段也允许为null。 + +如果用户上传的`BookUpdateInput`对象的`storeId`属性为null,那么用户的意图是将数据库中对应的外键`STORE_ID`更新为null,还是根本不更新改这段呢? + +实际上,两种诉求都是普遍存在的。长期以来,开发人员对这两种行为的约定非常随意,即使API配套文档提及这类细节,形式也非常随意。这构成了沟通和理解困难,并对行业形成了持久伤害。 + +Input DTO对这个问题进行标准化定义,以求用规范化的方式处理不同的诉求。 + +## Input DTO中可空属性的4种处理方法 + +为了解决上文提出的问题,[DTO语言](../../../object/view/dto-language)规定,如果一个DTO属性同时满足以下两个条件: + +- 被定义在input类型中 + +- 允许为null + +那么,可以为该DTO属性添加一个用于表示null处理模式的修饰符:可以为`fixed`、`static`、`dynamic`或`fuzzy`。 + +为了方便后续讨论,我们假设存在如下Web Controller: + + + + +```java +@RestController +public class BookController { + + @PutMapping("/book") + public void update( + // highlight-next-line + @RequestBody BookUpdateInput input + ) { + Book book = input.toEntity(); + System.out.println(book); + ...后续代码略... + } + + ...省略其他成员... +} +``` + + + + +```kotlin +@RestController +class BookController { + + @PutMapping("/book") + fun update( + // highlight-next-line + @RequestBody input: BookUpdateInput + ) { + val book = input.toEntity() + pirntln(book) + ...后续代码略... + } + + ...省略其他成员... +} +``` + + + + +这里,我们把用户上传的Input DTO对象转化为Jimmer实体,并打印出来。 + +我们只需要关注打印结果即可,如前文所言,我们只需关注由Input DTO转换而得的实体对象是什么即可,而无需讨论ORM会生成什么样的SQL语句。 + +因此,后续代码不重要,省略。 + +### 1. fixed + +DTO代码示范如下: + +```title="src/main/dto/Book.dto" +input BookUpdateInput { + id! + name + // highlight-next-line + fixed id(store) +} +``` + +也可称该模式为超级静态模式。 + +- 禁止用户提交`Input DTO`时不指定某些属性,即使想让某个属性为null,也需要明确指定。 + +- 如果Input DTO的属性为null,得到的Jimmer实体对象的对应属性也会被设置为null,即将数据库中对应的字段修改为null。 + +客户端提交数据的两种用法如下: + +- 提交`storeId`属性为null的Input DTO + + ```sh + curl -X 'PUT' \ + 'http://localhost:8080/book' \ + -H 'accept: */*' \ + -H 'Content-Type: application/json' \ + -d '{ + "id": 12, + "name": "TURING", + # highlight-next-line + "storeId": null + }' + ``` + + 打印结果 *(最终得到的Jimmer实体对象)* 如下: + + ```json + { + "id":12, + "name":"TURING", + // highlight-next-line + "store":null + } + ``` + + 即,后续操作会把数据库中对应字段修改为null。 + +- 提交没有`storeId`属性的Input DTO + + ```sh + curl -X 'PUT' \ + 'http://localhost:8080/book' \ + -H 'accept: */*' \ + -H 'Content-Type: application/json' \ + -d '{ + "id": 12, + "name": "TURING" + }' + ``` + + 该请求会被拒绝,HTTP错误代码400,参数错误。如果查看Java日志,可看到如下错误: + + ```sh + Resolved [org.springframework.http.converter.HttpMessageNotReadableException: + JSON parse error: Cannot construct instance of + `org.doc.j.model.dto.BookUpdateInput$Builder`, + problem: An object whose type is "org.doc.j.model.dto.BookUpdateInput" + cannot be deserialized by Jackson. + The current type is fixed input DTO so that + all JSON properties must be specified explicitly, + # highlight-next-line + however, the property "storeId" is not specified by JSON explicitly. + Please either explicitly specify the property as null in the JSON, + or specify the current input properties as static, dynamic or fuzzy + in the DTO language] + ``` + +:::tip +如果采用Jimmer中[自动生成TypeScript](../../../client/api)的功能,生成的TypeScript代码要求Web开发人员必须为`BookUpdateInput`对象提供`storeId`属性,否则无法通过编译。 +::: + +### 2. static + +DTO代码示范如下: + +```title="src/main/dto/Book.dto" +input BookUpdateInput { + id! + name + // highlight-next-line + static id(store) +} +``` + +- 用户提交`Input DTO`时,既可以将`storeId`属性指定为null,也可以根本不指定。 + +- 无论用户如何选择,行为不变,得到的Jimmer实体对象的对应属性一定会被设置为null。即,数据库中对应的字段会被修改为null。 + +客户端提交数据的两种用法如下: + +- 提交`storeId`属性为null的Input DTO + + ```sh + curl -X 'PUT' \ + 'http://localhost:8080/book' \ + -H 'accept: */*' \ + -H 'Content-Type: application/json' \ + -d '{ + "id": 12, + "name": "TURING", + # highlight-next-line + "storeId": null + }' + ``` + + 打印结果 *(最终得到的Jimmer实体对象)* 如下: + + ```json + { + "id":12, + "name":"TURING", + // highlight-next-line + "store":null + } + ``` + + 即,后续操作会把数据库中对应字段修改为null。 + +- 提交没有`storeId`属性的Input DTO + + ```sh + curl -X 'PUT' \ + 'http://localhost:8080/book' \ + -H 'accept: */*' \ + -H 'Content-Type: application/json' \ + -d '{ + "id": 12, + "name": "TURING" + }' + ``` + + 打印结果 *(最终得到的Jimmer实体对象)* 如下: + + ```json + { + "id":12, + "name":"TURING", + // highlight-next-line + "store":null + } + ``` + + 即,后续操作会把数据库中对应字段修改为null。 + +:::info +两种操作的效果一样,最终效果只受到DTO形状影响,与用户是否指定DTO属性无关。 +::: + +### 3. dynamic + +DTO代码示范如下: + +```title="src/main/dto/Book.dto" +input BookUpdateInput { + id! + name + // highlight-next-line + dynamic id(store) +} +``` + +- 如果用户选择将DTO的`storeId`属性设定为null,那么最终得到的Jimemr实体对象的`storeId`属性也为null。即,将数据库中对应字段修改为null。 + +- 如果用户根本不设置DTO的`storeId`属性,那么最终得到的Jimemr实体对象的`storeId`属性也不会被设置。即,将数据库中对应字段不会被修改。 + +客户端提交数据的两种用法如下: + +- 提交`storeId`属性为null的Input DTO + + ```sh + curl -X 'PUT' \ + 'http://localhost:8080/book' \ + -H 'accept: */*' \ + -H 'Content-Type: application/json' \ + -d '{ + "id": 12, + "name": "TURING", + # highlight-next-line + "storeId": null + }' + ``` + + 打印结果 *(最终得到的Jimmer实体对象)* 如下: + + ```json + { + "id":12, + "name":"TURING", + // highlight-next-line + "store":null + } + ``` + + 即,后续操作会把数据库中对应字段修改为null。 + +- 提交没有`storeId`属性的Input DTO + + ```sh + curl -X 'PUT' \ + 'http://localhost:8080/book' \ + -H 'accept: */*' \ + -H 'Content-Type: application/json' \ + -d '{ + "id": 12, + "name": "TURING" + }' + ``` + + 打印结果 *(最终得到的Jimmer实体对象)* 如下: + + ```json + { + "id":12, + "name":"TURING", + // highlight-next-line + // 此处没有storeId属性 + } + ``` + + 即,后续操作不会修改数据库中对应字段。 + +:::info +两种用法对应两种完全不同的行为,适合专业的客户端团队对服务行为进行灵活的控制。 +::: + +### 4. fuzzy + +:::warning +该模式以牺牲功能为代价换取保守和安全,是唯一一种功能不健全的模式。 +::: + +DTO代码示范如下: + +```title="src/main/dto/Book.dto" +input BookUpdateInput { + id! + name + // highlight-next-line + fuzzy id(store) +} +``` + +- 如果用户把DTO对象的`storeId`指定为非null值,那么最终得到的Jimemr实体对象的`storeId`属性被指定。即,将数据库中对应字段修改为对应的值。 + +- 否则 *(无论把DTO对象的`storeId`属性指定为null,还是根本不指定)*,最终得到的Jimemr实体对象的`storeId`属性都不会被指定。即,将数据库中对应字段不会被修改。 + +客户端提交数据的三种用法如下: + +- 提交`storeId`属性为null的Input DTO + + ```sh + curl -X 'PUT' \ + 'http://localhost:8080/book' \ + -H 'accept: */*' \ + -H 'Content-Type: application/json' \ + -d '{ + "id": 12, + "name": "TURING", + # highlight-next-line + "storeId": null + }' + ``` + + 打印结果 *(最终得到的Jimmer实体对象)* 如下: + + ```json + { + "id":12, + "name":"TURING", + // highlight-next-line + // 此处没有storeId属性 + } + ``` + + 即,后续操作不会修改数据库中对应字段。 + +- 提交没有`storeId`属性的Input DTO + + ```sh + curl -X 'PUT' \ + 'http://localhost:8080/book' \ + -H 'accept: */*' \ + -H 'Content-Type: application/json' \ + -d '{ + "id": 12, + "name": "TURING" + }' + ``` + + 打印结果 *(最终得到的Jimmer实体对象)* 如下: + + ```json + { + "id":12, + "name":"TURING", + // highlight-next-line + // 此处没有storeId属性 + } + ``` + + 即,后续操作不会修改数据库中对应字段。 + +- 提交`storeId`属性为非null的Input DTO + + 前面两种用法都无法修改数据库中的对应字段,除非指定非null值,如下: + + ```sh + curl -X 'PUT' \ + 'http://localhost:8080/book' \ + -H 'accept: */*' \ + -H 'Content-Type: application/json' \ + -d '{ + "id": 12, + "name": "TURING", + # highlight-next-line + "storeId": 2 + }' + ``` + + 打印结果 *(最终得到的Jimmer实体对象)* 如下: + + ```json + { + "id":12, + "name":"TURING", + // highlight-next-line + "store":3 + } + ``` + +:::info +该模式以牺牲不能把数据库中对应字段修改为null的功能为代价,换取绝对的保守和安全。尤其适合经验缺乏的客户端团队。 +::: + +## 更高级别的配置 + +在上面的例子中,`fixed`, `static`, `dynamic`和`fuzzy`这些关键字被用于修饰Input DTO的可空属性。 + +字段级别的控制是最细腻的。然而,如果Input DTO中的可空属性很多,一个一个配置可能比较麻烦。 + +Jimmer提供影响范围更大的配置方法 + +- input类型级别 + + ```sh + // highlight-next-line + dynamic interface XxxInput { + fixed nullableProp1 + static nullableProp2 + // highlight-next-line + nullableProp3 + fuzzy nullableProp4 + // highlight-next-line + nullableProp5 + } + ``` + + 这里,并没有`nullableProp3`和`nullableProp5`声明空处理模式,它们将共享input类型级别的配置 *(对于本例而言,就是`dynamic`)*。 + +- 预编译器级别 + + 如果在input类型级别也找不到配置,则参考预编译器 *(对Java而言,就是APT;对于kotlin而言,就是KSP)* 的全局配置参数`jimmer.dto.defaultNullableInputModifier`。 + + + + + ```xml + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + + + -Ajimmer.dto.defaultNullableInputModifier=fixed + + + + ``` + + + + + ```java gradle + tasks.withType().configureEach { + // highlight-next-line + options.compilerArgs.add("-Ajimmer.dto.defaultNullableInputModifier=fixed") + } + ``` + + + + + ```kotlin gradle + ksp { + // highlight-next-line + arg("jimmer.dto.defaultNullableInputModifier", "fixed") + } + ``` + + + + +- 最终默认模式 + + 如果预编译器级别也没有配置,最终默认为`static`。 + +:::info +不同级别的配置可能冲突,彼此之间优先级如下: + +input属性级配置 > input类型级配置 > 与编译器全局配置 > 最终默认`static` +::: + +## 注意事项 + +:::caution +对于`fixed`和`dynamic`模式而言,Jimmer要求服务端的采用[Jackson](https://github.com/FasterXML/jackson)进行反序列化。 +::: + +因此,如果你打算使用`fixed`或`dynamic`模式,请 + +- 添加`@RequestBody` + + > 如果你仔细看本文的例子,你会发现那里使用了`@RequestBody`。 + +- 请不要替换Spring Boot默认为你启用的Jackson Message Converter。 + + > 事实上,不仅是本文讨论的使用了`fixed`或`dynamic`模式的Input DTO会有此要求;如果用户需要使用Jimmer实体本身的序列化/反序列化,也需要使用Jackson。 + > + > Jackson经过精心设计,在功能和性能之间找到了最完美的平衡点。因此,Jimmer将Jackson视为必备基础设施。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/query/object-fetcher/dto.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/query/object-fetcher/dto.mdx index d53371282..1c5a9b7cd 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/query/object-fetcher/dto.mdx +++ b/i18n/zh/docusaurus-plugin-content-docs/current/query/object-fetcher/dto.mdx @@ -81,7 +81,7 @@ package com.yourcompany.yourpoject.model.dto; import com.yourcompany.yourpoject.model.Book; import org.babyfish.jimmer.View; -@lombok.Data +@GenertedBy(file = "/src/main/dto/Book.dto") public class BookDetailView implements Input { private long id; @@ -98,7 +98,6 @@ public class BookDetailView implements Input { // highlight-next-line private List authors; - @lombok.Data // highlight-next-line public static class TargetOf_store implements Input { @@ -112,7 +111,6 @@ public class BookDetailView implements Input { ...省略其他成员... } - @lombok.Data // highlight-next-line public static class TargetOf_authors implements Input { @@ -140,6 +138,7 @@ package com.yourcompany.yourpoject.model.dto import com.yourcompany.yourpoject.model.Book import org.babyfish.jimmer.View +@GenertedBy(file = "/src/main/dto/Book.dto") data class BookDetailView( val id: Long = 0, val name: String = "", diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/query/paging/reverse-sorting.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/query/paging/reverse-sorting.mdx index a541b60eb..7678eeb86 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/query/paging/reverse-sorting.mdx +++ b/i18n/zh/docusaurus-plugin-content-docs/current/query/paging/reverse-sorting.mdx @@ -26,33 +26,7 @@ import TabItem from '@theme/TabItem'; 让我们来看一个例子。 -SpringBoot的`Page`类型的定义过于复杂,不利于本文通过打印结果进行演示,所以我们并不采用SpringBoot并采用自定义Page类: - - - - -```java title="Page.java" -@lombok.Data -public class Page { - private final int totalRowCount; - private final int totalPage; - private final List entities; -} -``` - - - - -```kotlin title="Page.kt" -data class Page( - val totalRowCount: Int, - val totalPage: Int, - val entities: List -) -``` - - - +SpringBoot的`Page`类型的定义过于复杂,不利于本文通过打印结果进行演示,所以我们采用Jimmer定义的Page类,而非SpringBoot并采用自定义Page类。 分页查询代码为 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/spring/repository/dto.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/spring/repository/dto.mdx index cfa669f99..6ad9d45e4 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/spring/repository/dto.mdx +++ b/i18n/zh/docusaurus-plugin-content-docs/current/spring/repository/dto.mdx @@ -77,7 +77,7 @@ package com.yourcompany.yourpoject.model.dto; import com.yourcompany.yourpoject.model.Book; import org.babyfish.jimmer.View; -@lombok.Data +@GenertedBy(file = "/src/main/dto/Book.dto") public class BookDetailView implements Input { private long id; @@ -94,7 +94,6 @@ public class BookDetailView implements Input { // highlight-next-line private List authors; - @lombok.Data // highlight-next-line public static class TargetOf_store implements Input { @@ -108,7 +107,6 @@ public class BookDetailView implements Input { ...省略其他成员... } - @lombok.Data // highlight-next-line public static class TargetOf_authors implements Input { @@ -136,6 +134,7 @@ package com.yourcompany.yourpoject.model.dto import com.yourcompany.yourpoject.model.Book import org.babyfish.jimmer.View +@GenertedBy(file = "/src/main/dto/Book.dto") data class BookDetailView( val id: Long = 0, val name: String = "",