Spring项目JDBC查询空结果及CORS跨域问题求助
一、JDBC查询返回空列表问题
问题现象
手动配置DataSource和NamedParameterJdbcTemplate后,数据库连接正常(输入错误表/列名会触发SQL报错),但执行查询返回空列表;日志中test.size()和test.get(0)无实际数值输出,且调用test.get(0)未抛出异常。
原因及解决方法
1. 日志输出语法错误导致误判
原因:Service中的日志未使用占位符语法,无法正确打印列表数据:
log.info("test.size(): ", test.size()); // 错误写法,第二个参数被当作异常对象处理
解决:修改为占位符格式,恢复日志的数值输出能力:
log.info("test.size(): {}", test.size()); log.info("test.get(0): {}", test.get(0));
修正后可准确确认列表实际状态,排除日志误导。
2. TestDto的@Entity注解干扰字段映射
原因:TestDto添加了JPA的@Entity注解,但当前使用JdbcTemplate的BeanPropertyRowMapper做映射,该注解会导致反射逻辑异常,影响字段匹配。
解决:移除TestDto上的@Entity注解(若未使用JPA功能):
@Data @ToString @RequiredArgsConstructor @AllArgsConstructor // 移除@Entity注解 public class TestDto { private Long id; private String value; @Override public boolean equals(Object checkObject) { Boolean usersAreEqual = false; if (this == checkObject) { usersAreEqual = true; } else if (checkObject == null || Hibernate.getClass(this) != Hibernate.getClass(checkObject)) { usersAreEqual = false; } else { TestDto checkUser = (TestDto) checkObject; if (id != null) { usersAreEqual = Objects.equals(id, checkUser.id); } } return usersAreEqual; } @Override public int hashCode() { return getClass().hashCode(); } }
3. 手动配置的DataSource未启用连接池
原因:SecurityConfig中手动创建了DriverManagerDataSource(无连接池的简单数据源),导致application.properties中的Hikari配置完全失效,可能引发连接稳定性问题。
解决:删除SecurityConfig中手动配置的数据源相关Bean,依赖Spring Boot自动配置:
@Slf4j @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { log.info("In securityFilterChain"); http.csrf().disable().authorizeHttpRequests().anyRequest().permitAll(); return http.build(); } // 移除手动配置的dataSource()和namedParameterJdbcTemplate()方法 }
Spring Boot会自动读取application.properties中的配置,创建Hikari连接池及NamedParameterJdbcTemplate Bean,避免手动配置的潜在问题。
4. 直接映射验证数据可用性
原因:若BeanPropertyRowMapper存在映射问题,可通过手动映射确认数据库数据是否能被正常读取。
解决:临时修改Repository的查询逻辑,打印ResultSet数据:
@Transactional public List<TestDto> findAll() { log.info("running query..."); return this.namedParameterJdbcTemplate.query(FIND_ALL_QUERY, (rs, rowNum) -> { // 直接打印数据库返回的原始数据 log.info("查询到数据: id={}, value={}", rs.getLong("id"), rs.getString("value")); return new TestDto(rs.getLong("id"), rs.getString("value")); }); }
通过这种方式直接验证数据库数据是否能被正确获取,快速定位映射环节的问题。
二、CORS跨域问题
问题现象
已禁用CSRF并允许所有请求,但前端仍收到跨域错误:
Access to XMLHttpRequest at 'http://127.0.0.1:8080/archlands/api/test/value' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
原因及解决方法
原因:Spring Security仅配置了请求权限,未处理CORS预请求(OPTIONS),也未添加跨域响应头,导致浏览器拦截请求。
解决:在SecurityConfig中添加CORS规则配置,示例如下:
@Slf4j @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { log.info("In securityFilterChain"); http.csrf().disable() .cors(cors -> cors.configurationSource(corsConfigurationSource())) // 启用CORS配置 .authorizeHttpRequests().anyRequest().permitAll(); return http.build(); } // 定义CORS规则 private CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("http://localhost:4200")); // 允许的前端域名 config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); // 允许的请求方法 config.setAllowedHeaders(Arrays.asList("*")); // 允许所有请求头 config.setAllowCredentials(true); // 允许携带Cookie等凭证 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); // 所有接口生效 return source; } }
内容的提问来源于stack exchange,提问作者Fidelis

