일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- ffmpeg
- 국비 지원
- 스프링
- 리엑트
- Java
- 자바
- 프론트엔드
- 클론코딩
- 비전공자
- 프론트 엔드
- 비전공
- spring boot
- 코딩
- 풀스택
- 스타트업
- 개발자
- Redux
- 백엔드
- react-native
- 상태관리
- expo
- 인스타그램
- react native
- 개발
- 스프링 부트
- Spring
- 리엑트 네이티브
- react
- 풀스택 개발자
- 국비지원
- Today
- Total
오티스의개발일기
[SPRING BOOT + REACT-NATIVE] (8) jpaQueryFactory 와 queryDsl 를 사용하여 이메일 중복확인 기능 만들기 -git 첨부 - 본문
[SPRING BOOT + REACT-NATIVE] (8) jpaQueryFactory 와 queryDsl 를 사용하여 이메일 중복확인 기능 만들기 -git 첨부 -
안되면 될때까지.. 2022. 12. 29. 17:31
< 이전글
2022.12.29 - [개발/spring boot] - [SPRING BOOT + REACT-NATIVE] jpaRepository 를 사용하여 유저 데이터베이스에 저장하기
다음글 >
이번시간에는 저번 포스팅에이어
유저 아이디 중복확인 하는 기능을
JpaQueryFactory 를 사용하여 구현해보겠다.
일단 JpaQueryFactory 를 사용하기위해선 디펜던시와 configuration 설정을 해줘야한다
오늘 다룰 파일들 목록을 나열해보겠다.
1. build.gradle : 쿼리 dsl 을 사용하기위한 디펜던시 추가
2. QuerydslConfiguration : 쿼리dsl 설정파일
3. UserRepositorySupport : jpaRepositroy 처럼 querydslRepositorySupport 를 extends 한 파일
4. UserService : 비지니스 로직을 처리할 파일
5. UserController : 컨트롤러
시작해보겠다
# 0. 폴더 구조
# 1 . build.gradle 디펜던시 및 설정
dsl 관련 주석을 확인하면된다 하나도 빠짐없이 기입하자
buildscript { // <-- query dsl
ext {
queryDslVersion = "5.0.0"
}
}
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.7' // < ------- 스프링 부트 버전
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10" // <-- query dsl
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11' // <------- java 11
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("io.springfox:springfox-boot-starter:3.0.0") // <--------- spring boot starter
implementation("io.springfox:springfox-swagger-ui:3.0.0") // <--------- 스웨거 ui
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" // <-- query dsl
implementation "com.querydsl:querydsl-apt:${queryDslVersion}" // <-- query dsl
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
//querydsl 추가 시작
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main.java.srcDir querydslDir
}
compileQuerydsl{
options.annotationProcessorPath = configurations.querydsl
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
querydsl.extendsFrom compileClasspath
}
//querydsl 추가 끝
# 2 . QuerydslConfiguration 설정
package com.example.backend.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Configuration
@EnableJpaAuditing
public class QuerydslConfiguration {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
EntityManger 를 JPAQueryFactory 에 등록후 Bean 에 등록해야 동작한다.
# 2 . UserRepositorySupport 생성
package com.example.backend.repository.user;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
@Repository
public class UserRepositorySupport extends QuerydslRepositorySupport {
}
여기까지 작성하고 나면
이렇게 뜰것이다.
create 를 클릭하고 부모에있는 메서드를 상속시켜주자
package com.example.backend.repository.user;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
@Repository
public class UserRepositorySupport extends QuerydslRepositorySupport {
/**
* Creates a new {@link QuerydslRepositorySupport} instance for the given domain type.
*
* @param domainClass must not be {@literal null}.
*/
public UserRepositorySupport(Class<?> domainClass) {
super(domainClass);
}
}
그러면 이런식으로 생성될것이다 이제 아래부터 우리가 커스터마이징 해줄것이니 집중하자
*중요*
package com.example.backend.repository.user;
import com.example.backend.domain.User;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
@Repository
public class UserRepositorySupport extends QuerydslRepositorySupport {
private final JPAQueryFactory jpaQueryFactory;
/**
* Creates a new {@link QuerydslRepositorySupport} instance for the given domain type.
*
* @param jpaQueryFactory
*/
public UserRepositorySupport(JPAQueryFactory jpaQueryFactory) {
super(User.class);
this.jpaQueryFactory = jpaQueryFactory;
}
}
이런식으로 매게변수로 클래스를 따로받지않고 도메인(= 엔티티) 마다 각각의 repositorySupport 를 생성해줄것이기 때문에
그냥 super 안에 원하는 엔티티의 클래스를 적어주자
자이제 쿼리문을 작성해줄건데 그전에 추가해야할것과 확인해야 할것이있다
우리는 이제 QUser.user 를 임포트 해줄것이다 이클래스는 dslQuery에서 자동으로 생성하는데 이미 우리가 build.gradle 에 설정을 해놓았다.
이부분이다 dsl이 자동으로 Q클래스를 만들어주고 우리는 사용하기만 하면된다.
이제 email 중복확인 쿼리문을 만들어보자
아 쿼리문을 만들기전에 서버를 한번 재시작을 해줘야 Q클래스가 생성되니 주의 바란다.
# 2 . UserRepositorySupport 아이디 중복확인 쿼리 생성
package com.example.backend.repository.user;
import com.example.backend.domain.User;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
import static com.example.backend.domain.QUser.user;
@Repository
public class UserRepositorySupport extends QuerydslRepositorySupport {
private final JPAQueryFactory jpaQueryFactory;
/**
* Creates a new {@link QuerydslRepositorySupport} instance for the given domain type.
*
* @param jpaQueryFactory
*/
public UserRepositorySupport(JPAQueryFactory jpaQueryFactory) {
super(User.class);
this.jpaQueryFactory = jpaQueryFactory;
}
public User userEmailDoubleCheck (String email) {
return jpaQueryFactory.select(user)
.from(user)
.where(user.email.eq(email))
.fetchOne();
}
}
자 이제 쿼리문을 만들었으니 서비스와 컨트롤러에 등록하고 기능확인을 해보자
# 3 . UserService 아이디 중복확인 로직 처리
package com.example.backend.service;
import com.example.backend.common.exception.CustomApiException;
import com.example.backend.domain.User;
import com.example.backend.dto.user.request.RequestUserEmailDoubleCheckDto;
import com.example.backend.dto.user.request.RequestUserRegisterDto;
import com.example.backend.repository.user.UserRepository;
import com.example.backend.repository.user.UserRepositorySupport;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final UserRepositorySupport userRepositorySupport;
@Transactional(readOnly = false)
public void register (RequestUserRegisterDto requestUserRegisterDto) {
User user = requestUserRegisterDto.toEntity();
userRepository.save(user);
}
@Transactional(readOnly = true)
public Boolean userEmailDoubleCheck (RequestUserEmailDoubleCheckDto requestUserRegisterDto) {
User user = userRepositorySupport.userEmailDoubleCheck(requestUserRegisterDto.getEmail());
if (user != null) {
throw new CustomApiException("이미 사용중인 아이디 입니다.", HttpStatus.BAD_REQUEST);
} else {
return true;
}
}
}
같은 이메일의 유저가있으면 이전에 만든 CustomApiException 을 호출해 사용자에게 전달한다.
이제 파라미터로 받을 Dto 생성후 컨트롤러에 적용해보자
# 3 . RequestUserEmailDoubleCheckDto 생성
package com.example.backend.dto.user.request;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
@Data
public class RequestUserEmailDoubleCheckDto {
@NotBlank(message = "이메일을 입력해주세요")
@Email(message = "정확한 이메일을 입력해주세요")
private String email;
}
이곳에서도 이메일형식인지 확인하고 정확한 이메일이 아니라면 예외처리를 할것이다.
# 3 . UserController 적용
package com.example.backend.controller;
import com.example.backend.common.exception.CustomApiException;
import com.example.backend.dto.CMRespDto;
import com.example.backend.dto.user.request.RequestUserEmailDoubleCheckDto;
import com.example.backend.dto.user.request.RequestUserRegisterDto;
import com.example.backend.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.Email;
@RestController
@RequiredArgsConstructor
@CrossOrigin(origins = {"*"})
@RequestMapping("/api/user")
public class UserController {
private final UserService userService;
@PostMapping("/register")
public CMRespDto<?> register (@Valid @RequestBody RequestUserRegisterDto requestUserRegisterDto) {
userService.register(requestUserRegisterDto);
return new CMRespDto<>(200, "회원 가입 완료", requestUserRegisterDto);
}
@PostMapping("/userEmailDoubleCheck")
public CMRespDto<?> userEmailDoubleCheck (@Valid @RequestBody RequestUserEmailDoubleCheckDto requestUserRegisterDto) {
return new CMRespDto<>(200, "사용 가능한 이메일 입니다.", userService.userEmailDoubleCheck(requestUserRegisterDto));
}
}
아무런 예외가 발생하지 않는다면 자연스럽게 사용가능한 이메일이라는 메시지와 함께 true 를 리턴할것이다.
이제 swagger2 를 통해 확인해보자
아 그리고 테스트 하기전에 application.yml 의 ddl-auto : create => ddl-auto : update 로 바꾸어주자
create 로 하면 데이터까지 삭제되기 때문에 어떤 이메일을 넣어도 true 가 반환될것이다.
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/instagram?serverTimezone=Asia/Seoul
username: user
password: '1234'
mvc:
pathmatch:
matching-strategy: path_pattern_parser
jpa:
hibernate:
ddl-auto: update # <-- 매 서버 실행때마다 테이블이 삭제됬다가 다시 만들어짐 당연히 데이터 역시 날라감 하지만 테스트용으로 잠시 씀
properties:
hibernate:
format_sql: true # <-- 실행쿼리를 가독성있게 표현
show-sql: true # <-- 콘솔에 jpa 실행쿼리
generate-ddl: true # < -- true로 설정 시, Entity 어노테이션(@Entity)이 명시된 클래스를 찾아서 ddl을 생성하고 실행
테스트 해볼 상황은 3가지이다
1. 이미 존재하는 이메일
2. 형식에 맞지않는 이메일
3. 정상적인 존재하지않는 이메일
1. 이미 존재하는 이메일을 넣어보겠다.
2. 형식에 맞지않는 이메일
3. 정상적인 존재하지않는 이메일
3개의 상황모두 정상적으로 동작하는걸 볼수있다.
이것으로 포스팅을 마치도록 하겠다
다음포스팅을 다시 react-native 로 돌아가
회원가입 기능을 구현해보도록하겠다.....
그럼 다음시간에!!
깃 첨부
https://github.com/1domybest/react-native-ig-clone.git
다음글 >