Spring中访问users/update/{id}提交POST请求遇405方法不支持异常
问题:提交用户更新表单时出现405 Method Not Allowed错误
访问users/update/{id}(例如id=6)页面并点击“add”按钮提交表单时,返回405状态码,日志显示:
Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
预期流程
- 访问
users/update/{id}触发updateUser()方法,从Repository获取对应ID的用户; - 将该用户转换为
UserViewModel; - 把
UserViewModel作为“user”对象传入HTML模板registration-formUpdate的表单(表单代码:<form class="form-horizontal" method="post" th:href="@{~/registration}" th:object="${user}">); - 表单提交时将对象传递至
/registration端点,由RegistrationController的registrationUsersAdding()方法自动填充表单; - 点击“add”按钮后将更新后的用户保存至数据库。
此前在其他应用及本项目的Events模块中使用相同逻辑均正常,但此处出现异常。
相关代码
Controller类
@RequiredArgsConstructor @Controller public class RegistrationController { private final UserService userService; private final UserRepository userRepository; @PostMapping("/registration") public String registrationUsersAdding(@ModelAttribute("user") @Valid UserViewModel user2, BindingResult bindingResult) { if (bindingResult.hasErrors()) { if (user2.getId() == null) { return "registration-form"; } else { return "registration-formUpdate"; } } else { if (user2.getId() == null) { userService.add(user2); } else { userService.update(user2); } } return "redirect:/login"; } @Secured("ROLE_ADMIN") @GetMapping("users/update/{id}")//toooooooo public String updateUser(@PathVariable(value = "id") Long id, Model model) { var user = userService.userToViewModel(userRepository.getOne(id)); model.addAttribute("user", user); return "registration-formUpdate"; } }
Service类
@Service @RequiredArgsConstructor public class UserService implements AddUpdateGetDeleteUser { private final UserRepository userRepository; private final RoleRepository roleRepository; private final PasswordEncoder passwordEncoder; public void add(UserViewModel userViewModel) { List<Role> roles; Role role = new Role(); role.setType(RoleType.valueOf(userViewModel.getRoles()));// pomyslec nad tym roleRepository.save(role); roles = Collections.singletonList(role); User user1 = User.builder() .firstName(userViewModel.getFirstName()) .lastName(userViewModel.getLastName()) .login(userViewModel.getLogin()) .password(passwordEncoder.encode(userViewModel.getPassword())) .email(userViewModel.getEmail()) .roles(roles) .build(); userRepository.save(user1); } public void update(UserViewModel userDto) { Optional<User> optionalUser = userRepository.findById(userDto.getId()); if (optionalUser.isPresent()) { User user = optionalUser.get(); user.setId(userDto.getId()); user.setFirstName(userDto.getFirstName()); user.setLastName(userDto.getLastName()); user.setRoles(Collections.singletonList(GetRole(userDto.getRoles()))); user.setLogin(userDto.getLogin()); user.setEmail(userDto.getEmail()); user.setPassword(passwordEncoder.encode(userDto.getPassword())); userRepository.save(user); } } public UserViewModel userToViewModel(User user) { return UserViewModel.builder() .id(user.getId()) .firstName(user.getFirstName()) .lastName(user.getLastName()) .roles(user.getRoles().get(0).toString()) .login(user.getLogin()) .email(user.getEmail()) .password(passwordEncoder.encode(user.getPassword())) .build(); } private Role GetRole(String roleType) { var role = new Role(); role.setType(RoleType.valueOf(roleType)); return role; } }
日志信息
2022-12-30 00:35:43.807 INFO 5804 --- [ main] Z.Z.ZadanieRekrutacyjneApplication : Started ZadanieRekrutacyjneApplication in 10.364 seconds (JVM running for 11.253) 2022-12-30 00:36:28.052 INFO 5804 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2022-12-30 00:36:28.052 INFO 5804 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2022-12-30 00:36:28.055 INFO 5804 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms 2022-12-30 00:36:28.527 WARN 5804 --- [nio-8080-exec-1] o.a.c.util.SessionIdGeneratorBase : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [387] milliseconds. 2022-12-30 00:37:13.180 WARN 5804 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported] 2022-12-30 00:42:59.615 INFO 5804 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' 2022-12-30 00:42:59.621 INFO 5804 --- [extShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2022-12-30 00:42:59.624 INFO 5804 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2022-12-30 00:42:59.646 INFO 5804 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
问题原因及解决方案
核心原因
日志明确提示POST方法不被支持,说明表单提交的目标端点/registration存在路径解析或映射异常,结合代码排查可能的点:
- 表单路径写法错误:
@{~/registration}中的~符号可能导致Spring无法正确解析路径,无法匹配到@PostMapping("/registration"); - 权限拦截:Spring Security可能拦截了
/registration的POST请求; - 废弃方法风险:
userRepository.getOne(id)已废弃,可能引发懒加载或数据获取异常,导致后续流程出错; - 表单缺少ID字段:提交时未携带用户ID,可能引发逻辑分支错误或参数接收异常。
具体修复步骤
- 修正表单路径:将HTML表单中的
th:href="@{~/registration}"改为th:href="@{/registration}",确保路径正确映射到Controller的POST端点; - 添加ID隐藏字段:在表单中加入用户ID的隐藏字段,保证后端能正确接收更新标识:
<input type="hidden" th:field="*{id}" /> - 替换废弃方法:将
userRepository.getOne(id)改为userRepository.findById(id).orElseThrow(...),避免潜在异常:var user = userService.userToViewModel(userRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("User not found with id: " + id))); - 检查Security配置:确保
/registration路径允许POST请求访问,在Security配置中添加:.authorizeHttpRequests(auth -> auth .requestMatchers(HttpMethod.POST, "/registration").permitAll() // 其他权限规则... ) - 验证组件扫描:确认
RegistrationController被Spring正确扫描,没有被排除在组件扫描范围外。
内容的提问来源于stack exchange,提问作者Ign
相关产品推荐
相关产品推荐

