【发布时间】:2021-09-16 23:48:34
【问题描述】:
通过一个简单的 Spring Boot 应用程序,我试图了解 Spring Boot 注释 @RequestParam 和 @RequestBody 之间的区别以及它们各自的用途。 Spring 文档将 @RequestParam 定义为“表示方法参数应绑定到 Web 请求参数的注解”,将 @RequestBody 定义为“表示方法参数应绑定到 Web 请求正文的注解”。 因此,可以公平地假设注释和相关方法都可以用作等效的替代方法(类似结果的不同方法)以将参数传递给后端应用程序,例如插入值“电子邮件”、“用户名”和“密码”在用户数据库中(只是为了简单而忘记密码的必要加密)。
因此,可以预期下面的代码被剪断了
@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);
}
}
【问题讨论】:
-
嗨迈克尔,很抱歉,现在应该清楚了
-
您的编译器是否配置为在类文件中包含参数名称? javac 默认是丢弃它们。包含它们的参数是
-parameters。如果没有该标志,Spring 无法将每个参数映射到传入的查询参数名称。如果您不确定,可以将名称显式传递给每个@RequestParam(name="email")。 -
顺便说一句,邮递员中查询参数值周围的引号是多余的,我认为您最终会将引号作为字符串的一部分进入数据库。不应该让请求失败
-
您在 Postman 的设置选项卡上做了哪些更改?那里有一个绿点。您的日志中还应该有更详细的错误。
-
感谢这些好建议。但是,明确传递名称,例如 @RequestParam(name = "email") String email 并不能解决问题。请注意,错误现在是 405 'Method not allowed'
标签: java spring-boot