https://github.com/Moonseonhyeon/SpringBoot-blog/commits/master
DataSourceConfig.java 필요 없어서 삭제함!
TestController를 controller 패키지에 이름(IndexController)을 바꾼 뒤 넣고
패키지 생성
model
service
util
SQL에 만들어뒀던 테이블을 참고해서 model 작성
header와 footer 만들기
header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>zzz blog</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-md bg-dark navbar-dark">
<a class="navbar-brand" href="/blog/index.jsp">zzz blog</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="justify-content-between collapse navbar-collapse" id="collapsibleNavbar">
<ul class="navbar-nav">
<li class="nav-item"><a class="nav-link" href="#">로그인</a></li>
<li class="nav-item"><a class="nav-link" href="#">회원가입</a></li>
</ul>
</div>
</nav>
<br>
footer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<br/><br/>
<div class="jumbotron text-center" style="margin-bottom:0">
<p>Create by Cos 2020-05-29</p>
<p>🏴 부산 진구 중앙대로 708</p>
<p>📞 010-2222-8888</p>
</div>
</body>
</html>
index.jsp에 include한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="layout/header.jsp" %>
<h1>Index 페이지입니다.</h1>
</body>
</html>
<%@include file="layout/footer.jsp" %
jsp로 blog 만들었던 프로젝트에서 가져온다.
주소 설계 잘 해야한다.
로그인&회원가입 (지금은 라이브러리 미사용)
다음주부터 인터셉터, 시큐어리티를 배우게 되는데
주소 설계를 잘못하면 못하는게 user라는 데이터베이스 모델이 있는데
여기에 접근할때 필터링을 걸 수 있다.
/user/~
- 1번 유저의 정보를 보고 싶으면
(1. 인증(1번 유저의 정보를 보고 싶으면 로그인 되어있어야한다. ), 2. 권한(1번 유저만 볼 수 있어야 함))
- 1번 유저 수정(1번 인증, 2번 권한 필요함.)
- 1번 유저 삭제(1번 인증, 2번 권한 필요함.)
/auth/~ : 누구나 접근할 수 있는
- 2번 유저 Insert할 때는 무슨 권한도 필요없음.
- 2번 유저로 로그인 페이지 역시 무슨 권한도 필요 없음.
loginForm.jsp joinForm.jsp 만들었음.
form 태그로 요청안하고 ajax로 합니다. 그래서 변수명들 마다 id값을 model하고 맞춰서 적어주세요!
ajax하려면 js폴더를 정적인 static폴더 안에 만들어서 .js파일 만들자!
웹브라우저로 회원가입 요청을 할 것임.
요청할때 스프링서버한테 요청하지요.
요청시에 viewResolver가 관여하는 거면 html을 응답해주겠죠
안드로이드 한다면 서버쪽으로 서버안의 페이지 요청을 할 필요가 없어요. 스프링한테 물어볼 필요가 없음. Activity를 바꾸면 되니까.
리액트면 리액트서버(nodejs)한테 요청하는것임. 스프링한테 요청하는게 아니라 nodejs에게 요청. Nodejs가 react를 품고 있음.
안드로이드, 리액트 - Nodejs(React) - 스프링 서버
react : 싱글페이지 임. 다 ajax로 함.
form 태그로 요청 할 수 없음. 주소 요청으로 하면 get요청 빼고 post는 html을 return받는게 아니라 data를 반환 받을거고 예를 들어 1. 그래서 js에서 href.location.
form태그를 이용해서 요청하게 되면 안드로이드 같은 다른데에서 사용 할 수 없음.
->get 빼고
웹브라우저로 스프링서버에다가 요청할때
요청시 viewresolver가 html로 응답해줌
이러면 html 페이지가 나타나는데
회원가입 요청하면 회원가입을 돌려줌
스프링서버를 같이 쓴다는 가정하에 다른것들은
안드로이드로 - 서버에 요청할 필요 없이 액티비티를 전환하면 된다.
리액트 - 리액트서버(node.js)에 요청함 Node.js가 react를 품고 있다.
리액트는 SPA(Single Page Application)를 이용한다.
그러고나서 Spring server에 접근함
안드로이드나 리액트는 회원가입 페이지를 요청할 일 이 없다.
GET방식은 문제가 없는데
POST요청할때 문제가 된다.
response 해줄때 스프링 브라우저에서 html로 주게 되는데 이러면 안드로이드는 html을 모른다.
회원가입(post)로 요청시
응답할때 html이 아니라 data를 주면 된다.
그 data가 결과값인데 리턴 값으로 1을 주면
웹브라우저에서는 자바스크립트로 1이면
안드로이드는 결과값이 1이면 액티비티 전환
React는 Node.js에게 받으면 된다.
즉 응답할때 html으로 주면 서버를 각각 만들어야하는 문제때문이다.
결론은 data로 응답해주면 편하다.
form태그로 날리지 않을 거라서 <form>에 action="post"를 지우기.
arrow function 로 하면 this를 부모로 딱!
키=벨류로
모든 요청은 json으로 데이터 자바스크립트 요청한다. 그래야 협업도 하고 안드로이드랑 리액트도 연결할 수 있다.
<form>태그 안에 <button>은 기본으로 type속성 값이 submit인데 이렇게 안 할거라서 <button id="btn-login" type="button" >으로 적어야 한다.
joinForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<div class="container">
<form class="was-validated">
<div class="form-group">
<label for="username">Username:</label>
<button id="btn-username-check" type="button" class="btn btn-warning float-right" onclick="usernameCheck()">중복확인</button>
<input id="username" type="text" class="form-control" placeholder="Enter username" required>
<div class="valid-feedback">Valid.</div>
<div class="invalid-feedback">Please fill out this field.</div>
</div>
<div class="form-group">
<label for="pwd">Password:</label>
<input id="password" type="password" class="form-control" placeholder="Enter password" required>
<div class="valid-feedback">Valid.</div>
<div class="invalid-feedback">Please fill out this field.</div>
</div>
<div class="form-group">
<label for="email">Email:</label> <input id="email" type="email" class="form-control" placeholder="Enter Email"
required>
<div class="valid-feedback">Valid.</div>
<div class="invalid-feedback">Please fill out this field.</div>
</div>
<button id="btn-save" type="button" class="btn btn-primary">회원가입완료</button>
</form>
</div>
<!-- static은 /로 바로 찾아간다. -->
<script src="/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 class="was-validated">
<div class="form-group">
<label for="username">Username:</label> <input id="username" type="text" class="form-control"
placeholder="Enter username" required>
<div class="valid-feedback">Valid.</div>
<div class="invalid-feedback">Please fill out this field.</div>
</div>
<div class="form-group">
<label for="pwd">Password:</label> <input id="password" type="password" class="form-control"
placeholder="Enter password" required>
<div class="valid-feedback">Valid.</div>
<div class="invalid-feedback">Please fill out this field.</div>
</div>
<button id="btn-login" type="button" class="btn btn-primary">로그인</button>
</form>
</div>
<script src="/js/user.js"></script>
<%@ include file="../layout/footer.jsp"%>
GET방식을 제외한 모든 요청은 자바스크립트+JSON을 이용함
이렇게 사용하면 안드로이드랑 react때도 사용할 수 있음
web.xml에 필터로 Message Converter가 들어오는 타입 보니까 json이네 하고 자바로 바꿔주겠지. 하지만 보통 Message Converter는 key=value로 들어 올 것을 기대하고 파싱하려고 하고 있는데 ContentType을 읽어서 json이면 Message Converter를 Mapping해주는 컨버터로 바꿈! 이걸 jackson이 들고 있는 것 임.
UserController 생성
@ResponseBody와 @RequestBody를 붙이는 이유
ResponseBody는 응답을 html아니라 data로 하기 위해서
RequestBody를 붙여야 JSON data로 받을 수 있다. 안붙이면 x-www-form-urlencoded만 받을 수 있음
Spring에서는 web.xml에서 필터링을 하는데 스프링 필터를 등록(기본적으로 필터링해야될것)해두면
스프링필터에 ip 등등 많은데 그 중에서 MessageConverter는 기본적으로 key=value만 파싱하려고 대기있다.
@RequestBody를 걸면 컨텍트 타입을 확인하고 JSON을 보면 MessageConverter가 change함
(ex : 오브젝트 맵퍼=jackson) 자바오브젝트로 변경해줌
user.js
제이쿼리 ajax로 데이터를 주고 받을수도 있지만
fetch를 사용해도 된다.
ResponseEntity
ResponseEntity<?>
return new ResonseEntity<>("1", HttpStatus.OK);
1이라는 건 통신이 성공했는데 테이블에도 잘 들어갔다는 말임.
스프링에 들고 있는건 ResponseEntity<?>,return ResponseEntity<String>("1",HttpStatus.OK);
HttpStatus 컨트롤 클릭으로 들어가면 상태에따라서 숫자가 다르다.
스프링에서 ResponseEntity를 사용하지 않고 이해를 돕기 위해서 직접 만들었다.
스프링에서 주요 쓰이는 @어노테이션들
싱글톤 패턴으로 IoC하는 것, Controller는 특이하게 요청시마다 메모리(디스패쳐서블릿이 해준다)에 뜸
Controller, Repository, Configuration, Service, Component
RestController, Bean 등이 있다.
Controller는 ViewResolver가 관리해서 html만 return 하려고함
RestController는 4.0부터 나온것인데 특징은 데이터를 리턴함
Repository mapper가 대신 띄워주어서 생략가능함
Configuration 설정파일
Service 붙이면 IoC가 되니까 메모리에 뜨는데 누군가가 Service 호출하는순간 트랜잭션 시작
Bean 클래스에 못걸고 메소드에만 건다.
Service
@Transactional(readOnly = true)에 대한 설명
MYSQL
repeatableRead
commit된 걸 보게 하고 있음. 아래 UserService를 만들면서 로그인()가 @Transactional(readOnly = true)인데 설명해뒀다.
UserService
Exception Handler 개념을 배워야하며 간단한 어노테이션도 찾아봐야한다.
readOnly가 필요한 이유는 짧게 설명하면
처음에 SELECT 하고 로직 실행하다가 마지막에 SELECT 하는 경우가 있는데
만약 그 로직 도중에 다른곳에 의해서 값이 변경되었을경우 마지막에 SELECT를 하면
->ex) 5000과 10000은 임의로 정한 숫자
처음에 5000을 찾았다면 마지막에 10000을 찾을 수 있다.
그러면 로직이 전체적으로 망가지기 때문에 처음 찾았던 5000값을 이 로직을 하는 동안 유지하게 만들어준다.
->정합성 문제 , isolation
정합성 문제 때문에 select하는 거에도 @Transactional을 걸어주고 내 트랜잭션이 시작해서 끝날 때까지 undo를 보게 하는 것이 readOnly =true를 해주는 것임. 고립성! 고립시킴. 정확하게 하려고.
DB마다 commit된 걸 보게 정해져있기도 하고 undo를 보게 정해져있기도 하다. MYSQL은 repeatableRead.
회원가입
공통 리스폰스 dto
통신이 되면 무조건 done인데 저렇게 띄우는건 데이터베이스에도 정확하게 들어갔다는걸 알 수 있음
컨트롤러의 함수 끝에 request관련된 것들을 많이 넣을 수 있다.
DI하는 방법 2가지
1. @AutoWired로 전역에
2. 아니면 함수에 파라미터에서 적기
타이밍을 보면 이해할 수 있는 부분인데
Request가 session을 만들 수 있고
Request 객체는 요청시 만들어지고 Controller도 요청시 메모리에 띄워진다. 그래서 DI가 가능하고
Service나 Component 등은 처음에 실행 시 떠있기 때문에 타이밍상 session을 DI할 수 없다.
로그인
https://github.com/Moonseonhyeon/SpringBoot-blog/commit/4bb8b401d44b2775fdd47283ca1c41fec568028d
'Spring Boot' 카테고리의 다른 글
글쓰기/주소 설계/@Autowired DI하는 방법3가지 (0) | 2020.07.26 |
---|---|
InterceptorHandler (0) | 2020.07.24 |
송금 출금 앱 (0) | 2020.07.17 |
sts3 (0) | 2020.07.17 |
blog만들기 (0) | 2020.07.17 |