feat: 게시글 인라인 이미지 서버 업로드(DB 저장) — base64 대체
- board_image 테이블 + BoardImageController/Service/Mapper
· POST /api/board/images(로그인) → {url:/api/images/{id}}
· GET /api/images/{id}(공개, img src 로 로드) — 1년 캐시
- 본문엔 짧은 URL 만 들어가 글이 비대해지지 않음
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2da43b2f77
commit
f9abd0c989
@@ -0,0 +1,57 @@
|
||||
package com.sb.web.board.controller;
|
||||
|
||||
import com.sb.web.auth.dto.SessionUser;
|
||||
import com.sb.web.auth.web.AuthInterceptor;
|
||||
import com.sb.web.board.domain.BoardImage;
|
||||
import com.sb.web.board.service.BoardImageService;
|
||||
import com.sb.web.common.exception.ApiException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 게시글 인라인 이미지.
|
||||
* POST /api/board/images 업로드(로그인 필요) → {url: "/api/images/{id}"}
|
||||
* GET /api/images/{id} 이미지 바이트(공개 — img src 로 인증 없이 로드)
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class BoardImageController {
|
||||
|
||||
private final BoardImageService service;
|
||||
|
||||
@PostMapping("/api/board/images")
|
||||
public Map<String, String> upload(
|
||||
@RequestParam("image") MultipartFile file,
|
||||
@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) throws IOException {
|
||||
if (file.isEmpty()) {
|
||||
throw new ApiException(HttpStatus.BAD_REQUEST, "이미지가 비어 있습니다.");
|
||||
}
|
||||
String contentType = file.getContentType();
|
||||
if (contentType == null || !contentType.startsWith("image/")) {
|
||||
throw new ApiException(HttpStatus.BAD_REQUEST, "이미지 파일만 업로드할 수 있습니다.");
|
||||
}
|
||||
Long id = service.save(current.getId(), contentType, file.getBytes());
|
||||
return Map.of("url", "/api/images/" + id);
|
||||
}
|
||||
|
||||
@GetMapping("/api/images/{id}")
|
||||
public ResponseEntity<byte[]> get(@PathVariable Long id) {
|
||||
BoardImage img = service.get(id);
|
||||
if (img == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType(img.getContentType()))
|
||||
.cacheControl(CacheControl.maxAge(365, TimeUnit.DAYS).cachePublic())
|
||||
.body(img.getData());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user