카테고리 없음

스프링 일기 11 - JPA(3) Create

들쮜 2023. 6. 16. 00:10

데이터베이스의 기본 CRUD를 JPA를 이용해서 해보도록 하겠습니다.

 

1. CREATE

 

스프링에서 EntityManager를 이용해서 .persist를 이용해서 create를 할 수도 있지만, JpaRepository 클래스를 위해 좀 더 간편하게 Create를 실행할 수도 있습니다.

 

package com.example.demo.Entity;

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

import javax.persistence.*;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name", nullable = false, length = 100)
    private String name;
    
	@Column(name = "email", unique = true)
    private String email;

    @Transient
    private String password;

    public User() {};
    public User(Long id, String name, String email, String password) {
		super();
		this.id = id;
		this.name = name;
		this.email = email;
		this.password = password;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}



    // getters and setters
}

DTO를 만들어줍니다.

 

그리고 이제 값을 맵핑을 해줄 Repository를 만들어줍니다.

 

package com.example.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.demo.Entity.User;

public interface UserRepository extends JpaRepository<User, Long> {
}

JpaRepository가 얼마나 간편한지 한번 사용해보도록 합시다.

 

마지막으로 Repository를 구현해서 사용할 Service를 하나 만들어줍니다.

package com.example.demo.service;



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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.demo.Entity.User;
import com.example.demo.repository.UserRepository;

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }


    public List<User> getAllUsers() {
        return userRepository.findAll();
    }


    public Optional<User> getUserById(Long id) {
        return userRepository.findById(id);
    }

    public User createOrUpdateUser(User user) {
        return userRepository.save(user);
    }


    public void deleteUserById(Long id) {
        userRepository.deleteById(id);
    }
}

 

여기서 UserRepository는 인터페이스인데 어떻게 저렇게 의존성 주입이 가능한것인가? 의문이 들 수 있습니다.

 

Interface를 우리는 바로 사용할 수 없고 반드시 구현을 해서 사용해야 한다고 알고있기 때문이죠.

 

하지만 스프링 부트는 자동으로 컴포넌트 스캔을 진행하여 해당 인터페이스를 알아서 구현해줍니다.

 

JpaRepository를 상속받고 있는데 해당 객체가 가지고 있는 메서드들은 내부적으로 알아서 잘 구현을 해줄 것 같은데, 우리가 만드는 필드값은 어떻게 가지고 올 지 감이 안 잡힐 수 있습니다. 

 

Id야 기본적으로 모든 레코드에 있는 것이니 그렇다 쳐도 필드명은 천차만별이기 때문이죠.

 

Spring Data JPA에서 메서드의 이름 규칙을 분석하여 동적 쿼리를 생성하는 방법은 다양합니다. 일반적으로 메서드의 이름에 사용되는 키워드들을 분석하여 해당하는 쿼리 조건을 자동으로 생성합니다. 예를 들어, findBy, findDistinctBy, findByOrderBy, findTopBy 등의 키워드를 이용하여 메서드의 이름을 작성하면, Spring Data JPA는 이를 분석하여 자동으로 조건을 생성하고 적절한 쿼리를 실행합니다.

 

와... 굉장합니다. 메서드의 이름 규칙을 이용하여 자동으로 분석해준다니...

 

JpaRepository를 상속받은 이 interface의 구현체는 bean으로 등록이 되어있기 때문에, Autowired로 의존성 주입이 가능해집니다. Autowired를 생성자에 붙여 생성자주입을 해주도록 합시다.

 

자 그럼 이렇게 Service도 만들어봤으니 사용해봐야할텐데요

 

Controller를 이용해서 실행 시킬 수도 있겠지만 간단하게 확인을 하기 위해 Service 객체를 만들어서 해보도록 하겠습니다.

 

이렇게 만들어진 Bean을 가져오는 방법 기억이 나시나요?

 

getBean으로 가져올 수 있었습니다. ApplicationContext와 GenericApplicationContext("xml이름") 이런식으로 가져왔던게 기억이 나실텐데요

 

우리는 Bean을 직접 지정해주지 않고 Spring Boot에게 어노테이션을 통해 만들어달라고 대신 부탁하였습니다.

 

그럼 context를 어디서 가져와야할까요?

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}

프로젝트를 만들면 기본으로 생성되는 SpringBootApplication 어노테이션이 붙은 이 객체를 봅시다.

 

Application? ApplicationContext ? 뭔가 context 느낌이 확 오지 않습니까?

 

run 메소드를 보니 context를 return한다고 쓰여져있습니다.

 

그럼 이런식으로 작성할 수 있겠네요.

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

import com.example.demo.service.UserService;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
		
		UserService userService = context.getBean(UserService.class);
	}

}

이렇게 우리는 bean을 가지고 올 수 있게 되었습니다. 그럼 이 서비스 객체를 이용해 CRUD를 실습해봅시다.

 

일단 DTO를 만들어주고 @Entity를 이용하면 자동으로 테이블이 생성되는건 확인할 수 있었습니다.

 

레코드를 INSERT하는 것부터 해보도록 하겠습니다.

 

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

import com.example.demo.Entity.User;
import com.example.demo.service.UserService;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
		
		UserService userService = context.getBean(UserService.class);
		
		User user = new User();
		user.setName("duljji");
		user.setPassword("1234");
		user.setEmail("duljjii@naver.com");
		
		// 1. C
		userService.createOrUpdateUser(user);
		
		
		
	}

}

그런데 문제가 생겼습니다.

 

run을 실행시키니 그 이후의 문장이 실행이 되질 않습니다. 다른 방법을 찾아봐야할 것 같습니다

 

간단하게 테스트를 해보려고 했는데 더 복잡해지는 것 같습니다....

 

Bean으로 관리되는 Service를 굳이 new를 만들면, 의존성 Repository 의존성 주입을 해주어야 하는데 그럼 그걸 또 

 

아이고.. IoC의 소중함만 느끼게 돼버렸습니다. 

 

Controller를 만드는게 나을 것 같습니다 Controller를 만들겠습니다.

package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import com.example.demo.Entity.User;
import com.example.demo.service.UserService;


@Controller
public class UserController {
	private UserService userService;
	
	@Autowired
	public UserController(UserService userService) {
		this.userService = userService;
	};
	
	@GetMapping("/")
	public String test() {
		User user = new User();
		user.setEmail("duljjii@naver.com");
		user.setName("duljji");
		user.setPassword("1234");
		userService.createOrUpdateUser(user);
		System.out.println(userService.getAllUsers());
		return "home";
	}
	
	
}

이제 해당 url로 접근하면 Service 객체가 reposiotry의 save를 실행시키겠죠.

 

해당 User가 잘 들어갔는지 확인해봅시다.

 

 

잘 들어간 것을 확인 할 수 있습니다.