Migrate to MyBatis with proper Controller→Service→Mapper layering

- Add MyBatis Spring Boot Starter with XML mappers and domain classes
- Create 9 mapper interfaces + XML: Restaurant, Video, Channel, Review,
  User, Stats, DaemonConfig, Search, Vector
- Create 10 domain classes with Lombok: Restaurant, VideoSummary,
  VideoDetail, VideoRestaurantLink, Channel, Review, UserInfo,
  DaemonConfig, SiteVisitStats, VectorSearchResult
- Create 7 new service classes: RestaurantService, VideoService,
  ChannelService, ReviewService, UserService, StatsService,
  DaemonConfigService
- Refactor all controllers to be thin (HTTP + auth only), delegating
  business logic to services
- Refactor SearchService, PipelineService, DaemonScheduler, AuthService,
  YouTubeService to use mappers/services instead of JDBC/repositories
- Add Jackson SNAKE_CASE property naming for consistent API responses
- Add ClobTypeHandler for Oracle CLOB→String in MyBatis
- Add IdGenerator utility for centralized UUID generation
- Delete old repository/ package (6 files), JdbcConfig, LowerCaseKeyAdvice
- VectorService retains JDBC for Oracle VECTOR type support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
joungmin
2026-03-09 21:13:44 +09:00
parent 91d0ad4598
commit c16add08c3
63 changed files with 2155 additions and 1483 deletions

View File

@@ -1,82 +1,32 @@
package com.tasteby.controller;
import com.tasteby.domain.DaemonConfig;
import com.tasteby.security.AuthUtil;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import com.tasteby.service.DaemonConfigService;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/daemon")
public class DaemonController {
private final NamedParameterJdbcTemplate jdbc;
private final DaemonConfigService daemonConfigService;
public DaemonController(NamedParameterJdbcTemplate jdbc) {
this.jdbc = jdbc;
public DaemonController(DaemonConfigService daemonConfigService) {
this.daemonConfigService = daemonConfigService;
}
@GetMapping("/config")
public Map<String, Object> getConfig() {
String sql = """
SELECT scan_enabled, scan_interval_min, process_enabled, process_interval_min,
process_limit, last_scan_at, last_process_at, updated_at
FROM daemon_config WHERE id = 1
""";
var rows = jdbc.queryForList(sql, new MapSqlParameterSource());
if (rows.isEmpty()) return Map.of();
var row = rows.getFirst();
var result = new LinkedHashMap<String, Object>();
result.put("scan_enabled", toInt(row.get("scan_enabled")) == 1);
result.put("scan_interval_min", row.get("scan_interval_min"));
result.put("process_enabled", toInt(row.get("process_enabled")) == 1);
result.put("process_interval_min", row.get("process_interval_min"));
result.put("process_limit", row.get("process_limit"));
result.put("last_scan_at", row.get("last_scan_at") != null ? row.get("last_scan_at").toString() : null);
result.put("last_process_at", row.get("last_process_at") != null ? row.get("last_process_at").toString() : null);
result.put("updated_at", row.get("updated_at") != null ? row.get("updated_at").toString() : null);
return result;
public DaemonConfig getConfig() {
DaemonConfig config = daemonConfigService.getConfig();
return config != null ? config : DaemonConfig.builder().build();
}
@PutMapping("/config")
public Map<String, Object> updateConfig(@RequestBody Map<String, Object> body) {
AuthUtil.requireAdmin();
var sets = new ArrayList<String>();
var params = new MapSqlParameterSource();
if (body.containsKey("scan_enabled")) {
sets.add("scan_enabled = :se");
params.addValue("se", Boolean.TRUE.equals(body.get("scan_enabled")) ? 1 : 0);
}
if (body.containsKey("scan_interval_min")) {
sets.add("scan_interval_min = :si");
params.addValue("si", ((Number) body.get("scan_interval_min")).intValue());
}
if (body.containsKey("process_enabled")) {
sets.add("process_enabled = :pe");
params.addValue("pe", Boolean.TRUE.equals(body.get("process_enabled")) ? 1 : 0);
}
if (body.containsKey("process_interval_min")) {
sets.add("process_interval_min = :pi");
params.addValue("pi", ((Number) body.get("process_interval_min")).intValue());
}
if (body.containsKey("process_limit")) {
sets.add("process_limit = :pl");
params.addValue("pl", ((Number) body.get("process_limit")).intValue());
}
if (!sets.isEmpty()) {
sets.add("updated_at = SYSTIMESTAMP");
String sql = "UPDATE daemon_config SET " + String.join(", ", sets) + " WHERE id = 1";
jdbc.update(sql, params);
}
daemonConfigService.updateConfig(body);
return Map.of("ok", true);
}
private int toInt(Object val) {
if (val == null) return 0;
return ((Number) val).intValue();
}
}