Skip to content

Commit 8803b60

Browse files
chanrhanchanrhankih1015
authored
feature: 사진 앨범 도메인 추가 (#37)
* chore: 앨범 및 앨범-사진 관계 테이블 추가하는 마이그레이션 파일 추가 * fix: sql 문법 오류 수정 * feat: album 도메인 및 CRUD API 추가 * fix: 마이그레이션 파일 수정 * feat: 앨범-사진 관계 도메인 생성 및 사진 조회 로직 수정 * feat: 앨범 기준 사진 조회 API 추가 --------- Co-authored-by: chanrhan <km1104rs@naver.com> Co-authored-by: 강인화 <164142264+kih1015@users.noreply.github.com>
1 parent 281d522 commit 8803b60

19 files changed

Lines changed: 394 additions & 22 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package kr.kro.photoliner.domain.album.controller;
2+
3+
import jakarta.validation.Valid;
4+
import kr.kro.photoliner.domain.album.dto.request.AlbumCreateRequest;
5+
import kr.kro.photoliner.domain.album.dto.request.AlbumDeleteRequest;
6+
import kr.kro.photoliner.domain.album.dto.response.AlbumCreateResponse;
7+
import kr.kro.photoliner.domain.album.dto.response.AlbumsResponse;
8+
import kr.kro.photoliner.domain.album.service.AlbumService;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.data.domain.Pageable;
11+
import org.springframework.data.domain.Sort;
12+
import org.springframework.data.web.PageableDefault;
13+
import org.springframework.http.HttpStatus;
14+
import org.springframework.http.ResponseEntity;
15+
import org.springframework.web.bind.annotation.DeleteMapping;
16+
import org.springframework.web.bind.annotation.GetMapping;
17+
import org.springframework.web.bind.annotation.PostMapping;
18+
import org.springframework.web.bind.annotation.RequestBody;
19+
import org.springframework.web.bind.annotation.RequestMapping;
20+
import org.springframework.web.bind.annotation.RequestParam;
21+
import org.springframework.web.bind.annotation.RestController;
22+
23+
@RestController
24+
@RequiredArgsConstructor
25+
@RequestMapping("/api/v1/albums")
26+
public class AlbumController {
27+
28+
private final AlbumService albumService;
29+
30+
@PostMapping
31+
public ResponseEntity<AlbumCreateResponse> createAlbum(
32+
@Valid @RequestBody AlbumCreateRequest request
33+
) {
34+
AlbumCreateResponse response = albumService.createAlbum(request);
35+
return ResponseEntity.status(HttpStatus.CREATED).body(response);
36+
}
37+
38+
@GetMapping
39+
public ResponseEntity<AlbumsResponse> getAlbums(
40+
@RequestParam Long userId,
41+
@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable
42+
) {
43+
return ResponseEntity.ok(albumService.getAlbums(userId, pageable));
44+
}
45+
46+
@DeleteMapping
47+
public ResponseEntity<Void> deletePhoto(
48+
@Valid @RequestBody AlbumDeleteRequest request
49+
) {
50+
albumService.deleteAlbums(request);
51+
return ResponseEntity.noContent().build();
52+
}
53+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package kr.kro.photoliner.domain.album.dto.request;
2+
3+
import jakarta.validation.constraints.NotEmpty;
4+
import jakarta.validation.constraints.NotNull;
5+
6+
public record AlbumCreateRequest(
7+
@NotNull
8+
Long userId,
9+
@NotEmpty
10+
String name
11+
) {
12+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package kr.kro.photoliner.domain.album.dto.request;
2+
3+
import java.util.List;
4+
5+
public record AlbumDeleteRequest(
6+
List<Long> ids
7+
) {
8+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package kr.kro.photoliner.domain.album.dto.response;
2+
3+
import kr.kro.photoliner.domain.album.model.Album;
4+
5+
public record AlbumCreateResponse(
6+
InnerAlbum album
7+
) {
8+
9+
public static AlbumCreateResponse from(Album album) {
10+
return new AlbumCreateResponse(
11+
new InnerAlbum(
12+
album.getId(),
13+
album.getName()
14+
)
15+
);
16+
}
17+
18+
public record InnerAlbum(
19+
Long id,
20+
String name
21+
) {
22+
23+
}
24+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package kr.kro.photoliner.domain.album.dto.response;
2+
3+
import java.util.List;
4+
import kr.kro.photoliner.domain.album.model.Album;
5+
import org.springframework.data.domain.Page;
6+
7+
public record AlbumsResponse(
8+
List<InnerAlbum> albums,
9+
InnerPageInfo pageInfo
10+
) {
11+
12+
public static AlbumsResponse from(Page<Album> albumPage) {
13+
return new AlbumsResponse(
14+
albumPage.getContent().stream()
15+
.map(InnerAlbum::from)
16+
.toList(),
17+
InnerPageInfo.from(albumPage)
18+
);
19+
}
20+
21+
public record InnerAlbum(
22+
Long id,
23+
String name
24+
) {
25+
26+
public static InnerAlbum from(Album album) {
27+
return new InnerAlbum(
28+
album.getId(),
29+
album.getName()
30+
);
31+
}
32+
}
33+
34+
public record InnerPageInfo(
35+
long totalElements,
36+
int totalPages,
37+
int currentPage,
38+
int size,
39+
boolean hasNext,
40+
boolean hasPrevious
41+
) {
42+
43+
public static InnerPageInfo from(Page<Album> page) {
44+
return new InnerPageInfo(
45+
page.getTotalElements(),
46+
page.getTotalPages(),
47+
page.getNumber(),
48+
page.getSize(),
49+
page.hasNext(),
50+
page.hasPrevious()
51+
);
52+
}
53+
}
54+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package kr.kro.photoliner.domain.album.model;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.FetchType;
6+
import jakarta.persistence.GeneratedValue;
7+
import jakarta.persistence.GenerationType;
8+
import jakarta.persistence.Id;
9+
import jakarta.persistence.JoinColumn;
10+
import jakarta.persistence.ManyToOne;
11+
import jakarta.persistence.Table;
12+
import jakarta.validation.constraints.NotNull;
13+
import kr.kro.photoliner.common.model.BaseEntity;
14+
import kr.kro.photoliner.domain.user.model.User;
15+
import lombok.AccessLevel;
16+
import lombok.AllArgsConstructor;
17+
import lombok.Builder;
18+
import lombok.Getter;
19+
import lombok.NoArgsConstructor;
20+
21+
@Entity
22+
@Table(name = "albums")
23+
@Getter
24+
@AllArgsConstructor
25+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
26+
@Builder
27+
public class Album extends BaseEntity {
28+
29+
@Id
30+
@GeneratedValue(strategy = GenerationType.IDENTITY)
31+
private Long id;
32+
33+
@NotNull
34+
@Column(name = "name", nullable = false)
35+
private String name;
36+
37+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
38+
@JoinColumn(name = "user_id", referencedColumnName = "id")
39+
private User user;
40+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package kr.kro.photoliner.domain.album.model;
2+
3+
import java.util.List;
4+
5+
public record Albums(
6+
List<Album> albums
7+
) {
8+
9+
public int count() {
10+
return albums.size();
11+
}
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package kr.kro.photoliner.domain.album.repository;
2+
3+
import kr.kro.photoliner.domain.album.model.Album;
4+
import org.springframework.data.domain.Page;
5+
import org.springframework.data.domain.Pageable;
6+
import org.springframework.data.jpa.repository.JpaRepository;
7+
8+
public interface AlbumRepository extends JpaRepository<Album, Long> {
9+
10+
Album save(Album album);
11+
12+
Page<Album> findByUserId(Long userId, Pageable pageable);
13+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package kr.kro.photoliner.domain.album.service;
2+
3+
import kr.kro.photoliner.domain.album.dto.request.AlbumCreateRequest;
4+
import kr.kro.photoliner.domain.album.dto.request.AlbumDeleteRequest;
5+
import kr.kro.photoliner.domain.album.dto.response.AlbumCreateResponse;
6+
import kr.kro.photoliner.domain.album.dto.response.AlbumsResponse;
7+
import kr.kro.photoliner.domain.album.model.Album;
8+
import kr.kro.photoliner.domain.album.repository.AlbumRepository;
9+
import kr.kro.photoliner.domain.user.model.User;
10+
import kr.kro.photoliner.domain.user.repository.UserRepository;
11+
import kr.kro.photoliner.global.code.ApiResponseCode;
12+
import kr.kro.photoliner.global.exception.CustomException;
13+
import lombok.RequiredArgsConstructor;
14+
import org.springframework.data.domain.Page;
15+
import org.springframework.data.domain.Pageable;
16+
import org.springframework.stereotype.Service;
17+
import org.springframework.transaction.annotation.Transactional;
18+
19+
@Service
20+
@RequiredArgsConstructor
21+
public class AlbumService {
22+
23+
private final UserRepository userRepository;
24+
private final AlbumRepository albumRepository;
25+
26+
@Transactional
27+
public AlbumCreateResponse createAlbum(AlbumCreateRequest request) {
28+
User user = userRepository.findUserById(request.userId())
29+
.orElseThrow(() -> CustomException.of(ApiResponseCode.NOT_FOUND_USER, "user id: " + request.userId()));
30+
Album album = Album.builder()
31+
.name(request.name())
32+
.user(user)
33+
.build();
34+
Album savedAlbum = albumRepository.save(album);
35+
return AlbumCreateResponse.from(savedAlbum);
36+
}
37+
38+
@Transactional(readOnly = true)
39+
public AlbumsResponse getAlbums(Long userId, Pageable pageable) {
40+
Page<Album> albums = albumRepository.findByUserId(userId, pageable);
41+
return AlbumsResponse.from(albums);
42+
}
43+
44+
@Transactional
45+
public void deleteAlbums(AlbumDeleteRequest request) {
46+
albumRepository.deleteAllByIdInBatch(request.ids());
47+
}
48+
}

src/main/java/kr/kro/photoliner/domain/photo/controller/PhotoController.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,20 @@ public class PhotoController {
3939
private final PhotoUploadService photoUploadService;
4040

4141
@GetMapping
42-
public ResponseEntity<PhotosResponse> getPhotoList(
42+
public ResponseEntity<PhotosResponse> getPhotos(
4343
@RequestParam Long userId,
4444
@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable
4545
) {
46-
return ResponseEntity.ok(photoService.getPhotoList(userId, pageable));
46+
return ResponseEntity.ok(photoService.getPhotos(userId, pageable));
47+
}
48+
49+
@GetMapping("/albums/{albumId}")
50+
public ResponseEntity<PhotosResponse> getPhotosByAlbumId(
51+
@PathVariable Long albumId,
52+
@RequestParam Long userId,
53+
@PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable
54+
) {
55+
return ResponseEntity.ok(photoService.getPhotosByAlbumId(userId, albumId, pageable));
4756
}
4857

4958
@GetMapping("/markers")

0 commit comments

Comments
 (0)