회원가입 완료 버튼을 누를때 <form action="/user/join" method="POST"> 방식으로 하지않고

username, password, email 세개의 값을 자바스크립트에 들고가서 처리해보기

 

 

 

 

1. '회원가입 완료'  버튼 클릭시 alert 뜨는지 테스트

 

[joinForm]

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!-- ../layput 는 user보다 한 칸위의 폴더라는 뜻  -->
<%@ include file="../layout/header.jsp"%>

<div class="container">

	<form action="/action_page.php">
		<div class="form-group">
			<label for="username">UserName : </label> <input type="text" class="form-control" placeholder="Enter UserName" id="username">
		</div>
		
		<div class="form-group">
			<label for="email">Email : </label> <input type="email" class="form-control" placeholder="Enter email" id="email">
		</div>
		
		<div class="form-group">
			<label for="pwd">Password : </label> <input type="password" class="form-control" placeholder="Enter password" id="password">
		</div>
		
		<button type="submit" class="btn btn-primary">회원가입 완료</button>
	</form>

</div>

<%@ include file="../layout/footer.jsp"%>

 

 

- js 폴더를 만들고 user.js 파일생성 → 스프링이 static을 기본적으로 찾고있는데 정적파일인 js를 넣어준다. 

 

 

 

 

 

 

[ joinForm.jsp ]

 

form이 submit 안되도록 버튼 태그를 form 밖으로 내보내고 버튼 태그에 id를 넣어 자바스크립트와 연결해준다.

<form>
...
</form>
<button id="btn-save" class="btn btn-primary">회원가입 완료</button>
</div><script src="/js/user.js"></script>

<%@ include file="../layout/footer.jsp"%>

마지막 스크립트 추가하여 src="/js/user.js"를 참조한다. 

/blog 경로수정?

 

[user.js]

 

/js/user.js

let index = {
	init: function() {
		$("#btn-save").on("click", ()=>{
			this.save();
		});
	},
	
	save: function(){
		alert('user의 save함수 호출 됨');
	}
}

index.init();
  • $("#btn-save").on("click", ()=>{ });

 id가 btn-save 인 '회원가입 완료' 버튼을 클릭했을 때 this.save(); 함수가 실행할 것이다.

.on(첫번째 파라미터, 두번째 파라미터) ▶ 첫번째 파라미터 : click  / 두번째 파라미터는 무엇을 할건지? : this.save();

 

  • this.save();

클릭했을때 save함수가 실행된다.

 

  • index.init();

마지막에 index에 있는 init을 호출해줘야 실행된다.

 

 

 

 

= save함수 메세지가 성공적으로 뜬다.

 

 

 

 

2. 이번엔 id가 username, password, email 값들을 가져와 data에 담고 잘 불러오는지 console.log 테스트

 

...
save: function(){
		//alert('user의 save함수 호출 됨');
		let data = {
			username: $("#username").val(),
			password: $("#password").val(),
			email: $("#email").val()
		}
		
		console.log(data);
	}

 

회원가입 완료 버튼 클릭시 콘솔창에 잘 불러온다.

 

 

 

회원가입시 AJAX 를 사용하는 2가지 이유

 

1. 요청에 대한 응답을 html이 아닌 Data (json) 를 받기 위해서.

 

  • 웹과 앱의 통신 

- 웹 (html로 응답)

  클라이언트가 회원가입 화면을 요청 → 서버가 html로 만들어서 화면을 보여줌

  클라이언트가 회원가입 자체를 요청 → 서버가 회원가입 수행 → DB → 메인화면 html 보여줌

 

- 앱 (data로 응답)

 앱은 자바코드로 화면디자인이 돼있어서 응답은 html로 보여주면 안되니까

data만 리턴받고 메인페이지로 이동해면 된다

 

 

= 앱과 웹브라우저의 html리턴, 데이터리턴 응답방식이 다르다.

서버를 두번 만들지말고 Data를 리턴하는 서버로 만들면 된다.

 

 

  • data 리턴하는 서버 통신

브라우저 : 회원가입 요청 → 서버 → DB  서버가 Data(정상)를 리턴  브라우저 응답

다시 브라우저 : 메인페이지 요청 → 서버가 .html 메인페이지 응답

 

앱 : 회원가입 요청 → 서버 → DB 서버가 Data리턴  앱 자체적으로 화면이동

 

 

따라서 앱, 브라우저에서 data를 리턴해주는 서버로 통일시키기!

 

 

 

2. 비동기 통신을 하기 위해

 

비동기 통신이란?  순서에 상관없이 일처리한다.

 

1을 다운로드 하면서 기다릴때 다른것을 할 수 있는 다음절차 2로 넘어가서 일처리 ,다운로드가 완료되면 호출해줘!

- 2에서 하던일을 멈추고 1로 돌아가는것콜백

- 2에서 완료 후 쉬던 중 1로 돌아가는것비동기적

 

회원가입도 통신이기 때문에 잠깐 멈춰질때 이걸 비동기가 막아준다.

즉 순서대로 하지 않아도 돼서 효율적이라는 것

 

 

 

 


이제 username, password, email 값을 담은 data를 ajax 호출하기

 

ajax 호출시 default가 비동기 호출

: 회원가입 호출이 100초동안 실행되고 있다면 다음 단계를 실행하던 와중에 실행완료가 되면 다시 돌아가서 수행완료.

 

[user.js]

$.ajax({ 
        type: "POST",
        url: "/auth/joinProc",
        data: JSON.stringify(data), // http body데이터
        contentType: "application/json; charset=utf-8",// body데이터가 어떤 타입인지(MIME)
        dataType: "json" //javascript오브젝트로 변경
    }).done(function(resp){
        if(resp.status === 500){
            alert("회원가입에 실패하였습니다.");
        }else{
            alert("회원가입이 완료되었습니다.");
            location.href = "/";   // 회원가입 완료 후 메인페이지로
        }

    }).fail(function(error){
        alert(JSON.stringify(error));
    });
  • 회원가입 insert 할거니까 POST 로 보내기
  • data: JSON.stringify(data) : data가 자바스크립트 오브젝트라서 자바가 못읽기 때문에 JSON타입으로 바꾸기
  • dataType: "json" : 서버로부터 응답이 왔을 때 기본적으로 모든 것이 문자열이고 만약 생긴게 json이라면 자바스크립트 오브젝트로 변경해서 응답해줌

    

// 경로설정

 

자바스크립트 오브젝트 vs JSON 형태 비교
<body>
    <script>
        let data ={
          username:"love",
	  password:"1234",
	  email:"love@naver.com"
        };

        console.log(data); // 자바스크립트 오브젝트
        console.log(JSON.stringify(data)); // JSON 문자열
    </script>
</body>

 

자바스크립트 obj 와 JSON 형식

 

 

 

 

ajax의 url: "/auth/joinProc" 요청주소 Controller 만들기 

 

 

[UserApiController]

 

@RestController //데이터만 리턴
public class UserApiController {
	
	@PostMapping("/auth/joinProc")
	public int save(@RequestBody User user) {
		System.out.println("UserApiController : save 호출됨");
		return 1;
	}
}

console.log

성공적으로 회원가입이 완료 시 return 1 이 되면  ajax에 resp에 1이 들어가고

.done(function(resp){
        if(resp.status === 500){
            alert("회원가입에 실패하였습니다.");
        }else{
            alert("회원가입이 완료되었습니다.");
            location.href = "/";   // 회원가입 완료 후 메인페이지로
        }

회원가입 완료 팝업창이 뜨고 메인페이지로 이동

 

 

 

 

 

 

 

패키지 dto 를 만들고 ResponseDto 클래스 생성 - 응답할 때 쓸 것

 

 

 [ResponseDto]

 

 UserApiController 의 리턴 값이 되는 클래스

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResponseDto<T> {
	int status;
	T data;
}

 

 

[UserApiController]

@PostMapping("/auth/joinProc")
public ResponseDto<Integer> save(@RequestBody User user) {
    System.out.println("UserApiController : save 호출됨");
    return new ResponseDto<Integer>(HttpStatus.OK.value(),1);
}

 

return new ResponseDto<Integer>(HttpStatus.OK.value(),1);

  • 첫번째 파라미터는 status값  ( status 값이 200이면 = 통신이 정상적으로 성공했다. )
  • 두번째 파라미터는 data 

 

리턴 값을 resp에 넣고 ajax에서 console.log(resp) 했을 때 

ajax가 통신을 성공하고 서버가 json을 리턴해주면 자동으로 자바 오브젝트로 변환해줌

 

 

 

 

이제 회원가입을 하면 유저정보를 DB에 insert 하자

UserApiController 에서 userRepository.save(user); 를 써서 바로 insert 해도 되지만 중간에 Service가 필요한 이유

 

이유1 . 서비스 의미 

 

예를들어 '송금서비스'

홍길동이 임꺽정에게 빌린돈 일부를 갚았다.

= 두사람에게 두 개의 업데이트 발생.

repository 의 crud 처럼 송금서비스는 u(update)를 두 개 들고있다

 

둘다 오류가 없으면 commit 을 하지만 한개가 업뎃 실패? 둘다 원상복귀 rollback 을 해야한다.

즉 홍길동, 임꺽정 각 하나의 트랜젝션을 두 트랜잭션을 하나의 트랜잭션으로 묶어서 서비스화 할 수 있다.

 

 

[UserService]

@Service
public class UserService {

@Autowired
private UserRepository userRepository;

@Transactional
public int 회원가입(User user) {
    try {
    	user.setRole(RoleType.USER)
        userRepository.save(user);
        return 1;
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("UserService : 회원가입() : " + e.getMessage());
    }
    return -1;
}
}

 

@Service 은 스프링이 컴포넌트 스캔을 통해서 Bean에 등록을 해준다 (= IoC) 즉 메모리에 대신 띄워준다.

 

@Transactional  ( import org.springframework.transaction.annotation.Transactional; )

: '회원가입' 전체 서비스가 하나의 트랜잭션으로 묶이게 된다.

 

try catch 문 전체가 성공하면 commit , 실패시 rollback (원상복귀)

 

 

▼ UserService 를 여기에 리턴/요청하기 

 

[UserApiController]

@RestController //데이터만 리턴
public class UserApiController {

@Autowired
private UserService userService;  // DI 하기

@PostMapping("/auth/joinProc")
public ResponseDto<Integer> save(@RequestBody User user) { // 직접 받는건 username, password, email
    System.out.println("UserApiController : save 호출됨");
    int result = userService.회원가입(user);
    return new ResponseDto<Integer>(HttpStatus.OK.value(), result);
  }
}

User객체에서 id는 DB가 알아서 넣고 username, password, email 은 회원가입 페이지에 직접 받고

role은 서비스에서 받기. userService.회원가입에 넣었음 → user.setRole(RoleType.USER);

createDate 은 자동으로 넣어진다.

 

 

 

- DB에 insert가 된 결과 

 

 

 

 

만약 UserService 에서 회원가입 실패시 -1 로 리턴을 받고 UserApiController에서도 -1

[GlobalExceptionHandler] 로 호출가서 오류메세지가 응답이 된다. ( 예외 모든것을 여기서 처리하니까)

 

 

[GlobalExceptionHandler]

@ControllerAdvice
@RestController
public class GlobalExceptionHandler {
	
	@ExceptionHandler(value = IllegalArgumentException.class)
	public String handleArgumentException(IllegalArgumentException e) {
		return "<h1>" + e.getMessage() + "<h1>";
	}
}

 

 

리턴값을 e.getMessage() 메세지로 리턴하기보다 통신상태와 정상적으로 insert를 했는지 알기위해

ResponseDto 로 리턴하기

 

▶  return new ResponseDto<String>(HttpStatus.INTERNAL_SERVER_ERROR.value(),  e.getMessage());

@ControllerAdvice
@RestController
public class GlobalExceptionHandler {
	
	@ExceptionHandler(value = Exception.class)
	public ResponseDto<String> handleArgumentException(Exception e) {
		return new ResponseDto<String>(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
	}
}

ResponseDto 의 첫번째 파라미터가 int status 라서 .value() 를 붙인다.

 

  • [GlobalExceptionHandler]

HttpStatus.INTERNAL_SERVER_ERROR.value()

 

  • [UserApiController]

HttpStatus.OK.value()

 

 

 

[ResponseDto]

public class ResponseDto<T> {

   int  status;
   T data;
}

 

 

 

정상적으로 회원가입 save를 했을때 

 

반응형
LIST

+ Recent posts