
이전 포스팅에서 소개한 <기능 1> 구현을 위해 JPA를 프로젝트에 연동하고 USER, SPOT, ALBUM 테이블을 만드는 작업을 진행하였다. (※ PLACE 테이블의 명칭이 SPOT으로 바뀌었다.)
이번 포스팅에서는 postgresql 연동을 위한 JPA 초기 설정에서부터 entity 객체를 만들기까지의 작업 과정에 대해 정리해보려고 한다.
먼저 build.gradle 파일에서 jpa 및 데이터베이스 연동을 위한 dependency들을 추가하였다.
*build.gradle
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.postgresql:postgresql:42.6.0'
...
}
다음으로 application.properties 파일에 JPA 및 DB 관련 프로퍼티들을 추가하였다.
*application.properties
...
#Logging
...
logging.level.org.hibernate.sql=debug
logging.level.org.hibernate.type.descriptor.sql.spi=trace
#Set Database
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://your-url
spring.datasource.username=your username
spring.datasource.password=your password
#JPA
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.database=postgresql
spring.jpa.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect
#Set Database 영역에서는 실제 데이터베이스의 접속정보를 설정해 준다.
#JPA 영역에서는 JPA 동작과 관련된 설정들을 진행해준다. merci application 프로젝트에서는 공간정보 처리를 위해 postgresql 데이터베이스를 사용할 것이므로 spring.jpa.database를 postgresql로 설정하였다.
이제 JPA 설정이 끝났다. 다음으로 entity 객체를 프로젝트 내에서 생성하고 실제 데이터를 불러오는 작업까지의 과정을 정리해보겠다.
이번 개발 과정에서 총 3개의 테이블 및 entity 객체를 만들었으나 3개 테이블에 대한 작업 과정을 모두 소개하려면 내용이 너무 길어지므로 user 테이블 작업 하나만 다루어보겠다.
User 엔티티 클래스를 다음과 같이 생성하였다.
*User.java
@Getter
@Setter
@Entity
@Table(name="user", schema="your-database-schema")
@EqualsAndHashCode(of = "userUid", callSuper=false)
@ToString
public class User {
@Id
@Column(name="user_uid")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int userUid;
@Comment("유저이름")
@Column(name="name", length = 45, nullable = false)
private String name;
@Comment("이메일")
@Column(name="email", length = 45, nullable = false)
private String email;
@Comment("유저닉네임")
@Column(name="nickname", length = 45, nullable = false)
private String nickname;
@Comment("비밀번호")
@Column(name="password", length = 255, nullable = true)
private String password;
@Lob
@Comment("자기소개")
@Column(name="intro", nullable = true)
private String intro;
@Comment("상태정보")
@Column(name="status_cd")
@ColumnDefault("0")
private int statusCd;
@Comment("등록 날짜 시간")
@CreationTimestamp
@Column(name="reg_dt")
private LocalDateTime regDt;
@Comment("업데이트 날짜 시간")
@CreationTimestamp
@Column(name="mod_dt")
private LocalDateTime modDt;
@OneToMany(mappedBy = "user")
private List<Spot> spots = new ArrayList<Spot>();
}
엔티티 클래스를 지정하기 위해서는 꼭 다음과 같이 @Entity 어노테이션을 붙여서 이 객체가 JPA에서 사용되는 엔티티 클래스라는 것을 지정해주어야 한다.
@Table(name="user", schema="your-database-schema")
Table 어노테이션에서는 name과 schema를 지정해주었는데 여기서 name은 실제 데이터베이스에서 사용되는 해당 테이블 이름을, schema는 해당 테이블이 속해 있는 schema명을 나타낸다. 따라서 만약 해당 테이블을 sql의 from 절을 통해 검색하려고 한다면 select * from your-database-schema.user와 같이 표현될 것이다.
그냥 컬럼만 지정하면 나중에 컬럼이 어떤걸 의미하는지 알아보기 힘들기 때문에 @Comment 어노테이션을 이용해서 각각의 컬럼에 대한 comment를 달아주었다.
ER 다이어그램을 확인해보면 알 수 있듯이 user 테이블과 spot 테이블은 goes라는 이름의 연관관계를 가지고 user와 spot은 일대다 관계를 가진다. User 엔티티 클래스에서 일대다 관계에 있는 Spot에 접근할 필요가 있으므로 @OneToMany 어노테이션을 이용해 spots 프로퍼티를 생성해주었다. 일대다 관계는 여러 건과 연관관계를 맺을 수 있으므로 컬렉션(List)을 사용하였고 mappedBy 속성을 이용해 반대쪽 매핑(클래스)의 필드 이름값을 지정해주었다.
이외에도 UserRepository, UserService, UserServiceImpl을 만들어 user 테이블 내 데이터들을 프로젝트 내에서 잘 불러올 수 있는지 아래와 같이 확인해보았다.
*UserRepository.java
public interface UserRepository extends JpaRepository<User, Integer> {
User findByUserUid(Integer userUid);
}
*UserServiceImpl.java
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserRepository userRepository;
@Override
public List<User> getAllUsers() {
List<User> users = userRepository.findAll();
return users;
}
}
*GisController.java (User 엔티티 동작 확인)
@Slf4j
@Controller
public class GisController {
@Autowired
private UserService userService;
@GetMapping("/gis")
public String gis(Model model) {
log.debug("gis");
List<User> users = userService.getAllUsers();
List<Spot> spots = users.get(0).getSpots();
System.out.println("spots = " + spots.get(0).getLoc());
return "gis/gis";
}
}