SPRING email 전송

https://mvnrepository.com/ - spring context support 검색 - 첫번째 클릭 

- 아무버전 클릭 - maven 내용 복사 - pom.xml 붙여넣기(${org.springframework-version})

 

https://mvnrepository.com/ - javax 검색 - 첫번째 클릭 

- 1.5.4 버전 클릭 - maven 내용 복사 - pom.xml 붙여넣기

 

https://mvnrepository.com/ - javax 검색 - 세번째 클릭 

- 1.5.3 버전 클릭 - maven 내용 복사 - pom.xml 붙여넣기

 

* google 로그인 - 계정 관리 - 보안 - 2단계 인증 완료  

 

config관련 mail클래스 생성 - 

 

mailController 생성 - 

 

mail Service 생성 - 

 

https://myaccount.google.com/apppasswords - 계정 입력 - 받은 비밀번호 복사 

- config 파일의 .setPassword("붙여넣기")

 

* StringBuffer : 해당 객체는 지우고 새롭게 만드는 것이 아니라, 계속 유지된다.

 

* .setText(body, true) : 텍스트 형식 말고 html형식으로 보내는 방법

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING email 인증

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<c:if test="${ userId == null }">
		<form action="auth">
			<input type="text" name="email"><br>
			<input type="submit" value="이메일 인증">
		</form>
	</c:if>
	<c:if test="${ userId != null }">
		<h3>${userId }님 이메일 인증되었음!!</h3>	
	</c:if>
</body>
</html>
package com.care.root.controller;

import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.care.root.service.MailServiceImpl;

@Controller
public class MailController {
	@Autowired MailServiceImpl ms;
	@GetMapping("sendmail")
	public void sendMail(HttpServletRequest req,
					HttpServletResponse res) throws Exception{
		req.setCharacterEncoding("utf-8");
		res.setContentType("text/html; charset=utf-8");
		PrintWriter out = res.getWriter();
		
		ms.sendMail("xodud5080@gmail.com", "제목 : 테스트", "내용 : 안녕");
		
		out.print("메일을 보냈습니다");
	}
	
	@GetMapping("sendmail02")
	public void sendMail02(HttpServletRequest req,
			HttpServletResponse res) throws Exception{
		req.setCharacterEncoding("utf-8");
		res.setContentType("text/html; charset=utf-8");
		PrintWriter out = res.getWriter();
		
		StringBuffer body = new StringBuffer();
		body.append("<html><body>");
		body.append("<h1>제품 소개</h1>");
		body.append("<a href='https://www.naver.com/'>");
		body.append("<img alt='' src='https://search.pstatic.net/common/?src=http%3A%2F%2Fblogfiles.naver.net%2FMjAyNDAxMDRfMjMw%2FMDAxNzA0MzczODA3MTcz.SA2hQyKDRrje6lKrEnljRYPIsiByFlwzXv9fc5clJ9cg.qP2m0LDx9XqYJSJX5hrL73baolQe-8cwpsJr3fF4D40g.JPEG.uiuiui2200%2FIMG_9283.jpg&type=a340'>");
		body.append("</a>");
		body.append("</body></html>");
		
		ms.sendMail02("xodud5080@gmail.com", "제목 : 푸바오", body.toString());
		
		out.print("메일을 보냈습니다");
	}
	
	@GetMapping("auth_form")
	public String authForm() {
		return "auth";
	}
	
	@GetMapping("auth")
	public String auth(HttpServletRequest req) {
		ms.auth(req);
		return "redirect:http://www.google.com";
	}
	@GetMapping("auth_check")
	public String authCheck(@RequestParam String userId, 
					HttpSession session) {
		String userKey = (String)session.getAttribute("xodud5080@gmail.com");
		if (userKey.equals(userId)) {
			session.setAttribute("userId", "xodud5080");
			System.out.println("userId : " + session.getAttribute("userId"));
		}
		return "redirect:auth_form";
	}
}
package com.care.root.service;

import java.util.Random;

import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

@Service
public class MailServiceImpl {

	@Autowired JavaMailSender sender;
	public void sendMail(String to, String subject, String body) {
		MimeMessage messasge = sender.createMimeMessage(); // 보내는 형식 지정
		try {
			MimeMessageHelper h = new MimeMessageHelper(messasge, true, "UTF-8");
			// true = multipart로 사용하겠다는 의미
			h.setSubject(subject);
			h.setTo(to);
			h.setText(body);
			sender.send(messasge); // 메일 전송
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void sendMail02(String to, String subject, String body) {
		MimeMessage messasge = sender.createMimeMessage(); // 보내는 형식 지정
		try {
			MimeMessageHelper h = new MimeMessageHelper(messasge, true, "UTF-8");
			// true = multipart로 사용하겠다는 의미
			h.setSubject(subject);
			h.setTo(to);
			h.setText(body, true); // 텍스트 형식이 아니라고 명시
			sender.send(messasge); // 메일 전송
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private String rand() {
		Random ran = new Random();
		String str = "";
		int num;
		while(str.length() != 20) {
			num = ran.nextInt(75) + 48; // (0 ~ 75) + 48 = 48 ~ 122
			if ((num >= 48 && num <= 57) || (num >= 65 && num <= 90) || (num >= 97 && num <= 122)) {
				str += (char)num;
			}
		}
		return str;
	}
	public void auth(HttpServletRequest req) {
		HttpSession session = req.getSession();
		String userId = req.getParameter("email");
		String userKey = rand();
		session.setAttribute(userId, userKey);
		System.out.println("userId1 : " + session.getAttribute(userId));
		String body = "<h3>이메일 인증</h3>"
					+ "<a href='http://localhost:8080/root/auth_check?userId="+userKey+"'>인증하기</a>";
		sendMail02(userId, "이메일 인증", body);
	}
}

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING scheduler

scheduler : 지정한 시간대가 되면 동작하게 하는 것(예약)

scheduler 관련  config  클래스 생성

* @EnableScheduling, @Scheduled(cron = "시간 설정") 작성 

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING ajax (데이터 주고 받기)

ajax를 사용 안할 때

 

ajax를 사용 할 때

ajax 쓰는 이유 : 페이지를 새로고침 하지 않아, 처리속도가 더 빠르다

* <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> : jquery 라이브러리 가져오기

@ResponseBody : return에 값을 명시해도, jsp파일을 찾아가지 않고 데이터를 돌려준다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING data 전송 방식(json)

https://mvnrepository.com/ - jackson databind 검색 - 첫번째 클릭 

- 2.9.5 버전 클릭 - maven 내용 복사 - pom.xml 붙여넣기

JSON.stringify("데이터") : 해당 데이터를 json형식으로 변환

보내는 방식(type) : contentType

받는 방식(type) : dataType

* json형식으로 넘어오는 값은 @RequestBody형식으로 받는다

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
	function test() {
		let n = document.getElementById("name").value;
		let a = $("#age").val();
		let form = {name : n, age : a};
		$.ajax({
			url : "result03", type : "post",
			data : JSON.stringify(form), 
			dataType : "json",
			contentType : "application/json; charset=utf-8",
			success : (result) => {
				console.log(result);
				$("#result").html("name : " + result.name+ ", age : " + result.age)
			},
			error : () => {
				console.log("문제 발생!!!");
			}
		})
	}
</script>
</head>
<body>
	<input type="text" id="name"><br>
	<input type="text" id="age"><br>
	<input type="button" value="click" onclick="test()"><br>
	결과 : <span id="result"></span>
</body>
</html>
package com.care.root;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
	
	/**
	 * Simply selects the home view to render by returning its name.
	 */
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		logger.info("Welcome home! The client locale is {}.", locale);
		
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
		
		String formattedDate = dateFormat.format(date);
		
		model.addAttribute("serverTime", formattedDate );
		
		return "home";
	}
	
	@GetMapping("ajax03")
	public String ajax03() {
		System.out.println("ajax03");
		return "ajax03";
	}
	
	@PostMapping(value = "result03", produces = "application/json; charset=utf-8")
	@ResponseBody
	public InfoDTO result03(@RequestBody InfoDTO dto) {
		System.out.println("result03");
		System.out.println("dto.name" + dto.getName());
		System.out.println("dto.age" + dto.getAge());
//		System.out.println("map.name" + map.get("name"));
//		System.out.println("map.age" + map.get("age"));
		
		return dto;
	}
}

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING RestController

@RestController : jsp페이지 대신, data를 return으로 돌려주는 controller이다

* @ResponseBody를 쓸 필요가 없어진다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
	function getFunc() {
		$.ajax({
			url : "rest", type : "get", dataType : "json", 
			success : function (result) {
				$("#span").html(result.result);
			}, error : function () {
				alert("문제 발생!!!");
			}
		})
	}
	
	function postFunc() {
		$.ajax({
			url : "rest", type : "post", dataType : "json", 
			success : function (result) {
				$("#span").html(result.result);
			}, error : function () {
				alert("문제 발생!!!");
			}
		})
	}
	
	function putFunc() {
		$.ajax({
			url : "rest", type : "put", dataType : "json", 
			success : function (result) {
				$("#span").html(result.result);
			}, error : function () {
				alert("문제 발생!!!");
			}
		})
	}
	
	function deleteFunc() {
		$.ajax({
			url : "rest", type : "delete", dataType : "json", 
			success : function (result) {
				$("#span").html(result.result);
			}, error : function () {
				alert("문제 발생!!!");
			}
		})
	}
	
</script>
</head>
<body>
	<span id="span"></span><hr>
	<button type="button" onclick="getFunc()">get 요청</button>
	<button type="button" onclick="postFunc()">post 요청</button>
	<button type="button" onclick="putFunc()">put 요청</button>
	<button type="button" onclick="deleteFunc()">delete 요청</button>
</body>
</html>
package com.care.root;

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
	
	@GetMapping(value="rest", produces = "application/json; charset=utf-8")
	public Map<String, Object> get() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", "get : 데이터 요청");
		return map;
	}
	
	@PostMapping(value="rest", produces = "application/json; charset=utf-8")
	public Map<String, Object> post() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", "post : 데이터 추가");
		return map;
	}
	
	@PutMapping(value="rest", produces = "application/json; charset=utf-8")
	public Map<String, Object> put() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", "put : 데이터 수정");
		return map;
	}
	
	@DeleteMapping(value="rest", produces = "application/json; charset=utf-8")
	public Map<String, Object> delete() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", "delete : 데이터 삭제");
		return map;
	}
}

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING SPA

SPA : 브라우저를 최초에 한번 로드하고, 이후부터는 특정 부분만 ajax를 통해 바인딩하는 방식

* 경로로 전송한 값은, controller에서 {}로 받고, 해당 클래스에서는 @ParhVariable로 받는다

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>안녕 페이지</h1>
	<hr>
		<a href="index">HOME</a>
		<span style="cursor: pointer;" onclick="members()">MEMBERS</span>
	<hr>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
	function members() {
		$.ajax({
			url : "members", type : "get", dataType : "json", 
			success : (list) => {
				console.log(list);
				console.log(list[0].id);
				let msg = "<table border='1'>";
				msg += "<tr><th>id</th><th>name</th><th>age</th></tr>"
				for(let i = 0; i < list.length; i++){
					msg += "<tr>";
					msg += "<td>" + list[i].id + "</td>";
					msg += "<td onclick='getMember(\"" + list[i].id + "\")'>" + list[i].name + "</td>";
					msg += "<td>" + list[i].age + "</td>";
					msg += "</tr>";
				}
				msg += "</table>";
				$("#content").html(msg);
			}
		});
	}
	function getMember(userId) {
		console.log(userId)
		$.ajax({
			url : "members/"+userId, type : "get", dataType : "json",
			success : (member) => {
				console.log(member);
				let msg = "id : " + member.id + "<br>";
				msg += "name : " + member.name + "<br>";
				msg += "age : " + member.age + "<br>";
				$("#content").html(msg);
			}
		});
	}
</script>
</head>
<body>	
	<%@ include file="header.jsp" %>
	<div id="content">
		<h3>기본 페이지 입니다 </h3>
	</div>
</body>
</html>
package com.care.root;

import java.util.ArrayList;

import org.springframework.stereotype.Component;

@Component
public class DBClass {
	ArrayList<InfoDTO> DB;
	public DBClass() {
		DB = new ArrayList<InfoDTO>();
		for (int i = 0; i < 3; i++) {
			InfoDTO dto = new InfoDTO();
			dto.setId("aaa" + i);
			dto.setName("홍길동" + i);
			dto.setAge(10+i);
			DB.add(dto);
		}
	}
}
package com.care.root;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
	
	@Autowired DBClass db;
	
	@GetMapping(value="members", produces = "application/json; charset=utf-8")
	public ArrayList<InfoDTO> members() {
		return db.DB;
	}
	
	@GetMapping(value="members/{uId}", produces = "application/json; charset=utf-8")
	public InfoDTO getMember(@PathVariable String uId) {
		//System.out.println("Asdfasd");
		for(InfoDTO d : db.DB) {
			System.out.println(d.getId().equals(uId));
			if (d.getId().equals(uId)) {
				System.out.println(d.getId());
				System.out.println(d.getName());
				return d;
			}
		}
		return null;
	}
}

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING SPA 활용

* serializeArray() : name을 키로 만들어서, 배열 형식으로 만들어준다

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
	function members() {
		$.ajax({
			url : "members", type : "get", dataType : "json", 
			success : (list) => {
				console.log(list);
				console.log(list[0].id);
				let msg = "<table border='1'>";
				msg += "<tr><th>id</th><th>name</th><th>age</th></tr>"
				for(let i = 0; i < list.length; i++){
					msg += "<tr>";
					msg += "<td>" + list[i].id + "</td>";
					msg += "<td onclick='getMember(\"" + list[i].id + "\")'>" + list[i].name + "</td>";
					msg += "<td>" + list[i].age + "</td>";
					msg += "</tr>";
				}
				msg += "</table>";
				$("#content").html(msg);
			}
		});
	}
	function getMember(userId) {
		console.log(userId)
		$.ajax({
			url : "members/"+userId, type : "get", dataType : "json",
			success : (member) => {
				console.log(member);
				let msg = "id : " + member.id + "<br>";
				msg += "name : " + member.name + "<br>";
				msg += "age : " + member.age + "<br>";
				msg += "<span onclick='del(\"" + member.id + "\")'>삭제</span>"
				msg += "<span onclick='modify_form(\"" + member.id + "\")'>수정</span>"
				$("#content").html(msg);
			}
		});
	}
	function del(userId) {
		$.ajax({
			url : "delete?id="+userId, type : "delete", 
			dataType : "json", 
			success : function (result) {
				if (result == 1) {
					alert("삭제 성공");
					members();
				}else{
					alert("문제 발생!!!");
				}
			}
		})
	}
	function modify_form(userId) {
		$.ajax({
			url : "members/"+userId, type : "get", dataType : "json",
			success : (member) => {
				let msg = '<form id="mo">';
				msg += '<input type="text" value="'+member.id+'" name="id" ><br>';
				msg += '<input type="text" value="'+member.name+'" name="name" ><br>';
				msg += '<input type="text" value="'+member.age+'"name="age" ><br>';
				msg += '<input type="button" onclick="modify()" value="수정"><br>';
				msg += '</form>';
				$("#content").html(msg);
			}
		});
	}
	function modify() {
		let form = {}
		let arr = $("#mo").serializeArray();
		console.log(arr);
		for(let i = 0; i < arr.length; i++){
			form[arr[i].name] = arr[i].value;
		}
		console.log(form);
		$.ajax({
			url : "modify", type : "put", dataType : "json",
			data : JSON.stringify(form),
			contentType : "application/json; charset=utf-8",
			success : function (result) {
				if (result == 1) {
					alert("수정 성공");
					getMembers(form.id);
				}
			}
		});
	}
	function checkId() {
		console.log($("#id").val());
		if ($("#id").val().length < 3) {
			$("#id_chk").html("길이가 짧습니다!!!!");
			return;
		}
		$.ajax({
			url : "idChk/"+$("#id").val(), type : "get", 
			dataType : "json", 
			success : function (data) {
				if (data == 0) {
					$("#id_chk").html("사용 가능한 아이디 입니다");
				}else{
					$("#id_chk").html("존재하는 아이디입니다!!")
				}
			}
		})
	}
	function register() {
		let msg = '<form id="fo">';
		msg += '<input type="text" id="id" name="id" oninput="checkId()" placeholder="id"><br>';
		msg += '<span id="id_chk">아이디 확인</span><br>'
		msg += '<input type="text" name="name" placeholder="name"><br>';
		msg += '<input type="text" name="age" placeholder="age"><br>';
		msg += '<input type="button" onclick="reg()" value="가입"><br>';
		msg += '</form>';
		$("#content").html(msg);
	}
	function reg() {
		//alert("가입 클릭");
		let form = {}
		let arr = $("#fo").serializeArray();
		console.log(arr);
		for(let i = 0; i < arr.length; i++){
			form[arr[i].name] = arr[i].value;
		}
		console.log(form);
		$.ajax({
			url : "register", type : "post", dataType : "json",
			data : JSON.stringify(form),
			contentType : "application/json; charset=utf-8",
			success : function (result) {
				if (result.num == 1) {
					alert("저장 성공");
					members();
				}
			}
		});
	}
</script>
</head>
<body>	

	<%@ include file="header.jsp" %>
	<div id="content">
		<h3>기본 페이지 입니다 </h3>
	</div>
</body>
</html>
package com.care.root;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import oracle.jdbc.proxy.annotation.Post;

@RestController
public class TestController {
	
	@GetMapping(value="rest", produces = "application/json; charset=utf-8")
	public Map<String, Object> get() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", "get : 데이터 요청");
		return map;
	}
	
	@PostMapping(value="rest", produces = "application/json; charset=utf-8")
	public Map<String, Object> post() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", "post : 데이터 추가");
		return map;
	}
	
	@PutMapping(value="rest", produces = "application/json; charset=utf-8")
	public Map<String, Object> put() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", "put : 데이터 수정");
		return map;
	}
	
	@DeleteMapping(value="rest", produces = "application/json; charset=utf-8")
	public Map<String, Object> delete() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", "delete : 데이터 삭제");
		return map;
	}
	
	@Autowired DBClass db;
	
	@GetMapping(value="members", produces = "application/json; charset=utf-8")
	public ArrayList<InfoDTO> members() {
		return db.DB;
	}
	
	@GetMapping(value="members/{uId}", produces = "application/json; charset=utf-8")
	public InfoDTO getMember(@PathVariable String uId) {
		//System.out.println("Asdfasd");
		for(InfoDTO d : db.DB) {
			System.out.println(d.getId().equals(uId));
			if (d.getId().equals(uId)) {
				System.out.println(d.getId());
				System.out.println(d.getName());
				return d;
			}
		}
		return null;
	}
	
	@PostMapping(value="register", produces = "application/json; charset=utf-8")
	public String register(@RequestBody InfoDTO dto) {
		db.DB.add(dto);
		return "{\"num\" : 1}";
	}
	@GetMapping(value="idChk/{uId}", produces = "application/json; charset=utf-8")
	public int idChk(@PathVariable String uId) {
		for(InfoDTO d : db.DB) {
			if (d.getId().equals(uId)) {
				return 1;
			}
		}
		return 0;
	}
	@DeleteMapping(value="delete", produces = "application/json; charset=utf-8")
	public int delete(@RequestParam String id) {
		for(int i = 0; i < db.DB.size(); i++) {
			if (db.DB.get(i).getId().equals(id)) {
				db.DB.remove(i);
			}
		}
		return 1;
	}
	@PutMapping(value="modify", produces = "application/json; charset=utf-8")
	public int modify(@RequestBody InfoDTO dto) {
		for(int i = 0; i < db.DB.size(); i++) {
			if (db.DB.get(i).getId().equals(dto.getId())) {
				db.DB.set(i, dto);
			}
		}
		return 1;
	}
}

 

실행 결과

 

 

 

 

 

 

 

SPRING 자동 로그인 (Interceptor & cookie)

* 자동 로그인을 체크하면, 다시 로그인 할 필요 없이 바로 로그인 가능

WebUtils.getCookie(request, "쿠키명"): 해당하는 쿠키를 가져온다

 

구조 

1. login.jsp에서 checkbox를 체크 하면 controller의 user_check로 (on 또는 null)값을 보내준다.

2. user_check 컨트롤러에서 받은 값을 로그인을 성공하면 넘겨줘야 하기 때문에, 

RedirectAttributes rs를 통해 rs.addAttribute("키", "밸류")로 값을 넘겨준다.

3. 로그인을 성공하면, redirect:successLogin으로 id와 check유무(on 또는 null) 를 가지고 이동한다.

4. successLogin 컨트롤러로 오게되면, 받아온 id값의 세션을 부여한다.

만약 check가 on일 경우, 받아온 id값의 쿠키를 부여한다.

그리고, db에 현재 회원의 check유무를 부여한다.

5. 그리고 쿠키가 있으면, 자동 로그인을 해야하기 때문에, pre Interceptor에 쿠키값을 가져온다.

만약 쿠키가 있을 경우, 해당 회원이 자동로그인 유무를 db를 통해 가져온다. 

만약 체크를 했을 경우, 세션을 부여한다.

6. 로그아웃 선택시, 쿠키를 지우고, db에 check유무를 "nan"으로 바꾸고, 세션을 삭제한다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%@ include file="/WEB-INF/views/default/header.jsp" %>
	<h3>login 페이지</h3>
	<form action="user_check" method="post">
		<input type="text" name="id"><br>
		<input type="text" name="pwd"><br>
		<input type="submit" value="로그인" ><br>
		<input id="auto" type="checkbox" name="autoLogin">
		<label for="auto">자동 로그인!!!</label>
	</form>
	<a href="register_form">회원가입</a>
	
</body>
</html>

package com.care.root.member.controller;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.care.root.common.SessionCommon;
import com.care.root.member.dto.MemberDTO;
import com.care.root.member.service.MemberService;
import com.care.root.mybatis.member.MemberMapper;

@Controller
@RequestMapping("member")
public class MemberController implements SessionCommon{
	@Autowired MemberService ms;
	
	@GetMapping("login")
	public String login(HttpSession session) {
		if (session.getAttribute(LOGIN) != null) {
			return "redirect:/index";
		}
		return "member/login";
	}
	@PostMapping("user_check")
	public String userCheck( @RequestParam String id,
						@RequestParam String pwd , 
						@RequestParam(required = false) String autoLogin,
						RedirectAttributes rs) {
		int result = ms.userCheck(id, pwd);
		if(result == 1) {
			rs.addAttribute("id", id );
			rs.addAttribute("autoLogin", autoLogin );
			return "redirect:successLogin";
		}
		return "redirect:login";
	}
	@GetMapping("successLogin")
	public String successLogin(@RequestParam String id,
						@RequestParam(required = false) String autoLogin,
								HttpSession session, 
								HttpServletResponse res) {
		session.setAttribute( LOGIN , id);//("loginUser", id)
		if (autoLogin != null) {
			int limitTime = 60*60*24*90; // 90일동안 자동로그인 유지
			Cookie cook = new Cookie("loginCookie", id);
			cook.setPath("/");
			cook.setMaxAge(limitTime);
			res.addCookie(cook);
			
			ms.keepLogin(id, autoLogin);
		}
		return "member/successLogin";
	}

	@GetMapping("logout")
	public String logout(HttpSession session, 
			@CookieValue(value="loginCookie", required=false) Cookie cook, 
			HttpServletResponse res) {
		if (cook != null) {
			cook.setMaxAge(0);
			cook.setPath("/");
			res.addCookie(cook);
			ms.keepLogin((String)session.getAttribute(LOGIN), "nan");
		}
		session.invalidate();
		
		return "redirect:login";
	}
	@GetMapping("memberInfo")
	public String memberInfo(Model model, HttpSession session) {
		ms.memberInfo( model );
		return "member/memberInfo";
	}
	@GetMapping("info")
	public String info(Model model, @RequestParam String id) {
		ms.info(model, id);
		return "member/info";
	}
	@GetMapping("register_form")
	public String registerForm() {
		return "member/register";
	}
	@PostMapping("register")
	public String register(MemberDTO dto, HttpServletRequest req) {
		String[] addrs = req.getParameterValues("addr");
		int result = ms.register(dto);
		
		if(result == 1) {
			return "redirect:login";
		}
		return "redirect:register_form";
	}
}
package com.care.root.interceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.util.WebUtils;

import com.care.root.common.SessionCommon;
import com.care.root.member.dto.MemberDTO;
import com.care.root.mybatis.member.MemberMapper;

public class AutoLogin extends HandlerInterceptorAdapter implements SessionCommon{
	
	@Autowired MemberMapper mapper;
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("auto login 실행");
		Cookie cook = WebUtils.getCookie(request, "loginCookie");
		System.out.println("cook : " + cook);
		if (cook != null) {
			MemberDTO dto = mapper.getData(cook.getValue());
			if (dto.getSessionId().equals("on")) {
				request.getSession().setAttribute(LOGIN, dto.getId());
			}
		}
		return true;
	}
}

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING  보안처리 (crosssitescripting XSS)

* 회원가입 하거나, db에 저장할때 javascript형식으로 저장하면, script 문법이 실행됨

이러한 공격(XSS)을 막기 위한 방법

 

받아온 데이터 안에 스크립트 문법이 있는지 없는지 체크

첫번째 방법

검증하고 싶은 값을 받아와서, 받아온값.replcae()를 통해 수정

 

 

두번째 방법

써있는대로 저장

 

lucy-xss-servlet-filter-rule.xml
0.00MB

 

위에 파일 복사 - src/main/resource에 붙여넣기

= 알아서 보안처리를 해준다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING file upload & download

https://mvnrepository.com/ - commons fileupload(파일 업로드) 검색 - 첫번째 클릭 

- 1.3.3버전 클릭 - maven내용 복사 - pom.xml 붙여넣기

 

https://mvnrepository.com/ - commons io(파일 입출력) 검색 - 첫번째 클릭 

- 2.4버전 클릭 - maven내용 복사 - pom.xml 붙여넣기

 

 bean 추가하는 두가지 방법

1. config에서 bean 추가 ( 이 방법을 선호!! )

 

2. servlet-context.xml에서 bean 추가

 

 

<input>태그의 text는 @RequestParam이라는 타입으로 받아온다

<input>태그의 file은 MultipartFile이라는 타입으로 받아온다

 

file을 받아오는 두가지 방법

1. 파라미터 MultipartFile file로 받아온다

2. 파라미터 MultipartHttpServletRequest mReq로 받아온 후, 

MultipartFile file = MReq.getFile("파일name")으로 받아온다

 

 

파일에 저장

public static final String IMG_REPO = "c:/spring" : 파일 저장 위치

SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss-"); : 시간 형식 지정
String sysFileName = format.format(new Date()) : 지정한 형식으로 현재 시간 저장

File saveFile = new File(IMG_REPO + "/" + sysFileName) 

file.transferTo(saveFile) : 해당하는 위치에 파일 저장

 

 

db에 파일 저장 

 

화면에 띄우기 및 다운로드

res.addHeader("Content-dispostion", attachment;fileName="+file); 

: Content-dispostion = 다운로드 형식, attachment;fileName="+file = 파일명을 붙여서 다운

File f = new File(FileServiceImpl.IMG_REPO + "/" + file) : 해당 파일을 저장할 위치 지정

FileInputStream in = new FileInputStream(f) : FileInputStream()을 이용하여, 파일의 내용을 읽어옴
FileCopyUtils.copy(in, res.getOutputStream()) : 불러온 내용을 복사하여, 클라이언트에게 전송

 

 

파일 삭제

 

 

 

 

 

 

 

 

 

INTELLIJ 홈 화면 추가

* welcome페이지를 만들었다고 해도, controller에 이미 같은경로가 만들어져 있으면, 우선순위에 밀린다

package hello.hellospring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

    @GetMapping("/")
    public String home() {
        return "home";
    }
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div class="container">
    <div>
        <h1>Hello Spring</h1>
        <p>회원 기능</p>
        <p>
            <a href="/members/new">회원 가입</a>
            <a href="/members">회원 목록</a>
        </p>
    </div>
</div> <!-- /container -->

</body>
</html>

 

실행 결과 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 등록

package hello.hellospring.controller;

import hello.hellospring.domain.Member;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class MemberController {

    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }

    @GetMapping("/members/new")
    public String createForm(){
        return "members/createMemberForm";
    }

    @PostMapping("/members/new")
    public String create(MemberForm form) {
        Member member = new Member();
        member.setName(form.getName());

        memberService.join(member);

        return "redirect:/";
    }
}
package hello.hellospring.controller;

public class MemberForm {
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div class="container">
    <form action="/members/new" method="post">
        <div class="form-group">
            <label for="name">이름</label>
            <input type="text" id="name" name="name" placeholder="이름을 입력하세요">
        </div>
        <button type="submit">등록</button>
    </form>
</div> <!-- /container -->
</body>
</html>

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 조회

package hello.hellospring.controller;

import hello.hellospring.domain.Member;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.List;

@Controller
public class MemberController {

    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }

    @GetMapping("/members/new")
    public String createForm(){
        return "members/createMemberForm";
    }

    @PostMapping("/members/new")
    public String create(MemberForm form) {
        Member member = new Member();
        member.setName(form.getName());

        memberService.join(member);

        return "redirect:/";
    }

    @GetMapping("/members")
    public String list(Model model){
        List<Member> members = memberService.findMembers();
        model.addAttribute("members", members);
        return "members/memberList";
    }
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div class="container">
    <div>
        <table>
            <thead>
            <tr>
                <th>#</th>
                <th>이름</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="member : ${members}">
                <td th:text="${member.id}"></td>
                <td th:text="${member.name}"></td>
            </tr>
            </tbody>
        </table>
    </div>
</div> <!-- /container -->
</body>
</html>

 

실행 결과

 

 

 

 

 

 

 

SPRING 비밀번호 암호화(db에 저장)

https://mvnrepository.com/ - spring security web 검색 - 첫번째꺼 클릭 

- 아무버전(최신 버전) 클릭 - maven 부분 복사 -

pom.xml 붙여넣기(버전을 스프링 버전에 맞게 ${org.springframework-version})

 

service쪽에서 BCryptPasswordEncoder en = new BCryptPasswordEncoder();

en.encode(암호화 할 변수) : 해당 변수가 암호화 된다

en.matches("비교할 변수", "암호화된 변수") : 암호화한 변수를 풀어서 비교하는 방법 (복호화)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING 다음 주소 api 사용

다음 주소 api 검색 - 해당하는 api 복사 - register.jsp에 붙여넣기

같은 name의 여러개의 값을 dto로 받아오면 ,(콤마)를 기준으로 한번에 받아온다

* split을 사용하여 ,(콤마)를 기준으로 잘라낼 수 있다.

 

같은 name의 여러개의 값을 req로 받아오려면, req.getParameterValues()로 받아온다 (배열 형식)

 

* 해당하는 api관련 script문은 resources폴더 안에서 따로 관리 (javascript 파일)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
<script type="text/javascript" src="<%= request.getContextPath() %>/resources/js/daumPost.js">
</script>
</head>
<body>
	<%@ include file="/WEB-INF/views/default/header.jsp" %>
	<h3> - 회 원 가 입 -</h3>
	<form action="register" method="post">
		<input type="text" name="id"><br>
		<input type="text" name="pwd"><br>
		<input type="text" id="addr1" name="addr" readonly placeholder="우편번호"><br>
		<input type="text" id="addr2" name="addr" readonly placeholder="주소"><br>
		<input type="text" id="addr3" name="addr" placeholder="상세주소">
		<button type="button" onclick="daumPost()">우편번호 검색</button><br>
		<input type="submit" value="가입"><br>
	</form>
</body>
</html>
function daumPost() {
    new daum.Postcode({
        oncomplete: function(data) {
            // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분입니다.
            // 예제를 참고하여 다양한 활용법을 확인해 보세요.
            console.log(data);
            console.log(data.userSelectedType)
            let addr = "";
            if (data.userSelectedType == "R") {
            	addr = data.roadAddress;
			}else{
            	addr = data.jibunAddress;
			}
            document.getElementById("addr1").value=data.zonecode;
            document.getElementById("addr2").value=addr;
            document.getElementById("addr3").focus();
        }
    }).open();
}
	@PostMapping("register")
	public String register(MemberDTO dto, HttpServletRequest req) {
		System.out.println("addr : " + dto.getAddr());
		String[] addrs = req.getParameterValues("addr");
		System.out.println(addrs[0]);
		System.out.println(addrs[1]);
		System.out.println(addrs[2]);
		int result = ms.register(dto);
		
		if(result == 1) {
			return "redirect:login";
		}
		return "redirect:register_form";
	}

 

실행 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SPRING Interceptor

* 컨트롤러 실행 전, 컨트롤러가 실행 후 처리할 게 있으면 Interceptor 사용

Filter : DispatcherServlet이 실행되기 전, web.xml 설정

Interceptor : DispatcherServlet이 실행된 후, spring-web.xml 설정

preHandle : 컨트롤러가 호출되기 전 실행

postHandle : 컨트롤러가 실행된 후 호출

 

Interceptor 사용 설정

해당 클래스에 extends HandlerInterceptorAdapter 상속을 받아야 Interceptor 사용 가능

(alt + shift + s) - Override/Implement Methods - postHandle, preHandle 체크 - ok

preHandle 실행 전, postHandle 컨트롤러 실행 후

* preHandle, postHandle메소드의 파라미터값 변경 불가

* return true : 해당 경로로 보내줌, return false : 해당 경로로 안 보내줌

 

Interceptor 빈 생성

servlet-context.xml - <beans:bean id="변수명" class="Interceptor클래스 위치" />

<interceptors><interceptor><mapping path="경로 지정" /><benas:ref bean="변수명" /></interceptor></interceptors>

* 초록색 : 같은 값

 

 

package com.care.root.interceptor;

import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.care.root.common.SessionCommon;

public class MemberInterceptor extends HandlerInterceptorAdapter implements SessionCommon{

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("index 실행 전 출력");
		HttpSession session = request.getSession();
		if (session.getAttribute(LOGIN) == null) {
			//response.sendRedirect("login");
			response.setContentType("text/html; charset=utf-8");
			PrintWriter out = response.getWriter();
			out.print("<script>alert('로그인 먼저 하세요');"
						+"location.href='login';</script>");
			return false;
		}
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("index 실행 후 동작");
	} 
}
	<beans:bean id="mi" class="com.care.root.interceptor.MemberInterceptor" />
	<interceptors>
		<interceptor>
			<mapping path="/member/memberInfo" />
			<mapping path="/member/info" />
			<beans:ref bean="mi" />
		</interceptor>
	</interceptors>

 

실행 결과

 

 

 

 

 

 

 

 

INTELLIJ 스프링 빈을 등록하는 방법 (컴포넌트 스캔과 자동 의존관계 설정)

* @Autowired를 한 객체는 @Service든 @Repository 등을 해줘야 한다

 

컴포넌트 스캔과 자동 의존관계 설정

: @Controller나 @Service등을 쓰는 방식 (해당하는 것들이 모두 컴포넌트이다, 싱글톤 형식)

*@Controller랑 @Service를 @Autowired로 연결해주는 형식

* 컴포넌트는 main메서드에 해당하는 패키지의 하위 패키지에서만 설정 가능

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 스프링 빈을 등록하는 방법 ( 자바 코드로 직접 스프링 빈 등록하기 )

자바 코드로 직접 등록

SpringConfig 클래스 생성 - @Configuration 작성 - @Bean 작성(SpringBean을 등록하겠다는 의미)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ DI

1. 생성자 주입(가장 좋다)

 

2. 필드 주입(세팅할 때, 변경이 힘들어 좋지 않다.)

 

3. Setter 주입(중간에 변경할 필요가 없지만, public으로 설정해야 한다)

(alt + insert) - setter - 생성 - 생성된 메소드에 @Autowried 작성

 

* 정형화된 것은 컴포넌트 스캔 사용, 정형화되지 않거나 구현 클래스를 변경해야 하면 스프링 빈 등록

 

 

 

 

 

 

 

 

 

INTELLIJ 비지니스 요구사항 정리

데이터 : 회원ID, 이름

기능 : 회원 등록, 조회

아직 데이터 저장소가 선정되지 않음

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 회원 도메인과 리포지토리 만들기

Optional : null일수도, 아닐수도 있는 객체를 감싸는 래퍼 클래스

Optional.ofNullable(객체명) : null인지 아닌지 모를 때 사용

 

store.values().stream()

.filter(member -> member.getName().equals(name))

.findAny();

: store의 values값을 반복문처럼 돌려서, 만약 .filter뒤쪽에 해당하는 값이 true일때만 필터링이 적용

finAny()는 하나라도 찾는것, 만약 찾으면 반환, 못찾으면 null값 반환

package hello.hellospring.domain;

public class Member {
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
}
package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import java.util.List;
import java.util.Optional;

public interface MemberRepository {
    Member save(Member member);
    Optional<Member> findById(Long id);
    Optional<Member> findByName(String name);
    List<Member> findAll();
}
package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import java.util.*;

public class MemoryMemberRepository implements MemberRepository {

    private static Map<Long, Member> store = new HashMap<>();
    private static long sequence = 0L;

    @Override
    public Member save(Member member) {
        member.setId(++sequence);
        store.put(member.getId(), member);
        return member;
    }
    @Override
    public Optional<Member> findById(Long id) {
       return Optional.ofNullable(store.get(id));
    }
    @Override
    public Optional<Member> findByName(String name) {
        return store.values().stream()
                   .filter(member -> member.getName().equals(name))
                   .findAny();
    }
    @Override
    public List<Member> findAll() {
        return new ArrayList<>(store.values());
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 회원 리포지토리 테스트 케이스 

* main메서드를 통해서 실행하면,  오래 걸리고 한번에 실행하기 어렵다

따라서, JUNIT을 통해 테스트를 한다

@Test : test실행이 가능하다

 

Assertions.assertThat(member).isEqualTo(result) : 만약 둘의 값이 같다면 ↓

 

값이 다르다면 ↓

 

* .get() : 해당 객체를 가져온다

 

* 아래와 같이 선택(alt + enter)하면, 

Assertions.assertThat(member).isEqualTo(result)를 assertThat(member).isEqualTo(result)으로 사용 가능

 

* test를 각 메소드에서 실행 시킬수도 있지만, 클래스에서 실행하면 전체 다 실행 가능하다.

* 테스트 순서는 보장되어 있지 않다

 

@AfterEach : 각 메소드의 테스트가 끝나면, @AfterEach 메소드를 호출한다.

해당하는 저장소를 clear하는 메소드를 만든후, @AfterEach에 해당하는 메소드에서 호출한다

* ↓아래에 해당하는 코드가, store를 clear하는 명령어 및 메소드이다.

 

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.*;

public class MemoryMemberRepositoryTest {

    MemoryMemberRepository repository = new MemoryMemberRepository();

    @AfterEach
    public void afterEach(){
        repository.clearStore();
    }

    @Test
    public void save(){
        Member member = new Member();
        member.setName("spring");

        repository.save(member);
        Member result = repository.findById(member.getId()).get();

        assertThat(member).isEqualTo(result);
        //Assertions.assertEquals(member, result);
    }

    @Test
    public void findByName(){
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        Member result = repository.findByName("spring1").get();

        assertThat(result).isEqualTo(member1);
    }

    @Test
    public void findAll(){
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        List<Member> result = repository.findAll();

        assertThat(result.size()).isEqualTo(2);
    }
}

 

실행 결과

정상적으로 test 실행

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 회원 서비스 개발

변수명.ifPresent(함수) : 변수의 값이 null이 아니면 함수 실행 (해당 변수가 Optional이여서 가능)

* (ctrl + t)를 통해 해당 기능 함수를 하나의 메소드로 묶어서 호출하는 형식으로 변환 가능

throw new IlligalStateException("어쩌고") : 해당 함수가 예외가 발생하였을 때, "어쩌고" 전송

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;

import java.util.List;
import java.util.Optional;

public class MemberService {
    private final MemberRepository memberRepository = new MemoryMemberRepository();

    public Long join(Member member){// 회원가입

        validateDuplicateMember(member);// 중복 회원 검증
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
            .ifPresent(m -> {
                 throw new IllegalStateException("이미 존재하는 회원입니다");
        });
    }
    public List<Member> findMembers() { // 전체 회원 조회
        return memberRepository.findAll();
    }

    public Optional<Member> findOne(Long memberId){
        return memberRepository.findById(memberId);
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 회원 서비스 테스트

 

(ctrl + shift + t) : 해당하는 클래스의 테스트 클래스를 자동으로 만들어주는 역할

 

* 왼쪽의 MemberService에서  (ctrl + shift + t)설정을 마치면 오른쪽에 클래스(MemberServieTest)클래스가 생성된다

* 테스트 클래스의 메소드 명을 한글로 써도 무관하다

 

* ctrl + alt + v : 해당하는 객체의 타입을 만들어서 지정해준다

왼쪽에서 오른쪽으로 변함

 

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;

import java.util.List;
import java.util.Optional;

public class MemberService {

    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }


    public Long join(Member member){// 회원가입

        validateDuplicateMember(member);// 중복 회원 검증
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
            .ifPresent(m -> {
                 throw new IllegalStateException("이미 존재하는 회원입니다");
        });
    }
    public List<Member> findMembers() { // 전체 회원 조회
        return memberRepository.findAll();
    }

    public Optional<Member> findOne(Long memberId){
        return memberRepository.findById(memberId);
    }
}
package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemoryMemberRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Optional;

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;

class MemberServiceTest {

    MemberService memberService;
    MemoryMemberRepository memberRepository;

    @BeforeEach
    public void beforeEach(){
        memberRepository = new MemoryMemberRepository();
        memberService = new MemberService(memberRepository);
    }

    @AfterEach
    public void afterEach(){
        memberRepository.clearStore();
    }

    @Test
    void 회원가입() {
        //given
        Member member = new Member();
        member.setName("spring");

        //when
        Long saveId = memberService.join(member);

        //then
        Member findMember = memberService.findOne(saveId).get(); //asdfasdfasd
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }

    @Test
    public void 중복_회원_예외(){
        Member member1 = new Member();
        member1.setName("sping");

        Member member2 = new Member();
        member2.setName("sping");

        memberService.join(member1);
        IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
        assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다");
//        try {
//            memberService.join(member2);
//            fail();
//        }catch (IllegalStateException e){
//            assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다");
//        }

    }

    @Test
    void findMembers() {
    }

    @Test
    void findOne() {
    }
}

 

 

 

 

 

 

 

 

 

INTELLIJ 정적 컨텐츠

정적 컨텐츠 : 웹브라우저에 그냥 내려주는 서비스, 변환하지 않고 넘겨준다

정적 컨텐츠 생성 위치 : src/main/resources/static/파일명(hello-static).html

해당 파일 경로 : localhost:8080/파일명(hello-static) .html

* 동작 원리 : 웹 브라우저에서 (hello-static).html의 경로를 요청 받으면, 먼저 컨트롤러에서 찾는다. 

해당 경로가 컨트롤러에 없으면,  src/main/resources/static/에서 찾는다.

<!DOCTYPE HTML>
<html>
<head>
    <title>static content</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
정적 컨텐츠 입니다.
</body>
</html>

 

실행 결과 

경로 확인

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ mvc & 템플릿 엔진

mvc, 템플릿 엔진 : 서버에서 html을 동적으로 바꿔서 내보내는 것, 변환 후 넘겨준다

* @RequestParam("아이디명") 타입 변수명 : req값을 넒겨 받는 용도

package hello.hellospring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class HelloController {

    @GetMapping("hello")
    public String hello(Model model){
        model.addAttribute("data", "hello!!");
        return "hello";
    }

    @GetMapping("hello-mvc")
    public String helloMvc(@RequestParam("name") String name, Model model){
        model.addAttribute("name", name);
        return "hello-template";
    }
}

 

실행 결과

경로 확인

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ api

api : json 구조로 클라이언트에게 전달하는 방식

@ResponseBody : HTTP body부분에 직접 넣겠다는 의미

따라서, 해당 페이지 페이지 소스를 보게 되면 보통 아래와 같이 html태그들이 보인다

 

하지만, @ResponseBody를 추가하게 되면 아래와 같이 html태그가 없다

 

 

json이란? key, value로 이루어진 구조

json형식 만드는법 : return 값을 html파일로 명시하지 않고, 보내고 싶은 데이터를 지정

위와 같이, 받아온 name을 getter setter를 통해 저장한 후 해당 객체를 보내준다.

 

실행 결과

json 형식 !!!

 

@Responsebody가 붙어있지 않으면, return을 통해  templates/html파일로 전달한다 (viewResolver 동작)

@ResponseBody 가 있으면, return값이 문자인 경우 문자 내용을 그대로 반환 (StringConverter 동작)

return값이 객체인 경우, default값으로 json형식으로 반환 (JsonConverter 동작)

 

 

 

 

 

 

 

 

INTELLIJ 기본 설정 및 실행

* gradle : 버전 설정, 라이브러리 땡겨옴

* 만약 실행(run)이 안될 경우, .idea를 삭제하고 다시 실행시켜본다.

해당 main이 실행이 되면

localhost:8080 검색 - 

위와 같이 뜨면 정상적으로 작동중.

 

* File - Settings - gradle 검색 - (Build and run using, Run tests using) intellij로 변경

이유 : gradle을 거치지 않아, 속도가 더 빠르다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 라이브러리

gradle 관련 라이브러리 등 확인 가능

* 실무에서는 system.out 대신 log를 사용한다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ view 환경 설정

* welcome 페이지 = domain(localhost:8080)만 입력했을 때 나오는 화면

* welcome 페이지 명 : html명은 반드시 index.html으로 설정해야 한다

* welcome 페이지 위치 : src/main/resources/static/index.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ controller

 

controller 설정 위치 : src/main/java/파일명(hello.hello-sping)/패키지(controller) 생성

해당 패키지 안에 클래스(HelloController) 생성

@Controller 및 @GetMapping 추가

 

해당하는 @GetMapping한 메소드 return한 내용은 src/main/resources/templates/파일명.html로 이동

* Thymeleaf는 템플릿 엔진으로, 동적으로 HTML파일을 처리하는데 사용

* 따라서 controller에서 받은 데이터를 처리해야 하므로 Thymeleaf를 사용

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

INTELLIJ 빌드 및 실행

 

* 빌드를 실행하기 전에는, 서버를 끄고 실행한다

빌드 실행 방법 : terminal창 이동 - 해당 프로젝트 위치로 이동(cd사용)

해당 프로젝트 위치에서 (./gradlew build) 명령어 실행

해당 브로젝트 위치/build 이동 - 해당 브로젝트 위치/build/libs 이동

ls를 통해 directoryf를 확인 - 마지막에 SNAPSHOT.jar가 포함된 Name 복사

해당 위치에서 (java -jav 붙여넣기) 명령어 실행 - 아래와 같이 화면 출력

- 해당 페이지가 뜨면, 서버도 정상적으로 실행 

* 만약 실행이 잘 안 될 경우, ./gradlew build 대신 ./gradlew clean build 실행

+ Recent posts