IT/development

[spring] @RequestBody String type 받기

알 수 없는 사용자 2023. 1. 24.
[spring] @RequestBody String type 받기

spring에서 @RequestBody로 String type의 변수 받기

스프링 RestFul방식으로 클라이언트에서 데이터를 전달 받을 때 당황했던 경험이 있어 이를 기록한다.
보통 스프링에서 클라이언트에서 전달한 데이터를 Dto나 Vo등의 객체 타입으로 바인딩 시 아래처럼 객체로 전달 받도록 하면 된다.

package study.lsyrestapitest1.controller.api;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import study.lsyrestapitest1.domain.dto.UserDto;
import study.lsyrestapitest1.service.UserService;

@RestController
@Slf4j
@RequiredArgsConstructor
@RequestMapping(value = "/v1/users")
public class UserApiController {

    private final UserService userService;

    @GetMapping(value = "")
    public Object findList(@RequestBody UserDto userDto) throws Exception {
        return null;// 이건 일단 무시하자
    }
}

하지만 만일 클라이언트에서 전달 받는 parameter가 여러개가 아니라 객체로 받기 애매한 경우는?
예를 들어 user_name등 1개만 전달 받는 경우, 뭔가 데이터 1개만 받기 위해 객체를 만드는 좀 애매하다는 생각이 들어 당연히 아래처럼 @RequestBody를 선언한 다음 String타입으로 userName을 받았다.
테스트를 위해 아래처럼 코드들을 작성했다.

테이블

--table create
CREATE TABLE `temp_user` (
  `user_seq` int(20) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(30) NOT NULL COMMENT '사용자명',
  `user_email` varchar(30) NOT NULL COMMENT '사용자 이메일',
  `reg_date` timestamp NULL DEFAULT NULL COMMENT '대출일',
  PRIMARY KEY (`user_seq`,`user_email`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

--------------------------------------------------------------------------------------

--test data insert
INSERT INTO reno.temp_user
(user_seq, user_name, user_email, reg_date)
VALUES(1, '토르', 'thor@naver.com', '2022-12-21 22:57:07.000');
INSERT INTO reno.temp_user
(user_seq, user_name, user_email, reg_date)
VALUES(2, '헐크', 'hulk@naver.com', '2022-12-21 22:57:07.000');
INSERT INTO reno.temp_user
(user_seq, user_name, user_email, reg_date)
VALUES(3, '타노스', 'tanos@naver.com', '2022-12-21 22:57:07.000');
INSERT INTO reno.temp_user
(user_seq, user_name, user_email, reg_date)
VALUES(4, '타노스', 'ta@naver.com', '2023-01-03 18:17:00.000');
INSERT INTO reno.temp_user
(user_seq, user_name, user_email, reg_date)
VALUES(5, '루갈', 'lo@naver.com', '2023-01-03 18:22:49.000');
INSERT INTO reno.temp_user
(user_seq, user_name, user_email, reg_date)
VALUES(6, '리본', 'libon@naver.com', '2023-01-03 18:25:31.000');
INSERT INTO reno.temp_user
(user_seq, user_name, user_email, reg_date)
VALUES(7, '', 'libon@naver.com', '2023-01-03 18:26:02.000');
INSERT INTO reno.temp_user
(user_seq, user_name, user_email, reg_date)
VALUES(8, '로키', 'libon@naver.com', '2023-01-03 18:28:13.000');
INSERT INTO reno.temp_user
(user_seq, user_name, user_email, reg_date)
VALUES(9, '테란', 'terran@naver.com', '2023-01-03 21:55:14.000');

dto

package study.lsyrestapitest1.domain.dto;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter @Setter
@ToString
@NoArgsConstructor
public class UserDto {

    private int user_seq;
    private String user_name;
    private String user_email;
    private String reg_date;
}

controller

package study.lsyrestapitest1.controller.api;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import study.lsyrestapitest1.service.UserService;

@RestController
@Slf4j
@RequiredArgsConstructor
@RequestMapping(value = "/v1/users")
public class UserApiController {

    private final UserService userService;

    @GetMapping(value = "")
    public Object findList(@RequestBody String userName) throws Exception {
        return userService.findMembers(userName);
    }
}

service

package study.lsyrestapitest1.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import study.lsyrestapitest1.domain.dto.UserDto;
import study.lsyrestapitest1.mapper.UserMapper;

import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserService {

    private final UserMapper userMapper;

    public List<UserDto> findMembers(String userName) throws Exception{
        return userMapper.findMembers(userName);
    }

}

mapper(interface)

package study.lsyrestapitest1.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import study.lsyrestapitest1.domain.dto.UserDto;

import java.util.List;

@Mapper @Repository
public interface UserMapper {

    List<UserDto> findMembers(String userName);

}

mapper(xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="study.lsyrestapitest1.mapper.UserMapper">

    <select id="findMembers" parameterType="String" resultType="study.lsyrestapitest1.domain.dto.UserDto">
        SELECT    user_seq
                , user_name
                , user_email
                , reg_date
        FROM temp_user
        <where>
            <if test="userName != null and userName != ''" >user_name = #{userName}</if>
        </where>
    </select>
                                                                                


</mapper>

위에서 사용된 <where></where>는 아래를 참조

[mybatis] mybatis 동적쿼리(feat. <where></where>)

목차 mybatis Dynamic SQL 😃 계속 실수 했던 동적쿼리이다. 오늘 나는 이걸 이해 했지만 미래의 넌 또 까먹을 수 있으니 여기에 메모해 둔다. 동적 WHERE 회원 테이블에서 회원이름과 이메일의 존재에 ...

yaga.tistory.com

잘 되겠지?😅 테스트를 해봤는데 아래처럼 당황스러운 결과를 확인 했다.
클라이언트에서 호출
이상하다. "토르"라는 사용자명은 테이블에 있는 데이터다.

[spring] @RequestBody String type 받기 - spring에서 @RequestBody로 String type의 변수 받기 - mapper(xml)

서버 쿼리 확인

[spring] @RequestBody String type 받기 - spring에서 @RequestBody로 String type의 변수 받기 - mapper(xml)

뭔가 제대로 변환되지 않은 느낌이다.
구글링 결과 String타입의 변수 1개만 받을 경우는 아래처럼 map으로 받으면 된다.

[spring] @RequestBody String type 받기 - spring에서 @RequestBody로 String type의 변수 받기 - mapper(xml)

이제 테스트를 하면 아래처럼 결과가 정상적으로 반환된다.

[spring] @RequestBody String type 받기 - spring에서 @RequestBody로 String type의 변수 받기 - mapper(xml)

정확히 이해 하려면 스프링의 HttpMessageConvert 내부적으로 공부해야 하고 나도 정확히 이해하지 못했으니 이 곳에 기록하지 않는게 낫겠다는 판단을 했다.
나중에 시간 내서 HttpMessageConvert에 대해서도 공부해 보자.(나한테 하는 말이다.)
관련해서 훨씬 잘 정리된 블로그 글들이 많다.
오늘 새로운 경험을 했으니 다음번엔 삽질 시간이 줄어들 것이다.

[spring] @RequestBody String type 받기 - spring에서 @RequestBody로 String type의 변수 받기 - mapper(xml)