사실 아직 만들고 싶은 프로젝트는 생각안해봤다.
다만 프로젝트를 해봐야 실력이 정말 늘 것 같아서 일단 대중적이고 레퍼런스 자료가 제일 많은
커뮤니티 사이트를 만들어보려한다.
환경은 일단 간단하게만 생각해봤다.
- spring boot 3.4.2
- JPA
- MySQL
- Thymeleaf -> react(욕심)
리액트를 예~전에 한 번 쓰윽 봤었으나 전혀 기억이 안나서 백지랑 똑같다.
일단 빨리 끝내는게 목표니 서버쪽을 Thymeleaf로 후다닥 만들고 리액트와 Next.js를 좀 배워서
화면쪽을 바꿔 볼 생각이다. 뭐 생각은 일단 그렇다.
아무튼.. 얼른 시작!
스프링 프로젝트는 아래와 같이 만들었다.
프로젝트를 여러 번 만들어봤지만 제일 떨리는 순간은 Generate 버튼을 누를 때!
깃 레포도 하나 만들어줬다.
클론 후 git ignore 설정을 위해 아래 사이트의 도움을 받는다.
gitignore.io
Create useful .gitignore files for your project
www.toptal.com
.gitignore 파일에 내용을 붙여넣고 커밋한다.
그리고 프로젝트 파일의 압축을 풀고 또 깃에 올린다.
브랜치까지 따줬다.
mysql DB까지 만들어주고
application.yml 설정도 해줬다.
spring:
application:
name: justComm
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/justComm?useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8
username: root
password:
jpa:
open-in-view: true
hibernate:
ddl-auto: create
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
show-sql: true
properties:
hibernate.format_sql: true
dialect: org.hibernate.dialect.MySQL8InnoDBDialect
logging:
level:
org.hibernate.sql : debug
그러고 메인 화면을 만드려고했는데 잘 생각해보니 Next.js 전환 계획을 갖고 있기 때문에 RESTful api로 개발할 거라 타임리프보다는 그냥 HTML + javascript 조합이 더 좋을 거 같아 타임리프를 뒤로 미뤄두고 HTML로 열심히 꾸미기로 했다.
그래서 메인의 경로는..!
resources/static 경로에 index.html 파일을 만들어주면 된다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>메인</title>
</head>
<body>
<h2>메인입니다.</h2>
</body>
</html>
그리고 서버 실행 후 localhost:8080으로 접속하면 메인이 딱 뜬다.
그럼 이제 회원가입 화면을 만들어보자. resources/static/member/signup.html로 만든다.
그리고 index.html에 a 링크를 하나 만들어 회원가입 화면으로 이동할 수 있게 한다.
<a href="member/signup.html">회원가입 이동</a>
그리고 빠른 개발 속도를 위해 챗GPT한테 일정 틀을 주고 CSS 꾸며달라고했다.
나름 예쁘게 꾸며줌 ㅎ
이제 자바스크립트를 작성하면 된다. 너무 오랜만이라 기억이 안나 챗GPT의 도움을 좀 받았다.
<body>
<div class="signup-container">
<h1>회원가입</h1>
<form id="signupForm">
<div>
<label for="userId">아이디:</label>
<input type="text" id="userId" name="userId" placeholder="아이디 입력"
pattern="^[A-Za-z][A-Za-z0-9]{1,}$"
title="영문+숫자. 숫자로 시작하면 안되며 최소 두 글자 이상이어야 합니다." required/>
</div>
<div>
<label for="password">비밀번호:</label>
<input type="password" id="password" name="password" placeholder="비밀번호 입력"
pattern="^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{8,}$"
title="비밀번호는 최소 8자 이상이며, 영어, 숫자, 특수문자(!@#$%^&*)가 모두 포함되어야 합니다."
required/>
</div>
<div>
<label for="confirmPassword">비밀번호 확인:</label>
<input type="password" id="confirmPassword" name="confirmPassword" placeholder="비밀번호 확인" required/>
</div>
<div>
<label for="nickname">닉네임:</label>
<input type="text" id="nickname" name="nickname" placeholder="닉네임 입력" minlength="2" required/>
</div>
<div>
<label for="email">이메일:</label>
<input type="email" id="email" name="email" placeholder="이메일 입력" required/>
</div>
<div>
<label for="job">직업:</label>
<input type="text" id="job" name="job" placeholder="직업 입력"/>
</div>
<div>
<label for="age">나이:</label>
<input type="number" id="age" name="age" placeholder="나이 입력"/>
</div>
<div>
<button type="submit">회원가입</button>
</div>
</form>
<!-- 결과 메시지를 보여줄 영역 -->
<div id="message"></div>
</div>
<script>
document.getElementById('signupForm').addEventListener('submit', function(event) {
event.preventDefault(); // 기본 폼 제출 동작 차단
const password = document.getElementById('password').value;
const password2 = document.getElementById('confirmPassword').value;
if(password !== password2) {
alert("비밀번호가 일치하지 않습니다.");
return;
}
const formData = {
userId: document.getElementById('userId').value
, password: document.getElementById('password').value
, nickname: document.getElementById('nickname').value
, email: document.getElementById('email').value
, job: document.getElementById('job').value
, age: document.getElementById('age').value
};
// API 엔드포인트로 JSON 데이터 전송
fetch('/api/member', {
method: 'POST',
headers: {
'Content-Type' : 'application/json'
},
body: JSON.stringify(formData)
})
.then(response => response.json())
.then(data => {
// API 응답에 따라 메세지 출력
alert("회원가입에 성공했습니다.");
setTimeout(() => {
window.location.href = "login.html";
}, 1000);
})
.catch(error => {
console.error('Error: ', error);
document.getElementById('message').innerText = '회원가입 중 오류 발생';
});
})
</script>
</body>
submit 이벤트를 가로채서 기본 폼 제출 동작을 차단하고 비밀번호와 비밀번호 확인을 검증 후 통과하면
폼에 작성된 모든 데이터를 JSON 객체로 만들어 api로 쏴버린다.
그리고 응답이 잘 오면 회원가입 완료라는 alert 창과 함께 login 페이지로 이동한다.
login.html 페이지도 만들어서 body에 h2 태그 안에 로그인 화면이라고만 적어놨다.
그리고 이제 서버쪽 기능을 만들어야한다.
먼저 Member 엔티티를 만들어준다.
@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String userId;
private String password;
private String nickname;
private String email;
private String job;
private int age;
}
일단 간단하게 저렇게만 만들어보자.
그리고 MemberRequestDto도 만들어보자.
@Getter
public class MemberRequest {
private String userId;
private String password;
private String nickname;
private String email;
private String job;
private int age;
public Member toEntity() {
return Member.builder()
.userId(this.userId)
.password(this.password)
.nickname(this.nickname)
.email(this.email)
.job(this.job)
.age(this.age)
.build();
}
}
이제 Controller를 만들어보자.
@RestController
@RequestMapping("/api/member")
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
@PostMapping()
public boolean signup(@RequestBody MemberRequest memberRequest) {
}
}
휴 Service랑 repository를 먼저 만들고 오자.
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
}
//================================
public interface MemberRepository extends JpaRepository<Member, Long> {
}
그리고 다시 Controller 작성
@PostMapping()
public ResponseEntity signup(@RequestBody MemberRequest memberRequest) {
boolean result = memberService.signup(memberRequest);
return ResponseEntity.ok(result);
}
service의 signup 메서드도 작성한다.
/**
* 회원가입
* @param memberRequest
* @return
*/
@Transactional
public boolean signup(MemberRequest memberRequest) {
memberRepository.save(memberRequest.toEntity());
return true;
}
뭔가 매우 부자연스러운 로직이지만 일단 이렇게하고 넘어가자.
나중에.. 시간이 되면 고쳐! 얼른 하고 자야된다.
자 이제 테스트를 해볼시간!
이렇게 입력하다가 엔터를 눌러서;; 갑자기 회원가입이 진행되어버렸다.
저장..된다.
DB에서도 .. 확인
20살이 되고 싶었던 나는 0살이 되어버렸다.
다음에는 회원가입 기능을 다듬어보는 시간을 가져야겠다.