개발 일기

20250930 uplus clone site 다시 만들기 본문

TIL

20250930 uplus clone site 다시 만들기

종현종현 2025. 9. 30. 20:00

오늘은 지금까지 배운 백엔드 내용을 이용해 클론 사이트를 만들어보는 실습 시간을 가졌다.

그리고 다시 만들어보는 과정을 기록했다.

 

LG 유플러스 클론 사이트 만들기

1. 프로젝트 생성

이전 실습에서는 MyBatis와 MySQL을 사용했었는데 이번엔 Lombok과 h2가 추가되었다.

 

2. 화면 만들기

화면은 강사님이 준비해주신 프론트엔드 코드들을 그대로 복사해서 사용했다.

 

첫 화면

로그인 화면

회원가입 화면

 

3. 서버 백엔드 구현

- Member.java

package com.ureca.web.model.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Member {
	private int no;
	private String id;
	private String pw;
	private String email;
}

Lombok을 사용해 코드를 작성했다.

@Data는 Lombok에서 제공하는 어노테이션으로 getter, setter, toString, equals, hashCode 등을 자동으로 생성해준다.

@NoArgsConstructor는 인자가 없는 기본 생성자를 자동 생성해준다.

@AllArgsConstructor는 모든 필드를 받는 생성자를 자동 생성해준다.

Lombok은 개발자 편의성 측면에서 편리하지만 유효성 검사 측면에서 취약점이 생길 수 있다.

그러므로 잘 판단하여 사용해야 한다.

 

- MemberDao.java

package com.ureca.web.model.dao;

import org.apache.ibatis.annotations.Mapper;

import com.ureca.web.model.dto.Member;

@Mapper
public interface MemberDao {
	
	public void registerMember(Member member);
	
}

interface라 구현체가 없다.

MyBatis가 Mapper XML과 매핑해서 실제 구현체를 런타임에 생성해준다.

 

- MemberService.java

package com.ureca.web.model.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ureca.web.model.dao.MemberDao;
import com.ureca.web.model.dto.Member;

@Service
public class MemberService {
	
	@Autowired
	MemberDao memberDao;
	
	public void registerMember(Member member) {
		memberDao.registerMember(member);
	}
}

@Service는 Spring Bean으로 등록되고 Controller에서 주입 받아서 사용 가능하다.

@Autowired Spring이 MemberDao 구현체를 찾아서 자동으로 주입해준다.

 

- MemberController.java

package com.ureca.web.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.ureca.web.model.dto.Member;
import com.ureca.web.model.service.MemberService;

@RestController
public class MemberController {
	
	@Autowired
	MemberService memberService;
	
	@PostMapping("/signup")
	public Map<String, Object> signup(@RequestBody Member m){
		Map<String, Object> response = new HashMap();
		
		try {
			memberService.registerMember(m);
			response.put("msg", "success");
			
		} catch(Exception e) {
			response.put("msg", e.getMessage());
		}
		
		return response;
	}
}

@RestController는 Spring MVC에서 사용하는 어노테이션이다.

@Controller + @ResponseBody가 합쳐진 형태이다. 메서드의 반환값을 JSON이나 XML 같은 HTTP 응답 Body로 바로 변환한다. 이 컨트롤러의 모든 메서드는 REST API로 동작한다.

멤버서비스처럼 @Autowired로 멤버서비스를 자동으로 주입해준다.

 

try-catch로 회원가입을 수행하고 Service에 Member를 전달하고 DB INSERT를 수행하게 된다.

성공하면 success를 반환하고 예외 발생 시, 예외 메세지를 그대로 JSON으로 전달한다.

실제 서비스에서는 민감 정보나 DB 에러 메세지를 그대로 반환하지 않는 것이 좋기 때문에 수정해야한다.

 

4. MyBatis

- member.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
  
<mapper namespace="com.ureca.web.model.dao.MemberDao">

  <insert id="registerMember" parameterType="Member" >
    INSERT INTO member (id,pw,email) VALUES (#{id}, #{pw}, #{email})
  </insert>
  
</mapper>

MyBatis는 namespace + id를 통해 SQL과 DAO 메서드를 매핑한다.

 

- secu.properties

DB_DRIVER=com.mysql.cj.jdbc.Driver
DB_URL=jdbc:mysql://localhost:3306/lg_uplus_clone?serverTimezone=UTC
DB_USER=ureca
DB_PW=ureca

// Application.java
package com.ureca.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@PropertySource("classpath:config/secu.properties") //추가
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

// application.properties
spring.application.name=0930_uplus_clone_Practice
spring.datasource.driver-class-name=${DB_DRIVER}
spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PW}

logging.level.com.ureca.web=debug

mybatis.type-aliases-package=com.ureca.web.model.dto
mybatis.mapper-locations=mapper/*.xml

 

5. MySQL

CREATE DATABASE IF NOT EXISTS lg_uplus_clone ;
USE lg_uplus_clone;

-- Member 테이블 생성
CREATE TABLE member (
    -- 기본 키 (자동 증가)
    no BIGINT AUTO_INCREMENT PRIMARY KEY,
    
    -- 회원 기본 정보
    id VARCHAR(20) NOT NULL UNIQUE COMMENT '사용자 아이디 (4-20자, 영문/숫자)',
    email VARCHAR(100) NOT NULL UNIQUE COMMENT '이메일 주소',
    pw VARCHAR(255) NOT NULL COMMENT '암호화된 비밀번호'
);

 

실행 결과

회원가입 성공 시

 

회원가입 실패 시

사용자가 이런 정보를 얻게 해서는 안된다. 사용자가 해커라면 많은 정보를 알 수 있게 되고 취약해진다.

 

코드 간단히 수정

@RestController
public class MemberController {
	
	@Autowired
	MemberService memberService;
	
	@PostMapping("/signup")
	public Map<String, Object> signup(@RequestBody Member m){
		Map<String, Object> response = new HashMap();
		
		try {
			memberService.registerMember(m);
			response.put("msg", "success");
			
		} catch(Exception e) {
			response.put("msg", "회원 가입 실패");
		}
		
		return response;
	}
}

예외 처리 시 회원 가입 실패했다는 정보만 주도록 수정했다.

 

 

느낀 점

백엔드 회원가입 기능 구현 과정을 직접 다시 해보면서 많은 것을 배웠다.

STS 실행 문제와 환경 변수 설정, MySQL 연결 등 사소하지만 중요한 설정 문제들이 생겨서 어려움도 있었다. 하지만 하나씩 해결해 나가고 다른 동료들의 디버깅 시간을 들여다보면서 환경 구성의 중요성, 디버깅의 중요성 등을 느낄 수 있었다.

또한 보안의 중요성에 대해서도 배울 수 있어 뜻 깊은 실습이었다.

 

이런 경험을 잘 쌓아간다면 나중에 하게 될 팀 프로젝트에서 백엔드 개발자들과의 협업에 도움이 많이 될 것 같다.

Comments