Spring Boot中如何实现查询数据以JSON格式返回?现有代码遇404错误求助
排查并修复你的REST服务404与数据返回问题
Hey,我帮你仔细梳理了代码里的问题,主要集中在路径匹配、数据映射、逻辑错误这几个方面,咱们一步步来解决:
一、核心问题拆解
1. Controller路径不匹配导致404
你的UserController类上标注了@RequestMapping("/users"),但getAllUsers方法又加了@GetMapping("/users"),这意味着这个接口的完整路径是/users/users,而不是你可能预期的/users。如果直接访问localhost:8080/users,Spring找不到对应的映射,自然返回404。
另外,即使你访问/users/user,因为Service层返回的是空列表,Postman也看不到任何内容。
2. Service层逻辑错误,永远返回空列表
在UserServiceImpl的findAll方法里,你调用了userDao.findAll()但完全没把结果赋值给返回的list,直接返回了空的ArrayList——这就是为什么Postman没有内容的直接原因:
public List<User> findAll() { List<User> list = new ArrayList<>(); userDao.findAll(); // 这里只是调用了方法,但结果被丢弃了! return list; }
3. Repository层SQL映射失败
- 你注释掉了
nativeQuery = true,JPA会把你的SQL当作JPQL解析,这必然会报错,因为JPQL的语法和原生SQL不一样。 - 方法名
findAll和JpaRepository自带的方法重名,容易混淆;而且查询返回的字段和User实体不匹配:SQL返回的是name、amount、cname,但User的字段是cName(大小写不一致),且查询结果里没有id(User的@Id字段是必填的),这会导致映射失败。
4. Entity类不符合JPA要求
User实体没有无参构造函数,JPA实例化对象时必须要有无参构造,否则会抛出实例化异常。- 你的
User标注了@Entity,但它对应的不是单表,而是多表聚合的查询结果,用DTO(数据传输对象)来接收会更合适,而不是JPA实体。
二、修复后的完整代码
1. 创建DTO类接收查询结果
因为你的查询是多表聚合的结果,不是单表实体,所以新建一个UserSummaryDTO来接收数据:
public class UserSummaryDTO { private String name; private long amount; private String cName; // 构造函数参数名要和SQL的别名一致(这里SQL里是cname,所以参数名用cname) public UserSummaryDTO(String name, long amount, String cname) { this.name = name; this.amount = amount; this.cName = cname; } // 必须要有Getter方法,否则Spring无法序列化为JSON public String getName() { return name; } public long getAmount() { return amount; } public String getcName() { return cName; } }
2. 修复Repository层
开启原生SQL,重命名方法避免冲突,并用DTO接收结果:
@Repository public interface UserDao extends JpaRepository<User, Long> { @Query(value = "SELECT ss.name AS name, \n" + " SUM(pp.amount) AS amount, \n" + " REPLACE(ss.name, 'SomeName', 'DifferentName') AS cname \n" + " FROM payments AS pp\n" + " INNER JOIN auth_user AS au ON au.id = pp.creator_id\n" + " INNER JOIN services AS ss ON ss.id = pp.service_id\n" + " WHERE\n" + " pp.created_dt >= '2021-09-28' AND pp.created_dt < '2021-09-29' \n" + " AND ss.name = 'SomeName' AND pp.status = 'SUCCESS' \n" + " GROUP BY ss.name", nativeQuery = true) List<UserSummaryDTO> findUserSummary(); // 重命名方法,避免和JpaRepository的findAll冲突 }
3. 修复Service层
修正逻辑,直接返回查询结果,移除无用的方法:
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public List<UserSummaryDTO> findAll() { return userDao.findUserSummary(); // 直接返回查询到的结果 } // 如果不需要保存User的逻辑,可以删掉这个方法 @Override public User save(User user) { return userDao.save(user); } }
同时调整UserService接口的返回类型:
public interface UserService { List<UserSummaryDTO> findAll(); User save(User user); // 不需要的话可以删除 }
4. 修复Controller层
调整路径,让接口更直观,确保路径匹配正确:
@RestController @RequestMapping("/users") public class UserController { @Autowired private UserService userService; // 访问路径:http://localhost:8080/users @GetMapping public List<UserSummaryDTO> getAllUsers() { return userService.findAll(); } // 如果需要保留/user路径,也可以保留,风格统一就行 @GetMapping("/user") public List<UserSummaryDTO> listUser() { return userService.findAll(); } // 不需要保存功能的话可以删除这个方法 @PostMapping("/user") public User create(@RequestBody User user) { return userService.save(user); } }
三、验证步骤
- 启动Spring Boot应用,检查控制台日志,确保没有启动或SQL执行异常。
- 用Postman访问
GET http://localhost:8080/users,应该能看到JSON格式的查询结果。 - 如果还是有问题,检查:
- 数据库连接配置是否正确(application.properties里的url、username、password)。
- 数据库里是否存在符合条件的数据(比如
pp.created_dt在指定日期范围内,ss.name='SomeName'等)。 - 控制台是否有异常日志,比如SQL语法错误、映射错误等。
内容的提问来源于stack exchange,提问作者Alexander




