SpringBoot控制器redirect跳转未执行问题排查求助
登录跳转失效问题排查修复
我开发的副业项目延误多日,目前遇到的问题是:控制器中return redirect:/相关语句始终无法按预期执行,代码逻辑看似正常,但跳转操作未生效。技术栈为MySQL、SpringBoot、JPA、Spring Data JPA、Lombok,请求帮忙排查。
相关代码
登录视图代码
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel = "stylesheet" href ="/css/sample.css"> <link href="https://getbootstrap.com/docs/5.2/assets/css/docs.css" rel="stylesheet"> <link href="/css/font.css" rel = "stylesheet"> <link href="/css/navbar.css" rel = "stylesheet"> <title>loginpage</title> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script> <script type="text/javascript"> function functionclick() { let email = document.getElementById('exampleDropdownFormEmail1').value; let password = document.getElementById('exampleDropdownFormPassword1').value; if (email == "" || password == "") { alert("회원 정보를 입력하세요"); history.back(); } else{ const url = new URL("/trylogin",location); url.searchParams.append('email',email); url.searchParams.append('password',password); location = url; } } </script> </head> <body class="p-3 m-0 border-0 bd-example"> <div class="dropdown-menu"> <form class="px-4 py-3" method="get" action="login"> <div class="mb-3"> <label for="exampleDropdownFormEmail1" class="form-label">이메일을 입력하세요</label> <input type="text" class="form-control" id="exampleDropdownFormEmail1" placeholder="email@example.com" name = "email"> </div> <div class="mb-3"> <label for="exampleDropdownFormPassword1" class="form-label">비밀번호를 입력하세요.</label> <input type="password" class="form-control" id="exampleDropdownFormPassword1" placeholder="Password" name = "password"> </div> <div class="mb-3"> <div class="form-check"> <input type="checkbox" class="form-check-input" id="dropdownCheck"> <label class="form-check-label" for="dropdownCheck"> 비밀번호 기억하기 </label> </div> </div> <button type="submit" class="btn btn-primary" ONCLICK="functionclick()">확인</button> </form> <div class="dropdown-divider"></div> <a class="dropdown-item" href="http://localhost:8080/signup">회원가입 하기</a> <a class="dropdown-item" href="http://localhost:8080/forgotpassword">비밀번호 찾기</a> </div> </body> </html>
LoginController代码
@Controller public class LoginController { @Autowired private UserService userService; @GetMapping("/trylogin") public String login(LoginDto loginDto) { try { if(userService.login(loginDto).isPresent()) { return "redirect:/loginSuccess"; } } catch (Exception e) { e.printStackTrace(); return "redirect:/loginFailed"; } return "redirect:/loginFailed"; } @GetMapping("/loginSuccess") public String loginSuccess() { return "login_success"; } @GetMapping("/loginFailed") public String loginFailed() { return "login_failed"; } }
服务层代码
@Service @RequiredArgsConstructor @Getter public class UserService { @Autowired private UsersRepository usersRepository; @Transactional public Optional<Users> login(LoginDto loginDto) throws Exception{ return usersRepository.findByEmailAndPassword(loginDto.getEmail(), loginDto.getPassword()); } }
Users实体代码
@Entity @Getter @NoArgsConstructor @AllArgsConstructor @Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"ssn","phone_number"})}) public class Users { @Column(name = "email", length = 40, updatable = false, nullable = false) @Id private String email; @Column(name = "password", length = 20, nullable = false) private String password; @Column(name = "name", length = 25, nullable = false) private String name; @Column(name = "phone_number", length = 12, nullable = false) private String phoneNumber; @Column(name = "ssn", length = 13, nullable = false, updatable = false) private String ssn; @Embedded private Address address; @Column(name = "point") private Long point; @OneToMany(mappedBy = "postedUser") private List<PostInfo> uploadedPost = new ArrayList<>(); @OneToMany(mappedBy = "userId") private List<PointHistory> pointHistories = new ArrayList<>(); @Embedded private Dates dates; public Users(UserInfoDto userInfoDto){ this.setEmail(userInfoDto.getEmail()); this.setPassword(userInfoDto.getPassword()); this.setPhoneNumber(userInfoDto.getPhone_number()); this.setSsn(userInfoDto.getSsn()); this.setPoint(0L); this.setName(userInfoDto.getName()); Address address = new Address( userInfoDto.getCity_name(), userInfoDto.getTown_name(), userInfoDto.getStreet_name(), userInfoDto.getZip_code(), userInfoDto.getDetails() ); this.setAddress(address); List<PostInfo> postInfoList = new ArrayList<>(); List<PointHistory> pointHistoryList = new ArrayList<>(); this.setUploadedPost(postInfoList); this.setPointHistories(pointHistoryList); Dates dates = new Dates(LocalDateTime.now(), LocalDateTime.now()); this.setDates(dates); } public void setEmail(String id) { this.email = id; } public void setPassword(String password) { this.password = password; } public void setName(String name) { this.name = name; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } public void setSsn(String ssn) { this.ssn = ssn; } public void setAddress(Address address) { this.address = address; } public void setPoint(Long point) { this.point = point; } public void setUploadedPost(List<PostInfo> uploadedPost) { this.uploadedPost = uploadedPost; } public void setPointHistories(List<PointHistory> pointHistories) { this.pointHistories = pointHistories; } public void setDates(Dates dates) { this.dates = dates; } }
LoginDto代码
@Getter @Setter @AllArgsConstructor public class LoginDto { private String email; private String password; }
登录成功页面代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Login Success</title> <script type = "text/javascript"> alert("로그인 성공"); location.href = "/"; </script> </head> <body> </body> </html>
问题排查与修复方案
1. 前端按钮冲突导致重复请求
按钮同时设置了type="submit"和onclick事件,点击时会先执行JS跳转逻辑,随后表单还会提交到action="login",两次请求互相干扰,导致跳转结果不符合预期。
修复:
将按钮类型改为button,避免表单自动提交:
<button type="button" class="btn btn-primary" ONCLICK="functionclick()">확인</button>
或者在functionclick末尾添加return false阻止表单提交:
function functionclick() { // 原有逻辑... } else{ const url = new URL("/trylogin",location); url.searchParams.append('email',email); url.searchParams.append('password',password); location = url; } return false; // 添加这行 }
2. LoginDto缺少无参构造方法
Spring MVC进行参数绑定时,需要目标类有无参构造方法。当前LoginDto仅标注了@AllArgsConstructor,没有无参构造,导致loginDto的email和password始终为null,查询不到用户,最终一直跳转到loginFailed。
修复:
给LoginDto添加无参构造:
@Getter @Setter @AllArgsConstructor @NoArgsConstructor // 添加无参构造 public class LoginDto { private String email; private String password; }
3. 服务层不必要的事务注解优化
login方法是查询操作,不需要@Transactional注解(或改为只读事务更合理),虽然不影响跳转,但可以优化代码:
// 去掉@Transactional,或改为@Transactional(readOnly = true) public Optional<Users> login(LoginDto loginDto) throws Exception{ return usersRepository.findByEmailAndPassword(loginDto.getEmail(), loginDto.getPassword()); }
4. 登录成功页面跳转逻辑调整
login_success.html中JS自动跳转到/的速度过快,可能导致用户看不到登录成功提示,误以为跳转未生效。可以增加延迟:
alert("로그인 성공"); setTimeout(() => { location.href = "/"; }, 1500); // 延迟1.5秒跳转
内容的提问来源于stack exchange,提问作者참직김
相关产品推荐
相关产品推荐

