본문 바로가기

스프링 스터디

회원 정보 수정 / 2022-02-09

회원의 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을 맞추는 게 제일 어려웠다. 여러 글들을 보고 따라했지만 최종적으로 실행을 할 수 있었던 건 김영한님의 설정이었다.

 

🔗 : 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을 사용하여 기능을 구현해봤다. 아무래도 눈으로 더 보기 편하다는 생각이 들었다. 앞으로 자주 사용할 것 같으니 기본적인 사용법 정도는 익혀둬야할 것 같다. 기본적인 설정이 너무 오래걸렸던 것 같다. 다행히도 같이 스터디하는 친구들이 잘 도와줘서 겨우 완성했다. 미리 예습했어도 따라가기 힘들었다. 좀더 분발해서 따라가야지~

 

 

 


 

 

 

🔗 : ISSUES #10 회원 수정 기능

🔗 : Spring Study