Skip to content

Commit

Permalink
feat: 차량 관리 기능과, 유저의 차량을 등록할 수 있는 기능을 구현한다 (#464)
Browse files Browse the repository at this point in the history
* feat: 차량 등록 기능 추가

* test: 차량 등록 기능 테스트

* feat: 유저의 개인 차량을 등록 및 조회하는 기능 추가

* test: 유저의 개인 차량을 등록 및 조회하는 기능 테스트

* feat: 차량 필터 기능 추가

* test: 차량 필터 기능 테스트

* refactor: 변수명 변경

* fix: 테스트 깨지는 버그 해결

* refactor: 코드 리팩토링

* refactor: 연관관계 매핑 OneToOne으로 변경

* refactor: 불필요한 기능 제거

* refactor: 제약조건 추가
  • Loading branch information
sosow0212 authored and drunkenhw committed Aug 13, 2023
1 parent f6e6e8a commit 312ca36
Show file tree
Hide file tree
Showing 37 changed files with 1,766 additions and 11 deletions.
68 changes: 68 additions & 0 deletions backend/src/docs/asciidoc/car.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
= Filter API 문서
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 3

== 차량을 모두 조회한다 (/cars)

=== Request

include::{snippets}/car-controller-test/find_all_cars/http-request.adoc[]

=== Response

include::{snippets}/car-controller-test/find_all_cars/response-fields.adoc[]
include::{snippets}/car-controller-test/find_all_cars/http-response.adoc[]

== 차량을 등록한다 (/cars)

=== Request

include::{snippets}/car-controller-test/save_all_cars/request-headers.adoc[]
include::{snippets}/car-controller-test/save_all_cars/request-fields.adoc[]
include::{snippets}/car-controller-test/save_all_cars/http-request.adoc[]

=== Response

include::{snippets}/car-controller-test/save_all_cars/response-fields.adoc[]
include::{snippets}/car-controller-test/save_all_cars/http-response.adoc[]

== 차량을 제거한다 (/cars/{carId})

=== Request

include::{snippets}/car-controller-test/delete_car/request-headers.adoc[]
include::{snippets}/car-controller-test/delete_car/path-parameters.adoc[]
include::{snippets}/car-controller-test/delete_car/http-request.adoc[]

=== Response

include::{snippets}/car-controller-test/delete_car/http-response.adoc[]

== 차량에 등록된 필터를 조회한다 (/cars/{carId}/filters)

=== Request

include::{snippets}/car-controller-test/find_car_filters/path-parameters.adoc[]
include::{snippets}/car-controller-test/find_car_filters/http-request.adoc[]

=== Response

include::{snippets}/car-controller-test/find_car_filters/response-fields.adoc[]
include::{snippets}/car-controller-test/find_car_filters/http-response.adoc[]

== 차량에 필터를 등록한다 (/cars/{carId}/filters)

=== Request

include::{snippets}/car-controller-test/add_car_filters/request-headers.adoc[]
include::{snippets}/car-controller-test/add_car_filters/path-parameters.adoc[]
include::{snippets}/car-controller-test/add_car_filters/request-body.adoc[]
include::{snippets}/car-controller-test/add_car_filters/http-request.adoc[]

=== Response

include::{snippets}/car-controller-test/add_car_filters/response-fields.adoc[]
include::{snippets}/car-controller-test/add_car_filters/http-response.adoc[]
1 change: 1 addition & 0 deletions backend/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ endif::[]

include::station.adoc[]
include::filter.adoc[]
include::car.adoc[]
25 changes: 25 additions & 0 deletions backend/src/docs/asciidoc/member.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,28 @@ include::{snippets}/member-controller-test/add_member_filters/http-request.adoc[
include::{snippets}/member-controller-test/add_member_filters/response-fields.adoc[]
include::{snippets}/member-controller-test/add_member_filters/http-response.adoc[]

== 회원이 등록한 차량을 조회한다

=== Request

include::{snippets}/member-controller-test/find_member_car/request-headers.adoc[]
include::{snippets}/member-controller-test/find_member_car/http-request.adoc[]

=== Response

include::{snippets}/member-controller-test/find_member_car/response-fields.adoc[]
include::{snippets}/member-controller-test/find_member_car/http-response.adoc[]

== 회원이 차량을 등록한다

=== Request

include::{snippets}/member-controller-test/add_member_car/request-headers.adoc[]
include::{snippets}/member-controller-test/add_member_car/path-parameters.adoc[]
include::{snippets}/member-controller-test/add_member_car/request-fields.adoc[]
include::{snippets}/member-controller-test/add_member_car/http-request.adoc[]

=== Response

include::{snippets}/member-controller-test/add_member_car/response-fields.adoc[]
include::{snippets}/member-controller-test/add_member_car/http-response.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.carffeine.carffeine.car.controller;

import com.carffeine.carffeine.auth.controller.AuthMember;
import com.carffeine.carffeine.car.controller.dto.CarsResponse;
import com.carffeine.carffeine.car.domain.Car;
import com.carffeine.carffeine.car.service.CarService;
import com.carffeine.carffeine.car.service.dto.CarsRequest;
import com.carffeine.carffeine.filter.controller.dto.FiltersResponse;
import com.carffeine.carffeine.filter.domain.Filter;
import com.carffeine.carffeine.filter.service.dto.FiltersRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RequiredArgsConstructor
@RequestMapping("/cars")
@RestController
public class CarController {

private final CarService carService;

@GetMapping
public ResponseEntity<CarsResponse> findAllCars() {
List<Car> cars = carService.findAllCars();
return ResponseEntity.ok(CarsResponse.from(cars));
}

@PostMapping
public ResponseEntity<CarsResponse> saveAllCars(@AuthMember Long memberId,
@RequestBody CarsRequest carsRequest) {
List<Car> cars = carService.saveCars(memberId, carsRequest);
return ResponseEntity.status(HttpStatus.CREATED)
.body(CarsResponse.from(cars));
}

@DeleteMapping("/{carId}")
public ResponseEntity<Void> deleteCarById(@AuthMember Long memberId,
@PathVariable Long carId) {
carService.deleteCar(memberId, carId);
return ResponseEntity.noContent().build();
}

@GetMapping("/{carId}/filters")
public ResponseEntity<FiltersResponse> findCarFilters(@PathVariable Long carId) {
List<Filter> filters = carService.findCarFilters(carId);
return ResponseEntity.ok(FiltersResponse.from(filters));
}

@PostMapping("/{carId}/filters")
public ResponseEntity<FiltersResponse> addCarFilters(@AuthMember Long memberId,
@PathVariable Long carId,
@RequestBody FiltersRequest filtersRequest) {
List<Filter> filters = carService.addCarFilters(memberId, carId, filtersRequest);
return ResponseEntity.status(HttpStatus.CREATED)
.body(FiltersResponse.from(filters));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.carffeine.carffeine.car.controller.dto;

import com.carffeine.carffeine.car.domain.Car;

public record CarResponse(
Long carId,
String name,
String vintage
) {

public static CarResponse from(Car car) {
return new CarResponse(
car.getId(),
car.getName(),
car.getVintage()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.carffeine.carffeine.car.controller.dto;

import com.carffeine.carffeine.car.domain.Car;

import java.util.List;
import java.util.stream.Collectors;

public record CarsResponse(List<CarResponse> cars) {

public static CarsResponse from(List<Car> cars) {
return cars.stream()
.map(CarResponse::from)
.collect(Collectors.collectingAndThen(Collectors.toList(), CarsResponse::new));

}
}
45 changes: 45 additions & 0 deletions backend/src/main/java/com/carffeine/carffeine/car/domain/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.carffeine.carffeine.car.domain;

import com.carffeine.carffeine.common.domain.BaseEntity;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode(of = {"id"}, callSuper = false)
@Table(name = "car")
@Entity
public class Car extends BaseEntity {

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

@Column(nullable = false, length = 64)
private String name;

@Column(nullable = false, length = 64)
private String vintage;

private Car(String name, String vintage) {
this.name = name;
this.vintage = vintage;
}

public static Car from(String name, String vintage) {
return new Car(name, vintage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.carffeine.carffeine.car.domain;

import com.carffeine.carffeine.common.domain.BaseEntity;
import com.carffeine.carffeine.filter.domain.Filter;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode(of = {"id"}, callSuper = false)
@Table(name = "car_filter")
@Entity
public class CarFilter extends BaseEntity {

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

@ManyToOne
@JoinColumn(name = "car_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private Car car;

@ManyToOne
@JoinColumn(name = "filter_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private Filter filter;

public CarFilter(Car car, Filter filter) {
this.car = car;
this.filter = filter;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.carffeine.carffeine.car.domain;

import org.springframework.data.repository.Repository;

import java.util.List;

public interface CarFilterRepository extends Repository<CarFilter, Long> {

List<CarFilter> findAllByCar(Car car);

<S extends CarFilter> List<S> saveAll(Iterable<S> carFilters);

void deleteAllByCar(Car car);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.carffeine.carffeine.car.domain;

import org.springframework.data.repository.Repository;

import java.util.List;
import java.util.Optional;

public interface CarRepository extends Repository<Car, Long> {

Optional<Car> findById(Long carId);

Optional<Car> findByNameAndVintage(String name, String vintage);

List<Car> findAll();

boolean existsByNameAndVintage(String name, String vintage);

Car save(Car car);

void deleteById(Long id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.carffeine.carffeine.car.exception;

import com.carffeine.carffeine.common.exception.BaseException;
import com.carffeine.carffeine.common.exception.ExceptionType;

public class CarException extends BaseException {

public CarException(ExceptionType exceptionType) {
super(exceptionType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.carffeine.carffeine.car.exception;

import com.carffeine.carffeine.common.exception.ExceptionType;
import com.carffeine.carffeine.common.exception.Status;

public enum CarExceptionType implements ExceptionType {

NOT_FOUND_EXCEPTION(Status.NOT_FOUND, 5001, "해당 차량을 찾을 수 없습니다.");

private final Status status;
private final int exceptionCode;
private final String message;

CarExceptionType(Status status, int exceptionCode, String message) {
this.status = status;
this.exceptionCode = exceptionCode;
this.message = message;
}

@Override
public Status status() {
return status;
}

@Override
public int exceptionCode() {
return exceptionCode;
}

@Override
public String message() {
return message;
}
}

0 comments on commit 312ca36

Please sign in to comment.