이번 포스팅에서는 스프링 부트(Spring Boot )와 스프링 시큐리티(Spring Security)를 활용해서 Spring Polling App을 만들어 보도록 하겠습니다!
(원본글은 https://www.callicoder.com/spring-boot-spring-security-jwt-mysql-react-app-part-1/)
데이터베이스로는 MySQL를 사용 할 것이고, 프론트엔드로는 React를 사용 해 보겠습니다.
본 포스팅의 코드는 Github 에 업로드 되어있습니다.
스프링 부트를 사용해 백엔드 어플리케이션 생성하기
우선 프로젝트 이름과, pom.xml을 starter를 통해 생성 해 주도록 하겠습니다.
프로젝트 구조는 위와 같습니다.
프로젝트 이름 : woolbro_polling
프로젝트 기본 패키지 : com.woolbro
pom.xml dependency : DevTools, Lombok, Spring Data JPA, Spring Security, Spring Web Starter, Spring Web Services, MySQL
그리고, 아래의 항목들을 pom.xml에 추가로 넣어 준 후에, Maven Update - Build 를 하겠습니다.
<!-- For Working with Json Web Tokens (JWT) -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- For Java 8 Date/Time Support -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
application.properties 설정
src/main/resource의 applicatio.properties 에 설정을 추가 해 주 도록 하겠습니다.
server.port를 통해서 서버 포트를 바꿔 줄 수 있습니다. default 는 8080이지만, 이번 포스팅에서는 괜히 8000으로 한번 바꿔주겠습니다 ㅋㅋㅋ
데이터베이스는 위에서 말씀드렸듯이 MySQL을 사용 할 것이구요, 접속을 위해 id와 pw를 적어줍니다.
## Server Properties
server.port= 8000
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url= jdbc:mysql://localhost:3306/polling_app?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username= root
spring.datasource.password= 1234
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto = update
## Hibernate Logging
logging.level.org.hibernate.SQL= DEBUG
# Initialize the datasource with available DDL and DML scripts
spring.datasource.initialization-mode=always
## Jackson Properties
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS= false
spring.jackson.time-zone= UTC
위에 잘 보시면
spring.jpa.hibernate.ddl-auto = update
라는 옵션이 있는데, 응용 프로그램의 엔티티에 따라 데이터베이스의 테이블이 자동으로 작성 / 업데이트 되는 옵션입니다.
WoolbroPollingApplication 설정하기 - JAVA 8 날짜 / 시간 변환기 및 UTC 사용하기
본 포스팅에서는 도메인 모델에서 Java 8 Data / Time 클래스를 사용하려고 합니다. JPA 2.1 변환기를 등록하면 도메인 모델의 모든 Java 8 Date / Time 필드가 데이터베이스에 유지 될 때 자동으로 SQL 형식으로 변환됩니다. 또한 응용 프로그램의 기본 시간대를 UTC로 설정합니다.
WoolbroPollingApplication.java (기본으로 만들어지는 최초의 파일)을 수정 해보도록 하겠습니다.
package com.woolbro;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.PostConstruct;
import java.util.TimeZone;
@SpringBootApplication
@EntityScan(basePackageClasses = { WoolbroPollingApplication.class, Jsr310JpaConverters.class })
public class WoolbroPollingApplication {
@PostConstruct
void init() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
public static void main(String[] args) {
SpringApplication.run(WoolbroPollingApplication.class, args);
}
}
이제 설정을 모두 마쳤으니, 모델을 추가 해 보도록 하겠습니다.
추가 할 모델은 User, Role 을 추가 하고, UserRepository, RoleRpository 까지 추가 해 주도록 하겠습니다.
추가 할 프로젝트 파일 구조
User.java
이 User모델에는 다음 필드가 포함되어 있습니다.
- id: 아이디
- username:사용자 이름
- email: 이메일
- password: 암호로 암호화 된 형식으로 저장됩니다.
- roles: role. ( Role엔티티 와 다 대 다 관계 )
package com.woolbro.model;
import org.hibernate.annotations.NaturalId;
import com.woolbro.model.audit.DateAudit;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "users", uniqueConstraints = { @UniqueConstraint(columnNames = { "username" }),
@UniqueConstraint(columnNames = { "email" }) })
public class User extends DateAudit {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@Size(max = 40)
private String name;
@NotBlank
@Size(max = 15)
private String username;
@NaturalId
@NotBlank
@Size(max = 40)
@Email
private String email;
@NotBlank
@Size(max = 100)
private String password;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles = new HashSet<>();
public User() {
}
public User(String name, String username, String email, String password) {
this.name = name;
this.username = username;
this.email = email;
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
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;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
여기서 작성한 User클래스는 DateAudit을 extends로 가지고 있는데, 이 DateAudit 클래스는 데이터의 Create,Update를 감시하고 이벤트를 감지하기 위해 작성 해 줄 클래스입니다.
DateAudit.java
DateAudit 모델을 정의 해 보겠습니다. createdAt 및 updatedAt 필드가 있습니다. 이러한 감시 필드가 필요한 다른 도메인 모델은 지금 작성한 DateAudit 클래스를 extends로 가지면 됩니다.
엔터티를 유지할 때 JPA의 AuditingEntityListener를 사용하여 createdAt 및 updatedAt 값을 자동으로 채 웁니다.
다음은 DateAudit.java 클래스입니다.
package com.woolbro.model.audit;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.time.Instant;
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(
value = {"createdAt", "updatedAt"},
allowGetters = true
)
public abstract class DateAudit implements Serializable {
@CreatedDate
@Column(nullable = false, updatable = false)
private Instant createdAt;
@LastModifiedDate
@Column(nullable = false)
private Instant updatedAt;
public Instant getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Instant createdAt) {
this.createdAt = createdAt;
}
public Instant getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Instant updatedAt) {
this.updatedAt = updatedAt;
}
}
AuditingConfig.java
JPA 감사를 사용하려면 @EnableJpaAuditing 주석을 주 클래스 나 다른 구성 클래스에 추가해야합니다.
AuditingConfig 구성 클래스를 만들고 @EnableJpaAuditing 주석을 추가하겠습니다.
나중에 감사 관련 설정을 추가 할 수 있게 별도의 클래스를 만들어 작성 해 주도록 하겠습니다.
모든 구성 클래스는 config라는 패키지 안에 보관할 것입니다. com.woolbro에 config 패키지를 만든 다음 config 패키지 내에 AuditingConfig 클래스를 만듭니다.
package com.woolbro.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@Configuration
@EnableJpaAuditing
public class AuditingConfig {
// 우선 추가 먼저 해주고, 이후에 작성 하도록 하겠습니다.
}
Role.java
다음은 Role관련 모델을 작성 하도록 하겠습니다.
작성한 Role 은 RoleName.java의 enum을 참조하도록 작성하겠습니다.
package com.woolbro.model;
import org.hibernate.annotations.NaturalId;
import javax.persistence.*;
@Entity
@Table(name = "roles")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(EnumType.STRING)
@NaturalId
@Column(length = 60)
private RoleName name;
public Role() {
}
public Role(RoleName name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public RoleName getName() {
return name;
}
public void setName(RoleName name) {
this.name = name;
}
}
RoleName.java (ENUM)
package com.woolbro.model;
public enum RoleName {
ROLE_USER,
ROLE_ADMIN
}
DB의 role에 ROLE_USER, ROLE_ADMIN을 생성 해 주도록 하겠습니다 :)
INSERT IGNORE INTO polling_app.roles(name) VALUES('ROLE_USER')
INSERT IGNORE INTO polling_app.roles(name) VALUES('ROLE_ADMIN')
User, Role 데이터에 접근하기위한 Repository 작성
UserRepository.java
package com.woolbro.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.woolbro.model.User;
import java.util.List;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
Optional<User> findByUsernameOrEmail(String username, String email);
List<User> findByIdIn(List<Long> userIds);
Optional<User> findByUsername(String username);
Boolean existsByUsername(String username);
Boolean existsByEmail(String email);
}
RoleRepository.java
package com.woolbro.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.woolbro.model.Role;
import com.woolbro.model.RoleName;
import java.util.Optional;
@Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
Optional<Role> findByName(RoleName roleName);
}
기본적인 모델을 작성 했으니, 이제 실행을 해서 정상적으로 작동하는지 확인 해야겠죠~?
SpringBoot App으로 실행 시켜주시고, console창에 아무런 에러없이 아래와같이 실행이 된다면, Database 설정과 Model 작성이 잘 이루어진 것으로 볼 수 있습니다.
'Old Branch' 카테고리의 다른 글
스프링 부트(Spring Boot)와 Security, MySQL, React를 사용한 Spring Polling App(3) (0) | 2019.07.18 |
---|---|
스프링 부트(Spring Boot)와 Security, MySQL, React를 사용한 Spring Polling App (2) (2) | 2019.07.18 |
Spring MVC 예제 - @RequestMapping 어노테이션 예제 (0) | 2019.07.16 |
Spring MVC 예제 - 직원 관리 프로그램 (2) | 2019.07.15 |
Spring Project 스프링 프로젝트 시작하기 - Spring Boot JPA (0) | 2019.07.13 |