- tag_category_board 매핑 테이블 추가(그룹 ↔ community/saving/tips) - TagCategory 응답에 boards 추가, 생성/수정 시 매핑 저장(유효 게시판만) - listWritableGroups(category): 해당 게시판에 매핑된 그룹만(매핑 없으면 전체=하위호환) - GET /board/tag-groups?category=... 로 게시판별 필터 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -125,10 +125,10 @@ public class BoardController {
|
||||
return boardService.allTags();
|
||||
}
|
||||
|
||||
/** 글 작성 시 선택 가능한 태그 (게시판 설정 카테고리로 제한) */
|
||||
/** 글 작성 시 선택 가능한 태그 (해당 게시판에 매핑된 그룹만) */
|
||||
@GetMapping("/tag-groups")
|
||||
public List<TagCategoryResponse> tagGroups() {
|
||||
return tagService.listWritableGroups();
|
||||
public List<TagCategoryResponse> tagGroups(@RequestParam(required = false) String category) {
|
||||
return tagService.listWritableGroups(category);
|
||||
}
|
||||
|
||||
@PostMapping("/posts/{id}/comments")
|
||||
|
||||
@@ -4,6 +4,8 @@ import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 태그 카테고리 생성/수정 요청.
|
||||
*/
|
||||
@@ -15,4 +17,7 @@ public class TagCategoryRequest {
|
||||
private String name;
|
||||
|
||||
private Integer sortOrder;
|
||||
|
||||
/** 이 그룹을 사용할 게시판 (community/saving/tips). 비어있으면 전체 게시판. */
|
||||
private List<String> boards;
|
||||
}
|
||||
|
||||
@@ -17,13 +17,15 @@ public class TagCategoryResponse {
|
||||
private String name;
|
||||
private Integer sortOrder;
|
||||
private List<TagResponse> tags;
|
||||
private List<String> boards; // 이 그룹을 사용할 게시판 (비어있으면 전체)
|
||||
|
||||
public static TagCategoryResponse of(TagCategory c, List<TagResponse> tags) {
|
||||
public static TagCategoryResponse of(TagCategory c, List<TagResponse> tags, List<String> boards) {
|
||||
return TagCategoryResponse.builder()
|
||||
.id(c.getId())
|
||||
.name(c.getName())
|
||||
.sortOrder(c.getSortOrder())
|
||||
.tags(tags)
|
||||
.boards(boards)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.sb.web.board.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 태그 카테고리(그룹) ↔ 게시판 매핑 (tag_category_board).
|
||||
*/
|
||||
@Mapper
|
||||
public interface TagCategoryBoardMapper {
|
||||
|
||||
/** 카테고리가 노출될 게시판 목록 */
|
||||
List<String> findBoards(@Param("categoryId") Long categoryId);
|
||||
|
||||
void deleteByCategory(@Param("categoryId") Long categoryId);
|
||||
|
||||
void insert(@Param("categoryId") Long categoryId, @Param("board") String board);
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import com.sb.web.board.dto.BoardSettingResponse;
|
||||
import com.sb.web.board.dto.TagRequest;
|
||||
import com.sb.web.board.dto.TagResponse;
|
||||
import com.sb.web.board.mapper.BoardSettingMapper;
|
||||
import com.sb.web.board.mapper.TagCategoryBoardMapper;
|
||||
import com.sb.web.board.mapper.TagCategoryMapper;
|
||||
import com.sb.web.board.mapper.TagMapper;
|
||||
import com.sb.web.common.exception.ApiException;
|
||||
@@ -18,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 태그 카테고리 + 태그 관리 서비스 (관리자 기능 + 그룹 조회).
|
||||
@@ -29,6 +31,10 @@ public class TagService {
|
||||
private final TagCategoryMapper categoryMapper;
|
||||
private final TagMapper tagMapper;
|
||||
private final BoardSettingMapper boardSettingMapper;
|
||||
private final TagCategoryBoardMapper categoryBoardMapper;
|
||||
|
||||
/** 게시판 매핑에 허용되는 값 */
|
||||
private static final Set<String> VALID_BOARDS = Set.of("community", "saving", "tips");
|
||||
|
||||
/** 카테고리별로 묶은 전체 태그 (관리 화면용) */
|
||||
public List<TagCategoryResponse> listGrouped() {
|
||||
@@ -39,20 +45,39 @@ public class TagService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 글 작성 시 선택 가능한 태그 그룹 — 게시판 설정 카테고리로 제한 (없으면 전체) */
|
||||
public List<TagCategoryResponse> listWritableGroups() {
|
||||
Long catId = boardSettingMapper.findTagCategoryId();
|
||||
if (catId == null) {
|
||||
return listGrouped();
|
||||
/**
|
||||
* 글 작성 시 선택 가능한 태그 그룹 — 해당 게시판에 매핑된 그룹만.
|
||||
* 매핑이 하나도 없는 그룹은 전체 게시판에서 노출(하위호환).
|
||||
*/
|
||||
public List<TagCategoryResponse> listWritableGroups(String boardCategory) {
|
||||
List<TagCategoryResponse> result = new ArrayList<>();
|
||||
for (TagCategory c : categoryMapper.findAll()) {
|
||||
TagCategoryResponse g = toGroup(c);
|
||||
List<String> boards = g.getBoards();
|
||||
if (boards == null || boards.isEmpty() || boards.contains(boardCategory)) {
|
||||
result.add(g);
|
||||
}
|
||||
}
|
||||
TagCategory c = categoryMapper.findById(catId);
|
||||
return c == null ? listGrouped() : List.of(toGroup(c));
|
||||
return result;
|
||||
}
|
||||
|
||||
private TagCategoryResponse toGroup(TagCategory c) {
|
||||
List<TagResponse> tags = tagMapper.findByCategoryId(c.getId())
|
||||
.stream().map(TagResponse::from).toList();
|
||||
return TagCategoryResponse.of(c, tags);
|
||||
List<String> boards = categoryBoardMapper.findBoards(c.getId());
|
||||
return TagCategoryResponse.of(c, tags, boards);
|
||||
}
|
||||
|
||||
/** 카테고리의 게시판 매핑을 교체 저장 (유효 게시판 값만, 중복 제거) */
|
||||
private void saveBoards(Long categoryId, List<String> boards) {
|
||||
categoryBoardMapper.deleteByCategory(categoryId);
|
||||
if (boards == null) {
|
||||
return;
|
||||
}
|
||||
boards.stream()
|
||||
.filter(b -> b != null && VALID_BOARDS.contains(b))
|
||||
.distinct()
|
||||
.forEach(b -> categoryBoardMapper.insert(categoryId, b));
|
||||
}
|
||||
|
||||
/* ===================== 게시판 설정 ===================== */
|
||||
@@ -85,7 +110,8 @@ public class TagService {
|
||||
.sortOrder(req.getSortOrder() != null ? req.getSortOrder() : 0)
|
||||
.build();
|
||||
categoryMapper.insert(c);
|
||||
return TagCategoryResponse.of(c, List.of());
|
||||
saveBoards(c.getId(), req.getBoards());
|
||||
return TagCategoryResponse.of(c, List.of(), categoryBoardMapper.findBoards(c.getId()));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -100,11 +126,12 @@ public class TagService {
|
||||
c.setSortOrder(req.getSortOrder());
|
||||
}
|
||||
categoryMapper.update(c);
|
||||
saveBoards(id, req.getBoards());
|
||||
List<TagResponse> tags = tagMapper.findByCategoryId(id).stream().map(TagResponse::from).toList();
|
||||
return TagCategoryResponse.of(c, tags);
|
||||
return TagCategoryResponse.of(c, tags, categoryBoardMapper.findBoards(id));
|
||||
}
|
||||
|
||||
/** 카테고리 삭제 — 소속 태그와 그 연결(post_tag)까지 함께 삭제 */
|
||||
/** 카테고리 삭제 — 소속 태그와 그 연결(post_tag)·게시판 매핑까지 함께 삭제 */
|
||||
@Transactional
|
||||
public void deleteCategory(Long id) {
|
||||
mustFindCategory(id);
|
||||
@@ -112,6 +139,7 @@ public class TagService {
|
||||
tagMapper.deletePostTagsByTagId(t.getId());
|
||||
tagMapper.delete(t.getId());
|
||||
}
|
||||
categoryBoardMapper.deleteByCategory(id);
|
||||
categoryMapper.delete(id);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,15 @@ CREATE TABLE IF NOT EXISTS tag (
|
||||
-- 기존 tag 테이블에 category_id 가 없으면 추가 (멱등)
|
||||
ALTER TABLE tag ADD COLUMN IF NOT EXISTS category_id BIGINT NULL;
|
||||
|
||||
-- 태그 카테고리(그룹) ↔ 게시판 매핑. 어느 게시판(community/saving/tips)에서 이 그룹을 쓸지 지정.
|
||||
-- 매핑이 하나도 없는 카테고리는 모든 게시판에서 사용(하위호환).
|
||||
CREATE TABLE IF NOT EXISTS tag_category_board (
|
||||
tag_category_id BIGINT NOT NULL,
|
||||
board_category VARCHAR(30) NOT NULL COMMENT 'community / saving / tips',
|
||||
PRIMARY KEY (tag_category_id, board_category),
|
||||
KEY idx_tcb_board (board_category)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 게시글-태그 (다대다)
|
||||
CREATE TABLE IF NOT EXISTS post_tag (
|
||||
post_id BIGINT NOT NULL,
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.sb.web.board.mapper.TagCategoryBoardMapper">
|
||||
|
||||
<select id="findBoards" parameterType="long" resultType="string">
|
||||
SELECT board_category FROM tag_category_board WHERE tag_category_id = #{categoryId}
|
||||
</select>
|
||||
|
||||
<delete id="deleteByCategory" parameterType="long">
|
||||
DELETE FROM tag_category_board WHERE tag_category_id = #{categoryId}
|
||||
</delete>
|
||||
|
||||
<insert id="insert">
|
||||
INSERT INTO tag_category_board (tag_category_id, board_category)
|
||||
VALUES (#{categoryId}, #{board})
|
||||
</insert>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user