feat: 시세 자동조회·퇴직연금 평가액·게시판 카테고리·태그 정렬·계좌번호 암호화
- 투자: 종목코드로 현재가 시세 자동조회(StockQuoteService, 투자탭/포트폴리오 진입 시 갱신) - 투자: 퇴직연금 등 평가액 직접입력형 계좌(currentValue 활성화, manualValuation) - 게시판: community/saving/tips 카테고리 분리(post.category + 목록 필터) - 태그: 순서 변경(account_tag.sort_order, /tags/reorder) - 보안: 계좌번호 AES-256-GCM 암호화 저장/복호화(EncryptedStringTypeHandler, account_number VARCHAR(255)) 키는 서버 .env ACCOUNT_CRYPTO_KEY 로 주입(미설정 시 평문 통과) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8fec057752
commit
fb94df8112
@@ -43,10 +43,11 @@ public class BoardController {
|
||||
public PageResponse<PostSummary> list(
|
||||
@RequestParam(defaultValue = "1") int page,
|
||||
@RequestParam(defaultValue = "10") int size,
|
||||
@RequestParam(required = false) String category,
|
||||
@RequestParam(required = false) String tag,
|
||||
@RequestParam(required = false) String keyword,
|
||||
@RequestParam(required = false) String searchType) {
|
||||
return boardService.list(page, size, tag, keyword, searchType);
|
||||
return boardService.list(page, size, category, tag, keyword, searchType);
|
||||
}
|
||||
|
||||
@GetMapping("/posts/{id}")
|
||||
|
||||
@@ -25,6 +25,7 @@ public class Post implements Serializable {
|
||||
private Integer viewCount;
|
||||
private Boolean blocked;
|
||||
private String blockReason;
|
||||
private String category; // 게시판 구분: community/saving/tips
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ public class PostDetail {
|
||||
private Integer viewCount;
|
||||
private Boolean blocked;
|
||||
private String blockReason;
|
||||
private String category;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private List<String> tags;
|
||||
@@ -37,6 +38,7 @@ public class PostDetail {
|
||||
.viewCount(p.getViewCount())
|
||||
.blocked(Boolean.TRUE.equals(p.getBlocked()))
|
||||
.blockReason(p.getBlockReason())
|
||||
.category(p.getCategory())
|
||||
.createdAt(p.getCreatedAt())
|
||||
.updatedAt(p.getUpdatedAt())
|
||||
.tags(tags)
|
||||
@@ -52,6 +54,7 @@ public class PostDetail {
|
||||
.authorName(p.getAuthorName())
|
||||
.viewCount(p.getViewCount())
|
||||
.blocked(true)
|
||||
.category(p.getCategory())
|
||||
.createdAt(p.getCreatedAt())
|
||||
.tags(List.of())
|
||||
.comments(List.of())
|
||||
|
||||
@@ -19,6 +19,9 @@ public class PostRequest {
|
||||
@NotBlank(message = "내용을 입력하세요.")
|
||||
private String content;
|
||||
|
||||
/** 게시판 구분: community/saving/tips. 없으면 community */
|
||||
private String category;
|
||||
|
||||
/** 선택한 태그 ID 목록 (DB에 등록된 태그만, 선택) */
|
||||
private List<Long> tagIds;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,13 @@ public interface PostMapper {
|
||||
|
||||
List<PostSummary> findPage(@Param("offset") int offset,
|
||||
@Param("size") int size,
|
||||
@Param("category") String category,
|
||||
@Param("tag") String tag,
|
||||
@Param("keyword") String keyword,
|
||||
@Param("searchType") String searchType);
|
||||
|
||||
long countPage(@Param("tag") String tag,
|
||||
long countPage(@Param("category") String category,
|
||||
@Param("tag") String tag,
|
||||
@Param("keyword") String keyword,
|
||||
@Param("searchType") String searchType);
|
||||
|
||||
|
||||
@@ -40,15 +40,16 @@ public class BoardService {
|
||||
|
||||
/* ===================== 게시글 ===================== */
|
||||
|
||||
public PageResponse<PostSummary> list(int page, int size, String tag, String keyword, String searchType) {
|
||||
public PageResponse<PostSummary> list(int page, int size, String category, String tag, String keyword, String searchType) {
|
||||
int p = Math.max(page, 1);
|
||||
int s = Math.min(Math.max(size, 1), 100);
|
||||
int offset = (p - 1) * s;
|
||||
String st = normalizeSearchType(searchType);
|
||||
String cat = normalizeCategory(category);
|
||||
|
||||
// 목록에는 태그를 표시하지 않으므로 게시글별 태그 조회를 생략한다.
|
||||
List<PostSummary> content = postMapper.findPage(offset, s, blankToNull(tag), blankToNull(keyword), st);
|
||||
long total = postMapper.countPage(blankToNull(tag), blankToNull(keyword), st);
|
||||
List<PostSummary> content = postMapper.findPage(offset, s, cat, blankToNull(tag), blankToNull(keyword), st);
|
||||
long total = postMapper.countPage(cat, blankToNull(tag), blankToNull(keyword), st);
|
||||
return PageResponse.of(content, p, s, total);
|
||||
}
|
||||
|
||||
@@ -56,6 +57,18 @@ public class BoardService {
|
||||
return ("content".equals(t) || "comment".equals(t)) ? t : "title";
|
||||
}
|
||||
|
||||
/** 목록 필터용: 빈값이면 null(전체), 알 수 없는 값은 community 로 보정 */
|
||||
private String normalizeCategory(String c) {
|
||||
if (c == null || c.isBlank()) return null;
|
||||
return ("saving".equals(c) || "tips".equals(c) || "community".equals(c)) ? c : "community";
|
||||
}
|
||||
|
||||
/** 저장용: 빈값/알 수 없는 값은 community 로 기본 설정 */
|
||||
private String toCategory(String c) {
|
||||
if (c == null || c.isBlank()) return "community";
|
||||
return ("saving".equals(c) || "tips".equals(c)) ? c : "community";
|
||||
}
|
||||
|
||||
/** 상세 조회 (열람 제한 글은 관리자만 전체 열람, 그 외엔 제한 응답) */
|
||||
@Transactional
|
||||
public PostDetail get(Long id, SessionUser viewer) {
|
||||
@@ -95,6 +108,7 @@ public class BoardService {
|
||||
.content(req.getContent())
|
||||
.authorId(author.getId())
|
||||
.authorName(author.getName())
|
||||
.category(toCategory(req.getCategory()))
|
||||
.build();
|
||||
postMapper.insert(post);
|
||||
applyTags(post.getId(), req.getTagIds());
|
||||
|
||||
Reference in New Issue
Block a user