테이블 생성할 때
application.yml 파일에서 create로 바꾸고

spring:
application:
name: login-spring
datasource:
url: jdbc:h2:tcp://localhost/~/testApi
driver-class-name: org.h2.Driver
username: sa
jpa:
hibernate:
ddl-auto: create #update
properties:
hibernate:
format_sql: true
thymeleaf:
prefix: classpath:/templates/
suffix: .html
logging:
level:
org.hibernate.SQL: debug
org.hibernate.orm.jdbc.bind: trace

package login.login_spring.domain;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Entity
@Setter
@Getter
public class EzenMember {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String loginId;
private String name;
private String password;
private String grade;
}
h2 들어가서 확인

- 회원 아이디로 조회하는 기능 추가
(interface로 생성)

package login.login_spring.reporitory;
import login.login_spring.domain.EzenMember;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface MemberRepository extends JpaRepository<EzenMember, Long> {
//사용자 아이디로 조회하는 기능 추가
Optional<EzenMember> findByLoginId(String loginId);
}
아래와 같이 콘솔창에 오류가 없으면 된다

- memberservice
작성순서 유의
package login.login_spring.service;
import login.login_spring.domain.EzenMember;
import login.login_spring.reporitory.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository; //final 붙이기
//회원가입
public Long join(EzenMember member) {
validateDuplicateMember(member);
this.memberRepository.save(member);
return member.getId();
}
//중복회원 검증
private void validateDuplicateMember(EzenMember member){
Optional<EzenMember> findMember = memberRepository.findByLoginId(member.getLoginId());
if(findMember.isPresent()){
throw new IllegalStateException("이미 존재하는 회원");
}
}
//전체회원 조회
public List<EzenMember> findMember(){
return memberRepository.findAll();
}
//회원 한 명 조회
public Optional<EzenMember> findOne(Long memberId) {
return memberRepository.findById(memberId);
}
// 회원삭제
public void delete(EzenMember member){
this.memberRepository.deleteById(member.getId());
}
}

- dto 폴더 생성 후 MemberForm 생성

Ezen멤버에서 코드를 긁어오면 된다
package login.login_spring.dto;
import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class MemberForm {
@NotEmpty
private String loginId;
@NotEmpty
private String name;
@NotEmpty(message = "비밀번호는 필수입니다")
private String password;
private String grade;
}
- 회원가입 폼 작성 addMemberForm
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>addMemberForm</title>
<link href="/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div>
<div class="py-3 text-center max600">
<h2>회원 가입</h2>
</div>
<div class="py-3">
<h2>회원 정보 입력</h2>
</div>
<form>
<div class="mb-3">
<label for="userId" class="form-label">로그인 ID</label>
<input type="text" class="form-control" id="userId" name="userId">
</div>
<div class="mb-3">
<label for="password" class="form-label">비밀번호</label>
<input type="password" class="form-control" id="password" name="password">
</div>
<div class="mb-3">
<label for="name" class="form-label">이름</label>
<input type="text" class="form-control" id="name" name="name">
</div>
<hr>
<div class="row">
<div class="col">
<button type="submit" class="btn btn-primary btn-lg w-100">회원가입</button>
</div>
<div class="col">
<button type="submit" class="btn btn-dark btn-lg w-100">취소</button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>

- 타임리프를 이용해서 addMemberForm 작성
th 를 사용하면 꼭 새로 새로고침▶버튼 클릭
th 를 사용하면 id, name 값이 필요없다 (버튼박스확인)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>addMemberForm</title>
<link href="/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div>
<div class="py-5 text-center max600">
<h2>회원 가입</h2>
</div>
<h4 class="mb-3">회원 정보 입력</h4>
<form th:action th:Object="${memberForm}" method="post">
<div class="mb-3">
<label th:for="loginId">로그인 ID</label>
<input type="text" th:field="*{loginId}" class="form-control" >
</div>
<div class="mb-3">
<label th:for="password">비밀번호</label>
<input type="password" th:field="*{password}" class="form-control" >
</div>
<div class="mb-3">
<label th:for="name">이름</label>
<input type="text" th:field="*{name}" class="form-control" >
</div>
<hr>
<div class="row">
<div class="col">
<button type="submit" class="btn btn-primary btn-lg w-100">회원가입</button>
</div>
<div class="col">
<button type="submit" class="btn btn-dark btn-lg w-100">취소</button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>
- MemberController 수정 (포스트)
순서에 유의

package login.login_spring.controller;
import login.login_spring.domain.EzenMember;
import login.login_spring.dto.MemberForm;
import login.login_spring.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
@GetMapping("/add")
public String createForm(Model model){
model.addAttribute("memberForm", new MemberForm());
return "user/addMemberForm";
}
@PostMapping("/add")
public String create(@ModelAttribute("memberForm") MemberForm memberForm) {
EzenMember ezenMember = new EzenMember();
ezenMember.setLoginId(memberForm.getLoginId());
ezenMember.setName(memberForm.getName());
ezenMember.setPassword(memberForm.getPassword());
ezenMember.setGrade("User");
memberService.join(ezenMember);
return "redirect:/";
}
}
- 빈 칸으로 입력하고 회원가입을 클릭해도 데이터 생성이 된다

- MemberController - @postMapping 부분을 다시 수정한다
(중복검사)
반드시 @Model ~ 앞으로 @valid(jakarta) 입력 후 MemberForm memberForm, BindingResult~
if(~
까지 입력

@PostMapping("/add")
public String create(@Valid @ModelAttribute("memberForm") MemberForm memberForm, BindingResult bindingResult) {
if(bindingResult.hasErrors()){
return "user/addMemberForm";
}
EzenMember ezenMember = new EzenMember();
ezenMember.setLoginId(memberForm.getLoginId());
ezenMember.setName(memberForm.getName());
ezenMember.setPassword(memberForm.getPassword());
ezenMember.setGrade("User");
memberService.join(ezenMember);
return "redirect:/";
}
}
- addMemberForm 수정

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>addMemberForm</title>
<link href="/css/bootstrap.css" rel="stylesheet">
<link href="/css/style.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div>
<div class="py-5 text-center max600">
<h2>회원 가입</h2>
</div>
<h4 class="mb-3">회원 정보 입력</h4>
<form th:action th:Object="${memberForm}" method="post">
<div class="mb-3">
<label th:for="loginId">로그인 ID</label>
<input type="text" th:field="*{loginId}" class="form-control" th:errorClass="field-error">
<div th:errors="*{loginId}" class="field-error"></div>
</div>
<div class="mb-3">
<label th:for="password">비밀번호</label>
<input type="password" th:field="*{password}" class="form-control" th:errorClass="field-error">
<div th:errors="*{password}" class="field-error"></div>
</div>
<div class="mb-3">
<label th:for="name">이름</label>
<input type="text" th:field="*{name}" class="form-control" th:errorClass="field-error">
<div th:errors="*{name}" class="field-error"></div>
</div>
빈칸 상태로 회원가입을 클릭하면
이렇게 비어있을 수 없다고 표시된다

그리고 중복 아이디를 입력하면 존재하는 회원이라고 뜬다

설정이 완료되면
application.yml 들어가서 create > update로 변경 - ▶ 오른쪽 상단 실행

- 회원목록 페이지를 만들자


- home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>home</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.css}">
<link th:href="@{/css/style.css}" rel="stylesheet">
</head>
<body>
<div class="container max600">
<div class="py-5 text-center">
<h2>홈 화면</h2>
</div>
<div class="row">
<div class="col">
<button th:onclick="|location.href='@{/add}'|" type="button" class="btn btn-secondary btn-lg w-100">회원 가입</button>
</div>
<div class="col">
<button th:onclick="|location.href='@{/members}'|" type="button" class="btn btn-dark btn-lg w-100">회원목록</button>
</div>
<div class="col">
<button th:onclick="|location.href='@{/login}'|" type="button" class="btn btn-dark btn-lg w-100">로그인</button>
</div>
</div>
</div>
<hr>
</body>
</html>

- memberController
//회원 목록
@GetMapping("/members")
public String listMembers(){
return "admin/memberList";
}
//admin 폴더 생성 후 memberList 생성
//회원 목록
@GetMapping("/members")
public String listMembers(Model model){
List<EzenMember> members = memberService.findAllMember();
model.addAttribute("members", members);
return "admin/memberList";
}
// 수정
- admin 폴더의 memberList.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>회원 목록</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.css}">
<link th:href="@{/css/style.css}" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2>회원 목록</h2>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>아이디</th>
<th>이름</th>
<th>비밀번호</th>
<th>등급</th>
<th>수정</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
<tr th:each = "member: ${members}">
<td th:text="${member.getId()}">#</td>
<td th:text="${member.getLoginId()}">아이디</td>
<td th:text="${member.getName()}">이름</td>
<td th:text="${member.getPassword()}">비밀번호</td>
<td th:text="${member.getGrade()}">등급</td>
<td><a th:href="@{/members/{id}/edit (id=${member.id})}" class="btn btn-primary">수정</a></td>
<td><a th:href="@{/members/{id}/delete (id=${member.id})}" class="btn btn-danger">삭제</a></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
여기까지의 화면


ctrl + alt + v 하면 위와같은 복사창이 뜬다
디렉터리와 이름 새로 설정 후 확인
- admin폴더의 updateMemberForm
// 매우 중요
<input type="hidden" th:field="*{id}">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>addMemberForm</title>
<link href="/css/bootstrap.css" rel="stylesheet">
<link href="/css/style.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div>
<div class="py-5 text-center max600">
<h2>회원 수정</h2>
</div>
<h4 class="mb-3">회원 정보 입력</h4>
<form th:action th:Object="${memberForm}" method="post">
<input type="hidden" th:field="*{id}">
<div class="mb-3">
<label th:for="loginId">로그인 ID</label>
<input type="text" th:field="*{loginId}" class="form-control" th:errorClass="field-error">
<div th:errors="*{loginId}" class="field-error"></div>
</div>
<div class="mb-3">
<label th:for="password">비밀번호</label>
<input type="password" th:field="*{password}" class="form-control" th:errorClass="field-error">
<div th:errors="*{password}" class="field-error"></div>
</div>
<div class="mb-3">
<label th:for="name">이름</label>
<input type="text" th:field="*{name}" class="form-control" th:errorClass="field-error">
<div th:errors="*{name}" class="field-error"></div>
</div>
<div class="mb-3">
<label th:for="name">등급</label>
<input type="text" th:field="*{grade}" class="form-control" th:errorClass="field-error">
<div th:errors="*{grade}" class="field-error"></div>
</div>
<hr>
<div class="row">
<div class="col">
<button type="submit" class="btn btn-primary btn-lg w-100">회원 수정</button>
</div>
<div class="col">
<button type="submit" class="btn btn-dark btn-lg w-100">취소</button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>
- dto.MemberForm 수정
아래코드 추가
private Long id;
package login.login_spring.dto;
import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class MemberForm {
private Long id;
@NotEmpty
private String loginId;
@NotEmpty
private String name;
@NotEmpty(message = "비밀번호는 필수입니다")
private String password;
private String grade;
}

- MemberController
회원 목록 밑에 멤버 멤버 수정 폼 보여주기
(수정 버튼 클릭했을 때 )
memberService.findOne(memberid);
// ctrl + alt + v 누르면 아래처럼처럼 바뀜
Optional<EzenMember> findMember = memberService.findOne(memberid);
바뀌기 전
// 멤버수정 폼(보여주기)
///members/{사용자마음대로설정}/edit
@GetMapping("/members/{memberid}/edit")
public String updateMemberForm(@PathVariable("memberid") Long memberid, Model model){
// 단, (@PathVariable("memberid") 와 "/members/{memberid}/edit") 같아야한다
Optional<EzenMember> findMember = memberService.findOne(memberid);
EzenMember findMemberGet = findMember.get();
MemberForm memberForm = new MemberForm();
memberForm.setId(findMemberGet.getId());
memberForm.setLoginId(findMemberGet.getLoginId());
memberForm.setName(findMemberGet.getName());
memberForm.setPassword(findMemberGet.getPassword());
memberForm.setGrade(findMemberGet.getGrade());
model.addAttribute("memberform", memberForm);
}
바뀐 후
//회원 목록
@GetMapping("/members")
public String listMembers(Model model){
List<EzenMember> members = memberService.findAllMember();
model.addAttribute("members", members);
return "admin/memberList";
}
// 멤버수정 폼(보여주기)
///members/{사용자마음대로설정}/edit
@GetMapping("/members/{memberid}/edit")
public String updateMemberForm(@PathVariable("memberid") Long memberid, Model model){
Optional<EzenMember> findMember = memberService.findOne(memberid);
EzenMember findMemberGet = findMember.get();
MemberForm memberForm = new MemberForm();
memberForm.setId(findMemberGet.getId());
memberForm.setLoginId(findMemberGet.getLoginId());
memberForm.setName(findMemberGet.getName());
memberForm.setPassword(findMemberGet.getPassword());
memberForm.setGrade(findMemberGet.getGrade());
model.addAttribute("memberForm", memberForm);
return "admin/updateMemberForm";
}
수정버튼까지 나왔다

여기서 등급을 user 가 아니라 admin으로 변경입력 후 회원수정 넣었을 때 바뀌게 해보자
- MemberController 에 아래의 코드를 입력
// 멤버수정 (저장)
@PostMapping("/members/{memberid}/edit")
public String updateMember(@ModelAttribute("memberForm") MemberForm form){
EzenMember ezenMember = new EzenMember();
ezenMember.setId(form.getId());
ezenMember.setLoginId(form.getLoginId());
ezenMember.setName(form.getName());
ezenMember.setPassword(form.getPassword());
ezenMember.setGrade(form.getGrade());
memberService.save(ezenMember);
return "redirect:/members";
//prg 패턴
}
public Long save(EzenMember member) {
this.memberRepository.save(member);
return member.getId();
}
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository; //final 붙이기
//회원가입
public Long join(EzenMember member) {
validateDuplicateMember(member);
this.memberRepository.save(member);
return member.getId();
}
public Long save(EzenMember member) {
this.memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(EzenMember member){
Optional<EzenMember> findMember = memberRepository.findByLoginId(member.getLoginId());
if(findMember.isPresent()){
throw new IllegalStateException("이미 존재하는 회원");

수정이된다

- 수정이 될 때 비밀번호 입력 안 해도 수정완료가 되는데
수정할 때 비밀번호를 입력하지 않으면 수정이 불가하게 만들어보자

- memberController
// 멤버수정 (저장)
@PostMapping("/members/{memberid}/edit")
public String updateMember(@Valid @ModelAttribute("memberForm") MemberForm form
, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "admin/updateMemberForm";
}
EzenMember ezenMember = new EzenMember();
ezenMember.setId(form.getId());
ezenMember.setLoginId(form.getLoginId());
ezenMember.setName(form.getName());
ezenMember.setPassword(form.getPassword());
ezenMember.setGrade(form.getGrade());


- updateMemberForm

비밀번호 div - input 에 아래코드 입력
th:placeholder="*{password}
th:placeholder="'힌트 : 비밀번호는: '+ *{password} +'입니다'"
<div class="mb-3">
<label th:for="password">비밀번호</label>
<input type="password" th:field="*{password}" class="form-control" th:errorClass="field-error" th:placeholder="*{password}">
<div th:errors="*{password}" class="field-error" ></div>
</div>

- 회원목록에서 회원 삭제버튼 클릭하면 삭제 후 회원목록 페이지가 뜨게 해보자
- memberController

- memberList에 있는 주소값을 가져온다
<td><a th:href="@{/members/{id}/delete (id=${member.id})}" class="btn btn-danger">삭제</a></td>
/members/{id}/delete
이 부분
// 멤버 삭제
@GetMapping ("/members/{memberid}/delete")
public String delete(@PathVariable("memberid") Long memberid) {
Optional<EzenMember> findMember = memberService.findOne(memberid);
if(findMember.isPresent()){
EzenMember deleteMember = findMember.get();
memberService.delete(deleteMember);
}
return "redirect:/members";
}
EzenMember findMember = memberService.findOne(memberid);
ctrl alt v 누르면
Optional<EzenMember> findMember = memberService.findOne(memberid);
삭제 잘 된다
'spring' 카테고리의 다른 글
| SPRING_Optinal (0) | 2024.11.22 |
|---|---|
| spring_application.yml (0) | 2024.11.01 |
| spring_IntellJ 트리식 구조로 프로젝트 패키지 보기 (0) | 2024.10.31 |
| spring_인텔리제이에서 부트스트랩 적용하기 (0) | 2024.10.31 |
| spring_home (0) | 2024.10.30 |