Coding/Back - Spring Framework

(review2) Spring 구성하기(Controller - Serivce - Repository) #Day12

꿀딴지- 2023. 9. 1. 15:13

spring으로 prj 시작 시 구성 순서

 

1. 프로젝트 생성

  • H2는 필요없으면 제거
  • Mapper 는 필요 시 추가
  • 객체를 JSON 포맷으로 변환 : Gson
  • 뷰 구현 시 타임리프 추가
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	//매퍼
	implementation 'org.mapstruct:mapstruct:1.4.2.Final'
	annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
	//Gson
	implementation 'com.google.code.gson:gson'
	//Swagger
	implementation 'io.springfox:springfox-swagger2:2.6.1'
	implementation 'io.springfox:springfox-swagger-ui:2.6.1'
	//타임리프
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

	//Spring Security
	implementation 'org.springframework.boot:spring-boot-starter-security'
	
}
spring:
  h2:
    console:
      enabled: true
      path: /h2     
  datasource:
    url: jdbc:h2:mem:test
  jpa:
    hibernate:
      ddl-auto: create  # (1) 스키마 자동 생성
    show-sql: true      # (2) SQL 쿼리 출력
		# defer-datasource-initialization: true #파일에 포함된 sql이 먼저 실행된다. ( 초기 자료 구축 )
	#OAuth2.0 연동 시 설정
	security:
	  oauth2:
	    client:
	      registration:
	        google:
	          clientId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx          
	          clientSecret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  
logging:  # (3) 로그 레벨 설정
  level:
    org:
      springframework:
        orm:
          jpa: DEBUG

server: #한글 깨져보일 경우 추가(테스트 시)
  servlet:
    encoding:
      force-response: true

 

2. 디렉토리 생성

  • 계층기반, 기능기반 가능하나 기본 디렉토리는 구성
  • controller(+dto), service(+entity), repository + exception
  • 필요 시 mapper

 

3. 클래스 생성

  • controller(~Controller) : @RestController @RequestMapping(”/”) @Validated @RequiredArgsConstructor
    • private final ~service
    • @PostmMapping @PatchMapping @GetMapping @DeleteMapping
    • 파라미터 : @RequestBody @PathVariable(”id”)
    • 유효성 검증 @Valid @Validated
    • 메서드 반환타입 : ResponseEntity
    • (~MethodDto)(3개) @Getter 각 필드별 validation
      • responseDto에 setter(혹은 buillder) 빠지면 안됨
  • service(~Service, ~ServiceImpl) : @Service
    • private final ~repository
    • 메서드 반환타입 : entity
  • entity(도메인명) : @Entity @Getter @Setter@NoArgsConstructor(access = AccessLevel.*PROTECTED*)
    • 필수 @Id @GeneratedValue(strategy = GenerationType.*IDENTITY*)
    • @Column(nullable, updatable, unique, length, name)
    • 엔티티 간 관계설정
      • 양방향일경우 메서드로 상대 객체에 값을 넣어줘야 함
      • 대소문자 구분 잘하기
    • 공통 Entity 설정(basic Entity)
      • (대상 class) @MappedSuperclass (@Getter @No~)
      • (메인) @EnableJpaAuditing
      • (extends class) @EntityListeners(AuditingEntityListener.class)
//Coffee Entity  : 1
@OneToMany(mappedBy = "coffee")
private List<OrderCoffee> orderCoffees = new ArrayList<>();

public void addOrderCoffee(OrderCoffee orderCoffee) {
    this.orderCoffees.add(orderCoffee);
    if (orderCoffee.getCoffee() != this) {
        orderCoffee.addCoffee(this);
    }
}

//OrderCoffee Entity : N
@ManyToOne
@JoinColumn(name = "COFFEE_ID")
private Coffee coffee;
public void addCoffee(Coffee coffee) {
    this.coffee = coffee;
    if (!this.coffee.getOrderCoffees().contains(this)) {
        this.coffee.addOrderCoffee(this);
    }
}

@ManyToOne
@JoinColumn(name = "ORDER_ID")
private Order order;
public void addOrder(Order order) {
    this.order = order;
    if (!this.order.getOrderCoffees().contains(this)) {
        this.order.getOrderCoffees().add(this);
    }
}

//Order Entity : 1
@OneToMany(mappedBy = "order", cascade = CascadeType.PERSIST)
private List<OrderCoffee> orderCoffees = new ArrayList<>();
public void addOrderCoffee(OrderCoffee orderCoffee) {
    this.orderCoffees.add(orderCoffee);
    if (orderCoffee.getOrder() != this) {
        orderCoffee.addOrder(this);
    }
}
  • mapper(~Mapper : interface) : @Mapper(componentModel = “spring”)
  • repository(~Repository : interface) : extends JpaRepository<entity, PKtype>
  • exception @RestControllerAdvice
    • @ExceptionHandler

 

4. 비즈니스 로직 작성 : 엔티티

4-1. 공통 엔티티 분리

  • @Getter @NoArgsConstructor(access = AccessLevel.*PROTECTED*) @MappedSuperclass

4-2. Validation설정 : dto, entity 클래스

4-3. 엔티티 연관관계 생성

  • @ManyToOne@JoinColumn(name = "MEMBER_ID")
  • @OneToMany(mappedBy = "member", cascade ={CascadeType.*PERSIST*, CascadeType.*REMOVE*})

공통엔티티 MappedSuperclass

@EnableJpaAuditing

@EntityListeners(AuditingEntityListener.class)

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@MappedSuperclass
public class BasicEntity {
    
    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdAt;
    
    @LastModifiedDate
    private LocalDateTime  updatedAt;
}

 

5. Service 클래스 작성

6. 예외 작성