@Service : 스프링이 컴포넌트 스캔을 통해서 Bean에 등록을 해주는 어노테이션입니다.(IoC)

 

- UserService.java 파일을 생성합니다.

package com.cos.blog.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cos.blog.model.User;
import com.cos.blog.repository.UserRepository;

// 스프링이 컴포넌트 스캔을 통해서 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;
	}
}

 

* Service가 필요한 이유

1. 트랜잭션 관리 -> 다음시간에 설명!

2. 서비스의 의미 때문

송금서비스로 예를 들어보겠습니다.

위의 경우 2개의 서비스가 존재합니다.

이때 홍길동의 송금은 정상처리되었으나, 임꺽정의 입금이 오류가 발생했다면 전체 서비스는 롤백이 됩니다.

하나하나의 일을 트랜잭션이라 하며, 이 트랜잭션들을 묶어서 서비스라 합니다.

 

 

 

 

강의 주소 : https://youtu.be/I-2Bug08D3Y

user.js를 생성하여 아래와 같이 작성합니다.

let index = {
	init: function() {
		$('#btn-save').on('click', () => { // function(){}, ()=>{} this를 바인딩하기 위해서!!
			this.save();
		});
	}
	
	, save: function() {
//		alert('user의 save함수 호출됨');
		let data = {
			user: $('#username').val(),
			password: $('#password').val(),
			email: $('#email').val()
		};
		
//		console.log(data);
		
		// ajax호출시 default가 비동기 호출
		// ajax 통신을 이용해서 3개의 데이터를 json으로 변경하여 insert 요청!!
		// ajax가 통신을 성공하고 서버가 json을 리턴해주면 자동으로 자바 오브젝트로 변환해준다.
		$.ajax({
			type : 'POST',
			url : '/blog/api/user',
			data : JSON.stringify(data), // http body데이터
			contentType : 'application/json; charset=utf-8', // body데이터가 어떤 타입인지(MIME)
			dataType : 'json' //요청을 서버로해서 응답이 왔을 때 기본적으로 모든 것이 문자열 (생긴게 json이라면) => javascript 오브젝트로 변환
		}).done(function(resp) {
			alert('회원가입이 완료되었습니다.');
//			console.log(resp);
			location.href = '/blog';
		}).fail(function(error) {
			alert(JSON.stringify(error));
		}); 
	}
}

index.init();

 

- ajax를 통한 회원가입 요청하기

위에서 jquery 라이브러리의 ajax를 통해 서버쪽으로 회원가입 서비스를 호출합니다.

이때 송신하는 데이터에 대해서는 json형태로 하여 보내주며, contentType도 작성 된 내용과 같이 작성합니다.

또한, response에 대해 dataType을 json으로 받겠다고 명시합니다.

(강의 내용 중 jquery버전 상승으로 인해 dataType을 명시하지 않아도 자동적으로 object형태로 변환해줍니다.)

 

- UserApiController.java 생성

package com.cos.blog.controller.api;

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.cos.blog.dto.ResponseDto;
import com.cos.blog.model.User;

@RestController
public class UserApiController {

	@PostMapping("/api/user")
	public ResponseDto<Integer> save(@RequestBody User user) {
		
		return new ResponseDto<Integer>(HttpStatus.OK, 1);
	}
}

 

데이터를 반환하기때문에 RestContorller 어노테이션을 선언했으며, save메소드에 대해 반환타입은 ResponseDto<Integer>로 했습니다.

 

- ResponseDto.java

package com.cos.blog.dto;

import org.springframework.http.HttpStatus;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

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

ResponseDto는 Generic 파라미터를 받아 처리하게 하였습니다.

Generic에 대한 자세한 설명은 아래 링크를 참고하세요.

https://jehuipark.github.io/java/java-generic

 

[JAVA] 제네릭(Generic)이란

List<Interger> list1 = new ArrayList<>();List list2 = new ArrayList<>();Map<String, String> map = new ArrayList<>();

jehuipark.github.io

 

 

 

 

강의 주소 : https://youtu.be/809058DGUPo

2. 비동기 통신을 하기 위해서이다.

 

 

강의 주소 : https://youtu.be/2PMMQHok3U4

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

 

 

강의 주소 : https://youtu.be/2PMMQHok3U4

Header, Footer와 같이 공통되는 영역에 대해서는 중복되는 코드를 줄이게 위해 아래와 같이 layout으로 설정합니다.

 

1. 기존에 작성되었던 index.jsp에서 스크립트 태그를 body 가장 하단에 위치시켜줍니다.

2. header.jsp로 아래의 내용을 복사해줍니다.

<!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">
</head>
<body>
	<nav class="navbar navbar-expand-md bg-dark navbar-dark">
		<a class="navbar-brand" href="/blog">Ukss</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="/user/login">로그인</a>
				</li>
				<li class="nav-item"><a class="nav-link" href="/user/join">회원가입</a>
				</li>
			</ul>
		</div>
	</nav>
	<br />

3. footer.jsp로 아래의 내용을 복사해줍니다.

	<br/>
	<div class="jumbotron text-center" style="margin-bottom: 0">
		<p>Created by Ukss</p>
		<p>📞 010-1234-1234</p>
		<p>🏴 서울시 강남구 테헤란로</p>
	</div>

<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></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>
</body>
</html>

4. index.jsp로 다시 돌아와 header.jsp, footer.jsp 파일들을 include 해줍니다.

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

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

	<div class="container">
	
		<div class="card m-2">
			<div class="card-body">
				<h4 class="card-title">제목 적는 부분</h4>
				<p class="card-text">내용 적는 부분</p>
				<a href="#" class="btn btn-primary">상세보기</a> 
			</div>
		</div>
		
	</div>
<%@ include file="layout/footer.jsp" %>

 

이제, 로그인화면과 회원가입 화면을 만들어줍니다.

이를 위해 UserController를 아래와 같이 작성합니다.

package com.cos.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";
	}

}

 

로그인(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">
		<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="password">Password</label> <input type="password" class="form-control" placeholder="Enter password" id="password">
		</div>
		<div class="form-group form-check">
			<label class="form-check-label"> <input class="form-check-input" type="checkbox"> Remember me
			</label>
		</div>
		<button type="submit" class="btn btn-primary">로그인</button>
	</form>
</div>
<%@ include file="../layout/footer.jsp"%>

 

 

회원가입(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">
		<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="password">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"%>

 

 

 

 

 

강의 주소 : https://youtu.be/7uz311JqQKI

1. blog package 하위에 controller package를 생성 후 아래의 클래스를 생성합니다.

- UserController.java

- BoardController.java

 

2. src/main/webapp/WEB-INF/views/ 하위에 아래의 jsp를 생성합니다.

- index.jsp

<%@ 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://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></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">Ukss</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="/user/login">로그인</a>
				</li>
				<li class="nav-item"><a class="nav-link" href="/user/join">회원가입</a>
				</li>
			</ul>
		</div>
	</nav>
	<br>

	<div class="container">
	
		<div class="card m-2">
			<div class="card-body">
				<h4 class="card-title">제목 적는 부분</h4>
				<p class="card-text">내용 적는 부분</p>
				<a href="#" class="btn btn-primary">상세보기</a>
			</div>
		</div>
		
	</div>
	
	<div class="jumbotron text-center" style="margin-bottom: 0">
		<p>Created by Ukss</p>
		<p>📞 010-1234-1234</p>
		<p>🏴 서울시 강남구 테헤란로</p>
	</div>

</body>
</html>

 

 

기본적인 HTML 구조를 완성합니다.

 

 

강의 주소 : https://youtu.be/f2IXBWi_8sA

1. Get요청(select)

http://localhost:8000/blog/user?username=ssar

특징 : body로 데이터를 담아 보내지 않습니다.

 

2. Post, Put, Delete 요청(데이터를 변경)

- 데이터를 담아 보내야 할 것이 많음.

- username, password, email, address, gender, createDate

- form 태그 method='Post'

- form 태그 -> get요청, post요청 (key=value)

- 자바스크립트로 요청을 해야함.

 

통일 : 자바스크립트로 ajax요청 + 데이터는 json으로 통일!! - 사용O

form:form 태그 -> post요청, put요청, delete요청, get요청 가능 - 사용X

 

3. 오브젝트로 데이터 받기

post방식의 key=value (x-www-form-urlencoded)

username=ssar

password=1234

오브젝트에 없는 key로는 값을 받을 수 없습니다.(없는 key를 보낸다고해서 오류가 나지는 않습니다.)

 

 

강의 주소 : https://youtu.be/gt17FdIl-3w

@ControllerAdvice
@RestController
public class GlobalExceptionHandler {

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

@ControllerAdvice : 모든 Exception에 대해 수렴되게 하는 어노테이션입니다.

@ExceptionHandler(value=Exception.class) : Exception의 종류를 선언하여, 해당 Exception에 대해서 받을 수 있습니다.

 

 

 

강의 주소 : https://youtu.be/qYxWWWVpJkA

@DeleteMapping("/dummy/user/{id}")
public String delete(@PathVariable int id) {
    try {
        userRepository.deleteById(id);
    } catch (EmptyResultDataAccessException e) {
        return "삭제에 실패하였습니다. 해당 id는 DB에 없습니다.";
    }

    return "삭제되었습니다. id : " + id;
}

deleteById는 void 반환타입이여서 try catch를 이용하여 예외처리를 잡아줍니다.

 

 

강의 주소 : https://youtu.be/vOXgQYX7nok

더티체킹

 

- 영속화 되었다 : Request에 의해 Controller에서 User객체를 Save 할때 JPA내의 영속성 컨텍스트내의 1차캐시에 해당 객체가 생성되는것을 말합니다.

 

- flush : 영속화 된 객체를 DB에 밀어넣는 행위를 말합니다.(버퍼를 비운다라고 말합니다.)

간단한 예로 어떤 창고에 있는 물건들을 더 큰 창고로 옮기는 행위라고 말 할 수 있습니다.

 

특징으로 flush긴 flush지만 이때 1차캐시에 있는 객체를 지우지는 않습니다.

 

- 더티체킹의 동작원리

메소드 상단에 Transactional 어노테이션을 선언한 이후, 2번 id를 가진 객체를 update를 하고 싶어 호출하였다고 가정합니다. 그러면, DB에서 2번 id를 가진 데이터를 JPA  영속성 컨텍스트에 객체를 영속화를 시키며, 컨트롤러의 user객체에 영속화 된 객체를 넣습니다.

이후, 컨트롤러의 user 객체의 값을 변경하고 해당 메소드가 끝나게 되면 영속성 컨텍스트 내의 user 객체와의 차이를 판단하여 자동으로 commit을 합니다.

 

 

해당 강의에 대한 자세한 설명은 강의 하단 댓글에 잘 정리되어있습니다. 참고하시면 좋을 듯 합니다.

 

 

강의 주소 : https://youtu.be/dDsI1J4QC6g

+ Recent posts