SpringBoot控制器页面重定向异常排查求助
登录逻辑异常排查与修复
我尝试了多种方法仍未找到问题原因,特此求助。login_success和login_failed均为模板路径下的HTML页面,调试发现失败案例中loginSuccess()或loginFailed()方法未执行。
测试结果
测试例1(执行成功)
[输入值](数据库中不存在的查询值)
id = abc
password = 1234[预期输出]
redirect:login_failed[实际输出]
redirect:login_failed
测试例2(执行失败)
[输入值](数据库中不存在的查询值)
id = abc@1234
password = abcd1234[预期输出]
redirect:login_failed[实际输出]
未触发重定向。
测试例3(执行失败)
[输入值](数据库中存在的查询值)
id = hihello1234@naver.com
password = byebye0000[预期输出]
redirect:login_success[实际输出]
未触发重定向。
相关代码
控制器代码
package My_Project.integration.controller; import My_Project.integration.entity.Dto.LoginDto; import My_Project.integration.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class LoginController { @Autowired private UserService userService; @GetMapping("/trylogin") public String login(LoginDto loginDto) { try { if (userService.login(loginDto)) { return "redirect:/loginSuccess"; } } catch (Exception e) { return "redirect:/loginFailed"; } return "redirect:/loginFailed"; } @GetMapping("/loginSuccess") public String loginSuccess() throws Exception { return "login_success"; } @GetMapping("/loginFailed") public String loginFailed() throws Exception { return "login_failed"; } // 似乎异常处理有问题?.... }
服务层代码
package My_Project.integration.service; import My_Project.integration.entity.Dto.LoginDto; import My_Project.integration.entity.Users; import My_Project.integration.repository.UsersRepository; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @Service @RequiredArgsConstructor @Getter public class UserService { @Autowired private UsersRepository usersRepository; public boolean login(LoginDto loginDto) throws Exception { return usersRepository.checkUserInfo(loginDto.getId(), loginDto.getPassword()); } }
持久层代码
package My_Project.integration.repository.UserCustom.Impl; import My_Project.integration.entity.Users; import My_Project.integration.repository.UserCustom.UserCustomRepository; import lombok.RequiredArgsConstructor; import javax.persistence.EntityManager; import javax.persistence.Query; import java.util.List; import java.util.Optional; @RequiredArgsConstructor public class UserCustomRepositoryImpl implements UserCustomRepository { private final EntityManager em; @Override public boolean checkUserInfo(String id,String password) throws Exception{ Optional<Users> matchedUser = Optional.ofNullable(em.createQuery("select u from Users u where u.id = :id", Users.class) .setParameter("id", id) .getSingleResult()); if (matchedUser.isPresent() || matchedUser.isEmpty()) { if(matchedUser.get().getPassword().equals(password)) { return true; }else { return false; } } return false; } }
问题根源与修复方案
1. 核心问题分析
- 请求方式错误:登录接口使用
@GetMapping,无法正确处理带@等特殊字符的参数,导致LoginDto的id字段绑定失败,后续查询逻辑完全混乱。 - 持久层查询逻辑错误:
getSingleResult()在无匹配数据时会直接抛出NoResultException,而非返回null,你用Optional.ofNullable()包裹的写法完全无效,异常会直接中断流程。 - 冗余逻辑无效:
if (matchedUser.isPresent() || matchedUser.isEmpty())是永真判断,完全起不到分支控制作用。
2. 具体修复步骤
步骤1:修改登录接口请求方式
将@GetMapping改为@PostMapping,适配登录操作的数据提交场景,同时避免特殊字符的参数解析问题:
@PostMapping("/trylogin") // 替换原@GetMapping public String login(LoginDto loginDto) { // 原有逻辑保留,后续可进一步简化 }
步骤2:修复持久层查询逻辑
放弃getSingleResult(),改用getResultList()避免抛出异常,逻辑更清晰稳定:
@Override public boolean checkUserInfo(String id,String password) { List<Users> userList = em.createQuery("select u from Users u where u.id = :id", Users.class) .setParameter("id", id) .getResultList(); if (!userList.isEmpty()) { return userList.get(0).getPassword().equals(password); } return false; }
如果要保留getSingleResult(),则需主动捕获异常:
@Override public boolean checkUserInfo(String id,String password) { try { Users matchedUser = em.createQuery("select u from Users u where u.id = :id", Users.class) .setParameter("id", id) .getSingleResult(); return matchedUser.getPassword().equals(password); } catch (NoResultException e) { return false; } }
步骤3:简化控制器异常处理
修复持久层后,无需再依赖异常处理控制流程,控制器逻辑可简化为:
public String login(LoginDto loginDto) { boolean isSuccess = userService.login(loginDto); return isSuccess ? "redirect:/loginSuccess" : "redirect:/loginFailed"; }
步骤4:确认LoginDto的参数绑定
确保LoginDto类存在id和password的getter/setter方法,否则Spring无法正确绑定请求参数:
public class LoginDto { private String id; private String password; // 必须实现以下getter/setter public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
3. 验证测试
修复后重新测试所有案例:
- 测试例2:id不存在时返回
false,触发redirect:/loginFailed - 测试例3:id存在且密码正确时返回
true,触发redirect:/loginSuccess;密码错误则返回false,触发失败重定向
内容的提问来源于stack exchange,提问作者참직김
相关产品推荐
相关产品推荐

