UserController.java
package com.pure.blog.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class UserController {
@GetMapping("/user/joinForm")
public String joinForm() {
return "user/joinForm";
}
@GetMapping("/user/loginForm")
public String loginForm() {
return "user/loginForm";
}
}
joinForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<div class="container">
<form action="/action_page.php" class="was-validated">
<div class="form-group">
<label for="uname">Username:</label> <input type="text" class="form-control" id="username" placeholder="아이디를 입력해주세요." name="username" required>
<div class="valid-feedback"></div>
<div class="invalid-feedback">멋진 아이디를 입력해주세요.</div>
</div>
<div class="form-group">
<label for="pwd">Password:</label> <input type="password" class="form-control" id="password" placeholder="비밀번호를 입력해주세요." name="password" required>
<div class="valid-feedback"></div>
<div class="invalid-feedback">비밀번호를 입력해주세요.</div>
</div>
<div class="form-group">
<label for="uname">Email:</label> <input type="text" class="form-control" id="email" placeholder="이메일 주소를 입력해주세요." name="email" required>
<div class="valid-feedback"></div>
<div class="invalid-feedback">이메일을 입력해 주세요</div>
</div>
</form>
<button id="btn-save" class="btn btn-primary">회원가입 완료</button>
</div>
<script src="/blog/js/user.js"></script>
<%@ include file="../layout/footer.jsp"%>
loginForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<div class="container">
<form action="/action_page.php" class="was-validated">
<div class="form-group">
<label for="uname">Username:</label> <input type="text" class="form-control" id="username" placeholder="아이디를 입력해주세요." name="username" required>
</div>
<div class="form-group">
<label for="pwd">Password:</label> <input type="password" class="form-control" id="password" placeholder="비밀번호를 입력해주세요." name="password" required>
</div>
<div class="form-group form-check">
<label class="form-check-label"> <input class="form-check-input" type="checkbox" name="remember" required> 로그인 상태 유지
</label>
</div>
<button type="submit" class="btn btn-primary">로그인</button>
</form>
</div>
<%@ include file="../layout/footer.jsp"%>
header.jsp 링크 수정 + jquery 최신으로 변경 ($.ajax를 인식하지 못하는 문제가 있었음.)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-md bg-dark navbar-dark">
<a class="navbar-brand" href="/blog/">Pure</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsibleNavbar">
<ul class="navbar-nav">
<li class="nav-item"><a class="nav-link" href="/blog/user/loginForm">로그인</a></li>
<li class="nav-item"><a class="nav-link" href="/blog/user/joinForm">회원가입</a></li>
</ul>
</div>
</nav>
<br>
회원가입시 Ajax를 사용하는 이유
1. 요청에 대한 응답을 html이 아닌 data로 받기 위함.
만약에 웹이 아니고 앱을 사용한다고 하면 html을 응답해주면 앱이 이해하질 못함.
이러면 앱용 서버, 웹용 서버 이렇게 두 개의 서버를 따로 만들어야 하는데 그럴 필요 없이 서버에서 data만 응답해주면
하나의 서버로 통합이 가능.
2. 비동기 통신을 하기 위함.
앱은 통신을 하게 되면 잠깐 멈추는 현상이 발생함. 이를 방지해줌.
페이지 로딩은 절차적임. --> 사용자 경험이 나빠짐.
비동기 통신을 통해 시간을 아낌.
user.js
let index = {
init: function() {
$("#btn-save").on("click", ()=>{
this.save();
});
},
save: function() {
let data = {
username: $("#username").val(),
password: $("#password").val(),
email: $("#email").val()
}; //javascript 오브젝트임.
//ajax 호출시 default가 비동기 호출
//ajax 통신을 이용하여 위의 data를 json으로 변경하여 insert 요청할 것임.
//ajax가 통신에 성공해서 서버가 json형태로 응답을 해주면 자동으로 자바 오브젝트로 변환해줌. (dataType을 지정하지 않아도.)
$.ajax({
//회원가입 수행 요청
type: "POST",
url: "/blog/api/user",
data: JSON.stringify(data), //js object를 JSON형태로 변경. http body 데이터.
contentType: "application/json; charset=utf-8" //body 데이터의 타입 지정 (MIME)
//dataType: "json" //서버에서 응답이 올 때 문자열로 오는데 문자열 형태가 'json'이라면 => js object로 파싱 해줌.
}).done(function(resp){
alert("회원가입이 완료되었습니다.");
location.href="/blog";
}).fail(function(error){
alert(JSON.stringify(error));
}); //ajax 통신을 이용하여 3개의 데이터를 JSON으로 변경하여 insert 요청.
}
}
index.init();
*화살표 함수를 쓰는 이유.*
https://poiemaweb.com/es6-arrow-function
ajax 요청을 받을 컨트롤러
UserApiController.java
package com.pure.blog.controller.api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.pure.blog.dto.ResponseDto;
import com.pure.blog.model.RoleType;
import com.pure.blog.model.User;
import com.pure.blog.service.UserService;
@RestController
public class UserApiController {
@Autowired
private UserService userService;
@PostMapping("/api/user")
public ResponseDto<Integer> save(@RequestBody User user) {
System.out.println("UserApiController: save 호출됨");
//DB에 insert 하기
user.setRole(RoleType.USER);
int result = userService.회원가입(user);
return new ResponseDto<Integer>(HttpStatus.OK.value(), result); //(status, data)
}
}
ResponseDto.java
package com.pure.blog.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResponseDto<T> {
int status;
T data;
}
UserService.java
package com.pure.blog.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.pure.blog.model.User;
import com.pure.blog.repository.UserRepository;
//component-scan으로 Bean에 등록. (IoC)
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public int 회원가입(User user) {
try {
userRepository.save(user);
return 1;
} catch (Exception e) {
e.printStackTrace();
System.out.println("UserService: 회원가입() : " + e.getMessage());
}
return -1;
}
}
GlobalExceptionHandler 수정
package com.pure.blog.handler;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import com.pure.blog.dto.ResponseDto;
@ControllerAdvice
@RestController
public class GlobalExceptionHandler {
@ExceptionHandler(value=IllegalArgumentException.class)
public ResponseDto<String> handleArgumentException(Exception e) {
return new ResponseDto<String>(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
}
}
상태값으로 status를 보는 것이 더 좋기 때문에 수정함.
'취업 준비 > Spring boot' 카테고리의 다른 글
23. 전통적인 방식의 로그인 방법 (0) | 2022.01.26 |
---|---|
22. DB 격리 수준 (0) | 2022.01.26 |
20. 메인화면 만들기 w/ bootstrap4 (0) | 2022.01.25 |
19. 스프링 기본 파싱전략과 JSON 통신 (0) | 2022.01.25 |
18. 예외처리 컨트롤러 만들기 (0) | 2022.01.24 |