JAVA SPRING/SpringBoot

SpringBootBoard) 점프 투 스프링부트 게시판 만들기 -3

오동순이 2023. 4. 3. 13:16

H2 x, MySQL로 연결 (application.properties 설정 , build.gradle 설정)

 

NEW Spring initializr 만들기

application.properties 설정 변경

server.port=9988

spring.datasource.url=jdbc:mysql://192.168.0.151/springbootboard_db
spring.datasource.username=root
spring.datasource.password=1234

#File Transfer Settings 파일 전송 사용 여부
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=110MB
file.image.board=/home/soribada/img

# #최종적으로 src/main/resources/templates/ 경로를 의미
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

# 보기좋게 출력 system out 으로 보기 좋게 포맷팅하기 때문에 로그가 용량을 좀 더 차지함
spring.jpa.properties.hibernate.format_sql=true

# # hibernate logging info , logger로 출력
logging.level.org.hibernate.SQL=debug

 

build.gradle 설정 변경

plugins {
	id 'java'
	id 'war'
	id 'org.springframework.boot' version '3.0.2'
	id 'io.spring.dependency-management' version '1.1.0'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-jdbc'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'com.mysql:mysql-connector-j'
	annotationProcessor 'org.projectlombok:lombok'
	providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.0'
	implementation 'org.springframework.boot:spring-boot-starter-validation'
}

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

 

Answer Entity 변경

package com.mysite.entity;

import java.time.LocalDateTime;

import jakarta.persistence.*;
import org.springframework.data.annotation.CreatedDate;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;



@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "answer")
public class Answer {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;

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

    @Column(name = "createDate")
    private LocalDateTime createDate;

    @JoinColumn(name = "questionId")
    @ManyToOne(fetch = FetchType.LAZY)
    private Question question;
}

Question Entity 변경

package com.mysite.entity;

import java.time.LocalDateTime;
import java.util.List;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;



@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "question")
public class Question {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;

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

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

    @Column(name = "createDate")
    private LocalDateTime createDate;

    @OneToMany(mappedBy = "Question")
    private List<Answer> answerList;
}

 

 

테이블 생성 Question & Answer

create table Question (
id Integer not null auto_increment	primary key,
subject varchar(255) not null,
content text null,
createDate datetime not null
);

create table Answer (
id Integer not null auto_increment	primary key,
content text null,
createDate datetime not null,
questionId Integer null
);

 

Repository 생성 _ 리포지터리

엔티티만으로는 데이터베이스에 데이터를 저장하거나 조회 할 수 없다. 데이터 처리를 위해서는 실제 데이터베이스와 연동하는 JPA 리포지터리가 필요하다.

리포지터리란?

리포지터리는 엔티티에 의해 생성된 데이터베이스 테이블에 접근하는 메서드들(예: findAll, save 등)을 사용하기 위한 인터페이스이다. 데이터 처리를 위해서는 테이블에 어떤 값을 넣거나 값을 조회하는 등의 CRUD(Create, Read, Update, Delete)가 필요하다. 이 때 이러한 CRUD를 어떻게 처리할지 정의하는 계층이 바로 리포지터리이다

 

리포지터리 생성

public interface AnswerRepository extends JpaRepository<Answer, Integer>{
    
}

public interface QuestionRepository extends JpaRepository<Question, Integer>{
    
}

 

테스트 코드 작성 실패

package com.mysite.SpringBootBoard;

import java.time.LocalDateTime;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.mysite.entity.Question;
import com.mysite.repository.QuestionRepository;

@SpringBootTest // 스프링부트 테스트 클래스
class SpringBootBoardApplicationTests {
	@Autowired QuestionRepository questionRepository; // 리포지터리와 연결 (스프링의 DI기능)

	@Test // 일단 테스트 실패
	void testJpa() {
		Question q1 = new Question();
		q1.setId(1);
		q1.setSubject("springbootboard?");
		q1.setContent("SpringBootBoard 에 내용을 입력합니다.");
		q1.setCreateDate(LocalDateTime.now());
		questionRepository.save(q1);

		Question q2 = new Question();
		q2.setSubject("스프링부트test제목입력");
		q2.setContent("ID는 자동으로 생성되나요?");
		q2.setCreateDate(LocalDateTime.now());
		this.questionRepository.save(q2);
	}

}

오류 코드

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.mysite.SpringBootBoard.SpringBootBoardApplicationTests': Unsatisfied dependency expressed through field 'questionRepository': No qualifying bean of type 'com.mysite.repository.QuestionRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

 

 

 

엔티티에 추가함

@NoArgsConstructor 파라미터가 없는 기본 생성자를 생성
@AllArgsConstructor 모든 필드 값을 파라미터로 받는 생성자를 만듦
@RequiredArgsConstructor final이나 @NonNull인 필드 값만 파라미터로 받는 생성자 만듦
@Data @Getter/ @Setter, @ToString, @EqualsAndHashCode와 @RequiredArgsConstructor
를 합친 어노테이션
@NoArgsConstructor
@RequiredArgsConstructor
@AllArgsConstructor
public class User {

  private Long id;
  
  @NonNull
  private String name;
  
  @NonNull
  private String pw;
  
  private int age;
  
}
User user1 = new User(); // @NoArgsConstructor
User user2 = new User("user2", "1234"); // @RequiredArgsConstructor
User user3 = new User(1L, "user3", "1234", null); // @AllArgsConstructor

참고 블로그

https://athena7.tistory.com/entry/Lombok-NoArgsConstructor-AllArgsConstructor-RequiredArgsConstructor

 

[Lombok] @NoArgsConstructor , @AllArgsConstructor , @RequiredArgsConstructor

@NoArgsConstructor 파라미터가 없는 기본 생성자를 생성 @AllArgsConstructor 모든 필드 값을 파라미터로 받는 생성자를 만듦 @RequiredArgsConstructor final이나 @NonNull인 필드 값만 파라미터로 받는 생성자 만듦

athena7.tistory.com

 

Lombok

lombok 프로젝트 : 자바 라이브러리로 코드 에디터나 빌드툴(InteliJ, Eclipse, Vscode 등)에 추가하여 코드를 효율적으로 작성할 수 있도록 도와준다. class명 위에 어노테이션을 명시해줌으로써 getter, setter, equals 와 같은 method를 따로 작성하는 번거로움을 줄여줌.

 

@Data

@Getter/ @Setter, @ToString, @EqualsAndHashCode와 @RequiredArgsConstructor를 합친 어노테이션

 

참고 사이트 https://projectlombok.org/features/

 

Stable

 

projectlombok.org

참고 블로그

https://zi-c.tistory.com/entry/JAVA-Lombok-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-Data

 

[JAVA] Lombok 어노테이션 @Data

Lombok이란? Lombok 프로젝트는 자바 라이브러리로 코드 에디터나 빌드 툴(IntelliJ, Eclipse, XCode 등)에 추가하여 코드를 효율적으로 작성할 수 있도록 도와준다. class명 위에 어노테이션을 명시해줌으

zi-c.tistory.com