AR삽질러

SpringBoot_Gradle_Mysql_JPA - listAPI만들기(1) 본문

JAVA/SpringBoot

SpringBoot_Gradle_Mysql_JPA - listAPI만들기(1)

아랑팡팡 2023. 5. 21. 23:49
728x90

 혼자서만 배우고 작업해봤지 협업은 처음이여서 API를 만드는데 애를 먹었다...Class명 DB명만 다르지 게시판이랑 똑같으니 보시는분들 참고하시고 도움이 되었으면 좋겠습니다!

 

RESTful API개발?

 Representational State Transfer(표현 상태 전이) 웹서비스를 구현하는 아키텍처 스타일 중 하나로 RESTful API개발은 REST 아키텍처 스타일을 따라 설계된 API를 구현하는것을 의미한다.

 1. Stateless

 - Client가 Server에 요청을 보낼때 요청에 필요한 모든 정보를 함께 보내게 되는데 서버는 각 요청에 대한 Context를 유지하거나 관리할 필요없이 상태 유지 문제를 해결할 수 있다.

 2. Uniform Interface

 - URL(Uniform Resource Identifier)로 리소스를 구분한다. HTTP Method(GET, POST, PUT, DELETE)를 이용해서 리소스에 대한 작업을 수행하고 요청과 응답메시지는 일관된 형식으로 구성한다.

 3. Cacheable

 - 캐시기능을 이용해 응답시간을 단축시키는것이 가능하다.

 4. Self-Descriptiveness

 - 요청과 응답의 내용을 이해할 수 있도록 자체적으로 설명할 수 있는 메시지를 제공해야한다.

 5. Client-Server구조

 - Server는 리소스 제공자의 역할만 수행, Client는 리소스 소비자의 역할만 수행

 - Servier - Client구조는 서로간의 의존성을 줄여 확장성과 유연성을 갖게 해준다.

 

1. 개발환경

OS : Window11

IDE : Intellij

FrameWork : SpringBoot

빌드도구 : Gradle : 2.7

Mysql : 8

JPA

 

 

2. bulid.gradle

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.11'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group =
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	developmentOnly
	runtimeClasspath {
		extendsFrom developmentOnly
	}
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'junit:junit:4.13.1'
    compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	implementation 'mysql:mysql-connector-java:8.0.33'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'


}

tasks.named('test') {
	useJUnitPlatform()
}

 

3. Controller

@RestController
@RequestMapping("/api/lectures")
public class LectureController {
	private final LectureService lectureService;

	public LectureController(LectureService lectureService) {
		this.lectureService = lectureService;
	}

	// GET /api/lectures
	@GetMapping
	public ResponseEntity<List<LectureDto>> getAllLectures() {
		List<LectureDto> lectureList = lectureService.getAllLectures();
		return ResponseEntity.ok(lectureList);
	}

@RestController

 - REST API요청을 처리한다.

 - @RestController 어노테이션이 붙은 클래스 내부에서는 웹 요청 경로와 요청방식(HTTP method)에 따라 메서드를 정의한다.

 

@RequestMapping("/api/lectures")

 - api/lectures는 /api/lectures경로로 들어오는 요청을 이 클래스가 처리한다는 것을 의미한다.

 

LectureController class

 - LectureService인스턴스를 매개변수로 받아 lectureSerice필드에 저장하여 LectureController내부에서 LectureService의 메서드를 호출할 수 있다.

  Instance(인스턴스) : class기반으로 생성된 object(객체)를 의미 = 특정 클래스의 속성과 메서드를 사용할 때 필요하며 객체를 생성하고 인스턴스로 만들어 객체의 속성들을 읽어 오거나 Method를 호출할 수 있다.

  Parameter(매개변수) : Method호출시 전달되는 값 = 객체를 생성할 때 해당 매개변수를 전달해 줄 수 있고 객체 내부에서 해당 값을 사용할 수 있다.

  Method(메소드 = 메서드) : Class내부에 있는 Function과 같은 기능으로 특정한 기능을 수행한다.

 

@GetMapping

 - HTTP GET요청을 처리하는 것을 나타내는 어노테이션으로 /api/lectures 경로로 GET요청이 들어오면 getAllLectures()메서드가 호출된다.

 

ReseponseEntity<List<LectureDto>>

 -반환할 데이터 : List<LectureDto> 타입을 나타낸다. = ResponseEntity는 응답 코드와 응답바디를 함께 전달하는데 사용되는 객체로 ok()메서드를 호출해 ResponseEntity객체를 생성하고 응답코드 200(OK)로 설정한다.

 

getAllLectures()

 - LectureService의 getAllLectures()메서드를 호출하여 모든 강의 정보를 List<LectureDto>형태로 가져와서 반환한다.

 

 

4. Entity

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Setter
@Entity
@Table(name = "lecture1")
public class LectureEntity extends TimeEntity {

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

    @Column(name = "author", nullable = false)
    private String author;

    @Column(name = "max_participants", nullable = false)
    private Integer max_participants;

    @Column(name = "category")
    private String category;

    @Column(name = "bank_name")
    private String bank_name;

    @Column(name = "account_name")
    private String account_name;

    @Column(name = "account_number")
    private String account_number;

    @Column(name = "price")
    private Integer price;

    @Column(name = "title")
    private String title;

    @Column(name = "content", columnDefinition = "TEXT")
    private String content;

    @Column(name = "start_date", columnDefinition = "datetime")
    private LocalDateTime start_date;

    @Column(name = "end_date", columnDefinition = "datetime")
    private LocalDateTime end_date;

    @Column(name = "region")
    private String region;

    @Column(name = "image_url")
    private String image_url;

    @Column(name = "created_date", columnDefinition = "datetime DEFAULT CURRENT_TIMESTAMP", nullable = false)
    @CreatedDate
    private LocalDateTime created_date;




    @Builder
    public LectureEntity(Long lecture_id, String author, Integer max_participants, String category,
                         String bank_name, String account_name, String account_number, Integer price, String title, String content,
                         LocalDateTime start_date, LocalDateTime end_date, String region, String image_url,
                         LocalDateTime created_date) {
        this.lecture_id = lecture_id;
        this.author = author;
        this.max_participants = max_participants;
        this.category = category;
        this.bank_name = bank_name;
        this.account_name = account_name;
        this.account_number = account_number;
        this.price = price;
        this.title = title;
        this.content = content;
        this.start_date = start_date;
        this.end_date = end_date;
        this.region = region;
        this.image_url = image_url;
        this.created_date = created_date;
    }
}

JPA(Java Peristence API)를 이용해 DataBase와 연동하기 위핸 Entity클래스이다.

@NoArgsConstructor(access = AccessLevel.PROTECTED)

 - 인자가 없는 생성자를 생성해 해당 생성자는 protected 접근제한자가 되어있다.

 

@Getter / @Setter 

 - 클래스내 모든 필드에 대한 Getter/Setter 메서드를 생성한다.

 

@Entity

 - JPA의 엔티티를 나타낸다.

 

@Table(name = "lecture")

 - 해당 엔티티가 매핑될 테이블명을 지정한다.

 

@Id

 - Primary Key를 나타낸다.

@GeneratedValue(strategy = GenerationType.IDENTITY)

 - Primary Key의 생성규칙

 

@Column(name = "author", nullable = false)

 - 필드에 매핑되는 컬럼 정보를 지정한다. = author컬럼 이름을 가지며 Not Null옵션이 설정되어 있다.

 

@Column(name = "content", columnDefinition = "TEXT")

 - columnDefinition을 이용하여 데이터 타입 및 길이 등을 설정할 수 있다.

 

@CreatedDate

 - create날자를 관리하기 위한 어노테이션이다.

 

public LectureEntity(Long lecture_id..........

 - 빌드메서드 배열 생성자로 @Builder어노테이션을 이용하여 생성자의 인자를 관리한다.

 

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class TimeEntity {
    @CreatedDate
    private LocalDateTime created_date;

    @LastModifiedDate
    private LocalDateTime updated_date;
}

JPA에서 제공하는 Auduting기능을 사용하기 위한 추상클래스이다.

@MappedSuperclass

 - 이 클래스를 상송하는 하위 클래스에서 매핑 정보를 상속받도록 지정한다.

 

@EntityListeners(AuditingEntityListener.class)

 - 이 엔티티에서 이벤트를 처리하기 위한 리스너를 지정한다.AuditingEntityListener.class를 지정하여 엔티티 저장시간을 자동으로 기록한다.

 

public abstract class TimeEntity

 - 클래스는 추상 클래스로 이 클래스를 상속받는 클래스에서 createDate, modifiedDate를 사용하기 위한 추상 메서드를 정의한다.

 

5. Dto

@Getter
@Setter
@ToString
@NoArgsConstructor
public class LectureDto {

    private Long lecture_id;
    private String author;
    private Integer max_participants;
    private String category;
    private String bank_name;
    private String account_name;
    private String account_number;
    private Integer price;
    private String title;
    private String content;
    @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm")
    private LocalDateTime start_date;
    @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm")
    private LocalDateTime end_date;
    private String region;
    private String image_url;

    private LocalDateTime created_date;

    public LectureEntity toEntity() {
        LectureEntity lectureEntity = LectureEntity.builder()
                .lecture_id(lecture_id)
                .author(author)
                .max_participants(max_participants)
                .category(category)
                .bank_name(bank_name)
                .account_name(account_name)
                .account_number(account_number)
                .price(price)
                .title(title)
                .content(content)
                .start_date(start_date)
                .end_date(end_date)
                .region(region)
                .image_url(image_url)
                .created_date(created_date)
                .build();
        return lectureEntity;
    }

    @Builder
    public LectureDto(Long lecture_id, String author, Integer max_participants, String category,
                      String bank_name, String account_name, String account_number, Integer price, String title, String content,
                      LocalDateTime start_date, LocalDateTime end_date, String region, String image_url,
                      LocalDateTime created_date) {
        this.lecture_id = lecture_id;
        this.author = author;
        this.max_participants = max_participants;
        this.category = category;
        this.bank_name = bank_name;
        this.account_name = account_name;
        this.account_number = account_number;
        this.price = price;
        this.title = title;
        this.content = content;
        this.start_date = start_date;
        this.end_date = end_date;
        this.region = region;
        this.image_url = image_url;
        this.created_date = created_date;
    }
}

DTO(Data Transfer Object)클래스로 Entity와 View에서 사용되는 다양한 모델간의 데이터를 변환하는 역할을 수행

@ToString

 - 클래스의 toString()메서드를 생성한다.

 

@NoArgsConstructor

 - 인자가 없는 생성자를 생성하는 어노테이션

 

LectureEntity toEntity()

 - LectureDto에서 LectureEntity로 변환하는 메소드로 Bulider패턴을 사용하는 생성자이다.

 

@DateTimeFormat(patter - "yyyy-MM-dd'T'HH:mm")

 - 문자열 형태로 받은 날짜를 LocalDateTime객체로 바꾸어준다.

 

6. Repository

public interface LectureRepository extends JpaRepository<LectureEntity, Long> {
    List<LectureEntity> findByTitleContaining(String title);
}

Spring Data JPA에서 제공하는 JpaResponsitory인터페이스를 상속하여 LectureEntity객체를 다루는 인터페이스이다.

 - extends JpaRepository<LectureEntity, Long> : JpaReposotory인터페이스를 상속해 Spring Data JPA에서 제공하는 CRUD기능을 제공하는 인터페이스이다. 이 기능을 통해 우리는 직접 구현할 필요하없다 :D

7. Service

@Service
public class LectureService {
    private final LectureRepository lectureRepository;

    public LectureService(LectureRepository lectureRepository) {
        this.lectureRepository = lectureRepository;
    }

    public List<LectureDto> getAllLectures() {
        List<LectureEntity> lectureEntities = lectureRepository.findAll();
        return lectureEntities.stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

LectureEntity를 LectureDto로 변환하고 객체들을 List로 반환하는 서비스 클래스

 

@Service

 - 클래스가 비즈니스 로직을 처리하는 Service클래스로 명시한다.

 

private final LectureRepository lectureRepository

 - LectureRepository 객체를 주입받는다.

 

 public LectureService(LectureRepository lectureRepository)

 - LectureService생성자로 DI(Dependency Injection)을 주입받는다.

 

public List<LectureDto> getAlllecture()

 - 모든 lectureEntity를 찾아 stream()메소드로 stream객체를 생성하고 map()으로 개별 Entity를 DTO로 변환후 collect()로 리스트를 리턴한다.

 

 

List<LectureEntity> lectureEntities = lectureRepository.findAll();

 - LectureEntity를 모두 찾는다.

 - List<LectureEntity>에서 Stream<LectureEntity>로 객체를 변환 후 map()을 사용해 convertToDto()메소드로 개별 객체(Entity)를 DTO로 변환후 Stream객체를 다시 리스트로 변환하여 반환한다.

 

 

---------------------------------

 

다음시간에는 postman VS Junit5 차이점과 postman사용법을 게시하겠습니다!

728x90
반응형
LIST