회원의 id를 템플릿 변수로 받고, 변경할 이름과 비밀번호를 body로 받아 수정했다.
RequestBody를 통해 들어오는 데이터의 정보 형식을 맞추기 위해 dto를 작성했다.
UserRequestUpdateDto
package com.second.spring_study.dto.request.ywoo;
import com.sun.istack.NotNull;
import lombok.*;
@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class UserRequestUpdateDto {
@NotNull
String user_password;
@NotNull
String user_name;
}
형식
{
"user_name" : "",
"user_password" : ""
}
Controller에서는 매핑과 메서드 호출을 구현했다.
UserYwooController
@PutMapping("/{id}")
public void updateUser(@PathVariable long id, @RequestBody UserRequestUpdateDto userRequestUpdateDto){
userYwooService.updateUser(id, userRequestUpdateDto.getUser_name(),userRequestUpdateDto.getUser_password());
}
@ 어노테이션
- @PutMapping
- update를 하기 위해 사용한다.
- @PostMapping과 비슷한 기능을 한다.
- 아래의 글을 통해 자세한 설명을 읽어보면 좋을 듯하다.
- 간단하게 설명하면 멱등성 이라는 차이를 가지고 있는데 put는 한번을 보내든 여러번 보내든 똑같기 때문에 멱등성을 가진다. Post는 멱등성을 가지지 않는다.
- 멱등성이란?
- @PostMapping vs @PutMapping
- @RequestBody
- json을 기반으로 한 데이터에 사용된다.
- UserRequestUpdateDto의 형식이 Json이기 때문에 사용했다.
Service는 실질적인 기능을 구현한다. 따라서 id값이 있는 지 없는 지 체크한 후 없을 경우 에러를 발생시키고, id가 존재한다면 정보를 수정한다.
UserYwooService
@Transactional
public void updateUser(long id, UserRequestUpdateDto userRequestUpdateDto){
UserYwoo userYwoo = userRepository.findById(id).orElseThrow();
userYwoo.updateUser(userRequestUpdateDto.getUser_name(), userRequestUpdateDto.getUser_password());
}
updateUser 메서드는 UserYwoo에서 구현하였다. 들어온 이름과 비밀번호를 넣어주고, 넣어준 객체(자기 자신)을 return 한다.
UserYwoo
public UserYwoo updateUser(String user_name, String user_password){
this.user_name = user_name;
this.user_password = user_password;
return this;
}
처음에는 위와 같은 방식으로 구현하였다. 방법을 조금 바꿔서 QueryDsl을 사용하여 수정을 하면 어떨까? 하는 의견을 모아 다시 구현했다.
QueryDSL은 무엇보다 gradle을 맞추는 게 제일 어려웠다. 여러 글들을 보고 따라했지만 최종적으로 실행을 할 수 있었던 건 김영한님의 설정이었다.
build.gradle
//dsl 설정
buildscript {
dependencies {
classpath("gradle.plugin.com.ewerk.gradle.plugins:querydsl-plugin:1.0.10")
}
}
//dsl 설정 (1)
plugins {
id 'org.springframework.boot' version '2.6.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
//dsl 설정(2)
apply plugin: "com.ewerk.gradle.plugins.querydsl"
group = 'com.second'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
//dsl 설정(3)
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
//dsl 설정(4)
implementation 'com.querydsl:querydsl-jpa'
implementation 'com.querydsl:querydsl-apt'
//lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
//db
runtimeOnly 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
//test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//추가
testImplementation("org.junit.vintage:junit-vintage-engine") {
exclude group: "org.hamcrest", module: "hamcrest-core"
}
}
tasks.named('test') {
useJUnitPlatform()
}
//dsl 설정(5)
def querydslDir = "$buildDir/generated/querydsl"
//dsl 설정(6)
querydsl {
library = "com.querydsl:querydsl-apt"
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main {
java {
srcDirs = ['src/main/java', querydslDir]
}
}
}
compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}
configurations {
querydsl.extendsFrom compileClasspath
}
//dsl 설정(6)
롬북과 h2 등의 설정도 포함 되어있다.
그런 다음 gradle - tasks - clean을 해준 후 gradle - tasks - build를 해준다. 그 다음 gradle - tasks - other - compileQueryDsl을 해주면 기본 설정은 끝났다.
해당 과정을 거치고 나면 build - generated - querydsl 밑에 Q파일이 생성되어 있다.
다음은 config 파일 설정이다.
config.QueryDslConfig
package com.second.spring_study.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Configuration
public class QueryDslConfig {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory queryFactory(){
return new JPAQueryFactory(entityManager);
}
}
repository 밑에 interface와 구현해줄 파일을 생성한다.
entity.repository.UserYwooRepositoryExtension
package com.second.spring_study.entity.user_ywoo.repository;
import com.second.spring_study.dto.request.ywoo.UserRequestUpdateDto;
public interface UserYwooRepositoryExtension {
void updateUser(long id, UserRequestUpdateDto userUpdateDto);
}
entity.repository.yUserYwooRepositoryImpl
package com.second.spring_study.entity.user_ywoo.repository;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.JPQLQueryFactory;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.second.spring_study.dto.request.ywoo.UserRequestUpdateDto;
import com.second.spring_study.entity.user_ywoo.UserYwoo;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import static com.second.spring_study.entity.user_ywoo.QUserYwoo.userYwoo;
public class UserYwooRepositoryImpl extends QuerydslRepositorySupport implements UserYwooRepositoryExtension {
private final JPQLQueryFactory queryFactory;
public UserYwooRepositoryImpl(JPAQueryFactory jpaQueryFactory) {
super(UserYwoo.class);
this.queryFactory=jpaQueryFactory;
}
}
여기서 제일 중요했던 건 import문에 있는 static이다.
import static com.second.spring_study.entity.user_ywoo.QUserYwoo.userYwoo;
static을 붙이지 않으면 객체를 사용할 수 없었다. 왜 그런지는 잘 모르겠다.
원래 있던 UserYwooRepository에 interface를 상속해준다. 자바는 다중상속이 가능하다.
UserYwooRepository
package com.second.spring_study.entity.user_ywoo.repository;
import com.second.spring_study.entity.user_ywoo.UserYwoo;
import org.springframework.data.repository.CrudRepository;
public interface UserYwooRepository extends CrudRepository<UserYwoo, Long>, UserYwooRepositoryExtension {
UserYwoo save(UserYwoo userYwoo);
}
모든 설정이 끝났으니 본격적으로 회원을 수정하는 메서드를 구현한다. 구현은 UserYwooRepositoryImpl 파일에서 한다.
repository.UserYwooRepositoryImpl
package com.second.spring_study.entity.user_ywoo.repository;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.JPQLQueryFactory;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.second.spring_study.dto.request.ywoo.UserRequestUpdateDto;
import com.second.spring_study.entity.user_ywoo.UserYwoo;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import static com.second.spring_study.entity.user_ywoo.QUserYwoo.userYwoo;
public class UserYwooRepositoryImpl extends QuerydslRepositorySupport implements UserYwooRepositoryExtension {
private final JPQLQueryFactory queryFactory;
public UserYwooRepositoryImpl(JPAQueryFactory jpaQueryFactory) {
super(UserYwoo.class);
this.queryFactory=jpaQueryFactory;
}
@Override
public void updateUser(long id, UserRequestUpdateDto userRequestUpdateDto) {
queryFactory.update(userYwoo) //update문
.set(userYwoo.user_password, userRequestUpdateDto.getUser_password()) //객체에 해당되는 값을 넣어줌
.set(userYwoo.user_name, userRequestUpdateDto.getUser_name())
.where(userYwoo.id.eq(id)) //들어온 id와 객체의 id가 같을 경우
.execute();
}
//값으로 null이 들어올 경우
private BooleanExpression userPassWordEq(String user_password){
return user_password !=null ? userYwoo.user_password.eq(user_password) : null;
}
private BooleanExpression userNameEq(String user_name){
return user_name !=null ? userYwoo.user_name.eq(user_name) : null;
}
}
제일 밑에 있는 null이 들어올 경우 사용하는 메서드는 where문에서 사용된다. 즉 select와 같이 조회할 때 사용되는 메서드이다.
updateUser에서는 객체를 수정하는 기능을 한다.
- set() : 받아온 정보를 객체에 넣어준다. 첫번째 매개변수는 정보를 넣어줄 곳, 두번째 매개변수는 넣어줄 값이다.
- where() : 조건문이다. 객체의 id값과 들어온 id값이 일치할 경우에 실행한다.
- excute() : 바뀐 값들을 반영해주기 위해 사용한다.
수정한 메서드를 사용하기 위해 service를 바꿔준다.
UserYwooService
@Transactional
public void updateUser(long id, UserRequestUpdateDto userRequestUpdateDto){
userRepository.findById(id).orElseThrow();
updateUser(id,userRequestUpdateDto);
}
Controller 또한 수정해준다.
@PutMapping("/{id}")
public void updateUser(@PathVariable long id, @RequestBody UserRequestUpdateDto userRequestUpdateDto){
userYwooService.updateUser(id,userRequestUpdateDto);
}
처음으로 QueryDSL을 사용하여 기능을 구현해봤다. 아무래도 눈으로 더 보기 편하다는 생각이 들었다. 앞으로 자주 사용할 것 같으니 기본적인 사용법 정도는 익혀둬야할 것 같다. 기본적인 설정이 너무 오래걸렸던 것 같다. 다행히도 같이 스터디하는 친구들이 잘 도와줘서 겨우 완성했다. 미리 예습했어도 따라가기 힘들었다. 좀더 분발해서 따라가야지~
🔗 : Spring Study
'스프링 스터디' 카테고리의 다른 글
게시글 추가 기능 구현 / 2022-02-15 (0) | 2022.02.15 |
---|---|
1주차 스프링 스터디 회고록 (0) | 2022.02.14 |
Controller 전역 예외 처리(Custom Exception) / 2022-02-10 (0) | 2022.02.11 |
회원 전체 조회 및 상세 조회 / 2022-02-08 (0) | 2022.02.09 |
회원 삭제 기능 / 2022-02-07 (0) | 2022.02.08 |