강사님이 만드신 todo에서 필요한 것만 직접 코드적고 할 수 있게 만들어오셨다.
나중에 git에 올려 주소를 넣어놓겠다.
TODO주석 아래에 코드가 적혀있는 것들로 보면 된다.
(설명은 주석으로)
package com.example.my.domain.auth.service;
import com.example.my.common.dto.ResponseDTO;
import com.example.my.domain.auth.dto.ReqJoinDTO;
import com.example.my.domain.auth.dto.ReqLoginDTO;
import com.example.my.model.user.entity.UserEntity;
import com.example.my.model.user.repository.UserRepository;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import java.time.LocalDateTime;
import java.util.Optional;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor //final 같은 친구들 땜에 , Autowired안쓰면 private final이랑 같이
@Transactional(readOnly = true)
public class AuthServiceApiV1 {
private final UserRepository userRepository;
public ResponseEntity<?> login(ReqLoginDTO dto, HttpSession session) {
// TODO : 리파지토리에서 아이디로 삭제되지 않은 유저 찾기
// TODO : 없으면 (존재하지 않는 사용자입니다.) 메시지 리턴
// TODO : 비밀번호가 일치하지 않으면 (비밀번호가 일치하지 않습니다.) 메시지 리턴
// TODO : 세션에 로그인 유저 정보 저장
// TODO : 응답 데이터로 리턴하기 (로그인에 성공하였습니다.)
return null;
}
public ResponseEntity<?> join(ReqJoinDTO dto) {
// TODO : 회원가입 정보 입력했는지 확인
if(
dto.getUser().getId() == null ||
dto.getUser().getId().equals("") ||
dto.getUser().getPassword() ==null ||
dto.getUser().getPassword().equals("")
){
return new ResponseEntity<>(
ResponseDTO.builder()
.code(1)
.message("아이디나 비밀번호를 입력해주세요")
.build(),
HttpStatus.BAD_REQUEST
);
}
// TODO : 리파지토리에서 아이디로 유저 찾기
Optional<UserEntity> userEntityOptional = userRepository.findById(dto.getUser().getId());
// optional - null 체크 하기위해서 쓴다
// TODO : 있으면 (이미 존재하는 아이디입니다.) 메시지 리턴
if(userEntityOptional.isPresent()){
return new ResponseEntity<>(
ResponseDTO.builder()
.code(1)
.message("이미 존재하는 아이디입니다.")
.build(),
HttpStatus.BAD_REQUEST
);
}
// TODO : 없으면 회원가입 처리
UserEntity userEntity = UserEntity.builder()
.id(dto.getUser().getId())
.password(dto.getUser().getPassword())
.createDate(LocalDateTime.now())
.build();
userRepository.save(userEntity);
// TODO : 응답 데이터로 리턴하기 (회원가입에 성공하였습니다.)
return new ResponseEntity<>(
ResponseDTO.builder()
.code(0)
.message("회원가입에 성공하였습니다.")
.build(),
HttpStatus.OK
);
}
}
필요한 부분만 가져옴.
@PostMapping("/join")
public ResponseEntity<?> join(@RequestBody ReqJoinDTO dto) {
// TODO : 서비스에서 회원가입하기
return authServiceApiV1.join(dto);
}
실행하고 POSTMAN에 들어가서 body에 적어 send를 해준다.
id, password 둘다 null이면 아래의 message가 나온다.
값을 입력하면 성공했다고 나온다.
db 설치, 툴 안깔아도 어디서든 사용할 수 있다.
아래 그림의 주소를 따라 적어서 들어가 연결을 클릭한다.
user테이블을 클릭하면 기본 쿼리문이 만들엊고 실행해보면 데이터가 나온다.
유효성 체크를 위해 @Valid를 해준다.
package com.example.my.domain.auth.dto;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class ReqJoinDTO {
@Valid
@NotNull(message = "유저 정보를 입력해주세요.")
private User user;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
public static class User {
@NotBlank(message = "아이디를 입력해주세요")
@Size(min = 4, message = "아이디는 4자 이상 입력해주세요.")
private String id;
@NotBlank(message = "비밀번호를 입력해주세요")
@Pattern(regexp = "^(?=.*[a-zA-Z])(?=.*\\\\d)(?=.*[@#$%^&+=])(?=\\\\S+$).{8,16}$", message = "비밀번호 양식에 맞추어서 입력해주세요.")
private String password;
}
}
유효성 체크(validation)을 해서 값이 있다는 걸아니까 script를 작성해준다.
// 회원가입 요청
// 회원가입 버튼을 누르면 실행되는 함수
const requestJoin = () => {
// 서버와 통신하기 전에 입력값 검증
if (!validateFields()) {
return;
}
// TODO 회원가입 요청
const dto = {
user: {
id: document.getElementById("id").value,
password: document.getElementById("password").value,
},
};
fetch("/api/v1/auth/join",{
method : "POST",
headers : {
"Content-Type" : "application/json;charset=utf-8"
},
body : JSON.stringify(dto)
})
.then((response) => response.json())
.then((result) => {
alert(result.message);
if(result.code === 0){
//회원가입 성공
location.replace("/auth/login"); //현재페이지에서 다음페이지로(뒤로가기 안됨)
}
})
};
실행해서 join페이지로 들어가 테스트를 해본다.
DB에 이미 존재하는 아이디 이기 때문에 해당 알림창이 뜬다.
없으면 성공하였다고 뜬다.
성공하면 로그인페이지로 넘어간다.
로그인을 실행하기 위해 AuthServiceApiV1에서 해결하지 않은 나머지 todo를 해결한다.
public class AuthServiceApiV1 {
private final UserRepository userRepository;
public ResponseEntity<?> login(ReqLoginDTO dto, HttpSession session) {
// 유효성체크
if(
dto.getUser().getId() == null ||
dto.getUser().getId().equals("") ||
dto.getUser().getPassword() ==null ||
dto.getUser().getPassword().equals("")
){
return new ResponseEntity<>(
ResponseDTO.builder()
.code(1)
.message("아이디나 비밀번호를 입력해주세요")
.build(),
HttpStatus.BAD_REQUEST
);
}
// 리파지토리에서 아이디로 삭제되지 않은 유저 찾기
Optional<UserEntity> userEntityOptional = userRepository.findByIdAndDeleteDateIsNull(dto.getUser().getId());
// 없으면 (존재하지 않는 사용자입니다.) 메시지 리턴
if (userEntityOptional.isEmpty()) {
return new ResponseEntity<>(
ResponseDTO.builder()
.code(1)
.message("존재하지 않는 사용자입니다.")
.build(),
HttpStatus.BAD_REQUEST
);
}
UserEntity userEntity = userEntityOptional.get();
// 비밀번호가 일치하지 않으면 (비밀번호가 일치하지 않습니다.) 메시지 리턴
if(!userEntity.getPassword().equals(dto.getUser().getPassword())){
return new ResponseEntity<>(
ResponseDTO.builder()
.code(1)
.message("비밀번호가 일치하지 않습니다.")
.build(),
HttpStatus.BAD_REQUEST
);
}
// 세션에 로그인 유저 정보 저장
session.setAttribute("dto", LoginUserDTO.of(userEntity));
// 응답 데이터로 리턴하기 (로그인에 성공하였습니다.)
return new ResponseEntity<>(
ResponseDTO.builder()
.code(0)
.message("로그인에 성공하였습니다.")
.build(),
HttpStatus.OK
);
}
실행해서 localhost에 들어가 실행해보면 아래와 같이 된다.
login을 하기 위한 script를 작성해준다.
const requestLogin = () => {
// 서버와 통신하기 전에 입력값 검증
if (!validateFields()) {
return;
}
// 로그인 요청
const dto = {
user : {
id : document.getElementById("id").value,
password : document.getElementById("password").value
}
}
fetch("/api/v1/auth/login", {
method : "POST",
headers : {
"Content-Type" : "application/json;charset=utf-8"
},
body : JSON.stringify(dto)
})
.then(response => response.json())
.then(result => {
alert(result.message);
if (result.code === 0) {
location.replace("/");
}
});
};
db에 있는 아이디,비밀번호로 로그인을 하면 성공하였다고 나온다.
@ToString을 붙여준다.
package com.example.my.common.dto;
import com.example.my.model.user.entity.UserEntity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
@ToString
public class LoginUserDTO {
private User user;
public static LoginUserDTO of(UserEntity userEntity) {
return LoginUserDTO.builder()
.user(User.fromEntity(userEntity))
.build();
}
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
@ToString
public static class User {
private Long idx;
private String id;
private String password;
private List<String> roleList;
public static User fromEntity(UserEntity userEntity) {
return User.builder()
.idx(userEntity.getIdx())
.id(userEntity.getId())
.password(userEntity.getPassword())
.roleList(
userEntity.getUserRoleEntityList()
.stream()
.map(userRoleEntity -> userRoleEntity.getRole())
.toList()
)
.build();
}
}
}
로그인 성공시 유저 정보가 넘어갈 수 있도록 한다.
@GetMapping({"", "/"}) // 결로를 여러개 넣을 때
public ModelAndView todoTablePage(HttpSession session) {
ModelAndView modelAndView = new ModelAndView();
// 세션에서 유저정보가 null이면 로그인페이지로 강제이동 , 로그인 해야 넘어가짐
if (session.getAttribute("dto") == null) {
modelAndView.setViewName("redirect:/auth/login");
return modelAndView;
}
// null이 아니면 todo정보 담아서 메인 페이지 이동
System.out.println(session.getAttribute("dto"));
modelAndView.setViewName("todo/table");
return modelAndView;
}
실행해서 들어가 localhost:8080 뒤에 어떤 엔트포인트를 적어도 login페이지에 머물게 된다.
로그인 성공한 유저의 정보가 넘어올 수 있도록 한다.
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="javascript:void(0)">
<span id="userId" th:text="${session.dto.user.id}"></span>'s work
</a>
</div>
<button type="button" onclick="logout()" class="btn btn-default navbar-btn navbar-right">logout</button>
</div>
</nav>
로그인의 성공하면 user's work라고 임시로 되어있던 것이 유저의 정보를 받아 id인 test's work로 변경되어 있는 것을 볼 수 있다.
로그아웃을 하기 위해 함수를 만들어준다.
const logout = () => {
location.replace("/auth/logout");
}
로그아웃을 눌리게 되면
로그인 페이지로 돌아간다.
- 회원가입 페이지 이동
(컨틀롤러)- 회원정보 입력
- 회원가입 버튼 클릭
4.유효성 체크(반드시 해야함)
(예를 들어 아이디를 입력안함, 비밀번호를 양식에 안맞게 입력함, 비밀번호와 비밀번호 확인이 다름)- fetch로 서버에 dto전송
- RestController -> service
- 유효성 체크
(화면에서 체크한 것 한번 더 체크
아이디 중복 확인)- DB에 유저정보 저장
- ResponseEntity + ResponseDTO + HttpStatus
- 화면에서 데이터 받아서 로그인페이지로 이동