프로젝트 생성 & 회원 가입 & 로그인 정리!
- 사용 IDE : IntelliJ IDEA Ultimate
- 사용 DB : MySQL
- 사용 언어 & SDK : Java & Amazon correto 11
- thymeleaf 사용을 가급적 줄인 예제입니다.
- 정리본입니다 참고용으로만 봐주세요 :D
- 회원가입부터 로그인까지 정리본
Project Name : MemberProject
pakage : com.icia.member
dependency는 아래와 같이 설정.
설정 후 생성
생성 후 가장 먼저 할 설정
Annotation Processors에 들어가 Enable anootation processing 체크 후 Apply
프로젝트마다 개별 설정이기 때문에 프로젝트를 생성할 때 마다 이를 설정해줘야함.
역할 : 어노테이션이 역할을 수행할 수 있게 해줌.
주의할점!!
# 포트 설정, port는 server안에서 들여써주세요.
server:
port: 8093
# DB접속 정보 MySQL에서 사용할 DB와 username 및 pw 설정
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springbootclass?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
username: bootuser
password: 1234
# Run시 cache값을 사용하지 않겠다는 의미 (완벽하진 않지만 오류 방지)
thymeleaf:
cache: false
# JPA 관련 설정, datasource: 위치와 같은 위치에 작성해줘야함.
# JPA를 사용하겠다는 코드
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
hibernate:
ddl-auto: update
# create : 실행할 때 마다 전체 재시작
# update : table을 drop하지 않고 계속해서 사용하겠다는 의미
프로젝트 생성할 때 추가하지 못한 Dependency를 추가할 수 있게 해주는 파일
Dependency 추가 후 우측 팝업에 코끼리 모양을 눌러줘야 추가한 Dependency가 적용됨.
plugins {
id 'org.springframework.boot' version '2.6.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.icia'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
// implementaion : 구현에 필요한 코드
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
// 공백 체크 및 각종 체크를 도와주는 어노테이션을 사용할 수 있게 해주는 Dependency
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// jpa를 사용하겠다는 Dependency
runtimeOnly 'mysql:mysql-connector-java'
// MySQL DB를 사용할 수 있게 해주는 Dependency
// compileOnly : 컴파일에만 사용하는 코드
compileOnly 'org.projectlombok:lombok'
// annotationProcessor : 어노테이션 지정 코드
annotationProcessor 'org.projectlombok:lombok'
// testImplementation : 테스트시 사용
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
src/java 안에 controller pakage 생성 & MainController 생성
MainController에 기본주소를 처리하는 메서드 생성
// 스프링 부트에서는 아래와 같은 방법으로 메서드 생성 가능.
// 기본주소 요청 시 index 페이지 출력
@GetMapping("/")
public String index() {
return "index";
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>index.html</h2>
<a href="/member/save">회원가입</a>
<a href="/member/login">로그인</a>
</body>
</html>
/member/*를 처리할 Controller 생성
회원가입 페이지 요청 주소 및 저장 주소 생성
// 회원가입 페이지 요청
@GetMapping("save")
public String saveForm() {
return "member/save";
}
이제 각종 DB처리를 해주는 Repository를 생성합니다.
Repository는 Interface Class로 만들고 JpaRepository를 상속받는 클래스로 설정합니다.
주의할점으로 Repository에는 @Repository를 붙이지 않게 주의합시다.
public interface MemberRepository extends JpaRepository<MemberEntity, Long> {
}
JPA는 maven클래스의 mybatis와 비슷한 역할을 수행하는 Java Class입니다.
mybatis처럼 직접 쿼리문을 작성하지 않아도 JpaRepository에 각종 쿼리문이 포함되어있어 호출만 해도 각종 CRUD를 처리할 수 있습니다.
templates 폴더 안에 member라는 폴더 생성
member 폴더 안에 save.html 생성
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2 class="mt-3 mb-3">회원가입</h2>
<form action="/member/save" method="post">
<input type="text" name="memberEmail" placeholder="이메일">
<input type="password" name="memberPassword" placeholder="비밀번호">
<input type="text" name="memberName" placeholder="이름">
<input type="submit" value="회원가입">
</form>
</body>
</html>
@Data
@NoArgsConstructor // 기본 생성자 생성
@AllArgsConstructor // 모든 필드를 매개변수로 하는 생성자 생성
public class MemberSaveDTO {
private String memberEmail;
private String memberPassword;
private String memberName;
}
순서
html에서 Controller로 정보 전달
Controller에서 정보를 받은 후 Service로 전달
Service에서 Entity로 정보 전달
Entity에서 DTO타입을 Entity타입으로 변환 후 Service에 전달
Service에서 받은 후 Repository(JPA)로 전달
처리 완료 후 지정한 메서드 or 페이지로 이동
// 회원가입 정보 저장
@PostMapping("save")
public String save(@ModelAttribute MemberSaveDTO memberSaveDTO) {
Long memberId = ms.save(memberSaveDTO);
return "member/login";
}
service pakage 생성 후 Service와 ServiceImpl 생성
Service : Interface Class로 생성
ServiceImpl : 일반 Java Class로 생성 및 implements 후 @Service 붙이기.
public interface MemberService {
Long save(MemberSaveDTO memberSaveDTO);
}
@Service
@RequiredArgsConstructor
public class MemberServiceImpl implements MemberService {
// Repository 생성자 주입.
private final MemberRepository mr;
// 회원가입 정보 저장
@Override
public Long save(MemberSaveDTO memberSaveDTO) {
// JPARepository는 무조건 Entity 타입만 받기 때문에 Entity 타입으로 바꿔줘야함.
MemberEntity memberEntity = MemberEntity.saveMember(memberSaveDTO);
// Long memberId = mr.save(memberEntity).getId();
// return memberId;
// 위 두줄과 아래 한줄은 같은 코드
// 앞으로 이런식으로 줄여서 사용할 예정임.
return mr.save(memberEntity).getId();
}
}
entity pakage 생성 & Entity Class 생성
Entity는 Java Class입니다. 주의해주세요.
Entity의 역할 : JPA에 정보를 보내거나 받기 위해 사용.
테이블명 및 컬럼을 선언하는 곳, 또한 데이터 타입을 Entity로 변환을 하는 곳.
@Entity // JPA를 사용하려면 Entity Class가 팔수적이다.
@Getter
@Setter
@Table(name="member_table") // table 이름을 member_table로 지정.
public class MemberEntity {
@Id // PK로 아래 컬럼을 사용하겠다는 뜻
@GeneratedValue(strategy = GenerationType.IDENTITY) // auto_increment와 같은 역할
@Column(name = "member_id") // 컬럼 이름을 member_id로 지정
private Long id;
@Column(length = 50, unique = true) // varchar(50)에 unipue 속성을 부여
private String memberEmail;
// Entity에서는 _(언더바) 절대 금물. 차후에 오류 발생 가능성 높음.
// 카멜케이스로 작성한 컬럼은 member_email로 자동으로 바뀜.
@Column(length = 20)
private String memberPassword;
@Column() // 아무 지정을 안해주면 varchar(255) 크기로 생성됨.
private String memberName;
// MemberSaveDTO -> MemberEntity 객체로 변환하기 위한 메서드
public static MemberEntity saveMember(MemberSaveDTO memberSaveDTO) {
// MemberEntity타입의 객체를 보내기 위해 memberEntity라는 객체 선언
MemberEntity memberEntity = new MemberEntity();
// memberEntity 객체에 memberSaveDTO 객체 안에 담긴 각 요소를 담아줌.
memberEntity.setMemberEmail(memberSaveDTO.getMemberEmail());
memberEntity.setMemberPassword(memberSaveDTO.getMemberPassword());
memberEntity.setMemberName(memberSaveDTO.getMemberName());
// 변환이 완료된 memberEntity 객체를 넘겨줌
return memberEntity;
}
}
위 코드를 잘 따라왔다면 DB에 데이터가 잘 들어간 것을 확인할 수 있습니다.
thymeleaf를 사용한다면 공백체크 & 아이디중복체크도 수행할 수 있지만 여기서는 다루지 않고 차후에 다루겠습니다. 그럼 로그인으로 넘어가겠습니다 :D
// 로그인 페이지 요청
@GetMapping("login")
public String loginForm() {
return "member/login";
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>login.html</h2>
<form action="/member/login" method="post">
<input type="text" name="memberEmail" placeholder="이메일을 입력하세요">
<input type="text" name="memberPassword" placeholder="비밀번호를 입력하세요">
<input type="submit" value="로그인">
</form>
</body>
</html>
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MemberLoginDTO {
private String memberEmail;
private String memberPassword;
}
순서
login.html에서 Controller로 정보 전달
Controller에서 정보를 받은 후 Service로 정보 전달
Service에서 Entity로 정보 전달
Entity에서 DTO타입을 Entity 타입으로 변환 후 Service에 전달
Service에서 받은 후 Repository(JPA)로 전달
JPA에서 처리 후 Service에 전달
Service에서 받은 후 null 체크 및 비밀번호 일치여부 확인
처리 결과를 Controller로 전달
사용자가 지정한 메서드 or 주소로 이동
// 로그인 성공여부 판별
@PostMapping("login")
public String login(@ModelAttribute MemberLoginDTO memberLoginDTO, HttpSession session) {
if (ms.login(memberLoginDTO)) {
// session.setAttribute("loginEmail",memberLoginDTO.getMemberEmail());
// 아래처럼 상수를 선언해 사용할 수 있음, 아무거나 편한걸로 사용
session.setAttribute(LOGIN_EMAIL,memberLoginDTO.getMemberEmail());
return "redirect:/member/";
} else {
return "member/login";
}
}
// 내용 추가
boolean login(MemberLoginDTO memberLoginDTO);
jpa에서 지원하는 메서드 중 findBy~ 를 사용하므로 메서드 이름을 멋대로 바꾸면 오류생김.
findAll, findBy~ 등이 있음.
findBy~ : ~인 데이터를 찾겠다 라는 뜻으로 뒤에 각 컬럼을 넣어 사용할 수 있다.
@Override
public boolean login(MemberLoginDTO memberLoginDTO) {
// MemberEntity타입의 객체 생성 후 jpa의 findBy 메서드 호출 및 정보 저장
// MemberLoginDTO의 memberEmail을 보내 값을 memberEntity에 담는것임.
MemberEntity memberEntity = mr.findByMemberEmail(memberLoginDTO.getMemberEmail());
// 정보가 비어있으면 로그인시도를 한 email을 가진 데이터 자체가 없는 정보라는 뜻임.
if (memberEntity!=null) {
// 로그인을 시도한 데이터의 비밀번호와 jpa에서 받아온 데이터의 비밀번호를 비교
if(memberEntity.getMemberPassword().equals(memberLoginDTO.getMemberPassword())) {
return true;
} else {
return false;
}
} else {
return false;
}
}
Repository는 기본적으로 메서드를 생성할 일이 거의 없습니다.
하지만 PK가 아닌 값으로 CRUD를 수행하기 위해선 Repository에 메서드를 생성해줘야 합니다.
아까 만든 Repository는 Interface Class이므로 추상메서드로 작성해야합니다.
// Repository에 아래 코드 한줄 추가.
MemberEntity findByMemberEmail(String memberEmail);
여기까지 잘 따라오셨으면 회원가입부터 로그인까지 잘 될겁니다.
원래 이 게시글에서 끝내려고 했지만 길이가 너무 길어진 관계로
회원목록 조회 및 상세조회, 삭제 등은 다음 게시글에서 정리하겠습니다:D