์ด๋ฒ ๊ธ์์๋ Post์ ๋ํ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๊ณ , ํ์ผ์ ์ ์ฅํ๋ File Service๊น์ง ์์ฑํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ค๋์ ์ ๊ฐ ๋ถ์คํฐ์ท์ ๋ง์ ๋ชธ์ํ๊ฐ ์ข์ง ์์ ๊ด๊ณ๋ก ํ ์คํธ์ฝ๋๊น์ง ์์ฑํ ํ์ ์์ด์, ํ ์คํธ์ฝ๋๋ ์ดํ ํฌ์คํ ์์ ์์ฑํ๋๋ก ํ๊ฒ ์ต๋๋ค.
- ์ํ๋ฆฌํฐ๋ฅผ ์ด์ฉํ JSON ๋ฐ์ดํฐ๋ก ๋ก๊ทธ์ธ (์๋ฃ)
- JWT๋ฅผ ์ด์ฉํ ์ธ์ฆ (์๋ฃ)
- ๋๋ฉ์ธ, ํ ์ด๋ธ ์ค๊ณ, ์ํฐํฐ ์์ฑ (์๋ฃ)
- ๋๊ธ ์ญ์ ๋ก์ง ๊ตฌํ (์๋ฃ)
- ํ์๊ฐ์ + ์ ๋ณด์์ ๋ฑ ํ์ ์๋น์ค ๊ตฌํ (์๋ฃ)
- ๊ฒ์ํ ์๋น์ค ๊ตฌํ (์งํ ์ค)
- ๋๊ธ ์๋น์ค ๊ตฌํ (1๋๊ธ -> *(๋ฌดํ) ๋๋๊ธ ๊ตฌ์กฐ)
- ์์ธ ์ฒ๋ฆฌ (์๋ฃ)
- ์์ธ ๋ฉ์ธ์ง ๊ตญ์ ํ
- ์นดํ ๊ณ ๋ฆฌ๋ณ ๊ฒ์ํ ๋ถ๋ฅ
- ๊ฒ์๊ธ ํ์ด์ง
- ๋์ ์ธ ๊ฒ์ ์กฐ๊ฑด์ ์ฌ์ฉํ ๊ฒ์
- ์ฌ์ฉ์ ๊ฐ ์ชฝ์ง ๊ธฐ๋ฅ
- ๋ฌดํ ์ชฝ์ง ์คํฌ๋กค
- ๊ฒ์๋ฌผ & ๋๊ธ์ ๋ํ ์๋
- ์ชฝ์ง์ ๋ํ ์๋
- ์ ์ํ ์ฌ์ฉ์ ๊ฐ ์ค์๊ฐ ์ฑํ
- ํ์๊ฐ์ ์ ๊ฒ์ฆ(์: XX๋ํ๊ต XX๊ณผ๊ฐ ์๋๋ฉด ๊ฐ์ ํ ์ ์๊ฒ)
- Swagger๋ฅผ ์ฌ์ฉํ API ๋ฌธ์ ๋ง๋ค๊ธฐ
- ์ ๊ณ & ๋ธ๋๋ฆฌ์คํธ ๊ธฐ๋ฅ
- AOP๋ฅผ ํตํ ๋ก๊ทธ
- ์ด๋๋ฏผ ํ์ด์ง
- ์บ์
- ๋ฐฐํฌ (+ ๋ฌด์ค๋จ ๋ฐฐํฌ)
- ๋ฐฐํฌ ์๋ํ
- ํฌํธ์ ์ด๋ํฐ ์ค๊ณ๋ฅผ ๋ฐ๋ฅด๋ ํจํค์ง ๊ตฌ์กฐ ์ค๊ณํ๊ธฐ
- ...
๊ฒ์๊ธ(Post) ์๋น์ค ๊ตฌํํ๊ธฐ
ํ์ฌ Post ํด๋์ค๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
@Table(name = "POST")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Post extends BaseTimeEntity {
@Id @GeneratedValue(strategy = IDENTITY)
@Column(name = "post_id")
private Long id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "writer_id")
private Member writer;
@Column(length = 40, nullable = false)
private String title;
@Lob
@Column(nullable = false)
private String content;
@Column(nullable = true)
private String filePath;
@Builder
public Post(String title, String content) {
this.title = title;
this.content = content;
}
//== ๊ฒ์๊ธ์ ์ญ์ ํ๋ฉด ๋ฌ๋ ค์๋ ๋๊ธ ๋ชจ๋ ์ญ์ ==//
@OneToMany(mappedBy = "post", cascade = ALL, orphanRemoval = true)
private List<Comment> commentList = new ArrayList<>();
//== ์ฐ๊ด๊ด๊ณ ํธ์ ๋ฉ์๋ ==//
public void confirmWriter(Member writer) {
//writer๋ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํ๋ฏ๋ก ์ด๋ ๊ฒ๋ง ํด์ฃผ์ด๋ ๋ ๋ฏ
this.writer = writer;
writer.addPost(this);
}
public void addComment(Comment comment){
//comment์ Post ์ค์ ์ comment์์ ํจ
commentList.add(comment);
}
//== ๋ด์ฉ ์์ ==//
public void updateTitle(String title) {
this.title = title;
}
public void updateContent(String content) {
this.content = content;
}
public void updateFilePath(String filePath) {
this.filePath = filePath;
}
}
์์ ๋ ์ฝ๋๋ ์์ผ๋, ์ง๊ธ๊น์ง ์์ฑํ ์ฝ๋๊ฐ ๋ง๋์ง ํ์ธ๋ง ํด์ฃผ์๋ฉด ๋ฉ๋๋ค.
์ด์ Post ์๋น์ค ๊ฐ๋ฐ์ ์์ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
PostRepository ๊ตฌํ
Jpa๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ฏ๋ก JpaRepository๋ฅผ ์์๋ฐ์ ๊ตฌํํ๊ฒ ์ต๋๋ค.
์์น๋ ์๋์ ๊ฐ์ต๋๋ค.
public interface PostRepository extends JpaRepository<Post, Long> {
}
PostService ๊ตฌํ
PostService๋ ๊ฒ์๊ธ์ CRUD ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ดํ ๊ฒ์ ์กฐ๊ฑด์ ์ถ๊ฐํ์ฌ ์กฐ๊ฑด์ ๋ฐ๋ผ ๊ฒ์ํ๊ณ , ํ์ด์ง ์ฒ๋ฆฌ๋ฅผ ํ๊ฒ๋ ๊ตฌํํ๊ฒ ์ง๋ง, ์ฐ์ ์ ๋๊ธ ๊ธฐ๋ฅ์ ๋ง๋ค๊ธฐ ์ ์ด๊ธฐ ๋๋ฌธ์, ์กฐํ ๊ธฐ๋ฅ์ ๊ตฌํํ์ง ์๊ณ , ์์ฑ๊ณผ ์์ , ์ญ์ ์ ๋ํด์๋ง ๊ตฌํํ๊ฒ ์ต๋๋ค.
์์น๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๊ตฌํ
public interface PostService {
/**
* ๊ฒ์๊ธ ๋ฑ๋ก
*/
void save(PostSaveDto postSaveDto) throws FileException;
/**
* ๊ฒ์๊ธ ์์
*/
void update(Long id, PostUpdateDto postUpdateDto);
/**
* ๊ฒ์๊ธ ์ญ์
*/
void delete(Long id);
/**
* ๊ฒ์๊ธ 1๊ฐ ์กฐํ
*/
PostInfoDto getPostInfo(Long id);
/**
* ๊ฒ์ ์กฐ๊ฑด์ ๋ฐ๋ฅธ ๊ฒ์๊ธ ๋ฆฌ์คํธ ์กฐํ + ํ์ด์ง
*/
PostPagingDto getPostList(Pageable pageable, PostSearchCondition postSearchCondition);
}
Pageable์ ์ดํ Controller์์ Pageable ๊ฐ์ฒด๋ฅผ ๋ฐ๋ก ๋ฐ์์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
page์ size์ ๋ํ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
์ด์ DTO๋ค๊ณผ, ๊ฒ์ ์กฐ๊ฑด์ธ PostSearchCondition์ ์์ฑํด ์ฃผ๋๋ก ํ๊ฒ ์ต๋๋ค.
๋จผ์ DTO๋ถํฐ ์์ฑํ๋๋ก ํ๊ฒ ์ต๋๋ค
DTO ์์ฑ
์์น๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
PostSaveDto ์์ฑ
public record PostSaveDto(@NotBlank(message = "์ ๋ชฉ์ ์
๋ ฅํด์ฃผ์ธ์") String title,
@NotBlank(message = "๋ด์ฉ์ ์
๋ ฅํด์ฃผ์ธ์") String content,
Optional<MultipartFile> uploadFile) {
public Post toEntity() {
return Post.builder().title(title).content(content).build();
}
}
์ ๋ชฉ(title)๊ณผ ๋ด์ฉ(content), ๊ทธ๋ฆฌ๊ณ ์ ๋ก๋ํ ํ์ผ(uploadFile)์ ๊ฐ์ง record ์ ๋๋ค. ํ์ผ์ ์ฌ๋ฌ๊ฐ ์ ๋ก๋ํ ์ ์๊ฒ ๋ง๋์๊ณ ์ถ์ผ์๋ค๋ฉด List๋ก ๋ฐ์์ค์๋ฉด ๋ฉ๋๋ค.
PostUpdateDto ์์ฑ
public record PostUpdateDto(
Optional<String> title,
Optional<String> content,
Optional<MultipartFile> uploadFile) {
}
์ ์ฅํ๋ ๊ฒฝ์ฐ์ ๋ง์ฐฌ๊ฐ์ง๋ก, ๋ฐ๊ฟ ์ ๋ชฉ๊ณผ ๋ด์ฉ, ์ ๋ก๋ํ ํ์ผ์ ๋ฐ์์ต๋๋ค.
PostInfoDto, PostPagingDto ์์ฑ
์ด๋ค์ ์ดํ ๋๊ธ๊ณผ ๋๋๊ธ์ ๊ตฌํํ๋ฉด, ๋๊ธ๊ณผ ๋๋๊ธ์ ์ถ๊ฐํ ๊ฒ์ด๊ธฐ์, ์ ์ ํด๋์ค๋ง ์์ฑํด ๋ ํ ๊ตฌํ์ ํ์ง ์๋๋ก ํ๊ฒ ์ต๋๋ค.
public class PostInfoDto {
}
public class PostPagingDto {
}
PostSearchCondition ์์ฑ
๊ฒ์ ์กฐ๊ฑด๋, ๋๊ธ๊ณผ ๋๋๊ธ์ ๋ชจ๋ ๊ตฌํํ๊ณ ๋ ํ ์๊ฐํด ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค. ์ฐ์ ํด๋์ค๋ง ๋ง๋ค๊ฒ ์ต๋๋ค.
์์น๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
public class PostSearchCondition {
}
์ด์ ๋ง์ง๋ง์ผ๋ก PostService๋ฅผ ๊ตฌํํด ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
PostServiceImpl ๊ตฌํ
@Service
@RequiredArgsConstructor
@Transactional
public class PostServiceImpl implements PostService{
private final PostRepository postRepository;
private final MemberRepository memberRepository;
private final FileService fileService;
@Override
public void save(PostSaveDto postSaveDto) throws FileException {
Post post = postSaveDto.toEntity();
post.confirmWriter(memberRepository.findByUsername(SecurityUtil.getLoginUsername())
.orElseThrow(() -> new MemberException(MemberExceptionType.NOT_FOUND_MEMBER)));
postSaveDto.uploadFile().ifPresent(
file -> post.updateFilePath(fileService.save(file))
);
postRepository.save(post);
}
@Override
public void update(Long id, PostUpdateDto postUpdateDto) {
Post post = postRepository.findById(id).orElseThrow(() ->
new PostException(PostExceptionType.POST_NOT_POUND));
checkAuthority(post,PostExceptionType.NOT_AUTHORITY_UPDATE_POST );
postUpdateDto.title().ifPresent(post::updateTitle);
postUpdateDto.content().ifPresent(post::updateContent);
if(post.getFilePath() !=null){
fileService.delete(post.getFilePath());//๊ธฐ์กด์ ์ฌ๋ฆฐ ํ์ผ ์ง์ฐ๊ธฐ
}
postUpdateDto.uploadFile().ifPresentOrElse(
multipartFile -> post.updateFilePath(fileService.save(multipartFile)),
() -> post.updateFilePath(null)
);
}
@Override
public void delete(Long id) {
Post post = postRepository.findById(id).orElseThrow(() ->
new PostException(PostExceptionType.POST_NOT_POUND));
checkAuthority(post,PostExceptionType.NOT_AUTHORITY_DELETE_POST);
if(post.getFilePath() !=null){
fileService.delete(post.getFilePath());//๊ธฐ์กด์ ์ฌ๋ฆฐ ํ์ผ ์ง์ฐ๊ธฐ
}
postRepository.delete(post);
}
private void checkAuthority(Post post, PostExceptionType postExceptionType) {
if(!post.getWriter().getUsername().equals(SecurityUtil.getLoginUsername()))
throw new PostException(postExceptionType);
}
@Override
public PostInfoDto getPostInfo(Long id) {
return null;
}
@Override
public PostPagingDto getPostList(Pageable pageable, PostSearchCondition postSearchCondition) {
return null;
}
}
getPostInfo์ getPostList๋ ์ดํ ๋๊ธ๊ณผ ๋๋๊ธ์ ๊ตฌํํ ํ์ ๊ตฌํํ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ค๋ช
save ๋ฉ์๋ ํ๋๋ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ PostSaveDto์์ title๊ณผ content๋ฅผ ๊ฐ์ง๊ณ Post ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
์ดํ ๋ก๊ทธ์ธํ ์ฌ์ฉ์๋ฅผ ์์ฑ์๋ก ๋งคํ์ํต๋๋ค. (๋ก๊ทธ์ธ ํ ์์ฑ์๊ฐ ์ด ๊ธ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.)
์ดํ FileService๋ฅผ ์ด์ฉํด File์ ์๋ฒ์ ์ ์ฅ์ํต๋๋ค. (ํ์ฌ๋ ์ปดํจํฐ์์ ์ ์ฅ๋๊ฒ ํ์ต๋๋ค๋ง, ์ดํ AWS๋ฅผ ์ฌ์ฉํ์ฌ, S3 ๋ฑ์ ์ ์ฅํ๋๋ก ๋ฐ๊พธ๊ฒ ์ต๋๋ค.)
๊ทธ ๋ค์ ์ ์ฅ๋ ๊ฒฝ๋ก๋ฅผ save์ ๋ฐํ๊ฐ์ผ๋ก ๊ฐ์ ธ์ ์ด๋ฅผ post์ uploadFilePath์ ์ ์ฅํฉ๋๋ค.
์ดํ ํด๋น Post ์ํฐํฐ๋ฅผ DB์ ์ ์ฅ์์ผ์ค๋๋ค.
FileService ๊ตฌํ
์ด์ file์ ์๋ฒ์ ์ ์ฅํ๋ ์ญํ ์ ๋ด๋นํ๋ fileService๋ฅผ ๊ตฌํํ๋๋ก ํ๊ฒ ์ต๋๋ค.
์์น๋ global -> file -> service ์ ๋๋ค.
public interface FileService {
//์ ์ฅ๋ ํ์ผ ๊ฒฝ๋ก ๋ฐํ
String save(MultipartFile multipartFile) throws FileException;
void delete(String filePath);
}
์ด๋ฅผ ๊ตฌํํ๊ธฐ ์ ์ ํ์ผ ์ ์ฅ๊ณผ ๊ด๋ จํ์ฌ ์ค์ ์ ์กฐ๊ธ ํ๊ณ ๋์ด๊ฐ๋๋ก ํ๊ฒ ์ต๋๋ค.
application.yml ์์
ํด๋น ์ฝ๋๋ฅผ ์ถ๊ฐํด์ค๋๋ค.
dir์๋ ํ์ผ์ ์ ์ฅํ ํด๋์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํด ์ฃผ์๋ฉด ๋ฉ๋๋ค.
์ ๋ ์๋ ์์นํด ์ถ๊ฐํด ์ฃผ๋๋ก ํ๊ฒ ์ต๋๋ค. (ํด๋๋ฅผ ๋ฏธ๋ฆฌ ๋ง๋ค์ด ์ฃผ์ ์ผ ํฉ๋๋ค.)
file:
dir: D:\files\
์ ์ฒด application.yml ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:tcp://localhost/~/jpa
username: sa
password: 1
jpa:
properties:
hibernate:
format_sql: true
user_sql_cooments: true
hibernate:
ddl-auto: create
profiles:
include: jwt
logging:
level:
org:
apache:
coyote:
http11: debug
hiberante:
SQL: debug
boardexample:
myboard: info
file:
dir: D:\files\
์ด์ ๊ตฌํ์ ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
FileServiceImpl ๊ตฌํ
@Service
public class FileServiceImpl implements FileService{
@Value("${file.dir}")//application.yml ํ์ผ์ ์๋ file.dir์ ๋ด์ฉ์ ๊ฐ์ ธ์ด
private String fileDir;
//TODO : ํ
์คํธ์ฝ๋ ์์ฑํด์ผ ํจ
@Override
public String save(MultipartFile multipartFile) {
String filePath = fileDir + UUID.randomUUID();
try {
multipartFile.transferTo(new File(filePath));
}catch (IOException e){
//ํ์ผ ์ ์ฅ ์๋ฌ!
throw new FileException(FileExceptionType.FILE_CAN_NOT_SAVE);
}
return filePath;
}
@Override
public void delete(String filePath) {
File file = new File(filePath);
//์กด์ฌํ์ง ์๋๋ฐ ๊ตณ์ด ์ง์ฐ๋..?
if(!file.exists()) return;
if(!file.delete()) throw new FileException(FileExceptionType.FILE_CAN_NOT_DELETE);
}
}
์ฐ์ @Value๋ฅผ ์ฌ์ฉํ ์ฝ๋๋ถํฐ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์์ ์ JWT๋ฅผ ๋ฐ๊ธํ ๋ ๋ค๋ค๋ฏ์ด application.yml ํ์ผ์์ ์ค์ ํ ๊ฐ์ ๊ฐ์ ธ์์ ์ฌ์ฉํ๋ ์ฝ๋์ ๋๋ค.
์ดํ save ๋ฉ์๋๋ฅผ ๋ณด์๋ฉด, ํ์ผ์ด ์ ์ฅ๋ ๊ฒฝ๋ก์ธ filePath๋ ์ฐ๋ฆฌ๊ฐ ์ง์ ํ fileDir์, UUID๋ฅผ ๋ฐ๊ธ๋ฐ์ ํ์ผ ์ด๋ฆ์ ๊ฒน์น์ง ์๊ณ ๋๋คํ๊ฒ ์ ์ฅํด์ฃผ๋๋ก ํ์์ต๋๋ค.
์ดํ transferTo ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ํ์ผ์ ์ปดํจํฐ์ ์ ์ฅํด์ค ํ, ์ ์ฅ๋ ๊ฒฝ๋ก๋ฅผ ๋ฐํํฉ๋๋ค.
์์ธ ์ฒ๋ฆฌ
๊ธฐ๋ณธ์ ์ธ ์ฝ๋ ์์ฑ์ ๋๋ฌ๊ณ , ์ด์ Post์ File Service์ ๋ํ ์์ธ ์ฒ๋ฆฌ๋ฅผ ์งํํด์ฃผ๋๋ก ํ๊ฒ ์ต๋๋ค.
FileException ๊ตฌํ
์์น๋ ์๋์ ๊ฐ์ต๋๋ค.
public class FileException extends BaseException {
private BaseExceptionType exceptionType;
public FileException(BaseExceptionType exceptionType) {
this.exceptionType = exceptionType;
}
@Override
public BaseExceptionType getExceptionType() {
return exceptionType;
}
}
public enum FileExceptionType implements BaseExceptionType {
FILE_CAN_NOT_SAVE(10000, HttpStatus.BAD_REQUEST, "ํ์ผ ์ ์ฅ์ ์คํจํ์ต๋๋ค."),
FILE_CAN_NOT_DELETE(10001, HttpStatus.BAD_REQUEST, "ํ์ผ ์ญ์ ์ ์คํจํ์ต๋๋ค.");
private int errorCode;
private HttpStatus httpStatus;
private String errorMessage;
FileExceptionType(int errorCode, HttpStatus httpStatus, String errorMessage) {
this.errorCode = errorCode;
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
}
@Override
public int getErrorCode() {
return this.errorCode;
}
@Override
public HttpStatus getHttpStatus() {
return this.httpStatus;
}
@Override
public String getErrorMessage() {
return this.errorMessage;
}
}
ํ์ผ ์ ์ฅ์ ์คํจํ์ ๋์, ํ์ผ ์ญ์ ์ ์คํจํ์ ๊ฒฝ์ฐ ๋ฐ์ํ๋ IOException์ ์ปค์คํ ์๋ฌ๋ก ์ ํํด์ฃผ๊ธฐ ์ํด์ ์์ฑํ์ต๋๋ค.
PostException ๊ตฌํ
์์น๋ ์๋์ ๊ฐ์ต๋๋ค.
public class PostException extends BaseException {
private BaseExceptionType baseExceptionType;
public PostException(BaseExceptionType baseExceptionType) {
this.baseExceptionType = baseExceptionType;
}
@Override
public BaseExceptionType getExceptionType() {
return this.baseExceptionType;
}
}
public enum PostExceptionType implements BaseExceptionType {
POST_NOT_POUND(700, HttpStatus.NOT_FOUND, "์ฐพ์ผ์๋ ํฌ์คํธ๊ฐ ์์ต๋๋ค"),
NOT_AUTHORITY_UPDATE_POST(701, HttpStatus.FORBIDDEN, "ํฌ์คํธ๋ฅผ ์
๋ฐ์ดํธํ ๊ถํ์ด ์์ต๋๋ค."),
NOT_AUTHORITY_DELETE_POST(702, HttpStatus.FORBIDDEN, "ํฌ์คํธ๋ฅผ ์ญ์ ํ ๊ถํ์ด ์์ต๋๋ค.");
private int errorCode;
private HttpStatus httpStatus;
private String errorMessage;
PostExceptionType(int errorCode, HttpStatus httpStatus, String errorMessage) {
this.errorCode = errorCode;
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
}
@Override
public int getErrorCode() {
return this.errorCode;
}
@Override
public HttpStatus getHttpStatus() {
return this.httpStatus;
}
@Override
public String getErrorMessage() {
return this.errorMessage;
}
}
ํ ์คํธ์ฝ๋ ์์ฑ - PostService
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
@SpringBootTest
@Transactional
class PostServiceImplTest {
@Autowired private EntityManager em;
@Autowired
private PostService postService;
@Autowired
private MemberService memberService;
private static final String USERNAME = "username";
private static final String PASSWORD = "PASSWORD123@@@";
private void clear(){
em.flush();
em.clear();
}
private void deleteFile(String filePath) {
File files = new File(filePath);
files.delete();
}
private MockMultipartFile getMockUploadFile() throws IOException {
return new MockMultipartFile("file", "file.jpg", "image/jpg", new FileInputStream("C:/Users/user/Desktop/tistory/diary.jpg"));
}
@BeforeEach
private void signUpAndSetAuthentication() throws Exception {
memberService.signUp(new MemberSignUpDto(USERNAME,PASSWORD,"name","nickName",22));
SecurityContext emptyContext = SecurityContextHolder.createEmptyContext();
emptyContext.setAuthentication(
new UsernamePasswordAuthenticationToken(
User.builder()
.username(USERNAME)
.password(PASSWORD)
.roles(Role.USER.toString())
.build(),
null)
);
SecurityContextHolder.setContext(emptyContext);
clear();
}
@Test
public void ํฌ์คํธ_์ ์ฅ_์ฑ๊ณต_์
๋ก๋_ํ์ผ_์์() throws Exception {
//given
String title = "์ ๋ชฉ";
String content = "๋ด์ฉ";
PostSaveDto postSaveDto = new PostSaveDto(title, content, Optional.empty());
//when
postService.save(postSaveDto);
clear();
//then
Post findPost = em.createQuery("select p from Post p", Post.class).getSingleResult();
Post post = em.find(Post.class, findPost.getId());
assertThat(post.getContent()).isEqualTo(content);
assertThat(post.getWriter().getUsername()).isEqualTo(USERNAME);
assertThat(post.getFilePath()).isNull();
}
@Test
public void ํฌ์คํธ_์ ์ฅ_์ฑ๊ณต_์
๋ก๋_ํ์ผ_์์() throws Exception {
//given
String title = "์ ๋ชฉ";
String content = "๋ด์ฉ";
PostSaveDto postSaveDto = new PostSaveDto(title,content, Optional.ofNullable(getMockUploadFile()));
//when
postService.save(postSaveDto);
clear();
//then
Post findPost = em.createQuery("select p from Post p", Post.class).getSingleResult();
Post post = em.find(Post.class, findPost.getId());
assertThat(post.getContent()).isEqualTo(content);
assertThat(post.getWriter().getUsername()).isEqualTo(USERNAME);
assertThat(post.getFilePath()).isNotNull();
deleteFile(post.getFilePath());
//์ฌ๋ฆฐ ํ์ผ ์ญ์
}
@Test
public void ํฌ์คํธ_์ ์ฅ_์คํจ_์ ๋ชฉ์ด๋_๋ด์ฉ์ด_์์() throws Exception {
//given
String title = "์ ๋ชฉ";
String content = "๋ด์ฉ";
PostSaveDto postSaveDto = new PostSaveDto(null,content, Optional.empty());
PostSaveDto postSaveDto2 = new PostSaveDto(title,null, Optional.empty());
//when,then
assertThrows(Exception.class, () -> postService.save(postSaveDto));
assertThrows(Exception.class, () -> postService.save(postSaveDto2));
}
@Test
public void ํฌ์คํธ_์
๋ฐ์ดํธ_์ฑ๊ณต_์
๋ก๋ํ์ผ_์์TO์์() throws Exception {
//given
String title = "์ ๋ชฉ";
String content = "๋ด์ฉ";
PostSaveDto postSaveDto = new PostSaveDto(title,content, Optional.empty());
postService.save(postSaveDto);
clear();
//when
Post findPost = em.createQuery("select p from Post p", Post.class).getSingleResult();
PostUpdateDto postUpdateDto = new PostUpdateDto(Optional.ofNullable("๋ฐ๊พผ์ ๋ชฉ"),Optional.ofNullable("๋ฐ๊พผ๋ด์ฉ"), Optional.empty());
postService.update(findPost.getId(),postUpdateDto);
clear();
//then
Post post = em.find(Post.class, findPost.getId());
assertThat(post.getContent()).isEqualTo("๋ฐ๊พผ๋ด์ฉ");
assertThat(post.getWriter().getUsername()).isEqualTo(USERNAME);
assertThat(post.getFilePath()).isNull();
}
@Test
public void ํฌ์คํธ_์
๋ฐ์ดํธ_์ฑ๊ณต_์
๋ก๋ํ์ผ_์์TO์์() throws Exception {
//given
String title = "์ ๋ชฉ";
String content = "๋ด์ฉ";
PostSaveDto postSaveDto = new PostSaveDto(title,content, Optional.empty());
postService.save(postSaveDto);
clear();
//when
Post findPost = em.createQuery("select p from Post p", Post.class).getSingleResult();
PostUpdateDto postUpdateDto = new PostUpdateDto(Optional.ofNullable("๋ฐ๊พผ์ ๋ชฉ"),Optional.ofNullable("๋ฐ๊พผ๋ด์ฉ"), Optional.ofNullable(getMockUploadFile()));
postService.update(findPost.getId(),postUpdateDto);
clear();
//then
Post post = em.find(Post.class, findPost.getId());
assertThat(post.getContent()).isEqualTo("๋ฐ๊พผ๋ด์ฉ");
assertThat(post.getWriter().getUsername()).isEqualTo(USERNAME);
assertThat(post.getFilePath()).isNotNull();
deleteFile(post.getFilePath());
//์ฌ๋ฆฐ ํ์ผ ์ญ์
}
@Test
public void ํฌ์คํธ_์
๋ฐ์ดํธ_์ฑ๊ณต_์
๋ก๋ํ์ผ_์์TO์์() throws Exception {
//given
String title = "์ ๋ชฉ";
String content = "๋ด์ฉ";
PostSaveDto postSaveDto = new PostSaveDto(title,content, Optional.ofNullable(getMockUploadFile()));
postService.save(postSaveDto);
Post findPost = em.createQuery("select p from Post p", Post.class).getSingleResult();
assertThat(findPost.getFilePath()).isNotNull();
clear();
//when
PostUpdateDto postUpdateDto = new PostUpdateDto(Optional.ofNullable("๋ฐ๊พผ์ ๋ชฉ"),Optional.ofNullable("๋ฐ๊พผ๋ด์ฉ"), Optional.empty());
postService.update(findPost.getId(),postUpdateDto);
clear();
//then
findPost = em.find(Post.class, findPost.getId());
assertThat(findPost.getContent()).isEqualTo("๋ฐ๊พผ๋ด์ฉ");
assertThat(findPost.getWriter().getUsername()).isEqualTo(USERNAME);
assertThat(findPost.getFilePath()).isNull();
}
@Test
public void ํฌ์คํธ_์
๋ฐ์ดํธ_์ฑ๊ณต_์
๋ก๋ํ์ผ_์์TO์์() throws Exception {
//given
String title = "์ ๋ชฉ";
String content = "๋ด์ฉ";
PostSaveDto postSaveDto = new PostSaveDto(title,content, Optional.empty());
postService.save(postSaveDto);
Post findPost = em.createQuery("select p from Post p", Post.class).getSingleResult();
Post post = em.find(Post.class, findPost.getId());
String filePath = post.getFilePath();
clear();
//when
PostUpdateDto postUpdateDto = new PostUpdateDto(Optional.ofNullable("๋ฐ๊พผ์ ๋ชฉ"),Optional.ofNullable("๋ฐ๊พผ๋ด์ฉ"), Optional.ofNullable(getMockUploadFile()));
postService.update(findPost.getId(),postUpdateDto);
clear();
//then
post = em.find(Post.class, findPost.getId());
assertThat(post.getContent()).isEqualTo("๋ฐ๊พผ๋ด์ฉ");
assertThat(post.getWriter().getUsername()).isEqualTo(USERNAME);
assertThat(post.getFilePath()).isNotEqualTo(filePath);
deleteFile(post.getFilePath());
//์ฌ๋ฆฐ ํ์ผ ์ญ์
}
private void setAnotherAuthentication() throws Exception {
memberService.signUp(new MemberSignUpDto(USERNAME+"123",PASSWORD,"name","nickName",22));
SecurityContext emptyContext = SecurityContextHolder.createEmptyContext();
emptyContext.setAuthentication(
new UsernamePasswordAuthenticationToken(
User.builder()
.username(USERNAME+"123")
.password(PASSWORD)
.roles(Role.USER.toString())
.build(),
null)
);
SecurityContextHolder.setContext(emptyContext);
clear();
}
@Test
public void ํฌ์คํธ_์
๋ฐ์ดํธ_์คํจ_๊ถํ์ด์์() throws Exception {
String title = "์ ๋ชฉ";
String content = "๋ด์ฉ";
PostSaveDto postSaveDto = new PostSaveDto(title, content, Optional.empty());
postService.save(postSaveDto);
clear();
//when, then
setAnotherAuthentication();
Post findPost = em.createQuery("select p from Post p", Post.class).getSingleResult();
PostUpdateDto postUpdateDto = new PostUpdateDto(Optional.ofNullable("๋ฐ๊พผ์ ๋ชฉ"),Optional.ofNullable("๋ฐ๊พผ๋ด์ฉ"), Optional.empty());
assertThrows(PostException.class, ()-> postService.update(findPost.getId(),postUpdateDto));
}
@Test
public void ํฌ์คํธ์ญ์ _์ฑ๊ณต() throws Exception {
String title = "์ ๋ชฉ";
String content = "๋ด์ฉ";
PostSaveDto postSaveDto = new PostSaveDto(title, content, Optional.empty());
postService.save(postSaveDto);
clear();
//when
Post findPost = em.createQuery("select p from Post p", Post.class).getSingleResult();
postService.delete(findPost.getId());
//then
List<Post> findPosts = em.createQuery("select p from Post p", Post.class).getResultList();
assertThat(findPosts.size()).isEqualTo(0);
}
@Test
public void ํฌ์คํธ์ญ์ _์คํจ() throws Exception {
String title = "์ ๋ชฉ";
String content = "๋ด์ฉ";
PostSaveDto postSaveDto = new PostSaveDto(title, content, Optional.empty());
postService.save(postSaveDto);
clear();
//when, then
setAnotherAuthentication();
Post findPost = em.createQuery("select p from Post p", Post.class).getSingleResult();
assertThrows(PostException.class, ()-> postService.delete(findPost.getId()));
}
}
MockMultipartFile์ ์์ฑ์์๋ ์์๋๋ก name, originalFilename, contentType, FileInputStream("ํ์ผ๊ฒฝ๋ก")๋ฅผ ๋ฃ์ด์ฃผ์๋ฉด ๋ฉ๋๋ค.
์ ์ฝ๋๋ฅผ ์ฐธ๊ณ ํ์ ์ ์์ฑํด์ฃผ์๋ฉด ๋ฉ๋๋ค.
ํ ์คํธ์ฝ๋ ์์ฑ - FileService
import static org.assertj.core.api.Assertions.*;
@SpringBootTest
class FileServiceTest {
@Autowired FileService fileService;
private MockMultipartFile getMockUploadFile() throws IOException {
return new MockMultipartFile("file", "file.jpg", "image/jpg", new FileInputStream("C:/Users/user/Desktop/tistory/diary.jpg"));
}
@Test
public void ํ์ผ์ ์ฅ_์ฑ๊ณต() throws Exception {
//given, when
String filePath = fileService.save(getMockUploadFile());
//then
File file = new File(filePath);
assertThat(file.exists()).isTrue();
//finally
file.delete();//ํ์ผ ์ญ์
}
@Test
public void ํ์ผ์ญ์ _์ฑ๊ณต() throws Exception {
//given, when
String filePath = fileService.save(getMockUploadFile());
fileService.delete(filePath);
//then
File file = new File(filePath);
assertThat(file.exists()).isFalse();
}
}
์ด๋ ๊ฒ ํด์ ๊ฐ๋จํ Post์ ๋ํ ์๋น์ค์, ํ์ผ์ ์ ์ฅํ๋ ์ฝ๋๋ฅผ ์์ฑํด ๋ณด์์ต๋๋ค. ๋ค์๋ฒ์๋ ๋๊ธ๊ณผ ๋๋๊ธ์ ๊ตฌํํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค. ๊ฐ์ฌํฉ๋๋ค.
์ ์ฒด ์ฝ๋๋ ๊นํ๋ธ์์ ํ์ธํ์ค ์ ์์ต๋๋ค.
(์ถ๊ฐ๋ก ์ ๊ฐ ์ ์ ์ด ์์ด์ ๊ณ ์น๊ณ ๋ฐ์์ ํ์ง ๋ชปํ ๋ถ๋ถ์ด ์์ ์๋ ์๊ธฐ์, ์ฝ๋๊ฐ ์ ๋๋ก ์๋ํ์ง ์๋๋ค๋ฉด ์ธ์ ๋ ์ง ๋๊ธ์ด๋ ๋ฉ์ผ ๋ณด๋ด์ฃผ์๋ฉด ํ์ธํ๋๋ก ํ๊ฒ ์ต๋๋ค.)
https://github.com/ShinDongHun1/SpringBoot-Board-API