首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring Boot注解@RequestBody和@RequestParam是否可以等效地用于将参数传递到后端?

Spring Boot注解@RequestBody和@RequestParam是否可以等效地用于将参数传递到后端?
EN

Stack Overflow用户
提问于 2021-07-06 18:34:00
回答 3查看 271关注 0票数 0

通过一个简单的Spring Boot应用程序,我试图理解Spring Boot注释@RequestParam@RequestBody之间的区别以及它们各自的用法。Spring文档将@RequestParam定义为“指示方法参数应绑定到web请求参数的注释”,将@RequestBody定义为“指示方法参数应绑定到web请求主体的注释”。因此,可以公平地假设注释和相关方法都可以用作相同的备选方案(类似结果的不同方法),以将参数传递到后端应用程序,例如在用户数据库中插入值“email”、“username”和“password”(只是为了简化必要的密码加密而忘记)。

因此,可以预期下面的代码会被截断

代码语言:javascript
复制
@PostMapping
public User save(@RequestBody User user) {
    return userService.createUser(user);
}

等同于

代码语言:javascript
复制
@PostMapping(value = "/users")
public ResponseEntity<User> createUser(
        @RequestParam  String email,
        @RequestParam String username,
        @RequestParam  String password

) {
    try {

        User user = new User();
        user.setEmail(email);
        user.setUsername(username);
        user.setPassword(password);

        userService.createUser(user);
        return ResponseEntity.noContent().build();

    } catch (Exception exception) {
        return new ResponseEntity<>(HttpStatus.I_AM_A_TEAPOT);
    }
}

尝试将@RequestBody替换为Postman会得到一个200OK响应:

但尝试@RequestParam替代方法会导致400“错误请求”错误:

为什么这个@RequestParam方法会触发一个错误,而显然等效的@RequestBody方法却如预期的那样工作?

为了完整起见,下面给出了用户模型:

代码语言:javascript
复制
@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String email;
    private String username;
    private String password;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

存储库如下所示:

代码语言:javascript
复制
public interface UserRepository extends JpaRepository<User, Long> {}

用户服务接口如下所示:

代码语言:javascript
复制
public interface UserService {
    List<User> getAllUsers();
    User getUserById(Long id);
    User createUser(User user);
    void deleteUser(Long id);
}

用户服务如下所示:

代码语言:javascript
复制
@Service
public class UserServiceImpl implements UserService {
    private UserRepository userRepository;

    @Autowired
    public UserServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    @Override
    public User createUser(User user) {
        return userRepository.save(user);
    }

    @Override
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }

    @Override
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
}
EN

回答 3

Stack Overflow用户

发布于 2021-07-06 19:23:10

这两种方法在功能上是等效的,如果不是在预期用途上的话。

您不应该在参数值两边使用引号。如果你删除了",那么它应该可以工作,至少在一个新的Spring Boot项目上是这样的,我把你的代码复制到了一个最新版本的Postman上。

Postman在“设置”标签上也有一个选项,可以自动对url进行编码。如果启用该选项,则将对引号进行编码并将其作为参数值的一部分。它在默认情况下是启用的,但在您的屏幕截图上有一个绿点,表示您更改了某些内容。我猜是你设置的一个设置导致了错误的请求(可能是禁用了url的编码)。

当我禁用编码时,我在日志中得到这个错误:

代码语言:javascript
复制
java.lang.IllegalArgumentException:
Invalid character found in the request target 
[/users?email=bla&username=hello&password="bla" ]. 
The valid characters are defined in RFC 7230 and RFC 3986
票数 0
EN

Stack Overflow用户

发布于 2021-07-07 18:30:19

首先,感谢您的支持和您花时间测试代码!@requestParam和@requestBody确实都可以用作两种将值传递到后端的替代方法,正如前面的答案(谢谢!)所断言的那样。仍然需要一个解释,为什么使用我的问题中提供的代码不是这种情况,因为按照指示修改postman中的请求没有帮助,使用cUrl发布请求会导致完全相同的405错误。因此,必须在代码中找到解决方案。我花了一段时间才找到它,但是在我的控制器类上面有一个@RequestMapping(value="/users")注释,它必须被禁用。注意,显然,@RequestMapping的错误使用只会影响@RequestParam,而不会影响@RequestBody。下面的代码现在可以工作了(这里省略了@GetMapping和@deleteMapping ),并给出了与问题中给出的@RequestBody完全相同的结果。

代码语言:javascript
复制
@RestController
//@RequestMapping(value="/users")
@CrossOrigin
public class UserController {

    @Autowired
    private UserServiceImpl userService;

    @PostMapping(value = "/users")
    public ResponseEntity<Object> createUser(
            @RequestParam(name = "email") String email,
            @RequestParam(name = "username") String username,
            @RequestParam(name = "password") String password
   ) {
        try {
            User user = new User();
            user.setEmail(email);
            user.setUsername(username);
            user.setPassword(password);
            userService.createUser(user);
            return ResponseEntity.noContent().build();
        } catch (Exception exception) {
            return new ResponseEntity<>(HttpStatus.I_AM_A_TEAPOT);
        }
    }
票数 0
EN

Stack Overflow用户

发布于 2021-07-06 18:51:54

在url中为@RequestParam传递请求参数值的方式不正确。对于多个参数,可以传递如下所示的值:

代码语言:javascript
复制
http://<url>:<port>/user/101?param1=10&param2=20

并参考以下答案:

How to put RequestParam value as URL

Pass multiple parameters to rest API - Spring

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68268962

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档