Skip to content

Commit

Permalink
feat: GET /lands API 구현 (#148)
Browse files Browse the repository at this point in the history
* feat : 도메인 생성

* faet : controller 구현

* feat : response DTO 생성

* feat : 전체 조회 service 구현

* feat : 전체 조회 repository 생성

* feat : Domain 생성

* test : 인수 테스트 작성

* refactor : 하위 패키지 중 domain을 model로 수정

* refactor : DTO 클래스에 JsonNaming 어노테이션 사용

* refactor : Column 어노테이션 안에 필요없는 내용 제거

* refactor : 복덕방 리스트 조회 메서드에 Transaction(readOnly=true)가 적용되도록 수정

* refactor : 리스트 원소로 사용하던 LandResponse의 이름을 LandListItemResponse로 수정

(cherry picked from commit f8dc249)
  • Loading branch information
daheeParkk authored and Choi-JJunho committed May 9, 2024
1 parent a3bb6d6 commit 4849080
Show file tree
Hide file tree
Showing 6 changed files with 339 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package in.koreatech.koin.domain.land.controller;

import java.util.List;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import in.koreatech.koin.domain.land.dto.LandListItemResponse;
import in.koreatech.koin.domain.land.service.LandService;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
public class LandController {

private final LandService landService;

@GetMapping("/lands")
public ResponseEntity<List<LandListItemResponse>> getLands() {
List<LandListItemResponse> responses = landService.getLands();
return ResponseEntity.ok(responses);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package in.koreatech.koin.domain.land.dto;

import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;

import com.fasterxml.jackson.databind.annotation.JsonNaming;

import in.koreatech.koin.domain.land.model.Land;

@JsonNaming(value = SnakeCaseStrategy.class)
public record LandListItemResponse(
String internalName,
String monthlyFee,
String latitude,
String charterFee,
String name,
Long id,
String longitude,
String roomType) {

public static LandListItemResponse from(Land land) {
return new LandListItemResponse(
land.getInternalName(),
land.getMonthlyFee(),
land.getLatitude(),
land.getCharterFee(),
land.getName(),
land.getId(),
land.getLongitude(),
land.getRoomType()
);
}
}
177 changes: 177 additions & 0 deletions src/main/java/in/koreatech/koin/domain/land/model/Land.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package in.koreatech.koin.domain.land.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Lob;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@Table(name = "lands")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Land {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@Size(max = 255)
@NotNull
@Column(name = "name", nullable = false)
private String name;

@Size(max = 50)
@NotNull
@Column(name = "internal_name", nullable = false, length = 50)
private String internalName;

@Size(max = 20)
@Column(name = "size", length = 20)
private String size;

@Size(max = 20)
@Column(name = "room_type", length = 20)
private String roomType;

@Size(max = 20)
@Column(name = "latitude", length = 20)
private String latitude;

@Size(max = 20)
@Column(name = "longitude", length = 20)
private String longitude;

@Size(max = 20)
@Column(name = "phone", length = 20)
private String phone;

@Lob
@Column(name = "image_urls")
private String imageUrls;

@Lob
@Column(name = "address")
private String address;

@Lob
@Column(name = "description")
private String description;

@Column(name = "floor")
private Long floor;

@Size(max = 255)
@Column(name = "deposit")
private String deposit;

@Size(max = 255)
@Column(name = "monthly_fee")
private String monthlyFee;

@Size(max = 20)
@Column(name = "charter_fee", length = 20)
private String charterFee;

@Size(max = 255)
@Column(name = "management_fee")
private String managementFee;

@NotNull
@Column(name = "opt_refrigerator", nullable = false)
private Boolean optRefrigerator = false;

@NotNull
@Column(name = "opt_closet", nullable = false)
private Boolean optCloset = false;

@NotNull
@Column(name = "opt_tv", nullable = false)
private Boolean optTv = false;

@NotNull
@Column(name = "opt_microwave", nullable = false)
private Boolean optMicrowave = false;

@NotNull
@Column(name = "opt_gas_range", nullable = false)
private Boolean optGasRange = false;

@NotNull
@Column(name = "opt_induction", nullable = false)
private Boolean optInduction = false;

@NotNull
@Column(name = "opt_water_purifier", nullable = false)
private Boolean optWaterPurifier = false;

@NotNull
@Column(name = "opt_air_conditioner", nullable = false)
private Boolean optAirConditioner = false;

@NotNull
@Column(name = "opt_washer", nullable = false)
private Boolean optWasher = false;

@NotNull
@Column(name = "opt_bed", nullable = false)
private Boolean optBed = false;

@NotNull
@Column(name = "opt_desk", nullable = false)
private Boolean optDesk = false;

@NotNull
@Column(name = "opt_shoe_closet", nullable = false)
private Boolean optShoeCloset = false;

@NotNull
@Column(name = "opt_electronic_door_locks", nullable = false)
private Boolean optElectronicDoorLocks = false;

@NotNull
@Column(name = "opt_bidet", nullable = false)
private Boolean optBidet = false;

@NotNull
@Column(name = "opt_veranda", nullable = false)
private Boolean optVeranda = false;

@NotNull
@Column(name = "opt_elevator", nullable = false)
private Boolean optElevator = false;

@NotNull
@Column(name = "is_deleted", nullable = false)
private Boolean isDeleted = false;

@Builder
private Land(String internalName, String name, String size, String roomType, String latitude, String longitude,
String phone, String imageUrls, String address, String description, Long floor, String deposit,
String monthlyFee, String charterFee, String managementFee) {
this.internalName = internalName;
this.name = name;
this.size = size;
this.roomType = roomType;
this.latitude = latitude;
this.longitude = longitude;
this.phone = phone;
this.imageUrls = imageUrls;
this.address = address;
this.description = description;
this.floor = floor;
this.deposit = deposit;
this.monthlyFee = monthlyFee;
this.charterFee = charterFee;
this.managementFee = managementFee;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package in.koreatech.koin.domain.land.repository;

import java.util.List;

import org.springframework.data.repository.Repository;

import in.koreatech.koin.domain.land.model.Land;

public interface LandRepository extends Repository<Land, Long> {

List<Land> findAll();

Land save(Land request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package in.koreatech.koin.domain.land.service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import in.koreatech.koin.domain.land.dto.LandListItemResponse;
import in.koreatech.koin.domain.land.repository.LandRepository;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class LandService {

private final LandRepository landRepository;

public List<LandListItemResponse> getLands() {
return landRepository.findAll()
.stream()
.map(LandListItemResponse::from)
.toList();
}
}
67 changes: 67 additions & 0 deletions src/test/java/in/koreatech/koin/acceptance/LandApiTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package in.koreatech.koin.acceptance;

import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;

import in.koreatech.koin.AcceptanceTest;
import in.koreatech.koin.domain.land.model.Land;
import in.koreatech.koin.domain.land.repository.LandRepository;
import io.restassured.RestAssured;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;

class LandApiTest extends AcceptanceTest {

@Autowired
private LandRepository landRepository;

@Test
@DisplayName("복덕방 리스트를 조회한다.")
void getLands() {
Land request = Land.builder()
.internalName("복덕방")
.name("복덕방")
.roomType("원룸")
.latitude("37.555")
.longitude("126.555")
.monthlyFee("100")
.charterFee("1000")
.build();

Land land = landRepository.save(request);

ExtractableResponse<Response> response = RestAssured
.given()
.log().all()
.when()
.log().all()
.get("/lands")
.then()
.log().all()
.statusCode(HttpStatus.OK.value())
.extract();

SoftAssertions.assertSoftly(
softly -> {
softly.assertThat(response.body().jsonPath().getList(".").size()).isEqualTo(1);
softly.assertThat(response.body().jsonPath().getLong("[0].id")).isEqualTo(land.getId());
softly.assertThat(response.body().jsonPath().getString("[0].internal_name"))
.isEqualTo(land.getInternalName());
softly.assertThat(response.body().jsonPath().getString("[0].name")).isEqualTo(land.getName());
softly.assertThat(response.body().jsonPath().getString("[0].room_type"))
.isEqualTo(land.getRoomType());
softly.assertThat(response.body().jsonPath().getString("[0].latitude"))
.isEqualTo(land.getLatitude());
softly.assertThat(response.body().jsonPath().getString("[0].longitude"))
.isEqualTo(land.getLongitude());
softly.assertThat(response.body().jsonPath().getString("[0].monthly_fee"))
.isEqualTo(land.getMonthlyFee());
softly.assertThat(response.body().jsonPath().getString("[0].charter_fee"))
.isEqualTo(land.getCharterFee());
}
);
}
}

0 comments on commit 4849080

Please sign in to comment.