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

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tasteby.mapper.ChannelMapper">
<resultMap id="channelResultMap" type="com.tasteby.domain.Channel">
<id property="id" column="id"/>
<result property="channelId" column="channel_id"/>
<result property="channelName" column="channel_name"/>
<result property="titleFilter" column="title_filter"/>
<result property="videoCount" column="video_count"/>
<result property="lastVideoAt" column="last_video_at"/>
</resultMap>
<select id="findAllActive" resultMap="channelResultMap">
SELECT c.id, c.channel_id, c.channel_name, c.title_filter,
(SELECT COUNT(*) FROM videos v WHERE v.channel_id = c.id) AS video_count,
(SELECT MAX(v.published_at) FROM videos v WHERE v.channel_id = c.id) AS last_video_at
FROM channels c
WHERE c.is_active = 1
ORDER BY c.channel_name
</select>
<insert id="insert">
INSERT INTO channels (id, channel_id, channel_name, title_filter)
VALUES (#{id}, #{channelId}, #{channelName}, #{titleFilter})
</insert>
<update id="deactivateByChannelId">
UPDATE channels SET is_active = 0
WHERE channel_id = #{channelId} AND is_active = 1
</update>
<update id="deactivateById">
UPDATE channels SET is_active = 0
WHERE id = #{id} AND is_active = 1
</update>
<select id="findByChannelId" resultMap="channelResultMap">
SELECT id, channel_id, channel_name, title_filter
FROM channels
WHERE channel_id = #{channelId} AND is_active = 1
</select>
</mapper>