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,8 +1,11 @@
package com.tasteby.controller;
import com.tasteby.repository.ChannelRepository;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tasteby.domain.Channel;
import com.tasteby.security.AuthUtil;
import com.tasteby.service.CacheService;
import com.tasteby.service.ChannelService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
@@ -14,26 +17,26 @@ import java.util.Map;
@RequestMapping("/api/channels")
public class ChannelController {
private final ChannelRepository repo;
private final ChannelService channelService;
private final CacheService cache;
private final ObjectMapper objectMapper;
public ChannelController(ChannelRepository repo, CacheService cache) {
this.repo = repo;
public ChannelController(ChannelService channelService, CacheService cache, ObjectMapper objectMapper) {
this.channelService = channelService;
this.cache = cache;
this.objectMapper = objectMapper;
}
@GetMapping
public List<Map<String, Object>> list() {
public List<Channel> list() {
String key = cache.makeKey("channels");
String cached = cache.getRaw(key);
if (cached != null) {
try {
var mapper = new com.fasterxml.jackson.databind.ObjectMapper();
return mapper.readValue(cached,
new com.fasterxml.jackson.core.type.TypeReference<>() {});
return objectMapper.readValue(cached, new TypeReference<List<Channel>>() {});
} catch (Exception ignored) {}
}
var result = repo.findAllActive();
var result = channelService.findAllActive();
cache.set(key, result);
return result;
}
@@ -46,7 +49,7 @@ public class ChannelController {
String channelName = body.get("channel_name");
String titleFilter = body.get("title_filter");
try {
String id = repo.create(channelId, channelName, titleFilter);
String id = channelService.create(channelId, channelName, titleFilter);
cache.flush();
return Map.of("id", id, "channel_id", channelId);
} catch (Exception e) {
@@ -60,7 +63,7 @@ public class ChannelController {
@DeleteMapping("/{channelId}")
public Map<String, Object> delete(@PathVariable String channelId) {
AuthUtil.requireAdmin();
if (!repo.deactivate(channelId)) {
if (!channelService.deactivate(channelId)) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Channel not found");
}
cache.flush();