使用 Fetch for List进行一对多保存 (POST) 会导致错误请求 (400)

发布于 2025-01-09 21:50:51 字数 4391 浏览 3 评论 0原文

我试图同时保存父实体(一)和子实体(许多)。

我从这里获取帮助< /a> 和 此处

我有一个如下所示的用户实体:

@Entity
@Table(name = "app_user")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class AppUser {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "salutation")
    private String salutation;

    @Column(name = "name")
    private String name;

    @Column(name = "email")
    private String email;

    @Column(name = "preference")
    private String preference;

    public AppUser(String salutation, String name, String email, String preference, List<Address> addressList,
            List<Expertise> expertise) {
        super();
        this.salutation = salutation;
        this.name = name;
        this.email = email;
        this.preference = preference;
        this.addressList = addressList;
        this.expertise = expertise;
    }

    @OneToMany(orphanRemoval = true, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinColumn(name = "address_id")
    private List<Address> addressList = new ArrayList<>();

    @OneToMany(orphanRemoval = true, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinColumn(name = "expertise_id")
    private List<Expertise> expertise = new ArrayList<>();

我的 POST 控制器方法。

@PostMapping("/appUsers")
public ResponseEntity<AppUser> createUser(@RequestBody AppUser appUser) {
    try {
        AppUser _appUser = appUserRepository.save(
            new AppUser(appUser.getSalutation(), appUser.getName(), appUser.getEmail(), 
                    appUser.getPreference(), appUser.getAddressList(), 
                    appUser.getExpertise()));
        return new ResponseEntity<>(_appUser, HttpStatus.CREATED);
    } catch (Exception e) {
        return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

我的纯 JS(获取)片段:

<script>
async function postDataToServer(postData) {
    const baseURL = "http://localhost:8080/api";
    try {
        const res = await fetch(`${baseURL}/appUsers`, {
            method: "post",
            headers: {
                "Content-Type": "application/json",
                Accept: "application/json",
            },
            body: JSON.stringify(postData),
        });
        if (!res.ok) {
            const message = `An error has occured: ${res.status} - ${res.statusText}`;
            throw new Error(message);
        }
    } catch (err) {
        alert(err.message);
    }
}
</script>

使用上面的内容,我可以看到表单数据很好地形成,如下所示:

{
  "salutation": "Mr.",
  "name": "Ajay Kumar",
  "email": "[email protected]",
  "address_main": "1234 StreetName State 12345",
  "address_1": "2345 StreetName State 23456",
  "address_2": "3456 StreetName State 34567",
  "preference": "Vegeterian",
  "expertise": [
    "java",
    "springboot",
    "javascript"
  ],
  "secret": "1abc1234-1abc-4321-1234-1234abcd1234"
}

在提交期间,如果我不选择专业知识,那么一切都会找到。即用户被保存,但如果我选择专业知识复选框,我会在浏览器控制台和 JSON 解析错误控制台收到 400 错误请求消息,如下所示:

2022-02-25 11:02:53.009 WARN 25007 --- [nio-8080-exec-1] .wsmsDefaultHandlerExceptionResolver:已解决[org.springframework.http.converter.HttpMessageNotReadableException:JSON解析错误:无法构造实例com.spring.boot.rocks.model.Expertise (尽管至少存在一个 Creator):没有字符串参数构造函数/工厂方法来从字符串值('java')反序列化;嵌套异常是 com.fasterxml.jackson.databind.exc.MismatchedInputException:无法构造 com.spring.boot.rocks.model.Expertise 的实例(尽管至少存在一个 Creator):没有字符串参数从字符串值('java')反序列化的构造函数/工厂方法 [Source: (PushbackInputStream);行:1,列:234](通过参考链:com.spring.boot.rocks.model.AppUser["expertise"]->java.util.ArrayList[0])]

我创建了一个 github 项目

问题:我缺少什么?如何仅使用纯 JS 将 expertise 集合转换为 List?或者如何处理控制器中的专业知识集合?

I am trying to save Parent (One) and Children (Many) entities at the same time.

I took help from here and here.

I have an User Entity like below:

@Entity
@Table(name = "app_user")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class AppUser {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "salutation")
    private String salutation;

    @Column(name = "name")
    private String name;

    @Column(name = "email")
    private String email;

    @Column(name = "preference")
    private String preference;

    public AppUser(String salutation, String name, String email, String preference, List<Address> addressList,
            List<Expertise> expertise) {
        super();
        this.salutation = salutation;
        this.name = name;
        this.email = email;
        this.preference = preference;
        this.addressList = addressList;
        this.expertise = expertise;
    }

    @OneToMany(orphanRemoval = true, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinColumn(name = "address_id")
    private List<Address> addressList = new ArrayList<>();

    @OneToMany(orphanRemoval = true, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinColumn(name = "expertise_id")
    private List<Expertise> expertise = new ArrayList<>();

My POST controller method.

@PostMapping("/appUsers")
public ResponseEntity<AppUser> createUser(@RequestBody AppUser appUser) {
    try {
        AppUser _appUser = appUserRepository.save(
            new AppUser(appUser.getSalutation(), appUser.getName(), appUser.getEmail(), 
                    appUser.getPreference(), appUser.getAddressList(), 
                    appUser.getExpertise()));
        return new ResponseEntity<>(_appUser, HttpStatus.CREATED);
    } catch (Exception e) {
        return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

My pure JS (Fetch) snippet:

<script>
async function postDataToServer(postData) {
    const baseURL = "http://localhost:8080/api";
    try {
        const res = await fetch(`${baseURL}/appUsers`, {
            method: "post",
            headers: {
                "Content-Type": "application/json",
                Accept: "application/json",
            },
            body: JSON.stringify(postData),
        });
        if (!res.ok) {
            const message = `An error has occured: ${res.status} - ${res.statusText}`;
            throw new Error(message);
        }
    } catch (err) {
        alert(err.message);
    }
}
</script>

Using above, I can see the form data nicely forming up like below:

{
  "salutation": "Mr.",
  "name": "Ajay Kumar",
  "email": "[email protected]",
  "address_main": "1234 StreetName State 12345",
  "address_1": "2345 StreetName State 23456",
  "address_2": "3456 StreetName State 34567",
  "preference": "Vegeterian",
  "expertise": [
    "java",
    "springboot",
    "javascript"
  ],
  "secret": "1abc1234-1abc-4321-1234-1234abcd1234"
}

During submit if I don't select expertise, it all works find. i.e. the user gets saved but if I select expertise checkboxes I get a 400 bad request message at the browser console and JSON parse erroSTS console like this:

2022-02-25 11:02:53.009 WARN 25007 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of com.spring.boot.rocks.model.Expertise (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('java'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of com.spring.boot.rocks.model.Expertise (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('java') at [Source: (PushbackInputStream); line: 1, column: 234] (through reference chain: com.spring.boot.rocks.model.AppUser["expertise"]->java.util.ArrayList[0])]

I created a github project here if any more details are required.

Question: What I am missing? How do I convert expertise collection to List using pure JS only ? Or how do I handle expertise collection in controller?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

指尖上得阳光 2025-01-16 21:50:51

您的表单数据格式不正确。这应该是这样的:

{
  "salutation": "Mr.",
  "name": "Ajay Kumar",
  "email": "[email protected]",
  "address_main": "1234 StreetName State 12345",
  "address_1": "2345 StreetName State 23456",
  "address_2": "3456 StreetName State 34567",
  "preference": "Vegeterian",
  "expertise": [
       {
        "java",
        "springboot",
       "javascript"
       }
  ],
  "secret": "1abc1234-1abc-4321-1234-1234abcd1234"
}

父类中的专业知识和地址是列表,而不是普通的 objectType 实体。如果这两个列表中的任何一个不存在,请在保存之前尝试将它们设置为空列表。

Your form data is not in correct format. This should be like this:

{
  "salutation": "Mr.",
  "name": "Ajay Kumar",
  "email": "[email protected]",
  "address_main": "1234 StreetName State 12345",
  "address_1": "2345 StreetName State 23456",
  "address_2": "3456 StreetName State 34567",
  "preference": "Vegeterian",
  "expertise": [
       {
        "java",
        "springboot",
       "javascript"
       }
  ],
  "secret": "1abc1234-1abc-4321-1234-1234abcd1234"
}

Expertise and address in your parent class are lists, not normal objectType entity. If any of these two lists are not present, try to set them as emptyList before saving.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文