본문 바로가기

🧑🏻‍💻 Dev/SpringBoot

[SpringBoot] Annotation(@) 기능 정리

스프링부트로 웹 서비스 출시하기 1, 2, 3편을 보면서 실습하고 정리해둔 내용 입니다. 틀린 내용이 있다면 피드백 주시면 감사할 거 같습니다. 🙂

 

3번째 글까지 모두 완주했고, SpringBoot는 2.7.7 버전을 사용해서 진행했습니다. 자세한 소스코드는 깃허브 주소에 가시면 볼 수 있습니다.

 

📘 JPA/Javax 에서 제공하는 Annotation

@Entity

  • 데이터베이스 테이블과 연결되는 객체임을 나타내줍니다. 테이블의 이름은 ‘_’ 언더바를 이용하여 매칭합니다.
  • 예를 들어 파일이름이 MyPage.java라면 테이블 이름은 my_page로 매핑됩니다.

 

@Id

  • 해당 테이블의 primary key임을 나타냅니다.

 

@GeneratedValue

  • PK 생성 규칙을 결정할 수 있습니다. springboot 2.0 버전 이전에는 기본 값이 Auto로 설정되어 있지만 그 이후로는 직접 옵션을 추가해줘야 합니다.
  • 여기서 Auto란 데이터가 생성될 때마다 1씩 자동으로 증가하는 것을 의미합니다.
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    저는 springboot 2.7 버전을 사용하기 때문에 직접 IDENTITY 옵션을 추가해줬습니다.

 

@Column

  • Entity 객체 안에 정의되는 변수들은 모두 데이터베이스의 컬럼이 됩니다. Column 어노테이션을 쓰는 이유는 기본값 외에 옵션을 추가하고 싶을 때 사용합니다.
  • VARCHAR의 경우 기본값이 255인데 만약 500으로 늘리고 싶거나, TEXT 타입으로 컬럼을 사용하고 싶을 때 사용합니다.
    @Column(length = 500, nullable = false)
    private String title;
    
    @Column(columnDefinition = "TEXT", nullable = false)
    private String content;

 

@MappedSuperclass

  • 만약 JPA의 Entity 클래스가 MappedSuperclass로 선언된 추상 클래스를 상속받을 경우 createdTime와 modifiedTime도 Entity의 컬럼으로 인식하도록 합니다.
    @MappedSuperclass
    @EntityListeners(AuditingEntityListener.class)
    public abstract class BaseTimeEntity {
        @CreatedDate
        private LocalDateTime createdTime;
    
        @LastModifiedDate
        private LocalDateTime modifiedTime;
    }

 

@EntityListeners(AuditingEntityListener.class)

  • 해당 클래스에 Auditing 기능을 포함시킵니다.

 

@CreatedDate

  • Entity가 생성될 때의 시간을 자동으로 저장합니다.

 

@LastModifiedDate

  • 조회한 Entity의 값을 변경했을 때의 시간을 저장합니다.

 

@EnableJpaAuditing

  • main 메서드가 있는 객체에서 Jpa의 Auditing 기능을 사용할 수 있게 해줍니다.
    @EnableJpaAuditing
    @SpringBootApplication
    public class SpringWebApplication {
    	public static void main(String[] args) {
    		SpringApplication.run(SpringWebApplication.class, args);
    	}
    }

 

@Transactional

  • Service 로직을 구성할 때 반드시 따라오는 어노테이션 중에 하나입니다.
  • 메서드 하나를 하나의 트랜잭션으로 하겠다는 것을 의미합니다. 여기서 하나의 트랜잭션이란 만약 save()라는 메서드에서 10개의 데이터를 저장해야 되는데, 6개를 저장하고 오류가 발생했다면 해당 데이터는 저장하지 않고 모두 rollback 시키는 것을 의미합니다.
    @Transactional
    public Long save(PostsSaveRequestDto dto){
        return postsRepository.save(dto.toEntity()).getId();
    }

 

 

📘 Lombok 라이브러리의 Annotation

 

@NoArgsConstructor

  • 기본 생성자를 자동으로 추가해줍니다.
  • 사용하는 이유는 프로젝트 코드 상에서는 Entity 객체를 기본 생성자로 생성하는 것을 막되, JPA에서 Entity 객체를 생성하는 것은 허용하기 위해서 추가해줍니다.
  • access = AccessLevel.PROTECTED 옵션을 추가해주면 기본 생성자가 protected로 생성됩니다.

 

@AllArgsConstructor

  • 해당 클래스 내에 있는 모든 필드를 인자 값으로 하는 생성자를 만들어줍니다.

 

@Getter

  • 클래스 내에 있는 모든 필드의 getter 메서드를 생성해줍니다.

 

@Setter

  • 클래스 내에 있는 모든 필드의 setter 메서드를 생성해줍니다.
  • Entity 객체에서는 setter는 잘 사용하지 않는다고 했지만, DTO와 같은 경우에는 setter를 사용합니다.
    • @RequestBody를 통해서 외부로 부터 데이터를 받는 경우에는 기본생성자 + setter를 통해서만 값이 할당되기 때문에 이때는 setter를 허용합니다.

 

@Builder

  • 해당 클래스의 빌더 패턴 클래스를 생성합니다.
  • 생성자 상단에 선언할 경우 생성자에 포함되어 있는 필드만 빌더에 포함됩니다.
    @Builder
    public Posts(String title, String content, String author) {
        this.title = title;
        this.content = content;
        this.author = author;
    }

 

 

📘 Springboot/SpringFramework Annotation

 

@SpringBootTest

  • 통합 테스트를 기본으로 제공하는 어노테이션입니다.
  • Junit4를 사용할 때는 @RunWith(SpringRunner.class) 또는 @ExtendWith(SpringExtension.class과 같은 어노테이션을 추가해줘야 한다.
  • Junit5를 사용할 때는 별도로 추가해주지 않아도 된다.

 

@Controller

  • View를 반환하기 위해서 사용합니다. 여기서 말하는 View는 html과 같은 랜더링되는 파일을 의미합니다.
  • 만약 JSON 형태의 데이터를 반환하고 싶다면 @ResponseBody와 함께 사용해야 합니다.

 

@RestController

  • @Controller에 @ResponseBody를 더한 기능을 합니다. 즉, JSON 형태로 객체의 데이터를 반환합니다.
  • view를 반환하는 Controller와 JSON 형태의 데이터를 반환하는 RestController는 분리하여 사용하는 것이 좋습니다.

 

 

👨🏻‍💻 알아두면 좋을 지식들

1. 스프링 프레임워크에서 Bean을 주입(의존성 주입)받는 방식

  • 생성자를 통한 주입 (권장하는 방식)
    • 대부분의 의존 관계는 Application이 끝나기 전까지 변경될 일이 없기 때문에 생성자를 통한 의존성 주입 방법이 가장 권장되는 방법입니다.
    • 생성자를 자동으로 생성해주는 @AllArgsConstructor 또는 @RequiredArgsConstructor 어노테이션을 사용하면 생성자로 Bean을 주입받을 수 있다. 대신 Lombok을 사용해야하는 번거로움이 있지만, 코드 수정 시 필드가 추가되면 생성자에 일일히 코드를 추가시켜주는 번거로움을 없앨 수 있음.
    • Lombok을 사용하지 않는다면 생성자 위에 @Autowired 어노테이션을 선언하여 의존성을 주입할 수 있습니다. 만약 생성자가 하나밖에 없는 객체라면 굳이 @Autowired를 써주지 않아도 자동으로 주입이 됩니다.
  • setter 메서드를 통한 주입
    • setter 메서드 위에 @Autowired 어노테이션을 선언해주면 됩니다.
  • 필드(변수)를 통한 주입 (권장하지 않는 방식)
    • 필드에 직접 @Autowired를 선언하여 의존성을 주입하는 방법으로 실제 코드에서는 사용하지 않는 것이 좋습니다.
  • 일반 메서드를 통한 주입
    • 필드 여러 개에 동시에 의존성을 주입해줄 수 있지만 일반적으로 많이 사용되는 방법이 아닙니다.

 

2. DTO 객체를 따로 사용하는 이유

  • Entity 객체는 DB에 직관적으로 연결되어있는 객체이기 때문에 Entity를 건드리는 것은 위험이 있다.
  • 즉, DB를 위한 Layer와 View를 위한 Layer를 철저하게 구분하기 위헤서 DTO를 사용한다.
    • DB Layer는 Entity 객체에서 관리하고, View Layer는 DTO 객체에서 관리한다.

 

3. JPA Auditing을 사용하여 생성/수정 시간 자동화

  • 새로운 추상 클래스를 만들어서 Entity의 생성, 수정 시간을 자동적으로 저장할 수 있다.
  • LocalDateTime 클래스로 필드들을 선언하고, @MappedSuperclass와 @EntityListeners(AuditingEntityListener.class)를 사용하면 간단하게 기능을 생성할 수 있다.