当前位置: 首页 > 知识库问答 >
问题:

Spring Boot批注@刚体和@刚体可以等效地用于将参数传递给后端吗?

高建本
2023-03-14

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

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

@PostMapping
public User save(@RequestBody User user) {
    return userService.createUser(user);
}

相当于

@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);
    }
}

使用Postman尝试@RequestBody替代方案会得到200 OK响应:

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

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

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

@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;
    }
}

存储库如下所示:

public interface UserRepository extends JpaRepository<User, Long> {}

用户服务界面如下所示:

public interface UserService {
    List<User> getAllUsers();
    User getUserById(Long id);
    User createUser(User user);
    void deleteUser(Long id);
}

用户服务如下:

@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);
    }
}

共有3个答案

凌长恨
2023-03-14

你在url中传递请求参数值的方式是不正确的。对于多个参数,u可以传递如下值:

http://<url>:<port>/user/101?param1=10&param2=20

并参考以下答案:

如何将RequestParam值设置为URL

将多个参数传递给RestAPI-Spring

司空默
2023-03-14

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

@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);
        }
    }
鲁杜吟
2023-03-14

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

您不应该在参数值周围使用引号。如果您删除",那么它应该可以工作,至少在我将您的代码复制到最近版本的Postman的新Spring Boot项目上可以工作。

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

当我禁用编码我得到这个错误的日志

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
 类似资料:
  • 获取刚体组件 TypeScript的代码示例:const rigidBody = this.getComponent(RigidBody); 刚体类型 刚体一般分为三种类型,static,dynamic,kinematic. static,表示静态刚体,犹如质量巨大无比的石头,具体为质量为0的,或者只有碰撞组件的物理元素。 dynamic,表示动力学刚体,能够受到力的作用,具体为质量大于0并且is

  • 流氓和静态刚体 一般当我们创建一个刚体并将它添加到空间上后,空间就开始对之进行模拟,包括了对刚体位置、速度、受力以及重力影响等的模拟。没被添加到空间(没有被模拟)的刚体我们把它称之为流氓刚体。流氓刚体最重要的用途就是用来当作静态刚体,但是你仍然可以使用它来实现如移动平台这样的直接受控物体。 内存管理函数 cpBody *cpBodyAlloc(void) cpBody *cpBodyInit(cp

  • 刚体是组成物理世界的基本对象,可以让一个节点受到物理影响并产生反应。该组件在使用 Builtin 物理引擎时无效。 点击 属性检查器 下方的 添加组件 -> 物理组件 -> Rigid Body 3D,即可添加刚体组件到节点上。 刚体属性 属性 功能说明 Mass 刚体的质量 Linear Damping 线性阻尼,用于减小刚体的线性速率,值越大物体移动越慢 Angular Damping 角阻尼

  • 刚体是组成物理世界的基本对象,你可以将刚体想象成一个你不能看到(绘制)也不能摸到(碰撞)的带有属性的物体。 刚体属性 质量 刚体的质量是通过碰撞组件的 密度 与 大小 自动计算得到的。 当你需要计算物体应该受到多大的力时可能需要使用到这个属性。 var mass = rigidbody.getMass(); 移动速度 // 获取移动速度 var velocity = rigidbody.line

  • 我目前正在做一个三维刚体模拟程序。我目前已经设法使刚体碰撞地板和弹跳正确地利用冲力。然而,我的问题是,一旦他们反弹,他们不断地加速,尽管使用摩擦矢量试图减缓他们。 谢谢 编辑:这里是集成代码。

  • 我有一个模型类和一个控制器。我在post man的正文中发布json类型的数据。但每次我都会收到一个不受支持的媒体类型415错误。这是我的模型课: 我的控制器是: 我已经用HttpServletRequest代替@RequestBody,它起到了作用。但为什么在我使用@RequestBody时它不工作呢? 这是邮递员的快照。这是邮递员请求的图片 这是请求中使用的标题的屏幕截图