从数据库导出数据生成CSV为空及日期字段拆分问题求解
核心问题根因(CSV文件为空)
- DTO构造方法为空:
ClientDto中接收ClientEntity的构造方法public ClientDto(ClientEntity clientEntity) {}没有任何字段赋值逻辑,getAll()方法将查询到的ClientEntity转DTO后,所有字段都是默认空值,输出自然为空。 - IO流未刷缓存、未关闭:Scheduler里的Writer写完内容后没有调用
flush()刷缓冲区,也没有close()释放资源,内存中的内容没有写入磁盘,就算数据正确也会生成空文件。 - 方法调用不匹配:Scheduler里调用的是
clientService.getAll(),该方法走的是JpaRepository自带的findAll()查全表,你自定义的带过滤条件的getAllByRegDate()根本没被调用,如果全表无数据输出自然为空。另外查询方法上加了@Modifying注解,该注解仅用于增删改操作,查询方法加了会导致逻辑异常。 - 冗余映射(非直接原因):Scheduler里
clientService.getAll().stream().map(ClientDto::new).collect(Collectors.toList())属于多余操作,getAll()已经返回了ClientDto列表,不需要二次转换。
修复步骤
1. 补全ClientDto的构造方法
public ClientDto(ClientEntity clientEntity) { this.id = clientEntity.getId(); this.created_dt = clientEntity.getCreated_dt(); this.username = clientEntity.getUsername(); this.name = clientEntity.getName(); this.amount = clientEntity.getAmount(); this.status = clientEntity.getStatus(); this.account = clientEntity.getAccount(); this.external_id = clientEntity.getExternal_id(); this.external_status = clientEntity.getExternal_status(); }
2. 修正Scheduler的IO逻辑,用try-with-resources自动管理流
@Scheduled(fixedRate = 5000) public void downloadBlockedClients() { String fileName = "select.csv"; // try-with-resources会自动关闭流、刷缓冲区,无需手动操作 try (FileOutputStream outputStream = new FileOutputStream(fileName); Writer writer = Channels.newWriter(outputStream.getChannel(), "UTF-8")) { // 如果需要用自定义条件的查询,这里改成 clientService.getAllByRegDateAfter() List<ClientDto> clientDtos = clientService.getAll(); writer.append("id|created_dt|username|name|amount|status|account|external_id|external_status").append("\n"); for (ClientDto dto : clientDtos) { writer.append(dto.toString()).append("\n"); } } catch (Exception e) { e.printStackTrace(); } }
3. 移除Repository查询方法的无效注解
删掉getAllByRegDate()上的@Modifying和@Transactional注解,这两个注解仅用于增删改操作,查询不需要。
created_dt拆分日期、时间两列实现
- 首先将
ClientEntity的created_dt字段类型从LocalDate改为LocalDateTime,LocalDate仅存储日期没有时间信息,无法拆分:
@Column(name = "created_dt") private LocalDateTime created_dt;
ClientDto新增两个字段,修改构造方法和toString逻辑:
// 新增字段 private LocalDate createdDate; private LocalTime createdTime; // 构造方法里补充赋值逻辑,以ClientEntity构造方法为例 public ClientDto(ClientEntity clientEntity) { this.id = clientEntity.getId(); // 拆分日期时间 this.createdDate = clientEntity.getCreated_dt().toLocalDate(); this.createdTime = clientEntity.getCreated_dt().toLocalTime(); // 其他字段赋值省略... } // 修改toString方法,加入两个新字段 @Override public String toString() { return "" + id + "|" + createdDate + "|" + createdTime + "|" + username + "|" + name + "|" + amount + "|" + status + "|" + account + "|" + external_id + "|" + external_status; }
- 修改CSV表头,新增两列:
writer.append("id|created_date|created_time|username|name|amount|status|account|external_id|external_status").append("\n");
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

