You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,提问作者참직김

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:35:20