Map으로 왜 도배를 해놨어??

shinhyocheol·2021년 6월 29일
0

불타는 금요일!! 에 기분 좋은 마음으로 퇴근하기 전에 아는 지인에게 개인적인 코드리뷰를 부탁했었고 다음날인 토요일 오전에 답장이 왔다.

근데 왜 모든 서비스가 요청과 응답 타입을 Map으로 도배해놨어??

설명을 못했다. 당연히 그동안 습관적으로 그렇게 해왔으니까.. 형의 답변은 이러했다.

Java는 class기반의 OOP(객치지향 프로그래밍)를 지향하는 언어인데
모든 타입을 이렇게 Map으로 맞춰놓은거 부터 OOP와 맞지 않을 뿐더러
저런 식으로 Map을 사용하면 처음엔 큰 불편함을 못느낄 수도 있겠지만
나중에 규모가 커질수록 유지보수가 상당히 어려워질꺼야 왜냐면 Map안에
뭐가 있는지 모르니까 파악하는데 더 시간을 쏟아야 하잖아

늘상 이렇게 해왔으니 이부분에 대해 무엇이 잘못되었는지를 파악해볼 생각은 안했던것이다. 사실 이말을 듣고나서 많은 생각을 했다. 늬우치는것뿐만이 아니라 나는 과연 개발자를 계속해도 되는 것인가?? 근데 뭐 생각은 생각일뿐이고 틀린부분이 있다면 바로 잡고 나아가야지. 고치면 되는거 아니겠어? 🤪

그래서 다시 수정작업에 들어갔다. 다행히 프로젝트는 만들어가는 과정이라 하나씩 수정하면 된다는 생각을 그리 어렵지 않게 했다.

@RequestMapping(value = {"/signin"}, method = {RequestMethod.POST},
			params = {"id", "password"})
public ResponseEntity<String> apiUserSignin(
		HttpServletRequest request,
        HttpServletResponse response) throws Exception {
       	Map<String, Object> resultMap =new HashMap<>();
	try {
		Map<String, Object> dataMap = validateParams(request);
		if(IsEmpty.check(dataMap)) {
			resultMap.put("result", false);
			return JSONUtil.returnJSON(response, resultMap);
		}
		resultMap = apiSignService.loginUserProcessService(dataMap);
	} catch (Exception e) {
		e.printStackTrace();
		resultMap.put("result", false);
		return JSONUtil.returnJSON(response, resultMap, HttpStatus.INTERNAL_SERVER_ERROR);
	}
	return JSONUtil.returnJSON(response, resultMap);
}

@Override
public Map<String, Object> loginUserProcessService(Map<String, Object> dataMap) {
	Map<String, Object> resultMap =new HashMap<>();
	try {
		Map<String, Object> resultData = apiSignDao.selectUserInfoById(dataMap);
		if(IsEmpty.check(resultData)) {
			resultMap.put("result", false);
			resultMap.put("msg", "NO_EXIST_DATA");
			return resultMap;
		}
		if(!passwordEncoder.matches(dataMap.get("password").toString(),
				resultData.get("member_password").toString())) {
			resultMap.put("result", false);
			resultMap.put("msg", "PASSWORD_DO_NOT_MATCH");
			return resultMap;
		}

		String token = jwtTokenProvider.createToken(resultData);
		resultData.remove("member_password");
		resultData.put("x-access-token", token);

		resultMap.put("data", resultData);
	} catch (Exception e) {
		e.printStackTrace();
		resultMap.put("result", false);
		resultMap.put("msg", "INTERNAL_SERVER_ERROR");
	}
return resultMap;
}

이게 기존에 작성한 컨트롤러와 서비스다. 우선 데이터 객체를 주고받으며 변환시켜줄 DTO 클래스를 만들어보자.

@Data
@AllArgsConstructor
@NoArgsConstructor
publicclassMember {

	private int reg_no;

	private String id;
	
	private String password;
	
	private String authority_level;
	
	private String name;
	
	private String email;
	
	private String mobile;
	
	private String reg_date;
	
	private String mod_date;

}

요런식으로 Member 클래스를 정의했다. 그리고 mapper.xml 또한 추가 수정이 필요했다. 참고로 DTO클래스는

요청 방식에 따라 여러 개 생성될 수 있다. 또한 @Data 어노테이션을 통해 getter와 setter를 생략할 수 있다.

<mapper.xml>

<mapper namespace="kr.co.platform.api.sign.dao.ApiSignDAO">

	<resultMap type="kr.co.platform.api.sign.dto.Member" id="Members">
		<result column="reg_no" property="reg_no" />
		<result column="member_id" property="id" />
		<result column="member_password" property="password" />
		<result column="authority_level" property="authority_level" />
		<result column="member_name" property="name" />
		<result column="member_email" property="email" />
		<result column="member_mobile" property="mobile" />
	</resultMap>

	<select id="selectUserInfoById"
		parameterType="kr.co.platform.api.sign.dto.Member"
		resultMap="Members">
		SELECT
			reg_no,
			member_id,
			member_password,
			authority_level,
			member_name,
			member_email,
			member_mobile,
			date_format(last_login_dt, '%Y.%m.%d %H:%i:%s') AS last_login_dt
		FROM
			members
		WHERE
			member_id = #{id}
				AND is_deleted != 'Y'
	</select>

	<insert id="insertUserInfo" parameterType="kr.co.platform.api.sign.dto.Member">
		INSERT INTO members (
			member_id, member_password, authority_level, member_name,
			member_email, member_mobile, reg_date
		) VALUES (
			#{id}, #{enc_password}, #{authority_level}, #{name},
			#{email}, #{mobile}, NOW()
		)
	</insert>

</mapper>

이런 식으로 resultMap 을 만들어주었다. 이제 필요한 재료는 준비했으니 소스를 수정해보자.(추후엔 카멜케이스 설정을 통해 resultMap이 아닌 resultType을 통해 결과를 받아 낼 DTO를 추가한 상태이다)

@AllArgsConstructor
@RestController
@CrossOrigin("*")
@RequestMapping(value = { "" }, produces = MediaType.APPLICATION_JSON_VALUE)
publicclassApiSignController {

	private ApiSignService apiSignService;

	private JwtTokenProvider jwtTokenProvider;

	@PostMapping(value = "/signin", params = { "id", "password" })
	public Member apiUserSignin(
			HttpServletRequest request,
			HttpServletResponse response,
			@RequestBody Member login) throws Exception {

		Member result = apiSignService.loginUserProcessService(login);
		response.setHeader("x-access-token", jwtTokenProvider.createToken(result));

		return result;
	}

	@PostMapping(value = { "/signup" }, params = { "id", "password" })
	public boolean apiUserSignUp(@RequestBody Member info) throws Exception {

		boolean result = apiSignService.insertUserInfo(info);

		return result;
	}
}

@AllArgsConstructor
@Service("apiSignService")
publicclassApiSignServieImplimplementsApiSignService {

	private ApiSignDAO apiSignDao;

	private BCryptPasswordEncoder passwordEncoder;

	@Override
	public MemberloginUserProcessService(Member login)throws Exception {
		
		Member result = apiSignDao.selectUserInfoById(login);
		if (IsEmpty.check(result)) {
			throw new Code700Exception("There is no Result Data");
		}
		if (!passwordEncoder.matches(login.getPassword(), result.getPassword())) {
			throw new ForbiddenException("Passwords do not match");
		}
		return result;
	}

  	@Override
	public boolean insertUserInfo(Member info) {
  	info.setPassword(passwordEncoder.encode(info.getPassword()));
		int result = apiSignDao.insertUserInfo(info);
		if (IsEmpty.check(result))
			throw new Code700Exception("The query was executed normally, but not a single data was affected");

		return true;
  }

}

위와같이 수정했다. 사실 이거말고도 수정한 것이 더 있지만 나머지는 데이터 변수명이나 기타 등등 차이지 큰 차이는 없어서 생략했다. 사실 이번에 수정하면서 느낀건 "내가 아직 Java라는 언어를 제대로 이해하고 사용하고 있지 않다" 라는 것이였다. 아직은 스트레스 받더라도 더 빡시게 공부해야 한다는 것을 다시 한번 느낀 시간이라고 생각한다.

profile
놀고싶다

0개의 댓글